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 isEdge = ua.indexOf("edge") > -1,
61 isGecko = !isSafari && ua.indexOf("gecko") > -1,
62 isBorderBox = isIE && !isStrict,
63 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65 isLinux = (ua.indexOf("linux") != -1),
66 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67 isIOS = /iphone|ipad/.test(ua),
68 isAndroid = /android/.test(ua),
69 isTouch = (function() {
71 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72 window.addEventListener('touchstart', function __set_has_touch__ () {
74 window.removeEventListener('touchstart', __set_has_touch__);
76 return false; // no touch on chrome!?
78 document.createEvent("TouchEvent");
85 // remove css image flicker
88 document.execCommand("BackgroundImageCache", false, true);
94 * True if the browser is in strict mode
99 * True if the page is running over SSL
104 * True when the document is fully initialized and ready for action
109 * Turn on debugging output (currently only the factory uses this)
116 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
119 enableGarbageCollector : true,
122 * True to automatically purge event listeners after uncaching an element (defaults to false).
123 * Note: this only happens if enableGarbageCollector is true.
126 enableListenerCollection:false,
129 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130 * the IE insecure content warning (defaults to javascript:false).
133 SSL_SECURE_URL : "javascript:false",
136 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
140 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
142 emptyFn : function(){},
145 * Copies all the properties of config to obj if they don't already exist.
146 * @param {Object} obj The receiver of the properties
147 * @param {Object} config The source of the properties
148 * @return {Object} returns obj
150 applyIf : function(o, c){
153 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
160 * Applies event listeners to elements by selectors when the document is ready.
161 * The event name is specified with an @ suffix.
164 // add a listener for click on all anchors in element with id foo
165 '#foo a@click' : function(e, t){
169 // add the same listener to multiple selectors (separated by comma BEFORE the @)
170 '#foo a, #bar span.some-class@mouseover' : function(){
175 * @param {Object} obj The list of behaviors to apply
177 addBehaviors : function(o){
179 Roo.onReady(function(){
184 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
186 var parts = b.split('@');
187 if(parts[1]){ // for Object prototype breakers
190 cache[s] = Roo.select(s);
192 cache[s].on(parts[1], o[b]);
199 * Generates unique ids. If the element already has an id, it is unchanged
200 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202 * @return {String} The generated Id.
204 id : function(el, prefix){
205 prefix = prefix || "roo-gen";
207 var id = prefix + (++idSeed);
208 return el ? (el.id ? el.id : (el.id = id)) : id;
213 * Extends one class with another class and optionally overrides members with the passed literal. This class
214 * also adds the function "override()" to the class that can be used to override
215 * members on an instance.
216 * @param {Object} subclass The class inheriting the functionality
217 * @param {Object} superclass The class being extended
218 * @param {Object} overrides (optional) A literal with members
223 var io = function(o){
228 return function(sb, sp, overrides){
229 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
232 sb = function(){sp.apply(this, arguments);};
234 var F = function(){}, sbp, spp = sp.prototype;
236 sbp = sb.prototype = new F();
240 if(spp.constructor == Object.prototype.constructor){
245 sb.override = function(o){
249 Roo.override(sb, overrides);
255 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
257 Roo.override(MyClass, {
258 newMethod1: function(){
261 newMethod2: function(foo){
266 * @param {Object} origclass The class to override
267 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
268 * containing one or more methods.
271 override : function(origclass, overrides){
273 var p = origclass.prototype;
274 for(var method in overrides){
275 p[method] = overrides[method];
280 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
286 * @param {String} namespace1
287 * @param {String} namespace2
288 * @param {String} etc
291 namespace : function(){
292 var a=arguments, o=null, i, j, d, rt;
293 for (i=0; i<a.length; ++i) {
297 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298 for (j=1; j<d.length; ++j) {
299 o[d[j]]=o[d[j]] || {};
305 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
310 * @param {String} classname
311 * @param {String} namespace (optional)
315 factory : function(c, ns)
317 // no xtype, no ns or c.xns - or forced off by c.xns
318 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
321 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322 if (c.constructor == ns[c.xtype]) {// already created...
326 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327 var ret = new ns[c.xtype](c);
331 c.xns = false; // prevent recursion..
335 * Logs to console if it can.
337 * @param {String|Object} string
342 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
349 * 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.
353 urlEncode : function(o){
359 var ov = o[key], k = Roo.encodeURIComponent(key);
360 var type = typeof ov;
361 if(type == 'undefined'){
363 }else if(type != "function" && type != "object"){
364 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365 }else if(ov instanceof Array){
367 for(var i = 0, len = ov.length; i < len; i++) {
368 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
379 * Safe version of encodeURIComponent
380 * @param {String} data
384 encodeURIComponent : function (data)
387 return encodeURIComponent(data);
388 } catch(e) {} // should be an uri encode error.
390 if (data == '' || data == null){
393 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394 function nibble_to_hex(nibble){
395 var chars = '0123456789ABCDEF';
396 return chars.charAt(nibble);
398 data = data.toString();
400 for(var i=0; i<data.length; i++){
401 var c = data.charCodeAt(i);
402 var bs = new Array();
405 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408 bs[3] = 0x80 | (c & 0x3F);
409 }else if (c > 0x800){
411 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413 bs[2] = 0x80 | (c & 0x3F);
416 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417 bs[1] = 0x80 | (c & 0x3F);
422 for(var j=0; j<bs.length; j++){
424 var hex = nibble_to_hex((b & 0xF0) >>> 4)
425 + nibble_to_hex(b &0x0F);
434 * 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]}.
435 * @param {String} string
436 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437 * @return {Object} A literal with members
439 urlDecode : function(string, overwrite){
440 if(!string || !string.length){
444 var pairs = string.split('&');
445 var pair, name, value;
446 for(var i = 0, len = pairs.length; i < len; i++){
447 pair = pairs[i].split('=');
448 name = decodeURIComponent(pair[0]);
449 value = decodeURIComponent(pair[1]);
450 if(overwrite !== true){
451 if(typeof obj[name] == "undefined"){
453 }else if(typeof obj[name] == "string"){
454 obj[name] = [obj[name]];
455 obj[name].push(value);
457 obj[name].push(value);
467 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468 * passed array is not really an array, your function is called once with it.
469 * The supplied function is called with (Object item, Number index, Array allItems).
470 * @param {Array/NodeList/Mixed} array
471 * @param {Function} fn
472 * @param {Object} scope
474 each : function(array, fn, scope){
475 if(typeof array.length == "undefined" || typeof array == "string"){
478 for(var i = 0, len = array.length; i < len; i++){
479 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
484 combine : function(){
485 var as = arguments, l = as.length, r = [];
486 for(var i = 0; i < l; i++){
488 if(a instanceof Array){
490 }else if(a.length !== undefined && !a.substr){
491 r = r.concat(Array.prototype.slice.call(a, 0));
500 * Escapes the passed string for use in a regular expression
501 * @param {String} str
504 escapeRe : function(s) {
505 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
509 callback : function(cb, scope, args, delay){
510 if(typeof cb == "function"){
512 cb.defer(delay, scope, args || []);
514 cb.apply(scope, args || []);
520 * Return the dom node for the passed string (id), dom node, or Roo.Element
521 * @param {String/HTMLElement/Roo.Element} el
522 * @return HTMLElement
524 getDom : function(el){
528 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
532 * Shorthand for {@link Roo.ComponentMgr#get}
534 * @return Roo.Component
536 getCmp : function(id){
537 return Roo.ComponentMgr.get(id);
540 num : function(v, defaultValue){
541 if(typeof v != 'number'){
547 destroy : function(){
548 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
552 as.removeAllListeners();
556 if(typeof as.purgeListeners == 'function'){
559 if(typeof as.destroy == 'function'){
566 // inpired by a similar function in mootools library
568 * Returns the type of object that is passed in. If the object passed in is null or undefined it
569 * return false otherwise it returns one of the following values:<ul>
570 * <li><b>string</b>: If the object passed is a string</li>
571 * <li><b>number</b>: If the object passed is a number</li>
572 * <li><b>boolean</b>: If the object passed is a boolean value</li>
573 * <li><b>function</b>: If the object passed is a function reference</li>
574 * <li><b>object</b>: If the object passed is an object</li>
575 * <li><b>array</b>: If the object passed is an array</li>
576 * <li><b>regexp</b>: If the object passed is a regular expression</li>
577 * <li><b>element</b>: If the object passed is a DOM Element</li>
578 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581 * @param {Mixed} object
585 if(o === undefined || o === null){
592 if(t == 'object' && o.nodeName) {
594 case 1: return 'element';
595 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
598 if(t == 'object' || t == 'function') {
599 switch(o.constructor) {
600 case Array: return 'array';
601 case RegExp: return 'regexp';
603 if(typeof o.length == 'number' && typeof o.item == 'function') {
611 * Returns true if the passed value is null, undefined or an empty string (optional).
612 * @param {Mixed} value The value to test
613 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
616 isEmpty : function(v, allowBlank){
617 return v === null || v === undefined || (!allowBlank ? v === '' : false);
625 isFirefox : isFirefox,
637 isBorderBox : isBorderBox,
639 isWindows : isWindows,
647 isAndroid : isAndroid,
652 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653 * you may want to set this to true.
656 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
661 * Selects a single element as a Roo Element
662 * This is about as close as you can get to jQuery's $('do crazy stuff')
663 * @param {String} selector The selector/xpath query
664 * @param {Node} root (optional) The start of the query (defaults to document).
665 * @return {Roo.Element}
667 selectNode : function(selector, root)
669 var node = Roo.DomQuery.selectNode(selector,root);
670 return node ? Roo.get(node) : new Roo.Element(false);
678 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
679 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
682 "Roo.bootstrap.dash");
685 * Ext JS Library 1.1.1
686 * Copyright(c) 2006-2007, Ext JS, LLC.
688 * Originally Released Under LGPL - original licence link has changed is not relivant.
691 * <script type="text/javascript">
695 // wrappedn so fnCleanup is not in global scope...
697 function fnCleanUp() {
698 var p = Function.prototype;
699 delete p.createSequence;
701 delete p.createDelegate;
702 delete p.createCallback;
703 delete p.createInterceptor;
705 window.detachEvent("onunload", fnCleanUp);
707 window.attachEvent("onunload", fnCleanUp);
714 * These functions are available on every Function object (any JavaScript function).
716 Roo.apply(Function.prototype, {
718 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
719 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
720 * Will create a function that is bound to those 2 args.
721 * @return {Function} The new function
723 createCallback : function(/*args...*/){
724 // make args available, in function below
725 var args = arguments;
728 return method.apply(window, args);
733 * Creates a delegate (callback) that sets the scope to obj.
734 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
735 * Will create a function that is automatically scoped to this.
736 * @param {Object} obj (optional) The object for which the scope is set
737 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
738 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
739 * if a number the args are inserted at the specified position
740 * @return {Function} The new function
742 createDelegate : function(obj, args, appendArgs){
745 var callArgs = args || arguments;
746 if(appendArgs === true){
747 callArgs = Array.prototype.slice.call(arguments, 0);
748 callArgs = callArgs.concat(args);
749 }else if(typeof appendArgs == "number"){
750 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
751 var applyArgs = [appendArgs, 0].concat(args); // create method call params
752 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
754 return method.apply(obj || window, callArgs);
759 * Calls this function after the number of millseconds specified.
760 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
761 * @param {Object} obj (optional) The object for which the scope is set
762 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
763 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
764 * if a number the args are inserted at the specified position
765 * @return {Number} The timeout id that can be used with clearTimeout
767 defer : function(millis, obj, args, appendArgs){
768 var fn = this.createDelegate(obj, args, appendArgs);
770 return setTimeout(fn, millis);
776 * Create a combined function call sequence of the original function + the passed function.
777 * The resulting function returns the results of the original function.
778 * The passed fcn is called with the parameters of the original function
779 * @param {Function} fcn The function to sequence
780 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
781 * @return {Function} The new function
783 createSequence : function(fcn, scope){
784 if(typeof fcn != "function"){
789 var retval = method.apply(this || window, arguments);
790 fcn.apply(scope || this || window, arguments);
796 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
797 * The resulting function returns the results of the original function.
798 * The passed fcn is called with the parameters of the original function.
800 * @param {Function} fcn The function to call before the original
801 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
802 * @return {Function} The new function
804 createInterceptor : function(fcn, scope){
805 if(typeof fcn != "function"){
812 if(fcn.apply(scope || this || window, arguments) === false){
815 return method.apply(this || window, arguments);
821 * Ext JS Library 1.1.1
822 * Copyright(c) 2006-2007, Ext JS, LLC.
824 * Originally Released Under LGPL - original licence link has changed is not relivant.
827 * <script type="text/javascript">
830 Roo.applyIf(String, {
835 * Escapes the passed string for ' and \
836 * @param {String} string The string to escape
837 * @return {String} The escaped string
840 escape : function(string) {
841 return string.replace(/('|\\)/g, "\\$1");
845 * Pads the left side of a string with a specified character. This is especially useful
846 * for normalizing number and date strings. Example usage:
848 var s = String.leftPad('123', 5, '0');
849 // s now contains the string: '00123'
851 * @param {String} string The original string
852 * @param {Number} size The total length of the output string
853 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
854 * @return {String} The padded string
857 leftPad : function (val, size, ch) {
858 var result = new String(val);
859 if(ch === null || ch === undefined || ch === '') {
862 while (result.length < size) {
863 result = ch + result;
869 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
870 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
872 var cls = 'my-class', text = 'Some text';
873 var s = String.format('<div class="{0}">{1}</div>', cls, text);
874 // s now contains the string: '<div class="my-class">Some text</div>'
876 * @param {String} string The tokenized string to be formatted
877 * @param {String} value1 The value to replace token {0}
878 * @param {String} value2 Etc...
879 * @return {String} The formatted string
882 format : function(format){
883 var args = Array.prototype.slice.call(arguments, 1);
884 return format.replace(/\{(\d+)\}/g, function(m, i){
885 return Roo.util.Format.htmlEncode(args[i]);
893 * Utility function that allows you to easily switch a string between two alternating values. The passed value
894 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
895 * they are already different, the first value passed in is returned. Note that this method returns the new value
896 * but does not change the current string.
898 // alternate sort directions
899 sort = sort.toggle('ASC', 'DESC');
901 // instead of conditional logic:
902 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
904 * @param {String} value The value to compare to the current string
905 * @param {String} other The new value to use if the string already equals the first value passed in
906 * @return {String} The new value
909 String.prototype.toggle = function(value, other){
910 return this == value ? other : value;
915 * Remove invalid unicode characters from a string
917 * @return {String} The clean string
919 String.prototype.unicodeClean = function () {
920 return this.replace(/[\s\S]/g,
921 function(character) {
922 if (character.charCodeAt()< 256) {
926 encodeURIComponent(character);
937 * Ext JS Library 1.1.1
938 * Copyright(c) 2006-2007, Ext JS, LLC.
940 * Originally Released Under LGPL - original licence link has changed is not relivant.
943 * <script type="text/javascript">
949 Roo.applyIf(Number.prototype, {
951 * Checks whether or not the current number is within a desired range. If the number is already within the
952 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
953 * exceeded. Note that this method returns the constrained value but does not change the current number.
954 * @param {Number} min The minimum number in the range
955 * @param {Number} max The maximum number in the range
956 * @return {Number} The constrained value if outside the range, otherwise the current value
958 constrain : function(min, max){
959 return Math.min(Math.max(this, min), max);
963 * Ext JS Library 1.1.1
964 * Copyright(c) 2006-2007, Ext JS, LLC.
966 * Originally Released Under LGPL - original licence link has changed is not relivant.
969 * <script type="text/javascript">
974 Roo.applyIf(Array.prototype, {
977 * Checks whether or not the specified object exists in the array.
978 * @param {Object} o The object to check for
979 * @return {Number} The index of o in the array (or -1 if it is not found)
981 indexOf : function(o){
982 for (var i = 0, len = this.length; i < len; i++){
983 if(this[i] == o) { return i; }
989 * Removes the specified object from the array. If the object is not found nothing happens.
990 * @param {Object} o The object to remove
992 remove : function(o){
993 var index = this.indexOf(o);
995 this.splice(index, 1);
999 * Map (JS 1.6 compatibility)
1000 * @param {Function} function to call
1002 map : function(fun )
1004 var len = this.length >>> 0;
1005 if (typeof fun != "function") {
1006 throw new TypeError();
1008 var res = new Array(len);
1009 var thisp = arguments[1];
1010 for (var i = 0; i < len; i++)
1013 res[i] = fun.call(thisp, this[i], i, this);
1026 * Ext JS Library 1.1.1
1027 * Copyright(c) 2006-2007, Ext JS, LLC.
1029 * Originally Released Under LGPL - original licence link has changed is not relivant.
1032 * <script type="text/javascript">
1038 * The date parsing and format syntax is a subset of
1039 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1040 * supported will provide results equivalent to their PHP versions.
1042 * Following is the list of all currently supported formats:
1045 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1047 Format Output Description
1048 ------ ---------- --------------------------------------------------------------
1049 d 10 Day of the month, 2 digits with leading zeros
1050 D Wed A textual representation of a day, three letters
1051 j 10 Day of the month without leading zeros
1052 l Wednesday A full textual representation of the day of the week
1053 S th English ordinal day of month suffix, 2 chars (use with j)
1054 w 3 Numeric representation of the day of the week
1055 z 9 The julian date, or day of the year (0-365)
1056 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1057 F January A full textual representation of the month
1058 m 01 Numeric representation of a month, with leading zeros
1059 M Jan Month name abbreviation, three letters
1060 n 1 Numeric representation of a month, without leading zeros
1061 t 31 Number of days in the given month
1062 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1063 Y 2007 A full numeric representation of a year, 4 digits
1064 y 07 A two digit representation of a year
1065 a pm Lowercase Ante meridiem and Post meridiem
1066 A PM Uppercase Ante meridiem and Post meridiem
1067 g 3 12-hour format of an hour without leading zeros
1068 G 15 24-hour format of an hour without leading zeros
1069 h 03 12-hour format of an hour with leading zeros
1070 H 15 24-hour format of an hour with leading zeros
1071 i 05 Minutes with leading zeros
1072 s 01 Seconds, with leading zeros
1073 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1074 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1075 T CST Timezone setting of the machine running the code
1076 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1079 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1081 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1082 document.write(dt.format('Y-m-d')); //2007-01-10
1083 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1084 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
1087 * Here are some standard date/time patterns that you might find helpful. They
1088 * are not part of the source of Date.js, but to use them you can simply copy this
1089 * block of code into any script that is included after Date.js and they will also become
1090 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1093 ISO8601Long:"Y-m-d H:i:s",
1094 ISO8601Short:"Y-m-d",
1096 LongDate: "l, F d, Y",
1097 FullDateTime: "l, F d, Y g:i:s A",
1100 LongTime: "g:i:s A",
1101 SortableDateTime: "Y-m-d\\TH:i:s",
1102 UniversalSortableDateTime: "Y-m-d H:i:sO",
1109 var dt = new Date();
1110 document.write(dt.format(Date.patterns.ShortDate));
1115 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1116 * They generate precompiled functions from date formats instead of parsing and
1117 * processing the pattern every time you format a date. These functions are available
1118 * on every Date object (any javascript function).
1120 * The original article and download are here:
1121 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1128 Returns the number of milliseconds between this date and date
1129 @param {Date} date (optional) Defaults to now
1130 @return {Number} The diff in milliseconds
1131 @member Date getElapsed
1133 Date.prototype.getElapsed = function(date) {
1134 return Math.abs((date || new Date()).getTime()-this.getTime());
1136 // was in date file..
1140 Date.parseFunctions = {count:0};
1142 Date.parseRegexes = [];
1144 Date.formatFunctions = {count:0};
1147 Date.prototype.dateFormat = function(format) {
1148 if (Date.formatFunctions[format] == null) {
1149 Date.createNewFormat(format);
1151 var func = Date.formatFunctions[format];
1152 return this[func]();
1157 * Formats a date given the supplied format string
1158 * @param {String} format The format string
1159 * @return {String} The formatted date
1162 Date.prototype.format = Date.prototype.dateFormat;
1165 Date.createNewFormat = function(format) {
1166 var funcName = "format" + Date.formatFunctions.count++;
1167 Date.formatFunctions[format] = funcName;
1168 var code = "Date.prototype." + funcName + " = function(){return ";
1169 var special = false;
1171 for (var i = 0; i < format.length; ++i) {
1172 ch = format.charAt(i);
1173 if (!special && ch == "\\") {
1178 code += "'" + String.escape(ch) + "' + ";
1181 code += Date.getFormatCode(ch);
1184 /** eval:var:zzzzzzzzzzzzz */
1185 eval(code.substring(0, code.length - 3) + ";}");
1189 Date.getFormatCode = function(character) {
1190 switch (character) {
1192 return "String.leftPad(this.getDate(), 2, '0') + ";
1194 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1196 return "this.getDate() + ";
1198 return "Date.dayNames[this.getDay()] + ";
1200 return "this.getSuffix() + ";
1202 return "this.getDay() + ";
1204 return "this.getDayOfYear() + ";
1206 return "this.getWeekOfYear() + ";
1208 return "Date.monthNames[this.getMonth()] + ";
1210 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1212 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1214 return "(this.getMonth() + 1) + ";
1216 return "this.getDaysInMonth() + ";
1218 return "(this.isLeapYear() ? 1 : 0) + ";
1220 return "this.getFullYear() + ";
1222 return "('' + this.getFullYear()).substring(2, 4) + ";
1224 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1226 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1228 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1230 return "this.getHours() + ";
1232 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1234 return "String.leftPad(this.getHours(), 2, '0') + ";
1236 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1238 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1240 return "this.getGMTOffset() + ";
1242 return "this.getGMTColonOffset() + ";
1244 return "this.getTimezone() + ";
1246 return "(this.getTimezoneOffset() * -60) + ";
1248 return "'" + String.escape(character) + "' + ";
1253 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1254 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1255 * the date format that is not specified will default to the current date value for that part. Time parts can also
1256 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1257 * string or the parse operation will fail.
1260 //dt = Fri May 25 2007 (current date)
1261 var dt = new Date();
1263 //dt = Thu May 25 2006 (today's month/day in 2006)
1264 dt = Date.parseDate("2006", "Y");
1266 //dt = Sun Jan 15 2006 (all date parts specified)
1267 dt = Date.parseDate("2006-1-15", "Y-m-d");
1269 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1270 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1272 * @param {String} input The unparsed date as a string
1273 * @param {String} format The format the date is in
1274 * @return {Date} The parsed date
1277 Date.parseDate = function(input, format) {
1278 if (Date.parseFunctions[format] == null) {
1279 Date.createParser(format);
1281 var func = Date.parseFunctions[format];
1282 return Date[func](input);
1288 Date.createParser = function(format) {
1289 var funcName = "parse" + Date.parseFunctions.count++;
1290 var regexNum = Date.parseRegexes.length;
1291 var currentGroup = 1;
1292 Date.parseFunctions[format] = funcName;
1294 var code = "Date." + funcName + " = function(input){\n"
1295 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1296 + "var d = new Date();\n"
1297 + "y = d.getFullYear();\n"
1298 + "m = d.getMonth();\n"
1299 + "d = d.getDate();\n"
1300 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1301 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1302 + "if (results && results.length > 0) {";
1305 var special = false;
1307 for (var i = 0; i < format.length; ++i) {
1308 ch = format.charAt(i);
1309 if (!special && ch == "\\") {
1314 regex += String.escape(ch);
1317 var obj = Date.formatCodeToRegex(ch, currentGroup);
1318 currentGroup += obj.g;
1320 if (obj.g && obj.c) {
1326 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1327 + "{v = new Date(y, m, d, h, i, s);}\n"
1328 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1329 + "{v = new Date(y, m, d, h, i);}\n"
1330 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1331 + "{v = new Date(y, m, d, h);}\n"
1332 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1333 + "{v = new Date(y, m, d);}\n"
1334 + "else if (y >= 0 && m >= 0)\n"
1335 + "{v = new Date(y, m);}\n"
1336 + "else if (y >= 0)\n"
1337 + "{v = new Date(y);}\n"
1338 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1339 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1340 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1343 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1344 /** eval:var:zzzzzzzzzzzzz */
1349 Date.formatCodeToRegex = function(character, currentGroup) {
1350 switch (character) {
1354 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1357 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1358 s:"(\\d{1,2})"}; // day of month without leading zeroes
1361 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1362 s:"(\\d{2})"}; // day of month with leading zeroes
1366 s:"(?:" + Date.dayNames.join("|") + ")"};
1370 s:"(?:st|nd|rd|th)"};
1385 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1386 s:"(" + Date.monthNames.join("|") + ")"};
1389 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1390 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1393 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1394 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1397 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1398 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1409 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1413 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1414 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1418 c:"if (results[" + currentGroup + "] == 'am') {\n"
1419 + "if (h == 12) { h = 0; }\n"
1420 + "} else { if (h < 12) { h += 12; }}",
1424 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1425 + "if (h == 12) { h = 0; }\n"
1426 + "} else { if (h < 12) { h += 12; }}",
1431 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1432 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1436 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1437 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1440 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1444 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1449 "o = results[", currentGroup, "];\n",
1450 "var sn = o.substring(0,1);\n", // get + / - sign
1451 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1452 "var mn = o.substring(3,5) % 60;\n", // get minutes
1453 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1454 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1456 s:"([+\-]\\d{2,4})"};
1462 "o = results[", currentGroup, "];\n",
1463 "var sn = o.substring(0,1);\n",
1464 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1465 "var mn = o.substring(4,6) % 60;\n",
1466 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1467 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1473 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1476 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1477 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1478 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1482 s:String.escape(character)};
1487 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1488 * @return {String} The abbreviated timezone name (e.g. 'CST')
1490 Date.prototype.getTimezone = function() {
1491 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1495 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1496 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1498 Date.prototype.getGMTOffset = function() {
1499 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1500 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1501 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1505 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1506 * @return {String} 2-characters representing hours and 2-characters representing minutes
1507 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1509 Date.prototype.getGMTColonOffset = function() {
1510 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1511 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1513 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1517 * Get the numeric day number of the year, adjusted for leap year.
1518 * @return {Number} 0 through 364 (365 in leap years)
1520 Date.prototype.getDayOfYear = function() {
1522 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1523 for (var i = 0; i < this.getMonth(); ++i) {
1524 num += Date.daysInMonth[i];
1526 return num + this.getDate() - 1;
1530 * Get the string representation of the numeric week number of the year
1531 * (equivalent to the format specifier 'W').
1532 * @return {String} '00' through '52'
1534 Date.prototype.getWeekOfYear = function() {
1535 // Skip to Thursday of this week
1536 var now = this.getDayOfYear() + (4 - this.getDay());
1537 // Find the first Thursday of the year
1538 var jan1 = new Date(this.getFullYear(), 0, 1);
1539 var then = (7 - jan1.getDay() + 4);
1540 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1544 * Whether or not the current date is in a leap year.
1545 * @return {Boolean} True if the current date is in a leap year, else false
1547 Date.prototype.isLeapYear = function() {
1548 var year = this.getFullYear();
1549 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1553 * Get the first day of the current month, adjusted for leap year. The returned value
1554 * is the numeric day index within the week (0-6) which can be used in conjunction with
1555 * the {@link #monthNames} array to retrieve the textual day name.
1558 var dt = new Date('1/10/2007');
1559 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1561 * @return {Number} The day number (0-6)
1563 Date.prototype.getFirstDayOfMonth = function() {
1564 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1565 return (day < 0) ? (day + 7) : day;
1569 * Get the last day of the current month, adjusted for leap year. The returned value
1570 * is the numeric day index within the week (0-6) which can be used in conjunction with
1571 * the {@link #monthNames} array to retrieve the textual day name.
1574 var dt = new Date('1/10/2007');
1575 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1577 * @return {Number} The day number (0-6)
1579 Date.prototype.getLastDayOfMonth = function() {
1580 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1581 return (day < 0) ? (day + 7) : day;
1586 * Get the first date of this date's month
1589 Date.prototype.getFirstDateOfMonth = function() {
1590 return new Date(this.getFullYear(), this.getMonth(), 1);
1594 * Get the last date of this date's month
1597 Date.prototype.getLastDateOfMonth = function() {
1598 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1601 * Get the number of days in the current month, adjusted for leap year.
1602 * @return {Number} The number of days in the month
1604 Date.prototype.getDaysInMonth = function() {
1605 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1606 return Date.daysInMonth[this.getMonth()];
1610 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1611 * @return {String} 'st, 'nd', 'rd' or 'th'
1613 Date.prototype.getSuffix = function() {
1614 switch (this.getDate()) {
1631 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1634 * An array of textual month names.
1635 * Override these values for international dates, for example...
1636 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1655 * An array of textual day names.
1656 * Override these values for international dates, for example...
1657 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1673 Date.monthNumbers = {
1688 * Creates and returns a new Date instance with the exact same date value as the called instance.
1689 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1690 * variable will also be changed. When the intention is to create a new variable that will not
1691 * modify the original instance, you should create a clone.
1693 * Example of correctly cloning a date:
1696 var orig = new Date('10/1/2006');
1699 document.write(orig); //returns 'Thu Oct 05 2006'!
1702 var orig = new Date('10/1/2006');
1703 var copy = orig.clone();
1705 document.write(orig); //returns 'Thu Oct 01 2006'
1707 * @return {Date} The new Date instance
1709 Date.prototype.clone = function() {
1710 return new Date(this.getTime());
1714 * Clears any time information from this date
1715 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1716 @return {Date} this or the clone
1718 Date.prototype.clearTime = function(clone){
1720 return this.clone().clearTime();
1725 this.setMilliseconds(0);
1730 // safari setMonth is broken -- check that this is only donw once...
1731 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1732 Date.brokenSetMonth = Date.prototype.setMonth;
1733 Date.prototype.setMonth = function(num){
1735 var n = Math.ceil(-num);
1736 var back_year = Math.ceil(n/12);
1737 var month = (n % 12) ? 12 - n % 12 : 0 ;
1738 this.setFullYear(this.getFullYear() - back_year);
1739 return Date.brokenSetMonth.call(this, month);
1741 return Date.brokenSetMonth.apply(this, arguments);
1746 /** Date interval constant
1750 /** Date interval constant
1754 /** Date interval constant
1758 /** Date interval constant
1762 /** Date interval constant
1766 /** Date interval constant
1770 /** Date interval constant
1776 * Provides a convenient method of performing basic date arithmetic. This method
1777 * does not modify the Date instance being called - it creates and returns
1778 * a new Date instance containing the resulting date value.
1783 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1784 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1786 //Negative values will subtract correctly:
1787 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1788 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1790 //You can even chain several calls together in one line!
1791 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1792 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1795 * @param {String} interval A valid date interval enum value
1796 * @param {Number} value The amount to add to the current date
1797 * @return {Date} The new Date instance
1799 Date.prototype.add = function(interval, value){
1800 var d = this.clone();
1801 if (!interval || value === 0) { return d; }
1802 switch(interval.toLowerCase()){
1804 d.setMilliseconds(this.getMilliseconds() + value);
1807 d.setSeconds(this.getSeconds() + value);
1810 d.setMinutes(this.getMinutes() + value);
1813 d.setHours(this.getHours() + value);
1816 d.setDate(this.getDate() + value);
1819 var day = this.getDate();
1821 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1824 d.setMonth(this.getMonth() + value);
1827 d.setFullYear(this.getFullYear() + value);
1834 * Ext JS Library 1.1.1
1835 * Copyright(c) 2006-2007, Ext JS, LLC.
1837 * Originally Released Under LGPL - original licence link has changed is not relivant.
1840 * <script type="text/javascript">
1844 * @class Roo.lib.Dom
1847 * Dom utils (from YIU afaik)
1852 * Get the view width
1853 * @param {Boolean} full True will get the full document, otherwise it's the view width
1854 * @return {Number} The width
1857 getViewWidth : function(full) {
1858 return full ? this.getDocumentWidth() : this.getViewportWidth();
1861 * Get the view height
1862 * @param {Boolean} full True will get the full document, otherwise it's the view height
1863 * @return {Number} The height
1865 getViewHeight : function(full) {
1866 return full ? this.getDocumentHeight() : this.getViewportHeight();
1869 getDocumentHeight: function() {
1870 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1871 return Math.max(scrollHeight, this.getViewportHeight());
1874 getDocumentWidth: function() {
1875 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1876 return Math.max(scrollWidth, this.getViewportWidth());
1879 getViewportHeight: function() {
1880 var height = self.innerHeight;
1881 var mode = document.compatMode;
1883 if ((mode || Roo.isIE) && !Roo.isOpera) {
1884 height = (mode == "CSS1Compat") ?
1885 document.documentElement.clientHeight :
1886 document.body.clientHeight;
1892 getViewportWidth: function() {
1893 var width = self.innerWidth;
1894 var mode = document.compatMode;
1896 if (mode || Roo.isIE) {
1897 width = (mode == "CSS1Compat") ?
1898 document.documentElement.clientWidth :
1899 document.body.clientWidth;
1904 isAncestor : function(p, c) {
1911 if (p.contains && !Roo.isSafari) {
1912 return p.contains(c);
1913 } else if (p.compareDocumentPosition) {
1914 return !!(p.compareDocumentPosition(c) & 16);
1916 var parent = c.parentNode;
1921 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1924 parent = parent.parentNode;
1930 getRegion : function(el) {
1931 return Roo.lib.Region.getRegion(el);
1934 getY : function(el) {
1935 return this.getXY(el)[1];
1938 getX : function(el) {
1939 return this.getXY(el)[0];
1942 getXY : function(el) {
1943 var p, pe, b, scroll, bd = document.body;
1944 el = Roo.getDom(el);
1945 var fly = Roo.lib.AnimBase.fly;
1946 if (el.getBoundingClientRect) {
1947 b = el.getBoundingClientRect();
1948 scroll = fly(document).getScroll();
1949 return [b.left + scroll.left, b.top + scroll.top];
1955 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1962 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1969 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1970 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1977 if (p != el && pe.getStyle('overflow') != 'visible') {
1985 if (Roo.isSafari && hasAbsolute) {
1990 if (Roo.isGecko && !hasAbsolute) {
1992 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1993 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1997 while (p && p != bd) {
1998 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2010 setXY : function(el, xy) {
2011 el = Roo.fly(el, '_setXY');
2013 var pts = el.translatePoints(xy);
2014 if (xy[0] !== false) {
2015 el.dom.style.left = pts.left + "px";
2017 if (xy[1] !== false) {
2018 el.dom.style.top = pts.top + "px";
2022 setX : function(el, x) {
2023 this.setXY(el, [x, false]);
2026 setY : function(el, y) {
2027 this.setXY(el, [false, y]);
2031 * Portions of this file are based on pieces of Yahoo User Interface Library
2032 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2033 * YUI licensed under the BSD License:
2034 * http://developer.yahoo.net/yui/license.txt
2035 * <script type="text/javascript">
2039 Roo.lib.Event = function() {
2040 var loadComplete = false;
2042 var unloadListeners = [];
2044 var onAvailStack = [];
2046 var lastError = null;
2059 startInterval: function() {
2060 if (!this._interval) {
2062 var callback = function() {
2063 self._tryPreloadAttach();
2065 this._interval = setInterval(callback, this.POLL_INTERVAL);
2070 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2071 onAvailStack.push({ id: p_id,
2074 override: p_override,
2075 checkReady: false });
2077 retryCount = this.POLL_RETRYS;
2078 this.startInterval();
2082 addListener: function(el, eventName, fn) {
2083 el = Roo.getDom(el);
2088 if ("unload" == eventName) {
2089 unloadListeners[unloadListeners.length] =
2090 [el, eventName, fn];
2094 var wrappedFn = function(e) {
2095 return fn(Roo.lib.Event.getEvent(e));
2098 var li = [el, eventName, fn, wrappedFn];
2100 var index = listeners.length;
2101 listeners[index] = li;
2103 this.doAdd(el, eventName, wrappedFn, false);
2109 removeListener: function(el, eventName, fn) {
2112 el = Roo.getDom(el);
2115 return this.purgeElement(el, false, eventName);
2119 if ("unload" == eventName) {
2121 for (i = 0,len = unloadListeners.length; i < len; i++) {
2122 var li = unloadListeners[i];
2125 li[1] == eventName &&
2127 unloadListeners.splice(i, 1);
2135 var cacheItem = null;
2138 var index = arguments[3];
2140 if ("undefined" == typeof index) {
2141 index = this._getCacheIndex(el, eventName, fn);
2145 cacheItem = listeners[index];
2148 if (!el || !cacheItem) {
2152 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2154 delete listeners[index][this.WFN];
2155 delete listeners[index][this.FN];
2156 listeners.splice(index, 1);
2163 getTarget: function(ev, resolveTextNode) {
2164 ev = ev.browserEvent || ev;
2165 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2166 var t = ev.target || ev.srcElement;
2167 return this.resolveTextNode(t);
2171 resolveTextNode: function(node) {
2172 if (Roo.isSafari && node && 3 == node.nodeType) {
2173 return node.parentNode;
2180 getPageX: function(ev) {
2181 ev = ev.browserEvent || ev;
2182 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2184 if (!x && 0 !== x) {
2185 x = ev.clientX || 0;
2188 x += this.getScroll()[1];
2196 getPageY: function(ev) {
2197 ev = ev.browserEvent || ev;
2198 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2200 if (!y && 0 !== y) {
2201 y = ev.clientY || 0;
2204 y += this.getScroll()[0];
2213 getXY: function(ev) {
2214 ev = ev.browserEvent || ev;
2215 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2216 return [this.getPageX(ev), this.getPageY(ev)];
2220 getRelatedTarget: function(ev) {
2221 ev = ev.browserEvent || ev;
2222 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2223 var t = ev.relatedTarget;
2225 if (ev.type == "mouseout") {
2227 } else if (ev.type == "mouseover") {
2232 return this.resolveTextNode(t);
2236 getTime: function(ev) {
2237 ev = ev.browserEvent || ev;
2238 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2240 var t = new Date().getTime();
2244 this.lastError = ex;
2253 stopEvent: function(ev) {
2254 this.stopPropagation(ev);
2255 this.preventDefault(ev);
2259 stopPropagation: function(ev) {
2260 ev = ev.browserEvent || ev;
2261 if (ev.stopPropagation) {
2262 ev.stopPropagation();
2264 ev.cancelBubble = true;
2269 preventDefault: function(ev) {
2270 ev = ev.browserEvent || ev;
2271 if(ev.preventDefault) {
2272 ev.preventDefault();
2274 ev.returnValue = false;
2279 getEvent: function(e) {
2280 var ev = e || window.event;
2282 var c = this.getEvent.caller;
2284 ev = c.arguments[0];
2285 if (ev && Event == ev.constructor) {
2295 getCharCode: function(ev) {
2296 ev = ev.browserEvent || ev;
2297 return ev.charCode || ev.keyCode || 0;
2301 _getCacheIndex: function(el, eventName, fn) {
2302 for (var i = 0,len = listeners.length; i < len; ++i) {
2303 var li = listeners[i];
2305 li[this.FN] == fn &&
2306 li[this.EL] == el &&
2307 li[this.TYPE] == eventName) {
2319 getEl: function(id) {
2320 return document.getElementById(id);
2324 clearCache: function() {
2328 _load: function(e) {
2329 loadComplete = true;
2330 var EU = Roo.lib.Event;
2334 EU.doRemove(window, "load", EU._load);
2339 _tryPreloadAttach: function() {
2348 var tryAgain = !loadComplete;
2350 tryAgain = (retryCount > 0);
2355 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2356 var item = onAvailStack[i];
2358 var el = this.getEl(item.id);
2361 if (!item.checkReady ||
2364 (document && document.body)) {
2367 if (item.override) {
2368 if (item.override === true) {
2371 scope = item.override;
2374 item.fn.call(scope, item.obj);
2375 onAvailStack[i] = null;
2378 notAvail.push(item);
2383 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2387 this.startInterval();
2389 clearInterval(this._interval);
2390 this._interval = null;
2393 this.locked = false;
2400 purgeElement: function(el, recurse, eventName) {
2401 var elListeners = this.getListeners(el, eventName);
2403 for (var i = 0,len = elListeners.length; i < len; ++i) {
2404 var l = elListeners[i];
2405 this.removeListener(el, l.type, l.fn);
2409 if (recurse && el && el.childNodes) {
2410 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2411 this.purgeElement(el.childNodes[i], recurse, eventName);
2417 getListeners: function(el, eventName) {
2418 var results = [], searchLists;
2420 searchLists = [listeners, unloadListeners];
2421 } else if (eventName == "unload") {
2422 searchLists = [unloadListeners];
2424 searchLists = [listeners];
2427 for (var j = 0; j < searchLists.length; ++j) {
2428 var searchList = searchLists[j];
2429 if (searchList && searchList.length > 0) {
2430 for (var i = 0,len = searchList.length; i < len; ++i) {
2431 var l = searchList[i];
2432 if (l && l[this.EL] === el &&
2433 (!eventName || eventName === l[this.TYPE])) {
2438 adjust: l[this.ADJ_SCOPE],
2446 return (results.length) ? results : null;
2450 _unload: function(e) {
2452 var EU = Roo.lib.Event, i, j, l, len, index;
2454 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2455 l = unloadListeners[i];
2458 if (l[EU.ADJ_SCOPE]) {
2459 if (l[EU.ADJ_SCOPE] === true) {
2462 scope = l[EU.ADJ_SCOPE];
2465 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2466 unloadListeners[i] = null;
2472 unloadListeners = null;
2474 if (listeners && listeners.length > 0) {
2475 j = listeners.length;
2478 l = listeners[index];
2480 EU.removeListener(l[EU.EL], l[EU.TYPE],
2490 EU.doRemove(window, "unload", EU._unload);
2495 getScroll: function() {
2496 var dd = document.documentElement, db = document.body;
2497 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2498 return [dd.scrollTop, dd.scrollLeft];
2500 return [db.scrollTop, db.scrollLeft];
2507 doAdd: function () {
2508 if (window.addEventListener) {
2509 return function(el, eventName, fn, capture) {
2510 el.addEventListener(eventName, fn, (capture));
2512 } else if (window.attachEvent) {
2513 return function(el, eventName, fn, capture) {
2514 el.attachEvent("on" + eventName, fn);
2523 doRemove: function() {
2524 if (window.removeEventListener) {
2525 return function (el, eventName, fn, capture) {
2526 el.removeEventListener(eventName, fn, (capture));
2528 } else if (window.detachEvent) {
2529 return function (el, eventName, fn) {
2530 el.detachEvent("on" + eventName, fn);
2542 var E = Roo.lib.Event;
2543 E.on = E.addListener;
2544 E.un = E.removeListener;
2546 if (document && document.body) {
2549 E.doAdd(window, "load", E._load);
2551 E.doAdd(window, "unload", E._unload);
2552 E._tryPreloadAttach();
2556 * Portions of this file are based on pieces of Yahoo User Interface Library
2557 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2558 * YUI licensed under the BSD License:
2559 * http://developer.yahoo.net/yui/license.txt
2560 * <script type="text/javascript">
2566 * @class Roo.lib.Ajax
2573 request : function(method, uri, cb, data, options) {
2575 var hs = options.headers;
2578 if(hs.hasOwnProperty(h)){
2579 this.initHeader(h, hs[h], false);
2583 if(options.xmlData){
2584 this.initHeader('Content-Type', 'text/xml', false);
2586 data = options.xmlData;
2590 return this.asyncRequest(method, uri, cb, data);
2593 serializeForm : function(form) {
2594 if(typeof form == 'string') {
2595 form = (document.getElementById(form) || document.forms[form]);
2598 var el, name, val, disabled, data = '', hasSubmit = false;
2599 for (var i = 0; i < form.elements.length; i++) {
2600 el = form.elements[i];
2601 disabled = form.elements[i].disabled;
2602 name = form.elements[i].name;
2603 val = form.elements[i].value;
2605 if (!disabled && name){
2609 case 'select-multiple':
2610 for (var j = 0; j < el.options.length; j++) {
2611 if (el.options[j].selected) {
2613 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2616 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2624 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2637 if(hasSubmit == false) {
2638 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2643 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2648 data = data.substr(0, data.length - 1);
2656 useDefaultHeader:true,
2658 defaultPostHeader:'application/x-www-form-urlencoded',
2660 useDefaultXhrHeader:true,
2662 defaultXhrHeader:'XMLHttpRequest',
2664 hasDefaultHeaders:true,
2676 setProgId:function(id)
2678 this.activeX.unshift(id);
2681 setDefaultPostHeader:function(b)
2683 this.useDefaultHeader = b;
2686 setDefaultXhrHeader:function(b)
2688 this.useDefaultXhrHeader = b;
2691 setPollingInterval:function(i)
2693 if (typeof i == 'number' && isFinite(i)) {
2694 this.pollInterval = i;
2698 createXhrObject:function(transactionId)
2704 http = new XMLHttpRequest();
2706 obj = { conn:http, tId:transactionId };
2710 for (var i = 0; i < this.activeX.length; ++i) {
2714 http = new ActiveXObject(this.activeX[i]);
2716 obj = { conn:http, tId:transactionId };
2729 getConnectionObject:function()
2732 var tId = this.transactionId;
2736 o = this.createXhrObject(tId);
2738 this.transactionId++;
2749 asyncRequest:function(method, uri, callback, postData)
2751 var o = this.getConnectionObject();
2757 o.conn.open(method, uri, true);
2759 if (this.useDefaultXhrHeader) {
2760 if (!this.defaultHeaders['X-Requested-With']) {
2761 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2765 if(postData && this.useDefaultHeader){
2766 this.initHeader('Content-Type', this.defaultPostHeader);
2769 if (this.hasDefaultHeaders || this.hasHeaders) {
2773 this.handleReadyState(o, callback);
2774 o.conn.send(postData || null);
2780 handleReadyState:function(o, callback)
2784 if (callback && callback.timeout) {
2786 this.timeout[o.tId] = window.setTimeout(function() {
2787 oConn.abort(o, callback, true);
2788 }, callback.timeout);
2791 this.poll[o.tId] = window.setInterval(
2793 if (o.conn && o.conn.readyState == 4) {
2794 window.clearInterval(oConn.poll[o.tId]);
2795 delete oConn.poll[o.tId];
2797 if(callback && callback.timeout) {
2798 window.clearTimeout(oConn.timeout[o.tId]);
2799 delete oConn.timeout[o.tId];
2802 oConn.handleTransactionResponse(o, callback);
2805 , this.pollInterval);
2808 handleTransactionResponse:function(o, callback, isAbort)
2812 this.releaseObject(o);
2816 var httpStatus, responseObject;
2820 if (o.conn.status !== undefined && o.conn.status != 0) {
2821 httpStatus = o.conn.status;
2833 if (httpStatus >= 200 && httpStatus < 300) {
2834 responseObject = this.createResponseObject(o, callback.argument);
2835 if (callback.success) {
2836 if (!callback.scope) {
2837 callback.success(responseObject);
2842 callback.success.apply(callback.scope, [responseObject]);
2847 switch (httpStatus) {
2855 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2856 if (callback.failure) {
2857 if (!callback.scope) {
2858 callback.failure(responseObject);
2861 callback.failure.apply(callback.scope, [responseObject]);
2866 responseObject = this.createResponseObject(o, callback.argument);
2867 if (callback.failure) {
2868 if (!callback.scope) {
2869 callback.failure(responseObject);
2872 callback.failure.apply(callback.scope, [responseObject]);
2878 this.releaseObject(o);
2879 responseObject = null;
2882 createResponseObject:function(o, callbackArg)
2889 var headerStr = o.conn.getAllResponseHeaders();
2890 var header = headerStr.split('\n');
2891 for (var i = 0; i < header.length; i++) {
2892 var delimitPos = header[i].indexOf(':');
2893 if (delimitPos != -1) {
2894 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2902 obj.status = o.conn.status;
2903 obj.statusText = o.conn.statusText;
2904 obj.getResponseHeader = headerObj;
2905 obj.getAllResponseHeaders = headerStr;
2906 obj.responseText = o.conn.responseText;
2907 obj.responseXML = o.conn.responseXML;
2909 if (typeof callbackArg !== undefined) {
2910 obj.argument = callbackArg;
2916 createExceptionObject:function(tId, callbackArg, isAbort)
2919 var COMM_ERROR = 'communication failure';
2920 var ABORT_CODE = -1;
2921 var ABORT_ERROR = 'transaction aborted';
2927 obj.status = ABORT_CODE;
2928 obj.statusText = ABORT_ERROR;
2931 obj.status = COMM_CODE;
2932 obj.statusText = COMM_ERROR;
2936 obj.argument = callbackArg;
2942 initHeader:function(label, value, isDefault)
2944 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2946 if (headerObj[label] === undefined) {
2947 headerObj[label] = value;
2952 headerObj[label] = value + "," + headerObj[label];
2956 this.hasDefaultHeaders = true;
2959 this.hasHeaders = true;
2964 setHeader:function(o)
2966 if (this.hasDefaultHeaders) {
2967 for (var prop in this.defaultHeaders) {
2968 if (this.defaultHeaders.hasOwnProperty(prop)) {
2969 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2974 if (this.hasHeaders) {
2975 for (var prop in this.headers) {
2976 if (this.headers.hasOwnProperty(prop)) {
2977 o.conn.setRequestHeader(prop, this.headers[prop]);
2981 this.hasHeaders = false;
2985 resetDefaultHeaders:function() {
2986 delete this.defaultHeaders;
2987 this.defaultHeaders = {};
2988 this.hasDefaultHeaders = false;
2991 abort:function(o, callback, isTimeout)
2993 if(this.isCallInProgress(o)) {
2995 window.clearInterval(this.poll[o.tId]);
2996 delete this.poll[o.tId];
2998 delete this.timeout[o.tId];
3001 this.handleTransactionResponse(o, callback, true);
3011 isCallInProgress:function(o)
3014 return o.conn.readyState != 4 && o.conn.readyState != 0;
3023 releaseObject:function(o)
3032 'MSXML2.XMLHTTP.3.0',
3040 * Portions of this file are based on pieces of Yahoo User Interface Library
3041 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3042 * YUI licensed under the BSD License:
3043 * http://developer.yahoo.net/yui/license.txt
3044 * <script type="text/javascript">
3048 Roo.lib.Region = function(t, r, b, l) {
3058 Roo.lib.Region.prototype = {
3059 contains : function(region) {
3060 return ( region.left >= this.left &&
3061 region.right <= this.right &&
3062 region.top >= this.top &&
3063 region.bottom <= this.bottom );
3067 getArea : function() {
3068 return ( (this.bottom - this.top) * (this.right - this.left) );
3071 intersect : function(region) {
3072 var t = Math.max(this.top, region.top);
3073 var r = Math.min(this.right, region.right);
3074 var b = Math.min(this.bottom, region.bottom);
3075 var l = Math.max(this.left, region.left);
3077 if (b >= t && r >= l) {
3078 return new Roo.lib.Region(t, r, b, l);
3083 union : function(region) {
3084 var t = Math.min(this.top, region.top);
3085 var r = Math.max(this.right, region.right);
3086 var b = Math.max(this.bottom, region.bottom);
3087 var l = Math.min(this.left, region.left);
3089 return new Roo.lib.Region(t, r, b, l);
3092 adjust : function(t, l, b, r) {
3101 Roo.lib.Region.getRegion = function(el) {
3102 var p = Roo.lib.Dom.getXY(el);
3105 var r = p[0] + el.offsetWidth;
3106 var b = p[1] + el.offsetHeight;
3109 return new Roo.lib.Region(t, r, b, l);
3112 * Portions of this file are based on pieces of Yahoo User Interface Library
3113 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3114 * YUI licensed under the BSD License:
3115 * http://developer.yahoo.net/yui/license.txt
3116 * <script type="text/javascript">
3119 //@@dep Roo.lib.Region
3122 Roo.lib.Point = function(x, y) {
3123 if (x instanceof Array) {
3127 this.x = this.right = this.left = this[0] = x;
3128 this.y = this.top = this.bottom = this[1] = y;
3131 Roo.lib.Point.prototype = new Roo.lib.Region();
3133 * Portions of this file are based on pieces of Yahoo User Interface Library
3134 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3135 * YUI licensed under the BSD License:
3136 * http://developer.yahoo.net/yui/license.txt
3137 * <script type="text/javascript">
3144 scroll : function(el, args, duration, easing, cb, scope) {
3145 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3148 motion : function(el, args, duration, easing, cb, scope) {
3149 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3152 color : function(el, args, duration, easing, cb, scope) {
3153 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3156 run : function(el, args, duration, easing, cb, scope, type) {
3157 type = type || Roo.lib.AnimBase;
3158 if (typeof easing == "string") {
3159 easing = Roo.lib.Easing[easing];
3161 var anim = new type(el, args, duration, easing);
3162 anim.animateX(function() {
3163 Roo.callback(cb, scope);
3169 * Portions of this file are based on pieces of Yahoo User Interface Library
3170 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3171 * YUI licensed under the BSD License:
3172 * http://developer.yahoo.net/yui/license.txt
3173 * <script type="text/javascript">
3181 if (!libFlyweight) {
3182 libFlyweight = new Roo.Element.Flyweight();
3184 libFlyweight.dom = el;
3185 return libFlyweight;
3188 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3192 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3194 this.init(el, attributes, duration, method);
3198 Roo.lib.AnimBase.fly = fly;
3202 Roo.lib.AnimBase.prototype = {
3204 toString: function() {
3205 var el = this.getEl();
3206 var id = el.id || el.tagName;
3207 return ("Anim " + id);
3211 noNegatives: /width|height|opacity|padding/i,
3212 offsetAttribute: /^((width|height)|(top|left))$/,
3213 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3214 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3218 doMethod: function(attr, start, end) {
3219 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3223 setAttribute: function(attr, val, unit) {
3224 if (this.patterns.noNegatives.test(attr)) {
3225 val = (val > 0) ? val : 0;
3228 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3232 getAttribute: function(attr) {
3233 var el = this.getEl();
3234 var val = fly(el).getStyle(attr);
3236 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3237 return parseFloat(val);
3240 var a = this.patterns.offsetAttribute.exec(attr) || [];
3241 var pos = !!( a[3] );
3242 var box = !!( a[2] );
3245 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3246 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3255 getDefaultUnit: function(attr) {
3256 if (this.patterns.defaultUnit.test(attr)) {
3263 animateX : function(callback, scope) {
3264 var f = function() {
3265 this.onComplete.removeListener(f);
3266 if (typeof callback == "function") {
3267 callback.call(scope || this, this);
3270 this.onComplete.addListener(f, this);
3275 setRuntimeAttribute: function(attr) {
3278 var attributes = this.attributes;
3280 this.runtimeAttributes[attr] = {};
3282 var isset = function(prop) {
3283 return (typeof prop !== 'undefined');
3286 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3290 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3293 if (isset(attributes[attr]['to'])) {
3294 end = attributes[attr]['to'];
3295 } else if (isset(attributes[attr]['by'])) {
3296 if (start.constructor == Array) {
3298 for (var i = 0, len = start.length; i < len; ++i) {
3299 end[i] = start[i] + attributes[attr]['by'][i];
3302 end = start + attributes[attr]['by'];
3306 this.runtimeAttributes[attr].start = start;
3307 this.runtimeAttributes[attr].end = end;
3310 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3314 init: function(el, attributes, duration, method) {
3316 var isAnimated = false;
3319 var startTime = null;
3322 var actualFrames = 0;
3325 el = Roo.getDom(el);
3328 this.attributes = attributes || {};
3331 this.duration = duration || 1;
3334 this.method = method || Roo.lib.Easing.easeNone;
3337 this.useSeconds = true;
3340 this.currentFrame = 0;
3343 this.totalFrames = Roo.lib.AnimMgr.fps;
3346 this.getEl = function() {
3351 this.isAnimated = function() {
3356 this.getStartTime = function() {
3360 this.runtimeAttributes = {};
3363 this.animate = function() {
3364 if (this.isAnimated()) {
3368 this.currentFrame = 0;
3370 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3372 Roo.lib.AnimMgr.registerElement(this);
3376 this.stop = function(finish) {
3378 this.currentFrame = this.totalFrames;
3379 this._onTween.fire();
3381 Roo.lib.AnimMgr.stop(this);
3384 var onStart = function() {
3385 this.onStart.fire();
3387 this.runtimeAttributes = {};
3388 for (var attr in this.attributes) {
3389 this.setRuntimeAttribute(attr);
3394 startTime = new Date();
3398 var onTween = function() {
3400 duration: new Date() - this.getStartTime(),
3401 currentFrame: this.currentFrame
3404 data.toString = function() {
3406 'duration: ' + data.duration +
3407 ', currentFrame: ' + data.currentFrame
3411 this.onTween.fire(data);
3413 var runtimeAttributes = this.runtimeAttributes;
3415 for (var attr in runtimeAttributes) {
3416 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3422 var onComplete = function() {
3423 var actual_duration = (new Date() - startTime) / 1000 ;
3426 duration: actual_duration,
3427 frames: actualFrames,
3428 fps: actualFrames / actual_duration
3431 data.toString = function() {
3433 'duration: ' + data.duration +
3434 ', frames: ' + data.frames +
3435 ', fps: ' + data.fps
3441 this.onComplete.fire(data);
3445 this._onStart = new Roo.util.Event(this);
3446 this.onStart = new Roo.util.Event(this);
3447 this.onTween = new Roo.util.Event(this);
3448 this._onTween = new Roo.util.Event(this);
3449 this.onComplete = new Roo.util.Event(this);
3450 this._onComplete = new Roo.util.Event(this);
3451 this._onStart.addListener(onStart);
3452 this._onTween.addListener(onTween);
3453 this._onComplete.addListener(onComplete);
3458 * Portions of this file are based on pieces of Yahoo User Interface Library
3459 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3460 * YUI licensed under the BSD License:
3461 * http://developer.yahoo.net/yui/license.txt
3462 * <script type="text/javascript">
3466 Roo.lib.AnimMgr = new function() {
3483 this.registerElement = function(tween) {
3484 queue[queue.length] = tween;
3486 tween._onStart.fire();
3491 this.unRegister = function(tween, index) {
3492 tween._onComplete.fire();
3493 index = index || getIndex(tween);
3495 queue.splice(index, 1);
3499 if (tweenCount <= 0) {
3505 this.start = function() {
3506 if (thread === null) {
3507 thread = setInterval(this.run, this.delay);
3512 this.stop = function(tween) {
3514 clearInterval(thread);
3516 for (var i = 0, len = queue.length; i < len; ++i) {
3517 if (queue[0].isAnimated()) {
3518 this.unRegister(queue[0], 0);
3527 this.unRegister(tween);
3532 this.run = function() {
3533 for (var i = 0, len = queue.length; i < len; ++i) {
3534 var tween = queue[i];
3535 if (!tween || !tween.isAnimated()) {
3539 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3541 tween.currentFrame += 1;
3543 if (tween.useSeconds) {
3544 correctFrame(tween);
3546 tween._onTween.fire();
3549 Roo.lib.AnimMgr.stop(tween, i);
3554 var getIndex = function(anim) {
3555 for (var i = 0, len = queue.length; i < len; ++i) {
3556 if (queue[i] == anim) {
3564 var correctFrame = function(tween) {
3565 var frames = tween.totalFrames;
3566 var frame = tween.currentFrame;
3567 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3568 var elapsed = (new Date() - tween.getStartTime());
3571 if (elapsed < tween.duration * 1000) {
3572 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3574 tweak = frames - (frame + 1);
3576 if (tweak > 0 && isFinite(tweak)) {
3577 if (tween.currentFrame + tweak >= frames) {
3578 tweak = frames - (frame + 1);
3581 tween.currentFrame += tweak;
3587 * Portions of this file are based on pieces of Yahoo User Interface Library
3588 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3589 * YUI licensed under the BSD License:
3590 * http://developer.yahoo.net/yui/license.txt
3591 * <script type="text/javascript">
3594 Roo.lib.Bezier = new function() {
3596 this.getPosition = function(points, t) {
3597 var n = points.length;
3600 for (var i = 0; i < n; ++i) {
3601 tmp[i] = [points[i][0], points[i][1]];
3604 for (var j = 1; j < n; ++j) {
3605 for (i = 0; i < n - j; ++i) {
3606 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3607 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3611 return [ tmp[0][0], tmp[0][1] ];
3615 * Portions of this file are based on pieces of Yahoo User Interface Library
3616 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3617 * YUI licensed under the BSD License:
3618 * http://developer.yahoo.net/yui/license.txt
3619 * <script type="text/javascript">
3624 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3625 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3628 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3630 var fly = Roo.lib.AnimBase.fly;
3632 var superclass = Y.ColorAnim.superclass;
3633 var proto = Y.ColorAnim.prototype;
3635 proto.toString = function() {
3636 var el = this.getEl();
3637 var id = el.id || el.tagName;
3638 return ("ColorAnim " + id);
3641 proto.patterns.color = /color$/i;
3642 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3643 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3644 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3645 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3648 proto.parseColor = function(s) {
3649 if (s.length == 3) {
3653 var c = this.patterns.hex.exec(s);
3654 if (c && c.length == 4) {
3655 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3658 c = this.patterns.rgb.exec(s);
3659 if (c && c.length == 4) {
3660 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3663 c = this.patterns.hex3.exec(s);
3664 if (c && c.length == 4) {
3665 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3670 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3671 proto.getAttribute = function(attr) {
3672 var el = this.getEl();
3673 if (this.patterns.color.test(attr)) {
3674 var val = fly(el).getStyle(attr);
3676 if (this.patterns.transparent.test(val)) {
3677 var parent = el.parentNode;
3678 val = fly(parent).getStyle(attr);
3680 while (parent && this.patterns.transparent.test(val)) {
3681 parent = parent.parentNode;
3682 val = fly(parent).getStyle(attr);
3683 if (parent.tagName.toUpperCase() == 'HTML') {
3689 val = superclass.getAttribute.call(this, attr);
3694 proto.getAttribute = function(attr) {
3695 var el = this.getEl();
3696 if (this.patterns.color.test(attr)) {
3697 var val = fly(el).getStyle(attr);
3699 if (this.patterns.transparent.test(val)) {
3700 var parent = el.parentNode;
3701 val = fly(parent).getStyle(attr);
3703 while (parent && this.patterns.transparent.test(val)) {
3704 parent = parent.parentNode;
3705 val = fly(parent).getStyle(attr);
3706 if (parent.tagName.toUpperCase() == 'HTML') {
3712 val = superclass.getAttribute.call(this, attr);
3718 proto.doMethod = function(attr, start, end) {
3721 if (this.patterns.color.test(attr)) {
3723 for (var i = 0, len = start.length; i < len; ++i) {
3724 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3727 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3730 val = superclass.doMethod.call(this, attr, start, end);
3736 proto.setRuntimeAttribute = function(attr) {
3737 superclass.setRuntimeAttribute.call(this, attr);
3739 if (this.patterns.color.test(attr)) {
3740 var attributes = this.attributes;
3741 var start = this.parseColor(this.runtimeAttributes[attr].start);
3742 var end = this.parseColor(this.runtimeAttributes[attr].end);
3744 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3745 end = this.parseColor(attributes[attr].by);
3747 for (var i = 0, len = start.length; i < len; ++i) {
3748 end[i] = start[i] + end[i];
3752 this.runtimeAttributes[attr].start = start;
3753 this.runtimeAttributes[attr].end = end;
3759 * Portions of this file are based on pieces of Yahoo User Interface Library
3760 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3761 * YUI licensed under the BSD License:
3762 * http://developer.yahoo.net/yui/license.txt
3763 * <script type="text/javascript">
3769 easeNone: function (t, b, c, d) {
3770 return c * t / d + b;
3774 easeIn: function (t, b, c, d) {
3775 return c * (t /= d) * t + b;
3779 easeOut: function (t, b, c, d) {
3780 return -c * (t /= d) * (t - 2) + b;
3784 easeBoth: function (t, b, c, d) {
3785 if ((t /= d / 2) < 1) {
3786 return c / 2 * t * t + b;
3789 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3793 easeInStrong: function (t, b, c, d) {
3794 return c * (t /= d) * t * t * t + b;
3798 easeOutStrong: function (t, b, c, d) {
3799 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3803 easeBothStrong: function (t, b, c, d) {
3804 if ((t /= d / 2) < 1) {
3805 return c / 2 * t * t * t * t + b;
3808 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3813 elasticIn: function (t, b, c, d, a, p) {
3817 if ((t /= d) == 1) {
3824 if (!a || a < Math.abs(c)) {
3829 var s = p / (2 * Math.PI) * Math.asin(c / a);
3832 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3836 elasticOut: function (t, b, c, d, a, p) {
3840 if ((t /= d) == 1) {
3847 if (!a || a < Math.abs(c)) {
3852 var s = p / (2 * Math.PI) * Math.asin(c / a);
3855 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3859 elasticBoth: function (t, b, c, d, a, p) {
3864 if ((t /= d / 2) == 2) {
3872 if (!a || a < Math.abs(c)) {
3877 var s = p / (2 * Math.PI) * Math.asin(c / a);
3881 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3882 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3884 return a * Math.pow(2, -10 * (t -= 1)) *
3885 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3890 backIn: function (t, b, c, d, s) {
3891 if (typeof s == 'undefined') {
3894 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3898 backOut: function (t, b, c, d, s) {
3899 if (typeof s == 'undefined') {
3902 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3906 backBoth: function (t, b, c, d, s) {
3907 if (typeof s == 'undefined') {
3911 if ((t /= d / 2 ) < 1) {
3912 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3914 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3918 bounceIn: function (t, b, c, d) {
3919 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3923 bounceOut: function (t, b, c, d) {
3924 if ((t /= d) < (1 / 2.75)) {
3925 return c * (7.5625 * t * t) + b;
3926 } else if (t < (2 / 2.75)) {
3927 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3928 } else if (t < (2.5 / 2.75)) {
3929 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3931 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3935 bounceBoth: function (t, b, c, d) {
3937 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3939 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3942 * Portions of this file are based on pieces of Yahoo User Interface Library
3943 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3944 * YUI licensed under the BSD License:
3945 * http://developer.yahoo.net/yui/license.txt
3946 * <script type="text/javascript">
3950 Roo.lib.Motion = function(el, attributes, duration, method) {
3952 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3956 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3960 var superclass = Y.Motion.superclass;
3961 var proto = Y.Motion.prototype;
3963 proto.toString = function() {
3964 var el = this.getEl();
3965 var id = el.id || el.tagName;
3966 return ("Motion " + id);
3969 proto.patterns.points = /^points$/i;
3971 proto.setAttribute = function(attr, val, unit) {
3972 if (this.patterns.points.test(attr)) {
3973 unit = unit || 'px';
3974 superclass.setAttribute.call(this, 'left', val[0], unit);
3975 superclass.setAttribute.call(this, 'top', val[1], unit);
3977 superclass.setAttribute.call(this, attr, val, unit);
3981 proto.getAttribute = function(attr) {
3982 if (this.patterns.points.test(attr)) {
3984 superclass.getAttribute.call(this, 'left'),
3985 superclass.getAttribute.call(this, 'top')
3988 val = superclass.getAttribute.call(this, attr);
3994 proto.doMethod = function(attr, start, end) {
3997 if (this.patterns.points.test(attr)) {
3998 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3999 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4001 val = superclass.doMethod.call(this, attr, start, end);
4006 proto.setRuntimeAttribute = function(attr) {
4007 if (this.patterns.points.test(attr)) {
4008 var el = this.getEl();
4009 var attributes = this.attributes;
4011 var control = attributes['points']['control'] || [];
4015 if (control.length > 0 && !(control[0] instanceof Array)) {
4016 control = [control];
4019 for (i = 0,len = control.length; i < len; ++i) {
4020 tmp[i] = control[i];
4025 Roo.fly(el).position();
4027 if (isset(attributes['points']['from'])) {
4028 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4031 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4034 start = this.getAttribute('points');
4037 if (isset(attributes['points']['to'])) {
4038 end = translateValues.call(this, attributes['points']['to'], start);
4040 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4041 for (i = 0,len = control.length; i < len; ++i) {
4042 control[i] = translateValues.call(this, control[i], start);
4046 } else if (isset(attributes['points']['by'])) {
4047 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4049 for (i = 0,len = control.length; i < len; ++i) {
4050 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4054 this.runtimeAttributes[attr] = [start];
4056 if (control.length > 0) {
4057 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4060 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4063 superclass.setRuntimeAttribute.call(this, attr);
4067 var translateValues = function(val, start) {
4068 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4069 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4074 var isset = function(prop) {
4075 return (typeof prop !== 'undefined');
4079 * Portions of this file are based on pieces of Yahoo User Interface Library
4080 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4081 * YUI licensed under the BSD License:
4082 * http://developer.yahoo.net/yui/license.txt
4083 * <script type="text/javascript">
4087 Roo.lib.Scroll = function(el, attributes, duration, method) {
4089 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4093 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4097 var superclass = Y.Scroll.superclass;
4098 var proto = Y.Scroll.prototype;
4100 proto.toString = function() {
4101 var el = this.getEl();
4102 var id = el.id || el.tagName;
4103 return ("Scroll " + id);
4106 proto.doMethod = function(attr, start, end) {
4109 if (attr == 'scroll') {
4111 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4112 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4116 val = superclass.doMethod.call(this, attr, start, end);
4121 proto.getAttribute = function(attr) {
4123 var el = this.getEl();
4125 if (attr == 'scroll') {
4126 val = [ el.scrollLeft, el.scrollTop ];
4128 val = superclass.getAttribute.call(this, attr);
4134 proto.setAttribute = function(attr, val, unit) {
4135 var el = this.getEl();
4137 if (attr == 'scroll') {
4138 el.scrollLeft = val[0];
4139 el.scrollTop = val[1];
4141 superclass.setAttribute.call(this, attr, val, unit);
4147 * Ext JS Library 1.1.1
4148 * Copyright(c) 2006-2007, Ext JS, LLC.
4150 * Originally Released Under LGPL - original licence link has changed is not relivant.
4153 * <script type="text/javascript">
4157 // nasty IE9 hack - what a pile of crap that is..
4159 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4160 Range.prototype.createContextualFragment = function (html) {
4161 var doc = window.document;
4162 var container = doc.createElement("div");
4163 container.innerHTML = html;
4164 var frag = doc.createDocumentFragment(), n;
4165 while ((n = container.firstChild)) {
4166 frag.appendChild(n);
4173 * @class Roo.DomHelper
4174 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4175 * 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>.
4178 Roo.DomHelper = function(){
4179 var tempTableEl = null;
4180 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4181 var tableRe = /^table|tbody|tr|td$/i;
4183 // build as innerHTML where available
4185 var createHtml = function(o){
4186 if(typeof o == 'string'){
4195 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4196 if(attr == "style"){
4198 if(typeof s == "function"){
4201 if(typeof s == "string"){
4202 b += ' style="' + s + '"';
4203 }else if(typeof s == "object"){
4206 if(typeof s[key] != "function"){
4207 b += key + ":" + s[key] + ";";
4214 b += ' class="' + o["cls"] + '"';
4215 }else if(attr == "htmlFor"){
4216 b += ' for="' + o["htmlFor"] + '"';
4218 b += " " + attr + '="' + o[attr] + '"';
4222 if(emptyTags.test(o.tag)){
4226 var cn = o.children || o.cn;
4228 //http://bugs.kde.org/show_bug.cgi?id=71506
4229 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4230 for(var i = 0, len = cn.length; i < len; i++) {
4231 b += createHtml(cn[i], b);
4234 b += createHtml(cn, b);
4240 b += "</" + o.tag + ">";
4247 var createDom = function(o, parentNode){
4249 // defininition craeted..
4251 if (o.ns && o.ns != 'html') {
4253 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4254 xmlns[o.ns] = o.xmlns;
4257 if (typeof(xmlns[o.ns]) == 'undefined') {
4258 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4264 if (typeof(o) == 'string') {
4265 return parentNode.appendChild(document.createTextNode(o));
4267 o.tag = o.tag || div;
4268 if (o.ns && Roo.isIE) {
4270 o.tag = o.ns + ':' + o.tag;
4273 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4274 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4277 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4278 attr == "style" || typeof o[attr] == "function") { continue; }
4280 if(attr=="cls" && Roo.isIE){
4281 el.className = o["cls"];
4283 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4289 Roo.DomHelper.applyStyles(el, o.style);
4290 var cn = o.children || o.cn;
4292 //http://bugs.kde.org/show_bug.cgi?id=71506
4293 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4294 for(var i = 0, len = cn.length; i < len; i++) {
4295 createDom(cn[i], el);
4302 el.innerHTML = o.html;
4305 parentNode.appendChild(el);
4310 var ieTable = function(depth, s, h, e){
4311 tempTableEl.innerHTML = [s, h, e].join('');
4312 var i = -1, el = tempTableEl;
4319 // kill repeat to save bytes
4323 tbe = '</tbody>'+te,
4329 * Nasty code for IE's broken table implementation
4331 var insertIntoTable = function(tag, where, el, html){
4333 tempTableEl = document.createElement('div');
4338 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4341 if(where == 'beforebegin'){
4345 before = el.nextSibling;
4348 node = ieTable(4, trs, html, tre);
4350 else if(tag == 'tr'){
4351 if(where == 'beforebegin'){
4354 node = ieTable(3, tbs, html, tbe);
4355 } else if(where == 'afterend'){
4356 before = el.nextSibling;
4358 node = ieTable(3, tbs, html, tbe);
4359 } else{ // INTO a TR
4360 if(where == 'afterbegin'){
4361 before = el.firstChild;
4363 node = ieTable(4, trs, html, tre);
4365 } else if(tag == 'tbody'){
4366 if(where == 'beforebegin'){
4369 node = ieTable(2, ts, html, te);
4370 } else if(where == 'afterend'){
4371 before = el.nextSibling;
4373 node = ieTable(2, ts, html, te);
4375 if(where == 'afterbegin'){
4376 before = el.firstChild;
4378 node = ieTable(3, tbs, html, tbe);
4381 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4384 if(where == 'afterbegin'){
4385 before = el.firstChild;
4387 node = ieTable(2, ts, html, te);
4389 el.insertBefore(node, before);
4394 /** True to force the use of DOM instead of html fragments @type Boolean */
4398 * Returns the markup for the passed Element(s) config
4399 * @param {Object} o The Dom object spec (and children)
4402 markup : function(o){
4403 return createHtml(o);
4407 * Applies a style specification to an element
4408 * @param {String/HTMLElement} el The element to apply styles to
4409 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4410 * a function which returns such a specification.
4412 applyStyles : function(el, styles){
4415 if(typeof styles == "string"){
4416 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4418 while ((matches = re.exec(styles)) != null){
4419 el.setStyle(matches[1], matches[2]);
4421 }else if (typeof styles == "object"){
4422 for (var style in styles){
4423 el.setStyle(style, styles[style]);
4425 }else if (typeof styles == "function"){
4426 Roo.DomHelper.applyStyles(el, styles.call());
4432 * Inserts an HTML fragment into the Dom
4433 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4434 * @param {HTMLElement} el The context element
4435 * @param {String} html The HTML fragmenet
4436 * @return {HTMLElement} The new node
4438 insertHtml : function(where, el, html){
4439 where = where.toLowerCase();
4440 if(el.insertAdjacentHTML){
4441 if(tableRe.test(el.tagName)){
4443 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4449 el.insertAdjacentHTML('BeforeBegin', html);
4450 return el.previousSibling;
4452 el.insertAdjacentHTML('AfterBegin', html);
4453 return el.firstChild;
4455 el.insertAdjacentHTML('BeforeEnd', html);
4456 return el.lastChild;
4458 el.insertAdjacentHTML('AfterEnd', html);
4459 return el.nextSibling;
4461 throw 'Illegal insertion point -> "' + where + '"';
4463 var range = el.ownerDocument.createRange();
4467 range.setStartBefore(el);
4468 frag = range.createContextualFragment(html);
4469 el.parentNode.insertBefore(frag, el);
4470 return el.previousSibling;
4473 range.setStartBefore(el.firstChild);
4474 frag = range.createContextualFragment(html);
4475 el.insertBefore(frag, el.firstChild);
4476 return el.firstChild;
4478 el.innerHTML = html;
4479 return el.firstChild;
4483 range.setStartAfter(el.lastChild);
4484 frag = range.createContextualFragment(html);
4485 el.appendChild(frag);
4486 return el.lastChild;
4488 el.innerHTML = html;
4489 return el.lastChild;
4492 range.setStartAfter(el);
4493 frag = range.createContextualFragment(html);
4494 el.parentNode.insertBefore(frag, el.nextSibling);
4495 return el.nextSibling;
4497 throw 'Illegal insertion point -> "' + where + '"';
4501 * Creates new Dom element(s) and inserts them before el
4502 * @param {String/HTMLElement/Element} el The context element
4503 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4504 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4505 * @return {HTMLElement/Roo.Element} The new node
4507 insertBefore : function(el, o, returnElement){
4508 return this.doInsert(el, o, returnElement, "beforeBegin");
4512 * Creates new Dom element(s) and inserts them after el
4513 * @param {String/HTMLElement/Element} el The context element
4514 * @param {Object} o The Dom object spec (and children)
4515 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4516 * @return {HTMLElement/Roo.Element} The new node
4518 insertAfter : function(el, o, returnElement){
4519 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4523 * Creates new Dom element(s) and inserts them as the first child of el
4524 * @param {String/HTMLElement/Element} el The context element
4525 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4526 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4527 * @return {HTMLElement/Roo.Element} The new node
4529 insertFirst : function(el, o, returnElement){
4530 return this.doInsert(el, o, returnElement, "afterBegin");
4534 doInsert : function(el, o, returnElement, pos, sibling){
4535 el = Roo.getDom(el);
4537 if(this.useDom || o.ns){
4538 newNode = createDom(o, null);
4539 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4541 var html = createHtml(o);
4542 newNode = this.insertHtml(pos, el, html);
4544 return returnElement ? Roo.get(newNode, true) : newNode;
4548 * Creates new Dom element(s) and appends them to el
4549 * @param {String/HTMLElement/Element} el The context element
4550 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4551 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4552 * @return {HTMLElement/Roo.Element} The new node
4554 append : function(el, o, returnElement){
4555 el = Roo.getDom(el);
4557 if(this.useDom || o.ns){
4558 newNode = createDom(o, null);
4559 el.appendChild(newNode);
4561 var html = createHtml(o);
4562 newNode = this.insertHtml("beforeEnd", el, html);
4564 return returnElement ? Roo.get(newNode, true) : newNode;
4568 * Creates new Dom element(s) and overwrites the contents of el with them
4569 * @param {String/HTMLElement/Element} el The context element
4570 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4571 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4572 * @return {HTMLElement/Roo.Element} The new node
4574 overwrite : function(el, o, returnElement){
4575 el = Roo.getDom(el);
4578 while (el.childNodes.length) {
4579 el.removeChild(el.firstChild);
4583 el.innerHTML = createHtml(o);
4586 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4590 * Creates a new Roo.DomHelper.Template from the Dom object spec
4591 * @param {Object} o The Dom object spec (and children)
4592 * @return {Roo.DomHelper.Template} The new template
4594 createTemplate : function(o){
4595 var html = createHtml(o);
4596 return new Roo.Template(html);
4602 * Ext JS Library 1.1.1
4603 * Copyright(c) 2006-2007, Ext JS, LLC.
4605 * Originally Released Under LGPL - original licence link has changed is not relivant.
4608 * <script type="text/javascript">
4612 * @class Roo.Template
4613 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4614 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4617 var t = new Roo.Template({
4618 html : '<div name="{id}">' +
4619 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4621 myformat: function (value, allValues) {
4622 return 'XX' + value;
4625 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4627 * For more information see this blog post with examples:
4628 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4629 - Create Elements using DOM, HTML fragments and Templates</a>.
4631 * @param {Object} cfg - Configuration object.
4633 Roo.Template = function(cfg){
4635 if(cfg instanceof Array){
4637 }else if(arguments.length > 1){
4638 cfg = Array.prototype.join.call(arguments, "");
4642 if (typeof(cfg) == 'object') {
4653 Roo.Template.prototype = {
4656 * @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..
4657 * it should be fixed so that template is observable...
4661 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4665 * Returns an HTML fragment of this template with the specified values applied.
4666 * @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'})
4667 * @return {String} The HTML fragment
4669 applyTemplate : function(values){
4670 Roo.log(["applyTemplate", values]);
4674 return this.compiled(values);
4676 var useF = this.disableFormats !== true;
4677 var fm = Roo.util.Format, tpl = this;
4678 var fn = function(m, name, format, args){
4680 if(format.substr(0, 5) == "this."){
4681 return tpl.call(format.substr(5), values[name], values);
4684 // quoted values are required for strings in compiled templates,
4685 // but for non compiled we need to strip them
4686 // quoted reversed for jsmin
4687 var re = /^\s*['"](.*)["']\s*$/;
4688 args = args.split(',');
4689 for(var i = 0, len = args.length; i < len; i++){
4690 args[i] = args[i].replace(re, "$1");
4692 args = [values[name]].concat(args);
4694 args = [values[name]];
4696 return fm[format].apply(fm, args);
4699 return values[name] !== undefined ? values[name] : "";
4702 return this.html.replace(this.re, fn);
4720 this.loading = true;
4721 this.compiled = false;
4723 var cx = new Roo.data.Connection();
4727 success : function (response) {
4729 _t.html = response.responseText;
4733 failure : function(response) {
4734 Roo.log("Template failed to load from " + _t.url);
4741 * Sets the HTML used as the template and optionally compiles it.
4742 * @param {String} html
4743 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4744 * @return {Roo.Template} this
4746 set : function(html, compile){
4748 this.compiled = null;
4756 * True to disable format functions (defaults to false)
4759 disableFormats : false,
4762 * The regular expression used to match template variables
4766 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4769 * Compiles the template into an internal function, eliminating the RegEx overhead.
4770 * @return {Roo.Template} this
4772 compile : function(){
4773 var fm = Roo.util.Format;
4774 var useF = this.disableFormats !== true;
4775 var sep = Roo.isGecko ? "+" : ",";
4776 var fn = function(m, name, format, args){
4778 args = args ? ',' + args : "";
4779 if(format.substr(0, 5) != "this."){
4780 format = "fm." + format + '(';
4782 format = 'this.call("'+ format.substr(5) + '", ';
4786 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4788 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4791 // branched to use + in gecko and [].join() in others
4793 body = "this.compiled = function(values){ return '" +
4794 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4797 body = ["this.compiled = function(values){ return ['"];
4798 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4799 body.push("'].join('');};");
4800 body = body.join('');
4810 // private function used to call members
4811 call : function(fnName, value, allValues){
4812 return this[fnName](value, allValues);
4816 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4817 * @param {String/HTMLElement/Roo.Element} el The context element
4818 * @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'})
4819 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4820 * @return {HTMLElement/Roo.Element} The new node or Element
4822 insertFirst: function(el, values, returnElement){
4823 return this.doInsert('afterBegin', el, values, returnElement);
4827 * Applies the supplied values to the template and inserts the new node(s) before el.
4828 * @param {String/HTMLElement/Roo.Element} el The context element
4829 * @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'})
4830 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4831 * @return {HTMLElement/Roo.Element} The new node or Element
4833 insertBefore: function(el, values, returnElement){
4834 return this.doInsert('beforeBegin', el, values, returnElement);
4838 * Applies the supplied values to the template and inserts the new node(s) after el.
4839 * @param {String/HTMLElement/Roo.Element} el The context element
4840 * @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'})
4841 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4842 * @return {HTMLElement/Roo.Element} The new node or Element
4844 insertAfter : function(el, values, returnElement){
4845 return this.doInsert('afterEnd', el, values, returnElement);
4849 * Applies the supplied values to the template and appends the new node(s) to el.
4850 * @param {String/HTMLElement/Roo.Element} el The context element
4851 * @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'})
4852 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4853 * @return {HTMLElement/Roo.Element} The new node or Element
4855 append : function(el, values, returnElement){
4856 return this.doInsert('beforeEnd', el, values, returnElement);
4859 doInsert : function(where, el, values, returnEl){
4860 el = Roo.getDom(el);
4861 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4862 return returnEl ? Roo.get(newNode, true) : newNode;
4866 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4867 * @param {String/HTMLElement/Roo.Element} el The context element
4868 * @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'})
4869 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4870 * @return {HTMLElement/Roo.Element} The new node or Element
4872 overwrite : function(el, values, returnElement){
4873 el = Roo.getDom(el);
4874 el.innerHTML = this.applyTemplate(values);
4875 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4879 * Alias for {@link #applyTemplate}
4882 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4885 Roo.DomHelper.Template = Roo.Template;
4888 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4889 * @param {String/HTMLElement} el A DOM element or its id
4890 * @returns {Roo.Template} The created template
4893 Roo.Template.from = function(el){
4894 el = Roo.getDom(el);
4895 return new Roo.Template(el.value || el.innerHTML);
4898 * Ext JS Library 1.1.1
4899 * Copyright(c) 2006-2007, Ext JS, LLC.
4901 * Originally Released Under LGPL - original licence link has changed is not relivant.
4904 * <script type="text/javascript">
4909 * This is code is also distributed under MIT license for use
4910 * with jQuery and prototype JavaScript libraries.
4913 * @class Roo.DomQuery
4914 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).
4916 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>
4919 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.
4921 <h4>Element Selectors:</h4>
4923 <li> <b>*</b> any element</li>
4924 <li> <b>E</b> an element with the tag E</li>
4925 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4926 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4927 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4928 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4930 <h4>Attribute Selectors:</h4>
4931 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4933 <li> <b>E[foo]</b> has an attribute "foo"</li>
4934 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4935 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4936 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4937 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4938 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4939 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4941 <h4>Pseudo Classes:</h4>
4943 <li> <b>E:first-child</b> E is the first child of its parent</li>
4944 <li> <b>E:last-child</b> E is the last child of its parent</li>
4945 <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>
4946 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4947 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4948 <li> <b>E:only-child</b> E is the only child of its parent</li>
4949 <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>
4950 <li> <b>E:first</b> the first E in the resultset</li>
4951 <li> <b>E:last</b> the last E in the resultset</li>
4952 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4953 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4954 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4955 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4956 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4957 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4958 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4959 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4960 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4962 <h4>CSS Value Selectors:</h4>
4964 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4965 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4966 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4967 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4968 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4969 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4973 Roo.DomQuery = function(){
4974 var cache = {}, simpleCache = {}, valueCache = {};
4975 var nonSpace = /\S/;
4976 var trimRe = /^\s+|\s+$/g;
4977 var tplRe = /\{(\d+)\}/g;
4978 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4979 var tagTokenRe = /^(#)?([\w-\*]+)/;
4980 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4982 function child(p, index){
4984 var n = p.firstChild;
4986 if(n.nodeType == 1){
4997 while((n = n.nextSibling) && n.nodeType != 1);
5002 while((n = n.previousSibling) && n.nodeType != 1);
5006 function children(d){
5007 var n = d.firstChild, ni = -1;
5009 var nx = n.nextSibling;
5010 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5020 function byClassName(c, a, v){
5024 var r = [], ri = -1, cn;
5025 for(var i = 0, ci; ci = c[i]; i++){
5026 if((' '+ci.className+' ').indexOf(v) != -1){
5033 function attrValue(n, attr){
5034 if(!n.tagName && typeof n.length != "undefined"){
5043 if(attr == "class" || attr == "className"){
5046 return n.getAttribute(attr) || n[attr];
5050 function getNodes(ns, mode, tagName){
5051 var result = [], ri = -1, cs;
5055 tagName = tagName || "*";
5056 if(typeof ns.getElementsByTagName != "undefined"){
5060 for(var i = 0, ni; ni = ns[i]; i++){
5061 cs = ni.getElementsByTagName(tagName);
5062 for(var j = 0, ci; ci = cs[j]; j++){
5066 }else if(mode == "/" || mode == ">"){
5067 var utag = tagName.toUpperCase();
5068 for(var i = 0, ni, cn; ni = ns[i]; i++){
5069 cn = ni.children || ni.childNodes;
5070 for(var j = 0, cj; cj = cn[j]; j++){
5071 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5076 }else if(mode == "+"){
5077 var utag = tagName.toUpperCase();
5078 for(var i = 0, n; n = ns[i]; i++){
5079 while((n = n.nextSibling) && n.nodeType != 1);
5080 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5084 }else if(mode == "~"){
5085 for(var i = 0, n; n = ns[i]; i++){
5086 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5095 function concat(a, b){
5099 for(var i = 0, l = b.length; i < l; i++){
5105 function byTag(cs, tagName){
5106 if(cs.tagName || cs == document){
5112 var r = [], ri = -1;
5113 tagName = tagName.toLowerCase();
5114 for(var i = 0, ci; ci = cs[i]; i++){
5115 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5122 function byId(cs, attr, id){
5123 if(cs.tagName || cs == document){
5129 var r = [], ri = -1;
5130 for(var i = 0,ci; ci = cs[i]; i++){
5131 if(ci && ci.id == id){
5139 function byAttribute(cs, attr, value, op, custom){
5140 var r = [], ri = -1, st = custom=="{";
5141 var f = Roo.DomQuery.operators[op];
5142 for(var i = 0, ci; ci = cs[i]; i++){
5145 a = Roo.DomQuery.getStyle(ci, attr);
5147 else if(attr == "class" || attr == "className"){
5149 }else if(attr == "for"){
5151 }else if(attr == "href"){
5152 a = ci.getAttribute("href", 2);
5154 a = ci.getAttribute(attr);
5156 if((f && f(a, value)) || (!f && a)){
5163 function byPseudo(cs, name, value){
5164 return Roo.DomQuery.pseudos[name](cs, value);
5167 // This is for IE MSXML which does not support expandos.
5168 // IE runs the same speed using setAttribute, however FF slows way down
5169 // and Safari completely fails so they need to continue to use expandos.
5170 var isIE = window.ActiveXObject ? true : false;
5172 // this eval is stop the compressor from
5173 // renaming the variable to something shorter
5175 /** eval:var:batch */
5180 function nodupIEXml(cs){
5182 cs[0].setAttribute("_nodup", d);
5184 for(var i = 1, len = cs.length; i < len; i++){
5186 if(!c.getAttribute("_nodup") != d){
5187 c.setAttribute("_nodup", d);
5191 for(var i = 0, len = cs.length; i < len; i++){
5192 cs[i].removeAttribute("_nodup");
5201 var len = cs.length, c, i, r = cs, cj, ri = -1;
5202 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5205 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5206 return nodupIEXml(cs);
5210 for(i = 1; c = cs[i]; i++){
5215 for(var j = 0; j < i; j++){
5218 for(j = i+1; cj = cs[j]; j++){
5230 function quickDiffIEXml(c1, c2){
5232 for(var i = 0, len = c1.length; i < len; i++){
5233 c1[i].setAttribute("_qdiff", d);
5236 for(var i = 0, len = c2.length; i < len; i++){
5237 if(c2[i].getAttribute("_qdiff") != d){
5238 r[r.length] = c2[i];
5241 for(var i = 0, len = c1.length; i < len; i++){
5242 c1[i].removeAttribute("_qdiff");
5247 function quickDiff(c1, c2){
5248 var len1 = c1.length;
5252 if(isIE && c1[0].selectSingleNode){
5253 return quickDiffIEXml(c1, c2);
5256 for(var i = 0; i < len1; i++){
5260 for(var i = 0, len = c2.length; i < len; i++){
5261 if(c2[i]._qdiff != d){
5262 r[r.length] = c2[i];
5268 function quickId(ns, mode, root, id){
5270 var d = root.ownerDocument || root;
5271 return d.getElementById(id);
5273 ns = getNodes(ns, mode, "*");
5274 return byId(ns, null, id);
5278 getStyle : function(el, name){
5279 return Roo.fly(el).getStyle(name);
5282 * Compiles a selector/xpath query into a reusable function. The returned function
5283 * takes one parameter "root" (optional), which is the context node from where the query should start.
5284 * @param {String} selector The selector/xpath query
5285 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5286 * @return {Function}
5288 compile : function(path, type){
5289 type = type || "select";
5291 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5292 var q = path, mode, lq;
5293 var tk = Roo.DomQuery.matchers;
5294 var tklen = tk.length;
5297 // accept leading mode switch
5298 var lmode = q.match(modeRe);
5299 if(lmode && lmode[1]){
5300 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5301 q = q.replace(lmode[1], "");
5303 // strip leading slashes
5304 while(path.substr(0, 1)=="/"){
5305 path = path.substr(1);
5308 while(q && lq != q){
5310 var tm = q.match(tagTokenRe);
5311 if(type == "select"){
5314 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5316 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5318 q = q.replace(tm[0], "");
5319 }else if(q.substr(0, 1) != '@'){
5320 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5325 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5327 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5329 q = q.replace(tm[0], "");
5332 while(!(mm = q.match(modeRe))){
5333 var matched = false;
5334 for(var j = 0; j < tklen; j++){
5336 var m = q.match(t.re);
5338 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5341 q = q.replace(m[0], "");
5346 // prevent infinite loop on bad selector
5348 throw 'Error parsing selector, parsing failed at "' + q + '"';
5352 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5353 q = q.replace(mm[1], "");
5356 fn[fn.length] = "return nodup(n);\n}";
5359 * list of variables that need from compression as they are used by eval.
5369 * eval:var:byClassName
5371 * eval:var:byAttribute
5372 * eval:var:attrValue
5380 * Selects a group of elements.
5381 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5382 * @param {Node} root (optional) The start of the query (defaults to document).
5385 select : function(path, root, type){
5386 if(!root || root == document){
5389 if(typeof root == "string"){
5390 root = document.getElementById(root);
5392 var paths = path.split(",");
5394 for(var i = 0, len = paths.length; i < len; i++){
5395 var p = paths[i].replace(trimRe, "");
5397 cache[p] = Roo.DomQuery.compile(p);
5399 throw p + " is not a valid selector";
5402 var result = cache[p](root);
5403 if(result && result != document){
5404 results = results.concat(result);
5407 if(paths.length > 1){
5408 return nodup(results);
5414 * Selects a single element.
5415 * @param {String} selector The selector/xpath query
5416 * @param {Node} root (optional) The start of the query (defaults to document).
5419 selectNode : function(path, root){
5420 return Roo.DomQuery.select(path, root)[0];
5424 * Selects the value of a node, optionally replacing null with the defaultValue.
5425 * @param {String} selector The selector/xpath query
5426 * @param {Node} root (optional) The start of the query (defaults to document).
5427 * @param {String} defaultValue
5429 selectValue : function(path, root, defaultValue){
5430 path = path.replace(trimRe, "");
5431 if(!valueCache[path]){
5432 valueCache[path] = Roo.DomQuery.compile(path, "select");
5434 var n = valueCache[path](root);
5435 n = n[0] ? n[0] : n;
5436 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5437 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5441 * Selects the value of a node, parsing integers and floats.
5442 * @param {String} selector The selector/xpath query
5443 * @param {Node} root (optional) The start of the query (defaults to document).
5444 * @param {Number} defaultValue
5447 selectNumber : function(path, root, defaultValue){
5448 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5449 return parseFloat(v);
5453 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5454 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5455 * @param {String} selector The simple selector to test
5458 is : function(el, ss){
5459 if(typeof el == "string"){
5460 el = document.getElementById(el);
5462 var isArray = (el instanceof Array);
5463 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5464 return isArray ? (result.length == el.length) : (result.length > 0);
5468 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5469 * @param {Array} el An array of elements to filter
5470 * @param {String} selector The simple selector to test
5471 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5472 * the selector instead of the ones that match
5475 filter : function(els, ss, nonMatches){
5476 ss = ss.replace(trimRe, "");
5477 if(!simpleCache[ss]){
5478 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5480 var result = simpleCache[ss](els);
5481 return nonMatches ? quickDiff(result, els) : result;
5485 * Collection of matching regular expressions and code snippets.
5489 select: 'n = byClassName(n, null, " {1} ");'
5491 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5492 select: 'n = byPseudo(n, "{1}", "{2}");'
5494 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5495 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5498 select: 'n = byId(n, null, "{1}");'
5501 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5506 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5507 * 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, > <.
5510 "=" : function(a, v){
5513 "!=" : function(a, v){
5516 "^=" : function(a, v){
5517 return a && a.substr(0, v.length) == v;
5519 "$=" : function(a, v){
5520 return a && a.substr(a.length-v.length) == v;
5522 "*=" : function(a, v){
5523 return a && a.indexOf(v) !== -1;
5525 "%=" : function(a, v){
5526 return (a % v) == 0;
5528 "|=" : function(a, v){
5529 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5531 "~=" : function(a, v){
5532 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5537 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5538 * and the argument (if any) supplied in the selector.
5541 "first-child" : function(c){
5542 var r = [], ri = -1, n;
5543 for(var i = 0, ci; ci = n = c[i]; i++){
5544 while((n = n.previousSibling) && n.nodeType != 1);
5552 "last-child" : function(c){
5553 var r = [], ri = -1, n;
5554 for(var i = 0, ci; ci = n = c[i]; i++){
5555 while((n = n.nextSibling) && n.nodeType != 1);
5563 "nth-child" : function(c, a) {
5564 var r = [], ri = -1;
5565 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5566 var f = (m[1] || 1) - 0, l = m[2] - 0;
5567 for(var i = 0, n; n = c[i]; i++){
5568 var pn = n.parentNode;
5569 if (batch != pn._batch) {
5571 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5572 if(cn.nodeType == 1){
5579 if (l == 0 || n.nodeIndex == l){
5582 } else if ((n.nodeIndex + l) % f == 0){
5590 "only-child" : function(c){
5591 var r = [], ri = -1;;
5592 for(var i = 0, ci; ci = c[i]; i++){
5593 if(!prev(ci) && !next(ci)){
5600 "empty" : function(c){
5601 var r = [], ri = -1;
5602 for(var i = 0, ci; ci = c[i]; i++){
5603 var cns = ci.childNodes, j = 0, cn, empty = true;
5606 if(cn.nodeType == 1 || cn.nodeType == 3){
5618 "contains" : function(c, v){
5619 var r = [], ri = -1;
5620 for(var i = 0, ci; ci = c[i]; i++){
5621 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5628 "nodeValue" : function(c, v){
5629 var r = [], ri = -1;
5630 for(var i = 0, ci; ci = c[i]; i++){
5631 if(ci.firstChild && ci.firstChild.nodeValue == v){
5638 "checked" : function(c){
5639 var r = [], ri = -1;
5640 for(var i = 0, ci; ci = c[i]; i++){
5641 if(ci.checked == true){
5648 "not" : function(c, ss){
5649 return Roo.DomQuery.filter(c, ss, true);
5652 "odd" : function(c){
5653 return this["nth-child"](c, "odd");
5656 "even" : function(c){
5657 return this["nth-child"](c, "even");
5660 "nth" : function(c, a){
5661 return c[a-1] || [];
5664 "first" : function(c){
5668 "last" : function(c){
5669 return c[c.length-1] || [];
5672 "has" : function(c, ss){
5673 var s = Roo.DomQuery.select;
5674 var r = [], ri = -1;
5675 for(var i = 0, ci; ci = c[i]; i++){
5676 if(s(ss, ci).length > 0){
5683 "next" : function(c, ss){
5684 var is = Roo.DomQuery.is;
5685 var r = [], ri = -1;
5686 for(var i = 0, ci; ci = c[i]; i++){
5695 "prev" : function(c, ss){
5696 var is = Roo.DomQuery.is;
5697 var r = [], ri = -1;
5698 for(var i = 0, ci; ci = c[i]; i++){
5711 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5712 * @param {String} path The selector/xpath query
5713 * @param {Node} root (optional) The start of the query (defaults to document).
5718 Roo.query = Roo.DomQuery.select;
5721 * Ext JS Library 1.1.1
5722 * Copyright(c) 2006-2007, Ext JS, LLC.
5724 * Originally Released Under LGPL - original licence link has changed is not relivant.
5727 * <script type="text/javascript">
5731 * @class Roo.util.Observable
5732 * Base class that provides a common interface for publishing events. Subclasses are expected to
5733 * to have a property "events" with all the events defined.<br>
5736 Employee = function(name){
5743 Roo.extend(Employee, Roo.util.Observable);
5745 * @param {Object} config properties to use (incuding events / listeners)
5748 Roo.util.Observable = function(cfg){
5751 this.addEvents(cfg.events || {});
5753 delete cfg.events; // make sure
5756 Roo.apply(this, cfg);
5759 this.on(this.listeners);
5760 delete this.listeners;
5763 Roo.util.Observable.prototype = {
5765 * @cfg {Object} listeners list of events and functions to call for this object,
5769 'click' : function(e) {
5779 * Fires the specified event with the passed parameters (minus the event name).
5780 * @param {String} eventName
5781 * @param {Object...} args Variable number of parameters are passed to handlers
5782 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5784 fireEvent : function(){
5785 var ce = this.events[arguments[0].toLowerCase()];
5786 if(typeof ce == "object"){
5787 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5794 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5797 * Appends an event handler to this component
5798 * @param {String} eventName The type of event to listen for
5799 * @param {Function} handler The method the event invokes
5800 * @param {Object} scope (optional) The scope in which to execute the handler
5801 * function. The handler function's "this" context.
5802 * @param {Object} options (optional) An object containing handler configuration
5803 * properties. This may contain any of the following properties:<ul>
5804 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5805 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5806 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5807 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5808 * by the specified number of milliseconds. If the event fires again within that time, the original
5809 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5812 * <b>Combining Options</b><br>
5813 * Using the options argument, it is possible to combine different types of listeners:<br>
5815 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5817 el.on('click', this.onClick, this, {
5824 * <b>Attaching multiple handlers in 1 call</b><br>
5825 * The method also allows for a single argument to be passed which is a config object containing properties
5826 * which specify multiple handlers.
5835 fn: this.onMouseOver,
5839 fn: this.onMouseOut,
5845 * Or a shorthand syntax which passes the same scope object to all handlers:
5848 'click': this.onClick,
5849 'mouseover': this.onMouseOver,
5850 'mouseout': this.onMouseOut,
5855 addListener : function(eventName, fn, scope, o){
5856 if(typeof eventName == "object"){
5859 if(this.filterOptRe.test(e)){
5862 if(typeof o[e] == "function"){
5864 this.addListener(e, o[e], o.scope, o);
5866 // individual options
5867 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5872 o = (!o || typeof o == "boolean") ? {} : o;
5873 eventName = eventName.toLowerCase();
5874 var ce = this.events[eventName] || true;
5875 if(typeof ce == "boolean"){
5876 ce = new Roo.util.Event(this, eventName);
5877 this.events[eventName] = ce;
5879 ce.addListener(fn, scope, o);
5883 * Removes a listener
5884 * @param {String} eventName The type of event to listen for
5885 * @param {Function} handler The handler to remove
5886 * @param {Object} scope (optional) The scope (this object) for the handler
5888 removeListener : function(eventName, fn, scope){
5889 var ce = this.events[eventName.toLowerCase()];
5890 if(typeof ce == "object"){
5891 ce.removeListener(fn, scope);
5896 * Removes all listeners for this object
5898 purgeListeners : function(){
5899 for(var evt in this.events){
5900 if(typeof this.events[evt] == "object"){
5901 this.events[evt].clearListeners();
5906 relayEvents : function(o, events){
5907 var createHandler = function(ename){
5909 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5912 for(var i = 0, len = events.length; i < len; i++){
5913 var ename = events[i];
5914 if(!this.events[ename]){ this.events[ename] = true; };
5915 o.on(ename, createHandler(ename), this);
5920 * Used to define events on this Observable
5921 * @param {Object} object The object with the events defined
5923 addEvents : function(o){
5927 Roo.applyIf(this.events, o);
5931 * Checks to see if this object has any listeners for a specified event
5932 * @param {String} eventName The name of the event to check for
5933 * @return {Boolean} True if the event is being listened for, else false
5935 hasListener : function(eventName){
5936 var e = this.events[eventName];
5937 return typeof e == "object" && e.listeners.length > 0;
5941 * Appends an event handler to this element (shorthand for addListener)
5942 * @param {String} eventName The type of event to listen for
5943 * @param {Function} handler The method the event invokes
5944 * @param {Object} scope (optional) The scope in which to execute the handler
5945 * function. The handler function's "this" context.
5946 * @param {Object} options (optional)
5949 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5951 * Removes a listener (shorthand for removeListener)
5952 * @param {String} eventName The type of event to listen for
5953 * @param {Function} handler The handler to remove
5954 * @param {Object} scope (optional) The scope (this object) for the handler
5957 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5960 * Starts capture on the specified Observable. All events will be passed
5961 * to the supplied function with the event name + standard signature of the event
5962 * <b>before</b> the event is fired. If the supplied function returns false,
5963 * the event will not fire.
5964 * @param {Observable} o The Observable to capture
5965 * @param {Function} fn The function to call
5966 * @param {Object} scope (optional) The scope (this object) for the fn
5969 Roo.util.Observable.capture = function(o, fn, scope){
5970 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5974 * Removes <b>all</b> added captures from the Observable.
5975 * @param {Observable} o The Observable to release
5978 Roo.util.Observable.releaseCapture = function(o){
5979 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5984 var createBuffered = function(h, o, scope){
5985 var task = new Roo.util.DelayedTask();
5987 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5991 var createSingle = function(h, e, fn, scope){
5993 e.removeListener(fn, scope);
5994 return h.apply(scope, arguments);
5998 var createDelayed = function(h, o, scope){
6000 var args = Array.prototype.slice.call(arguments, 0);
6001 setTimeout(function(){
6002 h.apply(scope, args);
6007 Roo.util.Event = function(obj, name){
6010 this.listeners = [];
6013 Roo.util.Event.prototype = {
6014 addListener : function(fn, scope, options){
6015 var o = options || {};
6016 scope = scope || this.obj;
6017 if(!this.isListening(fn, scope)){
6018 var l = {fn: fn, scope: scope, options: o};
6021 h = createDelayed(h, o, scope);
6024 h = createSingle(h, this, fn, scope);
6027 h = createBuffered(h, o, scope);
6030 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6031 this.listeners.push(l);
6033 this.listeners = this.listeners.slice(0);
6034 this.listeners.push(l);
6039 findListener : function(fn, scope){
6040 scope = scope || this.obj;
6041 var ls = this.listeners;
6042 for(var i = 0, len = ls.length; i < len; i++){
6044 if(l.fn == fn && l.scope == scope){
6051 isListening : function(fn, scope){
6052 return this.findListener(fn, scope) != -1;
6055 removeListener : function(fn, scope){
6057 if((index = this.findListener(fn, scope)) != -1){
6059 this.listeners.splice(index, 1);
6061 this.listeners = this.listeners.slice(0);
6062 this.listeners.splice(index, 1);
6069 clearListeners : function(){
6070 this.listeners = [];
6074 var ls = this.listeners, scope, len = ls.length;
6077 var args = Array.prototype.slice.call(arguments, 0);
6078 for(var i = 0; i < len; i++){
6080 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6081 this.firing = false;
6085 this.firing = false;
6092 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6099 * @class Roo.Document
6100 * @extends Roo.util.Observable
6101 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6103 * @param {Object} config the methods and properties of the 'base' class for the application.
6105 * Generic Page handler - implement this to start your app..
6108 * MyProject = new Roo.Document({
6110 'load' : true // your events..
6113 'ready' : function() {
6114 // fired on Roo.onReady()
6119 Roo.Document = function(cfg) {
6124 Roo.util.Observable.call(this,cfg);
6128 Roo.onReady(function() {
6129 _this.fireEvent('ready');
6135 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6137 * Ext JS Library 1.1.1
6138 * Copyright(c) 2006-2007, Ext JS, LLC.
6140 * Originally Released Under LGPL - original licence link has changed is not relivant.
6143 * <script type="text/javascript">
6147 * @class Roo.EventManager
6148 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6149 * several useful events directly.
6150 * See {@link Roo.EventObject} for more details on normalized event objects.
6153 Roo.EventManager = function(){
6154 var docReadyEvent, docReadyProcId, docReadyState = false;
6155 var resizeEvent, resizeTask, textEvent, textSize;
6156 var E = Roo.lib.Event;
6157 var D = Roo.lib.Dom;
6162 var fireDocReady = function(){
6164 docReadyState = true;
6167 clearInterval(docReadyProcId);
6169 if(Roo.isGecko || Roo.isOpera) {
6170 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6173 var defer = document.getElementById("ie-deferred-loader");
6175 defer.onreadystatechange = null;
6176 defer.parentNode.removeChild(defer);
6180 docReadyEvent.fire();
6181 docReadyEvent.clearListeners();
6186 var initDocReady = function(){
6187 docReadyEvent = new Roo.util.Event();
6188 if(Roo.isGecko || Roo.isOpera) {
6189 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6191 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6192 var defer = document.getElementById("ie-deferred-loader");
6193 defer.onreadystatechange = function(){
6194 if(this.readyState == "complete"){
6198 }else if(Roo.isSafari){
6199 docReadyProcId = setInterval(function(){
6200 var rs = document.readyState;
6201 if(rs == "complete") {
6206 // no matter what, make sure it fires on load
6207 E.on(window, "load", fireDocReady);
6210 var createBuffered = function(h, o){
6211 var task = new Roo.util.DelayedTask(h);
6213 // create new event object impl so new events don't wipe out properties
6214 e = new Roo.EventObjectImpl(e);
6215 task.delay(o.buffer, h, null, [e]);
6219 var createSingle = function(h, el, ename, fn){
6221 Roo.EventManager.removeListener(el, ename, fn);
6226 var createDelayed = function(h, o){
6228 // create new event object impl so new events don't wipe out properties
6229 e = new Roo.EventObjectImpl(e);
6230 setTimeout(function(){
6235 var transitionEndVal = false;
6237 var transitionEnd = function()
6239 if (transitionEndVal) {
6240 return transitionEndVal;
6242 var el = document.createElement('div');
6244 var transEndEventNames = {
6245 WebkitTransition : 'webkitTransitionEnd',
6246 MozTransition : 'transitionend',
6247 OTransition : 'oTransitionEnd otransitionend',
6248 transition : 'transitionend'
6251 for (var name in transEndEventNames) {
6252 if (el.style[name] !== undefined) {
6253 transitionEndVal = transEndEventNames[name];
6254 return transitionEndVal ;
6260 var listen = function(element, ename, opt, fn, scope){
6261 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6262 fn = fn || o.fn; scope = scope || o.scope;
6263 var el = Roo.getDom(element);
6267 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6270 if (ename == 'transitionend') {
6271 ename = transitionEnd();
6273 var h = function(e){
6274 e = Roo.EventObject.setEvent(e);
6277 t = e.getTarget(o.delegate, el);
6284 if(o.stopEvent === true){
6287 if(o.preventDefault === true){
6290 if(o.stopPropagation === true){
6291 e.stopPropagation();
6294 if(o.normalized === false){
6298 fn.call(scope || el, e, t, o);
6301 h = createDelayed(h, o);
6304 h = createSingle(h, el, ename, fn);
6307 h = createBuffered(h, o);
6310 fn._handlers = fn._handlers || [];
6313 fn._handlers.push([Roo.id(el), ename, h]);
6318 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6319 el.addEventListener("DOMMouseScroll", h, false);
6320 E.on(window, 'unload', function(){
6321 el.removeEventListener("DOMMouseScroll", h, false);
6324 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6325 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6330 var stopListening = function(el, ename, fn){
6331 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6333 for(var i = 0, len = hds.length; i < len; i++){
6335 if(h[0] == id && h[1] == ename){
6342 E.un(el, ename, hd);
6343 el = Roo.getDom(el);
6344 if(ename == "mousewheel" && el.addEventListener){
6345 el.removeEventListener("DOMMouseScroll", hd, false);
6347 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6348 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6352 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6359 * @scope Roo.EventManager
6364 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6365 * object with a Roo.EventObject
6366 * @param {Function} fn The method the event invokes
6367 * @param {Object} scope An object that becomes the scope of the handler
6368 * @param {boolean} override If true, the obj passed in becomes
6369 * the execution scope of the listener
6370 * @return {Function} The wrapped function
6373 wrap : function(fn, scope, override){
6375 Roo.EventObject.setEvent(e);
6376 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6381 * Appends an event handler to an element (shorthand for addListener)
6382 * @param {String/HTMLElement} element The html element or id to assign the
6383 * @param {String} eventName The type of event to listen for
6384 * @param {Function} handler The method the event invokes
6385 * @param {Object} scope (optional) The scope in which to execute the handler
6386 * function. The handler function's "this" context.
6387 * @param {Object} options (optional) An object containing handler configuration
6388 * properties. This may contain any of the following properties:<ul>
6389 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6390 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6391 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6392 * <li>preventDefault {Boolean} True to prevent the default action</li>
6393 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6394 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6395 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6396 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6397 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6398 * by the specified number of milliseconds. If the event fires again within that time, the original
6399 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6402 * <b>Combining Options</b><br>
6403 * Using the options argument, it is possible to combine different types of listeners:<br>
6405 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6407 el.on('click', this.onClick, this, {
6414 * <b>Attaching multiple handlers in 1 call</b><br>
6415 * The method also allows for a single argument to be passed which is a config object containing properties
6416 * which specify multiple handlers.
6426 fn: this.onMouseOver
6435 * Or a shorthand syntax:<br>
6438 'click' : this.onClick,
6439 'mouseover' : this.onMouseOver,
6440 'mouseout' : this.onMouseOut
6444 addListener : function(element, eventName, fn, scope, options){
6445 if(typeof eventName == "object"){
6451 if(typeof o[e] == "function"){
6453 listen(element, e, o, o[e], o.scope);
6455 // individual options
6456 listen(element, e, o[e]);
6461 return listen(element, eventName, options, fn, scope);
6465 * Removes an event handler
6467 * @param {String/HTMLElement} element The id or html element to remove the
6469 * @param {String} eventName The type of event
6470 * @param {Function} fn
6471 * @return {Boolean} True if a listener was actually removed
6473 removeListener : function(element, eventName, fn){
6474 return stopListening(element, eventName, fn);
6478 * Fires when the document is ready (before onload and before images are loaded). Can be
6479 * accessed shorthanded Roo.onReady().
6480 * @param {Function} fn The method the event invokes
6481 * @param {Object} scope An object that becomes the scope of the handler
6482 * @param {boolean} options
6484 onDocumentReady : function(fn, scope, options){
6485 if(docReadyState){ // if it already fired
6486 docReadyEvent.addListener(fn, scope, options);
6487 docReadyEvent.fire();
6488 docReadyEvent.clearListeners();
6494 docReadyEvent.addListener(fn, scope, options);
6498 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6499 * @param {Function} fn The method the event invokes
6500 * @param {Object} scope An object that becomes the scope of the handler
6501 * @param {boolean} options
6503 onWindowResize : function(fn, scope, options){
6505 resizeEvent = new Roo.util.Event();
6506 resizeTask = new Roo.util.DelayedTask(function(){
6507 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6509 E.on(window, "resize", function(){
6511 resizeTask.delay(50);
6513 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6517 resizeEvent.addListener(fn, scope, options);
6521 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6522 * @param {Function} fn The method the event invokes
6523 * @param {Object} scope An object that becomes the scope of the handler
6524 * @param {boolean} options
6526 onTextResize : function(fn, scope, options){
6528 textEvent = new Roo.util.Event();
6529 var textEl = new Roo.Element(document.createElement('div'));
6530 textEl.dom.className = 'x-text-resize';
6531 textEl.dom.innerHTML = 'X';
6532 textEl.appendTo(document.body);
6533 textSize = textEl.dom.offsetHeight;
6534 setInterval(function(){
6535 if(textEl.dom.offsetHeight != textSize){
6536 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6538 }, this.textResizeInterval);
6540 textEvent.addListener(fn, scope, options);
6544 * Removes the passed window resize listener.
6545 * @param {Function} fn The method the event invokes
6546 * @param {Object} scope The scope of handler
6548 removeResizeListener : function(fn, scope){
6550 resizeEvent.removeListener(fn, scope);
6555 fireResize : function(){
6557 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6561 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6565 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6567 textResizeInterval : 50
6572 * @scopeAlias pub=Roo.EventManager
6576 * Appends an event handler to an element (shorthand for addListener)
6577 * @param {String/HTMLElement} element The html element or id to assign the
6578 * @param {String} eventName The type of event to listen for
6579 * @param {Function} handler The method the event invokes
6580 * @param {Object} scope (optional) The scope in which to execute the handler
6581 * function. The handler function's "this" context.
6582 * @param {Object} options (optional) An object containing handler configuration
6583 * properties. This may contain any of the following properties:<ul>
6584 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6585 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6586 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6587 * <li>preventDefault {Boolean} True to prevent the default action</li>
6588 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6589 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6590 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6591 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6592 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6593 * by the specified number of milliseconds. If the event fires again within that time, the original
6594 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6597 * <b>Combining Options</b><br>
6598 * Using the options argument, it is possible to combine different types of listeners:<br>
6600 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6602 el.on('click', this.onClick, this, {
6609 * <b>Attaching multiple handlers in 1 call</b><br>
6610 * The method also allows for a single argument to be passed which is a config object containing properties
6611 * which specify multiple handlers.
6621 fn: this.onMouseOver
6630 * Or a shorthand syntax:<br>
6633 'click' : this.onClick,
6634 'mouseover' : this.onMouseOver,
6635 'mouseout' : this.onMouseOut
6639 pub.on = pub.addListener;
6640 pub.un = pub.removeListener;
6642 pub.stoppedMouseDownEvent = new Roo.util.Event();
6646 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6647 * @param {Function} fn The method the event invokes
6648 * @param {Object} scope An object that becomes the scope of the handler
6649 * @param {boolean} override If true, the obj passed in becomes
6650 * the execution scope of the listener
6654 Roo.onReady = Roo.EventManager.onDocumentReady;
6656 Roo.onReady(function(){
6657 var bd = Roo.get(document.body);
6662 : Roo.isIE11 ? "roo-ie11"
6663 : Roo.isEdge ? "roo-edge"
6664 : Roo.isGecko ? "roo-gecko"
6665 : Roo.isOpera ? "roo-opera"
6666 : Roo.isSafari ? "roo-safari" : ""];
6669 cls.push("roo-mac");
6672 cls.push("roo-linux");
6675 cls.push("roo-ios");
6678 cls.push("roo-touch");
6680 if(Roo.isBorderBox){
6681 cls.push('roo-border-box');
6683 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6684 var p = bd.dom.parentNode;
6686 p.className += ' roo-strict';
6689 bd.addClass(cls.join(' '));
6693 * @class Roo.EventObject
6694 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6695 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6698 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6700 var target = e.getTarget();
6703 var myDiv = Roo.get("myDiv");
6704 myDiv.on("click", handleClick);
6706 Roo.EventManager.on("myDiv", 'click', handleClick);
6707 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6711 Roo.EventObject = function(){
6713 var E = Roo.lib.Event;
6715 // safari keypress events for special keys return bad keycodes
6718 63235 : 39, // right
6721 63276 : 33, // page up
6722 63277 : 34, // page down
6723 63272 : 46, // delete
6728 // normalize button clicks
6729 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6730 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6732 Roo.EventObjectImpl = function(e){
6734 this.setEvent(e.browserEvent || e);
6737 Roo.EventObjectImpl.prototype = {
6739 * Used to fix doc tools.
6740 * @scope Roo.EventObject.prototype
6746 /** The normal browser event */
6747 browserEvent : null,
6748 /** The button pressed in a mouse event */
6750 /** True if the shift key was down during the event */
6752 /** True if the control key was down during the event */
6754 /** True if the alt key was down during the event */
6813 setEvent : function(e){
6814 if(e == this || (e && e.browserEvent)){ // already wrapped
6817 this.browserEvent = e;
6819 // normalize buttons
6820 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6821 if(e.type == 'click' && this.button == -1){
6825 this.shiftKey = e.shiftKey;
6826 // mac metaKey behaves like ctrlKey
6827 this.ctrlKey = e.ctrlKey || e.metaKey;
6828 this.altKey = e.altKey;
6829 // in getKey these will be normalized for the mac
6830 this.keyCode = e.keyCode;
6831 // keyup warnings on firefox.
6832 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6833 // cache the target for the delayed and or buffered events
6834 this.target = E.getTarget(e);
6836 this.xy = E.getXY(e);
6839 this.shiftKey = false;
6840 this.ctrlKey = false;
6841 this.altKey = false;
6851 * Stop the event (preventDefault and stopPropagation)
6853 stopEvent : function(){
6854 if(this.browserEvent){
6855 if(this.browserEvent.type == 'mousedown'){
6856 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6858 E.stopEvent(this.browserEvent);
6863 * Prevents the browsers default handling of the event.
6865 preventDefault : function(){
6866 if(this.browserEvent){
6867 E.preventDefault(this.browserEvent);
6872 isNavKeyPress : function(){
6873 var k = this.keyCode;
6874 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6875 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6878 isSpecialKey : function(){
6879 var k = this.keyCode;
6880 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6881 (k == 16) || (k == 17) ||
6882 (k >= 18 && k <= 20) ||
6883 (k >= 33 && k <= 35) ||
6884 (k >= 36 && k <= 39) ||
6885 (k >= 44 && k <= 45);
6888 * Cancels bubbling of the event.
6890 stopPropagation : function(){
6891 if(this.browserEvent){
6892 if(this.type == 'mousedown'){
6893 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6895 E.stopPropagation(this.browserEvent);
6900 * Gets the key code for the event.
6903 getCharCode : function(){
6904 return this.charCode || this.keyCode;
6908 * Returns a normalized keyCode for the event.
6909 * @return {Number} The key code
6911 getKey : function(){
6912 var k = this.keyCode || this.charCode;
6913 return Roo.isSafari ? (safariKeys[k] || k) : k;
6917 * Gets the x coordinate of the event.
6920 getPageX : function(){
6925 * Gets the y coordinate of the event.
6928 getPageY : function(){
6933 * Gets the time of the event.
6936 getTime : function(){
6937 if(this.browserEvent){
6938 return E.getTime(this.browserEvent);
6944 * Gets the page coordinates of the event.
6945 * @return {Array} The xy values like [x, y]
6952 * Gets the target for the event.
6953 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6954 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6955 search as a number or element (defaults to 10 || document.body)
6956 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6957 * @return {HTMLelement}
6959 getTarget : function(selector, maxDepth, returnEl){
6960 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6963 * Gets the related target.
6964 * @return {HTMLElement}
6966 getRelatedTarget : function(){
6967 if(this.browserEvent){
6968 return E.getRelatedTarget(this.browserEvent);
6974 * Normalizes mouse wheel delta across browsers
6975 * @return {Number} The delta
6977 getWheelDelta : function(){
6978 var e = this.browserEvent;
6980 if(e.wheelDelta){ /* IE/Opera. */
6981 delta = e.wheelDelta/120;
6982 }else if(e.detail){ /* Mozilla case. */
6983 delta = -e.detail/3;
6989 * Returns true if the control, meta, shift or alt key was pressed during this event.
6992 hasModifier : function(){
6993 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6997 * Returns true if the target of this event equals el or is a child of el
6998 * @param {String/HTMLElement/Element} el
6999 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7002 within : function(el, related){
7003 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7004 return t && Roo.fly(el).contains(t);
7007 getPoint : function(){
7008 return new Roo.lib.Point(this.xy[0], this.xy[1]);
7012 return new Roo.EventObjectImpl();
7017 * Ext JS Library 1.1.1
7018 * Copyright(c) 2006-2007, Ext JS, LLC.
7020 * Originally Released Under LGPL - original licence link has changed is not relivant.
7023 * <script type="text/javascript">
7027 // was in Composite Element!??!?!
7030 var D = Roo.lib.Dom;
7031 var E = Roo.lib.Event;
7032 var A = Roo.lib.Anim;
7034 // local style camelizing for speed
7036 var camelRe = /(-[a-z])/gi;
7037 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7038 var view = document.defaultView;
7041 * @class Roo.Element
7042 * Represents an Element in the DOM.<br><br>
7045 var el = Roo.get("my-div");
7048 var el = getEl("my-div");
7050 // or with a DOM element
7051 var el = Roo.get(myDivElement);
7053 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7054 * each call instead of constructing a new one.<br><br>
7055 * <b>Animations</b><br />
7056 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7057 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7059 Option Default Description
7060 --------- -------- ---------------------------------------------
7061 duration .35 The duration of the animation in seconds
7062 easing easeOut The YUI easing method
7063 callback none A function to execute when the anim completes
7064 scope this The scope (this) of the callback function
7066 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7067 * manipulate the animation. Here's an example:
7069 var el = Roo.get("my-div");
7074 // default animation
7075 el.setWidth(100, true);
7077 // animation with some options set
7084 // using the "anim" property to get the Anim object
7090 el.setWidth(100, opt);
7092 if(opt.anim.isAnimated()){
7096 * <b> Composite (Collections of) Elements</b><br />
7097 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7098 * @constructor Create a new Element directly.
7099 * @param {String/HTMLElement} element
7100 * @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).
7102 Roo.Element = function(element, forceNew){
7103 var dom = typeof element == "string" ?
7104 document.getElementById(element) : element;
7105 if(!dom){ // invalid id/element
7109 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7110 return Roo.Element.cache[id];
7120 * The DOM element ID
7123 this.id = id || Roo.id(dom);
7126 var El = Roo.Element;
7130 * The element's default display mode (defaults to "")
7133 originalDisplay : "",
7137 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7143 * Sets the element's visibility mode. When setVisible() is called it
7144 * will use this to determine whether to set the visibility or the display property.
7145 * @param visMode Element.VISIBILITY or Element.DISPLAY
7146 * @return {Roo.Element} this
7148 setVisibilityMode : function(visMode){
7149 this.visibilityMode = visMode;
7153 * Convenience method for setVisibilityMode(Element.DISPLAY)
7154 * @param {String} display (optional) What to set display to when visible
7155 * @return {Roo.Element} this
7157 enableDisplayMode : function(display){
7158 this.setVisibilityMode(El.DISPLAY);
7159 if(typeof display != "undefined") { this.originalDisplay = display; }
7164 * 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)
7165 * @param {String} selector The simple selector to test
7166 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7167 search as a number or element (defaults to 10 || document.body)
7168 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7169 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7171 findParent : function(simpleSelector, maxDepth, returnEl){
7172 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7173 maxDepth = maxDepth || 50;
7174 if(typeof maxDepth != "number"){
7175 stopEl = Roo.getDom(maxDepth);
7178 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7179 if(dq.is(p, simpleSelector)){
7180 return returnEl ? Roo.get(p) : p;
7190 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7191 * @param {String} selector The simple selector to test
7192 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7193 search as a number or element (defaults to 10 || document.body)
7194 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7195 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7197 findParentNode : function(simpleSelector, maxDepth, returnEl){
7198 var p = Roo.fly(this.dom.parentNode, '_internal');
7199 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7203 * Looks at the scrollable parent element
7205 findScrollableParent : function()
7207 var overflowRegex = /(auto|scroll)/;
7209 if(this.getStyle('position') === 'fixed'){
7210 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7213 var excludeStaticParent = this.getStyle('position') === "absolute";
7215 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7217 if (excludeStaticParent && parent.getStyle('position') === "static") {
7221 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7225 if(parent.dom.nodeName.toLowerCase() == 'body'){
7226 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7230 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7234 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7235 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7236 * @param {String} selector The simple selector to test
7237 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7238 search as a number or element (defaults to 10 || document.body)
7239 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7241 up : function(simpleSelector, maxDepth){
7242 return this.findParentNode(simpleSelector, maxDepth, true);
7248 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7249 * @param {String} selector The simple selector to test
7250 * @return {Boolean} True if this element matches the selector, else false
7252 is : function(simpleSelector){
7253 return Roo.DomQuery.is(this.dom, simpleSelector);
7257 * Perform animation on this element.
7258 * @param {Object} args The YUI animation control args
7259 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7260 * @param {Function} onComplete (optional) Function to call when animation completes
7261 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7262 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7263 * @return {Roo.Element} this
7265 animate : function(args, duration, onComplete, easing, animType){
7266 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7271 * @private Internal animation call
7273 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7274 animType = animType || 'run';
7276 var anim = Roo.lib.Anim[animType](
7278 (opt.duration || defaultDur) || .35,
7279 (opt.easing || defaultEase) || 'easeOut',
7281 Roo.callback(cb, this);
7282 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7290 // private legacy anim prep
7291 preanim : function(a, i){
7292 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7296 * Removes worthless text nodes
7297 * @param {Boolean} forceReclean (optional) By default the element
7298 * keeps track if it has been cleaned already so
7299 * you can call this over and over. However, if you update the element and
7300 * need to force a reclean, you can pass true.
7302 clean : function(forceReclean){
7303 if(this.isCleaned && forceReclean !== true){
7307 var d = this.dom, n = d.firstChild, ni = -1;
7309 var nx = n.nextSibling;
7310 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7317 this.isCleaned = true;
7322 calcOffsetsTo : function(el){
7325 var restorePos = false;
7326 if(el.getStyle('position') == 'static'){
7327 el.position('relative');
7332 while(op && op != d && op.tagName != 'HTML'){
7335 op = op.offsetParent;
7338 el.position('static');
7344 * Scrolls this element into view within the passed container.
7345 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7346 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7347 * @return {Roo.Element} this
7349 scrollIntoView : function(container, hscroll){
7350 var c = Roo.getDom(container) || document.body;
7353 var o = this.calcOffsetsTo(c),
7356 b = t+el.offsetHeight,
7357 r = l+el.offsetWidth;
7359 var ch = c.clientHeight;
7360 var ct = parseInt(c.scrollTop, 10);
7361 var cl = parseInt(c.scrollLeft, 10);
7363 var cr = cl + c.clientWidth;
7371 if(hscroll !== false){
7375 c.scrollLeft = r-c.clientWidth;
7382 scrollChildIntoView : function(child, hscroll){
7383 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7387 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7388 * the new height may not be available immediately.
7389 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7390 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7391 * @param {Function} onComplete (optional) Function to call when animation completes
7392 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7393 * @return {Roo.Element} this
7395 autoHeight : function(animate, duration, onComplete, easing){
7396 var oldHeight = this.getHeight();
7398 this.setHeight(1); // force clipping
7399 setTimeout(function(){
7400 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7402 this.setHeight(height);
7404 if(typeof onComplete == "function"){
7408 this.setHeight(oldHeight); // restore original height
7409 this.setHeight(height, animate, duration, function(){
7411 if(typeof onComplete == "function") { onComplete(); }
7412 }.createDelegate(this), easing);
7414 }.createDelegate(this), 0);
7419 * Returns true if this element is an ancestor of the passed element
7420 * @param {HTMLElement/String} el The element to check
7421 * @return {Boolean} True if this element is an ancestor of el, else false
7423 contains : function(el){
7424 if(!el){return false;}
7425 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7429 * Checks whether the element is currently visible using both visibility and display properties.
7430 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7431 * @return {Boolean} True if the element is currently visible, else false
7433 isVisible : function(deep) {
7434 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7435 if(deep !== true || !vis){
7438 var p = this.dom.parentNode;
7439 while(p && p.tagName.toLowerCase() != "body"){
7440 if(!Roo.fly(p, '_isVisible').isVisible()){
7449 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7450 * @param {String} selector The CSS selector
7451 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7452 * @return {CompositeElement/CompositeElementLite} The composite element
7454 select : function(selector, unique){
7455 return El.select(selector, unique, this.dom);
7459 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7460 * @param {String} selector The CSS selector
7461 * @return {Array} An array of the matched nodes
7463 query : function(selector, unique){
7464 return Roo.DomQuery.select(selector, this.dom);
7468 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7469 * @param {String} selector The CSS selector
7470 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7471 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7473 child : function(selector, returnDom){
7474 var n = Roo.DomQuery.selectNode(selector, this.dom);
7475 return returnDom ? n : Roo.get(n);
7479 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7480 * @param {String} selector The CSS selector
7481 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7482 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7484 down : function(selector, returnDom){
7485 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7486 return returnDom ? n : Roo.get(n);
7490 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7491 * @param {String} group The group the DD object is member of
7492 * @param {Object} config The DD config object
7493 * @param {Object} overrides An object containing methods to override/implement on the DD object
7494 * @return {Roo.dd.DD} The DD object
7496 initDD : function(group, config, overrides){
7497 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7498 return Roo.apply(dd, overrides);
7502 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7503 * @param {String} group The group the DDProxy object is member of
7504 * @param {Object} config The DDProxy config object
7505 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7506 * @return {Roo.dd.DDProxy} The DDProxy object
7508 initDDProxy : function(group, config, overrides){
7509 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7510 return Roo.apply(dd, overrides);
7514 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7515 * @param {String} group The group the DDTarget object is member of
7516 * @param {Object} config The DDTarget config object
7517 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7518 * @return {Roo.dd.DDTarget} The DDTarget object
7520 initDDTarget : function(group, config, overrides){
7521 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7522 return Roo.apply(dd, overrides);
7526 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7527 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7528 * @param {Boolean} visible Whether the element is visible
7529 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7530 * @return {Roo.Element} this
7532 setVisible : function(visible, animate){
7534 if(this.visibilityMode == El.DISPLAY){
7535 this.setDisplayed(visible);
7538 this.dom.style.visibility = visible ? "visible" : "hidden";
7541 // closure for composites
7543 var visMode = this.visibilityMode;
7545 this.setOpacity(.01);
7546 this.setVisible(true);
7548 this.anim({opacity: { to: (visible?1:0) }},
7549 this.preanim(arguments, 1),
7550 null, .35, 'easeIn', function(){
7552 if(visMode == El.DISPLAY){
7553 dom.style.display = "none";
7555 dom.style.visibility = "hidden";
7557 Roo.get(dom).setOpacity(1);
7565 * Returns true if display is not "none"
7568 isDisplayed : function() {
7569 return this.getStyle("display") != "none";
7573 * Toggles the element's visibility or display, depending on visibility mode.
7574 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7575 * @return {Roo.Element} this
7577 toggle : function(animate){
7578 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7583 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7584 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7585 * @return {Roo.Element} this
7587 setDisplayed : function(value) {
7588 if(typeof value == "boolean"){
7589 value = value ? this.originalDisplay : "none";
7591 this.setStyle("display", value);
7596 * Tries to focus the element. Any exceptions are caught and ignored.
7597 * @return {Roo.Element} this
7599 focus : function() {
7607 * Tries to blur the element. Any exceptions are caught and ignored.
7608 * @return {Roo.Element} this
7618 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7619 * @param {String/Array} className The CSS class to add, or an array of classes
7620 * @return {Roo.Element} this
7622 addClass : function(className){
7623 if(className instanceof Array){
7624 for(var i = 0, len = className.length; i < len; i++) {
7625 this.addClass(className[i]);
7628 if(className && !this.hasClass(className)){
7629 this.dom.className = this.dom.className + " " + className;
7636 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7637 * @param {String/Array} className The CSS class to add, or an array of classes
7638 * @return {Roo.Element} this
7640 radioClass : function(className){
7641 var siblings = this.dom.parentNode.childNodes;
7642 for(var i = 0; i < siblings.length; i++) {
7643 var s = siblings[i];
7644 if(s.nodeType == 1){
7645 Roo.get(s).removeClass(className);
7648 this.addClass(className);
7653 * Removes one or more CSS classes from the element.
7654 * @param {String/Array} className The CSS class to remove, or an array of classes
7655 * @return {Roo.Element} this
7657 removeClass : function(className){
7658 if(!className || !this.dom.className){
7661 if(className instanceof Array){
7662 for(var i = 0, len = className.length; i < len; i++) {
7663 this.removeClass(className[i]);
7666 if(this.hasClass(className)){
7667 var re = this.classReCache[className];
7669 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7670 this.classReCache[className] = re;
7672 this.dom.className =
7673 this.dom.className.replace(re, " ");
7683 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7684 * @param {String} className The CSS class to toggle
7685 * @return {Roo.Element} this
7687 toggleClass : function(className){
7688 if(this.hasClass(className)){
7689 this.removeClass(className);
7691 this.addClass(className);
7697 * Checks if the specified CSS class exists on this element's DOM node.
7698 * @param {String} className The CSS class to check for
7699 * @return {Boolean} True if the class exists, else false
7701 hasClass : function(className){
7702 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7706 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7707 * @param {String} oldClassName The CSS class to replace
7708 * @param {String} newClassName The replacement CSS class
7709 * @return {Roo.Element} this
7711 replaceClass : function(oldClassName, newClassName){
7712 this.removeClass(oldClassName);
7713 this.addClass(newClassName);
7718 * Returns an object with properties matching the styles requested.
7719 * For example, el.getStyles('color', 'font-size', 'width') might return
7720 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7721 * @param {String} style1 A style name
7722 * @param {String} style2 A style name
7723 * @param {String} etc.
7724 * @return {Object} The style object
7726 getStyles : function(){
7727 var a = arguments, len = a.length, r = {};
7728 for(var i = 0; i < len; i++){
7729 r[a[i]] = this.getStyle(a[i]);
7735 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7736 * @param {String} property The style property whose value is returned.
7737 * @return {String} The current value of the style property for this element.
7739 getStyle : function(){
7740 return view && view.getComputedStyle ?
7742 var el = this.dom, v, cs, camel;
7743 if(prop == 'float'){
7746 if(el.style && (v = el.style[prop])){
7749 if(cs = view.getComputedStyle(el, "")){
7750 if(!(camel = propCache[prop])){
7751 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7758 var el = this.dom, v, cs, camel;
7759 if(prop == 'opacity'){
7760 if(typeof el.style.filter == 'string'){
7761 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7763 var fv = parseFloat(m[1]);
7765 return fv ? fv / 100 : 0;
7770 }else if(prop == 'float'){
7771 prop = "styleFloat";
7773 if(!(camel = propCache[prop])){
7774 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7776 if(v = el.style[camel]){
7779 if(cs = el.currentStyle){
7787 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7788 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7789 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7790 * @return {Roo.Element} this
7792 setStyle : function(prop, value){
7793 if(typeof prop == "string"){
7795 if (prop == 'float') {
7796 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7801 if(!(camel = propCache[prop])){
7802 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7805 if(camel == 'opacity') {
7806 this.setOpacity(value);
7808 this.dom.style[camel] = value;
7811 for(var style in prop){
7812 if(typeof prop[style] != "function"){
7813 this.setStyle(style, prop[style]);
7821 * More flexible version of {@link #setStyle} for setting style properties.
7822 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7823 * a function which returns such a specification.
7824 * @return {Roo.Element} this
7826 applyStyles : function(style){
7827 Roo.DomHelper.applyStyles(this.dom, style);
7832 * 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).
7833 * @return {Number} The X position of the element
7836 return D.getX(this.dom);
7840 * 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).
7841 * @return {Number} The Y position of the element
7844 return D.getY(this.dom);
7848 * 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).
7849 * @return {Array} The XY position of the element
7852 return D.getXY(this.dom);
7856 * 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).
7857 * @param {Number} The X position of the element
7858 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7859 * @return {Roo.Element} this
7861 setX : function(x, animate){
7863 D.setX(this.dom, x);
7865 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7871 * 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).
7872 * @param {Number} The Y position of the element
7873 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7874 * @return {Roo.Element} this
7876 setY : function(y, animate){
7878 D.setY(this.dom, y);
7880 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7886 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7887 * @param {String} left The left CSS property value
7888 * @return {Roo.Element} this
7890 setLeft : function(left){
7891 this.setStyle("left", this.addUnits(left));
7896 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7897 * @param {String} top The top CSS property value
7898 * @return {Roo.Element} this
7900 setTop : function(top){
7901 this.setStyle("top", this.addUnits(top));
7906 * Sets the element's CSS right style.
7907 * @param {String} right The right CSS property value
7908 * @return {Roo.Element} this
7910 setRight : function(right){
7911 this.setStyle("right", this.addUnits(right));
7916 * Sets the element's CSS bottom style.
7917 * @param {String} bottom The bottom CSS property value
7918 * @return {Roo.Element} this
7920 setBottom : function(bottom){
7921 this.setStyle("bottom", this.addUnits(bottom));
7926 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7927 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7928 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7929 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7930 * @return {Roo.Element} this
7932 setXY : function(pos, animate){
7934 D.setXY(this.dom, pos);
7936 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7942 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7943 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7944 * @param {Number} x X value for new position (coordinates are page-based)
7945 * @param {Number} y Y value for new position (coordinates are page-based)
7946 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7947 * @return {Roo.Element} this
7949 setLocation : function(x, y, animate){
7950 this.setXY([x, y], this.preanim(arguments, 2));
7955 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7956 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7957 * @param {Number} x X value for new position (coordinates are page-based)
7958 * @param {Number} y Y value for new position (coordinates are page-based)
7959 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7960 * @return {Roo.Element} this
7962 moveTo : function(x, y, animate){
7963 this.setXY([x, y], this.preanim(arguments, 2));
7968 * Returns the region of the given element.
7969 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7970 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7972 getRegion : function(){
7973 return D.getRegion(this.dom);
7977 * Returns the offset height of the element
7978 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7979 * @return {Number} The element's height
7981 getHeight : function(contentHeight){
7982 var h = this.dom.offsetHeight || 0;
7983 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7987 * Returns the offset width of the element
7988 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7989 * @return {Number} The element's width
7991 getWidth : function(contentWidth){
7992 var w = this.dom.offsetWidth || 0;
7993 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7997 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7998 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7999 * if a height has not been set using CSS.
8002 getComputedHeight : function(){
8003 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8005 h = parseInt(this.getStyle('height'), 10) || 0;
8006 if(!this.isBorderBox()){
8007 h += this.getFrameWidth('tb');
8014 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8015 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8016 * if a width has not been set using CSS.
8019 getComputedWidth : function(){
8020 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8022 w = parseInt(this.getStyle('width'), 10) || 0;
8023 if(!this.isBorderBox()){
8024 w += this.getFrameWidth('lr');
8031 * Returns the size of the element.
8032 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8033 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8035 getSize : function(contentSize){
8036 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8040 * Returns the width and height of the viewport.
8041 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8043 getViewSize : function(){
8044 var d = this.dom, doc = document, aw = 0, ah = 0;
8045 if(d == doc || d == doc.body){
8046 return {width : D.getViewWidth(), height: D.getViewHeight()};
8049 width : d.clientWidth,
8050 height: d.clientHeight
8056 * Returns the value of the "value" attribute
8057 * @param {Boolean} asNumber true to parse the value as a number
8058 * @return {String/Number}
8060 getValue : function(asNumber){
8061 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8065 adjustWidth : function(width){
8066 if(typeof width == "number"){
8067 if(this.autoBoxAdjust && !this.isBorderBox()){
8068 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8078 adjustHeight : function(height){
8079 if(typeof height == "number"){
8080 if(this.autoBoxAdjust && !this.isBorderBox()){
8081 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8091 * Set the width of the element
8092 * @param {Number} width The new width
8093 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8094 * @return {Roo.Element} this
8096 setWidth : function(width, animate){
8097 width = this.adjustWidth(width);
8099 this.dom.style.width = this.addUnits(width);
8101 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8107 * Set the height of the element
8108 * @param {Number} height The new height
8109 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8110 * @return {Roo.Element} this
8112 setHeight : function(height, animate){
8113 height = this.adjustHeight(height);
8115 this.dom.style.height = this.addUnits(height);
8117 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8123 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8124 * @param {Number} width The new width
8125 * @param {Number} height The new height
8126 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8127 * @return {Roo.Element} this
8129 setSize : function(width, height, animate){
8130 if(typeof width == "object"){ // in case of object from getSize()
8131 height = width.height; width = width.width;
8133 width = this.adjustWidth(width); height = this.adjustHeight(height);
8135 this.dom.style.width = this.addUnits(width);
8136 this.dom.style.height = this.addUnits(height);
8138 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8144 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8145 * @param {Number} x X value for new position (coordinates are page-based)
8146 * @param {Number} y Y value for new position (coordinates are page-based)
8147 * @param {Number} width The new width
8148 * @param {Number} height The new height
8149 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8150 * @return {Roo.Element} this
8152 setBounds : function(x, y, width, height, animate){
8154 this.setSize(width, height);
8155 this.setLocation(x, y);
8157 width = this.adjustWidth(width); height = this.adjustHeight(height);
8158 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8159 this.preanim(arguments, 4), 'motion');
8165 * 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.
8166 * @param {Roo.lib.Region} region The region to fill
8167 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8168 * @return {Roo.Element} this
8170 setRegion : function(region, animate){
8171 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8176 * Appends an event handler
8178 * @param {String} eventName The type of event to append
8179 * @param {Function} fn The method the event invokes
8180 * @param {Object} scope (optional) The scope (this object) of the fn
8181 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8183 addListener : function(eventName, fn, scope, options){
8185 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8190 * Removes an event handler from this element
8191 * @param {String} eventName the type of event to remove
8192 * @param {Function} fn the method the event invokes
8193 * @return {Roo.Element} this
8195 removeListener : function(eventName, fn){
8196 Roo.EventManager.removeListener(this.dom, eventName, fn);
8201 * Removes all previous added listeners from this element
8202 * @return {Roo.Element} this
8204 removeAllListeners : function(){
8205 E.purgeElement(this.dom);
8209 relayEvent : function(eventName, observable){
8210 this.on(eventName, function(e){
8211 observable.fireEvent(eventName, e);
8216 * Set the opacity of the element
8217 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8218 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8219 * @return {Roo.Element} this
8221 setOpacity : function(opacity, animate){
8223 var s = this.dom.style;
8226 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8227 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8229 s.opacity = opacity;
8232 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8238 * Gets the left X coordinate
8239 * @param {Boolean} local True to get the local css position instead of page coordinate
8242 getLeft : function(local){
8246 return parseInt(this.getStyle("left"), 10) || 0;
8251 * Gets the right X coordinate of the element (element X position + element width)
8252 * @param {Boolean} local True to get the local css position instead of page coordinate
8255 getRight : function(local){
8257 return this.getX() + this.getWidth();
8259 return (this.getLeft(true) + this.getWidth()) || 0;
8264 * Gets the top Y coordinate
8265 * @param {Boolean} local True to get the local css position instead of page coordinate
8268 getTop : function(local) {
8272 return parseInt(this.getStyle("top"), 10) || 0;
8277 * Gets the bottom Y coordinate of the element (element Y position + element height)
8278 * @param {Boolean} local True to get the local css position instead of page coordinate
8281 getBottom : function(local){
8283 return this.getY() + this.getHeight();
8285 return (this.getTop(true) + this.getHeight()) || 0;
8290 * Initializes positioning on this element. If a desired position is not passed, it will make the
8291 * the element positioned relative IF it is not already positioned.
8292 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8293 * @param {Number} zIndex (optional) The zIndex to apply
8294 * @param {Number} x (optional) Set the page X position
8295 * @param {Number} y (optional) Set the page Y position
8297 position : function(pos, zIndex, x, y){
8299 if(this.getStyle('position') == 'static'){
8300 this.setStyle('position', 'relative');
8303 this.setStyle("position", pos);
8306 this.setStyle("z-index", zIndex);
8308 if(x !== undefined && y !== undefined){
8310 }else if(x !== undefined){
8312 }else if(y !== undefined){
8318 * Clear positioning back to the default when the document was loaded
8319 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8320 * @return {Roo.Element} this
8322 clearPositioning : function(value){
8330 "position" : "static"
8336 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8337 * snapshot before performing an update and then restoring the element.
8340 getPositioning : function(){
8341 var l = this.getStyle("left");
8342 var t = this.getStyle("top");
8344 "position" : this.getStyle("position"),
8346 "right" : l ? "" : this.getStyle("right"),
8348 "bottom" : t ? "" : this.getStyle("bottom"),
8349 "z-index" : this.getStyle("z-index")
8354 * Gets the width of the border(s) for the specified side(s)
8355 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8356 * passing lr would get the border (l)eft width + the border (r)ight width.
8357 * @return {Number} The width of the sides passed added together
8359 getBorderWidth : function(side){
8360 return this.addStyles(side, El.borders);
8364 * Gets the width of the padding(s) for the specified side(s)
8365 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8366 * passing lr would get the padding (l)eft + the padding (r)ight.
8367 * @return {Number} The padding of the sides passed added together
8369 getPadding : function(side){
8370 return this.addStyles(side, El.paddings);
8374 * Set positioning with an object returned by getPositioning().
8375 * @param {Object} posCfg
8376 * @return {Roo.Element} this
8378 setPositioning : function(pc){
8379 this.applyStyles(pc);
8380 if(pc.right == "auto"){
8381 this.dom.style.right = "";
8383 if(pc.bottom == "auto"){
8384 this.dom.style.bottom = "";
8390 fixDisplay : function(){
8391 if(this.getStyle("display") == "none"){
8392 this.setStyle("visibility", "hidden");
8393 this.setStyle("display", this.originalDisplay); // first try reverting to default
8394 if(this.getStyle("display") == "none"){ // if that fails, default to block
8395 this.setStyle("display", "block");
8401 * Quick set left and top adding default units
8402 * @param {String} left The left CSS property value
8403 * @param {String} top The top CSS property value
8404 * @return {Roo.Element} this
8406 setLeftTop : function(left, top){
8407 this.dom.style.left = this.addUnits(left);
8408 this.dom.style.top = this.addUnits(top);
8413 * Move this element relative to its current position.
8414 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8415 * @param {Number} distance How far to move the element in pixels
8416 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8417 * @return {Roo.Element} this
8419 move : function(direction, distance, animate){
8420 var xy = this.getXY();
8421 direction = direction.toLowerCase();
8425 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8429 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8434 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8439 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8446 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8447 * @return {Roo.Element} this
8450 if(!this.isClipped){
8451 this.isClipped = true;
8452 this.originalClip = {
8453 "o": this.getStyle("overflow"),
8454 "x": this.getStyle("overflow-x"),
8455 "y": this.getStyle("overflow-y")
8457 this.setStyle("overflow", "hidden");
8458 this.setStyle("overflow-x", "hidden");
8459 this.setStyle("overflow-y", "hidden");
8465 * Return clipping (overflow) to original clipping before clip() was called
8466 * @return {Roo.Element} this
8468 unclip : function(){
8470 this.isClipped = false;
8471 var o = this.originalClip;
8472 if(o.o){this.setStyle("overflow", o.o);}
8473 if(o.x){this.setStyle("overflow-x", o.x);}
8474 if(o.y){this.setStyle("overflow-y", o.y);}
8481 * Gets the x,y coordinates specified by the anchor position on the element.
8482 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8483 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8484 * {width: (target width), height: (target height)} (defaults to the element's current size)
8485 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8486 * @return {Array} [x, y] An array containing the element's x and y coordinates
8488 getAnchorXY : function(anchor, local, s){
8489 //Passing a different size is useful for pre-calculating anchors,
8490 //especially for anchored animations that change the el size.
8492 var w, h, vp = false;
8495 if(d == document.body || d == document){
8497 w = D.getViewWidth(); h = D.getViewHeight();
8499 w = this.getWidth(); h = this.getHeight();
8502 w = s.width; h = s.height;
8504 var x = 0, y = 0, r = Math.round;
8505 switch((anchor || "tl").toLowerCase()){
8547 var sc = this.getScroll();
8548 return [x + sc.left, y + sc.top];
8550 //Add the element's offset xy
8551 var o = this.getXY();
8552 return [x+o[0], y+o[1]];
8556 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8557 * supported position values.
8558 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8559 * @param {String} position The position to align to.
8560 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8561 * @return {Array} [x, y]
8563 getAlignToXY : function(el, p, o){
8567 throw "Element.alignTo with an element that doesn't exist";
8569 var c = false; //constrain to viewport
8570 var p1 = "", p2 = "";
8577 }else if(p.indexOf("-") == -1){
8580 p = p.toLowerCase();
8581 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8583 throw "Element.alignTo with an invalid alignment " + p;
8585 p1 = m[1]; p2 = m[2]; c = !!m[3];
8587 //Subtract the aligned el's internal xy from the target's offset xy
8588 //plus custom offset to get the aligned el's new offset xy
8589 var a1 = this.getAnchorXY(p1, true);
8590 var a2 = el.getAnchorXY(p2, false);
8591 var x = a2[0] - a1[0] + o[0];
8592 var y = a2[1] - a1[1] + o[1];
8594 //constrain the aligned el to viewport if necessary
8595 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8596 // 5px of margin for ie
8597 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8599 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8600 //perpendicular to the vp border, allow the aligned el to slide on that border,
8601 //otherwise swap the aligned el to the opposite border of the target.
8602 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8603 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8604 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8605 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8608 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8609 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8611 if((x+w) > dw + scrollX){
8612 x = swapX ? r.left-w : dw+scrollX-w;
8615 x = swapX ? r.right : scrollX;
8617 if((y+h) > dh + scrollY){
8618 y = swapY ? r.top-h : dh+scrollY-h;
8621 y = swapY ? r.bottom : scrollY;
8628 getConstrainToXY : function(){
8629 var os = {top:0, left:0, bottom:0, right: 0};
8631 return function(el, local, offsets, proposedXY){
8633 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8635 var vw, vh, vx = 0, vy = 0;
8636 if(el.dom == document.body || el.dom == document){
8637 vw = Roo.lib.Dom.getViewWidth();
8638 vh = Roo.lib.Dom.getViewHeight();
8640 vw = el.dom.clientWidth;
8641 vh = el.dom.clientHeight;
8643 var vxy = el.getXY();
8649 var s = el.getScroll();
8651 vx += offsets.left + s.left;
8652 vy += offsets.top + s.top;
8654 vw -= offsets.right;
8655 vh -= offsets.bottom;
8660 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8661 var x = xy[0], y = xy[1];
8662 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8664 // only move it if it needs it
8667 // first validate right/bottom
8676 // then make sure top/left isn't negative
8685 return moved ? [x, y] : false;
8690 adjustForConstraints : function(xy, parent, offsets){
8691 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8695 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8696 * document it aligns it to the viewport.
8697 * The position parameter is optional, and can be specified in any one of the following formats:
8699 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8700 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8701 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8702 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8703 * <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
8704 * element's anchor point, and the second value is used as the target's anchor point.</li>
8706 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8707 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8708 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8709 * that specified in order to enforce the viewport constraints.
8710 * Following are all of the supported anchor positions:
8713 ----- -----------------------------
8714 tl The top left corner (default)
8715 t The center of the top edge
8716 tr The top right corner
8717 l The center of the left edge
8718 c In the center of the element
8719 r The center of the right edge
8720 bl The bottom left corner
8721 b The center of the bottom edge
8722 br The bottom right corner
8726 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8727 el.alignTo("other-el");
8729 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8730 el.alignTo("other-el", "tr?");
8732 // align the bottom right corner of el with the center left edge of other-el
8733 el.alignTo("other-el", "br-l?");
8735 // align the center of el with the bottom left corner of other-el and
8736 // adjust the x position by -6 pixels (and the y position by 0)
8737 el.alignTo("other-el", "c-bl", [-6, 0]);
8739 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8740 * @param {String} position The position to align to.
8741 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8742 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8743 * @return {Roo.Element} this
8745 alignTo : function(element, position, offsets, animate){
8746 var xy = this.getAlignToXY(element, position, offsets);
8747 this.setXY(xy, this.preanim(arguments, 3));
8752 * Anchors an element to another element and realigns it when the window is resized.
8753 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8754 * @param {String} position The position to align to.
8755 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8756 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8757 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8758 * is a number, it is used as the buffer delay (defaults to 50ms).
8759 * @param {Function} callback The function to call after the animation finishes
8760 * @return {Roo.Element} this
8762 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8763 var action = function(){
8764 this.alignTo(el, alignment, offsets, animate);
8765 Roo.callback(callback, this);
8767 Roo.EventManager.onWindowResize(action, this);
8768 var tm = typeof monitorScroll;
8769 if(tm != 'undefined'){
8770 Roo.EventManager.on(window, 'scroll', action, this,
8771 {buffer: tm == 'number' ? monitorScroll : 50});
8773 action.call(this); // align immediately
8777 * Clears any opacity settings from this element. Required in some cases for IE.
8778 * @return {Roo.Element} this
8780 clearOpacity : function(){
8781 if (window.ActiveXObject) {
8782 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8783 this.dom.style.filter = "";
8786 this.dom.style.opacity = "";
8787 this.dom.style["-moz-opacity"] = "";
8788 this.dom.style["-khtml-opacity"] = "";
8794 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8795 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8796 * @return {Roo.Element} this
8798 hide : function(animate){
8799 this.setVisible(false, this.preanim(arguments, 0));
8804 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8805 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8806 * @return {Roo.Element} this
8808 show : function(animate){
8809 this.setVisible(true, this.preanim(arguments, 0));
8814 * @private Test if size has a unit, otherwise appends the default
8816 addUnits : function(size){
8817 return Roo.Element.addUnits(size, this.defaultUnit);
8821 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8822 * @return {Roo.Element} this
8824 beginMeasure : function(){
8826 if(el.offsetWidth || el.offsetHeight){
8827 return this; // offsets work already
8830 var p = this.dom, b = document.body; // start with this element
8831 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8832 var pe = Roo.get(p);
8833 if(pe.getStyle('display') == 'none'){
8834 changed.push({el: p, visibility: pe.getStyle("visibility")});
8835 p.style.visibility = "hidden";
8836 p.style.display = "block";
8840 this._measureChanged = changed;
8846 * Restores displays to before beginMeasure was called
8847 * @return {Roo.Element} this
8849 endMeasure : function(){
8850 var changed = this._measureChanged;
8852 for(var i = 0, len = changed.length; i < len; i++) {
8854 r.el.style.visibility = r.visibility;
8855 r.el.style.display = "none";
8857 this._measureChanged = null;
8863 * Update the innerHTML of this element, optionally searching for and processing scripts
8864 * @param {String} html The new HTML
8865 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8866 * @param {Function} callback For async script loading you can be noticed when the update completes
8867 * @return {Roo.Element} this
8869 update : function(html, loadScripts, callback){
8870 if(typeof html == "undefined"){
8873 if(loadScripts !== true){
8874 this.dom.innerHTML = html;
8875 if(typeof callback == "function"){
8883 html += '<span id="' + id + '"></span>';
8885 E.onAvailable(id, function(){
8886 var hd = document.getElementsByTagName("head")[0];
8887 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8888 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8889 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8892 while(match = re.exec(html)){
8893 var attrs = match[1];
8894 var srcMatch = attrs ? attrs.match(srcRe) : false;
8895 if(srcMatch && srcMatch[2]){
8896 var s = document.createElement("script");
8897 s.src = srcMatch[2];
8898 var typeMatch = attrs.match(typeRe);
8899 if(typeMatch && typeMatch[2]){
8900 s.type = typeMatch[2];
8903 }else if(match[2] && match[2].length > 0){
8904 if(window.execScript) {
8905 window.execScript(match[2]);
8913 window.eval(match[2]);
8917 var el = document.getElementById(id);
8918 if(el){el.parentNode.removeChild(el);}
8919 if(typeof callback == "function"){
8923 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8928 * Direct access to the UpdateManager update() method (takes the same parameters).
8929 * @param {String/Function} url The url for this request or a function to call to get the url
8930 * @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}
8931 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8932 * @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.
8933 * @return {Roo.Element} this
8936 var um = this.getUpdateManager();
8937 um.update.apply(um, arguments);
8942 * Gets this element's UpdateManager
8943 * @return {Roo.UpdateManager} The UpdateManager
8945 getUpdateManager : function(){
8946 if(!this.updateManager){
8947 this.updateManager = new Roo.UpdateManager(this);
8949 return this.updateManager;
8953 * Disables text selection for this element (normalized across browsers)
8954 * @return {Roo.Element} this
8956 unselectable : function(){
8957 this.dom.unselectable = "on";
8958 this.swallowEvent("selectstart", true);
8959 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8960 this.addClass("x-unselectable");
8965 * Calculates the x, y to center this element on the screen
8966 * @return {Array} The x, y values [x, y]
8968 getCenterXY : function(){
8969 return this.getAlignToXY(document, 'c-c');
8973 * Centers the Element in either the viewport, or another Element.
8974 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8976 center : function(centerIn){
8977 this.alignTo(centerIn || document, 'c-c');
8982 * Tests various css rules/browsers to determine if this element uses a border box
8985 isBorderBox : function(){
8986 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8990 * Return a box {x, y, width, height} that can be used to set another elements
8991 * size/location to match this element.
8992 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8993 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8994 * @return {Object} box An object in the format {x, y, width, height}
8996 getBox : function(contentBox, local){
9001 var left = parseInt(this.getStyle("left"), 10) || 0;
9002 var top = parseInt(this.getStyle("top"), 10) || 0;
9005 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9007 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9009 var l = this.getBorderWidth("l")+this.getPadding("l");
9010 var r = this.getBorderWidth("r")+this.getPadding("r");
9011 var t = this.getBorderWidth("t")+this.getPadding("t");
9012 var b = this.getBorderWidth("b")+this.getPadding("b");
9013 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)};
9015 bx.right = bx.x + bx.width;
9016 bx.bottom = bx.y + bx.height;
9021 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9022 for more information about the sides.
9023 * @param {String} sides
9026 getFrameWidth : function(sides, onlyContentBox){
9027 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9031 * 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.
9032 * @param {Object} box The box to fill {x, y, width, height}
9033 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9034 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9035 * @return {Roo.Element} this
9037 setBox : function(box, adjust, animate){
9038 var w = box.width, h = box.height;
9039 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9040 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9041 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9043 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9048 * Forces the browser to repaint this element
9049 * @return {Roo.Element} this
9051 repaint : function(){
9053 this.addClass("x-repaint");
9054 setTimeout(function(){
9055 Roo.get(dom).removeClass("x-repaint");
9061 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9062 * then it returns the calculated width of the sides (see getPadding)
9063 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9064 * @return {Object/Number}
9066 getMargins : function(side){
9069 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9070 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9071 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9072 right: parseInt(this.getStyle("margin-right"), 10) || 0
9075 return this.addStyles(side, El.margins);
9080 addStyles : function(sides, styles){
9082 for(var i = 0, len = sides.length; i < len; i++){
9083 v = this.getStyle(styles[sides.charAt(i)]);
9085 w = parseInt(v, 10);
9093 * Creates a proxy element of this element
9094 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9095 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9096 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9097 * @return {Roo.Element} The new proxy element
9099 createProxy : function(config, renderTo, matchBox){
9101 renderTo = Roo.getDom(renderTo);
9103 renderTo = document.body;
9105 config = typeof config == "object" ?
9106 config : {tag : "div", cls: config};
9107 var proxy = Roo.DomHelper.append(renderTo, config, true);
9109 proxy.setBox(this.getBox());
9115 * Puts a mask over this element to disable user interaction. Requires core.css.
9116 * This method can only be applied to elements which accept child nodes.
9117 * @param {String} msg (optional) A message to display in the mask
9118 * @param {String} msgCls (optional) A css class to apply to the msg element
9119 * @return {Element} The mask element
9121 mask : function(msg, msgCls)
9123 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9124 this.setStyle("position", "relative");
9127 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9130 this.addClass("x-masked");
9131 this._mask.setDisplayed(true);
9136 while (dom && dom.style) {
9137 if (!isNaN(parseInt(dom.style.zIndex))) {
9138 z = Math.max(z, parseInt(dom.style.zIndex));
9140 dom = dom.parentNode;
9142 // if we are masking the body - then it hides everything..
9143 if (this.dom == document.body) {
9145 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9146 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9149 if(typeof msg == 'string'){
9151 this._maskMsg = Roo.DomHelper.append(this.dom, {
9152 cls: "roo-el-mask-msg",
9156 cls: 'fa fa-spinner fa-spin'
9164 var mm = this._maskMsg;
9165 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9166 if (mm.dom.lastChild) { // weird IE issue?
9167 mm.dom.lastChild.innerHTML = msg;
9169 mm.setDisplayed(true);
9171 mm.setStyle('z-index', z + 102);
9173 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9174 this._mask.setHeight(this.getHeight());
9176 this._mask.setStyle('z-index', z + 100);
9182 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9183 * it is cached for reuse.
9185 unmask : function(removeEl){
9187 if(removeEl === true){
9188 this._mask.remove();
9191 this._maskMsg.remove();
9192 delete this._maskMsg;
9195 this._mask.setDisplayed(false);
9197 this._maskMsg.setDisplayed(false);
9201 this.removeClass("x-masked");
9205 * Returns true if this element is masked
9208 isMasked : function(){
9209 return this._mask && this._mask.isVisible();
9213 * Creates an iframe shim for this element to keep selects and other windowed objects from
9215 * @return {Roo.Element} The new shim element
9217 createShim : function(){
9218 var el = document.createElement('iframe');
9219 el.frameBorder = 'no';
9220 el.className = 'roo-shim';
9221 if(Roo.isIE && Roo.isSecure){
9222 el.src = Roo.SSL_SECURE_URL;
9224 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9225 shim.autoBoxAdjust = false;
9230 * Removes this element from the DOM and deletes it from the cache
9232 remove : function(){
9233 if(this.dom.parentNode){
9234 this.dom.parentNode.removeChild(this.dom);
9236 delete El.cache[this.dom.id];
9240 * Sets up event handlers to add and remove a css class when the mouse is over this element
9241 * @param {String} className
9242 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9243 * mouseout events for children elements
9244 * @return {Roo.Element} this
9246 addClassOnOver : function(className, preventFlicker){
9247 this.on("mouseover", function(){
9248 Roo.fly(this, '_internal').addClass(className);
9250 var removeFn = function(e){
9251 if(preventFlicker !== true || !e.within(this, true)){
9252 Roo.fly(this, '_internal').removeClass(className);
9255 this.on("mouseout", removeFn, this.dom);
9260 * Sets up event handlers to add and remove a css class when this element has the focus
9261 * @param {String} className
9262 * @return {Roo.Element} this
9264 addClassOnFocus : function(className){
9265 this.on("focus", function(){
9266 Roo.fly(this, '_internal').addClass(className);
9268 this.on("blur", function(){
9269 Roo.fly(this, '_internal').removeClass(className);
9274 * 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)
9275 * @param {String} className
9276 * @return {Roo.Element} this
9278 addClassOnClick : function(className){
9280 this.on("mousedown", function(){
9281 Roo.fly(dom, '_internal').addClass(className);
9282 var d = Roo.get(document);
9283 var fn = function(){
9284 Roo.fly(dom, '_internal').removeClass(className);
9285 d.removeListener("mouseup", fn);
9287 d.on("mouseup", fn);
9293 * Stops the specified event from bubbling and optionally prevents the default action
9294 * @param {String} eventName
9295 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9296 * @return {Roo.Element} this
9298 swallowEvent : function(eventName, preventDefault){
9299 var fn = function(e){
9300 e.stopPropagation();
9305 if(eventName instanceof Array){
9306 for(var i = 0, len = eventName.length; i < len; i++){
9307 this.on(eventName[i], fn);
9311 this.on(eventName, fn);
9318 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9321 * Sizes this element to its parent element's dimensions performing
9322 * neccessary box adjustments.
9323 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9324 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9325 * @return {Roo.Element} this
9327 fitToParent : function(monitorResize, targetParent) {
9328 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9329 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9330 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9333 var p = Roo.get(targetParent || this.dom.parentNode);
9334 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9335 if (monitorResize === true) {
9336 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9337 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9343 * Gets the next sibling, skipping text nodes
9344 * @return {HTMLElement} The next sibling or null
9346 getNextSibling : function(){
9347 var n = this.dom.nextSibling;
9348 while(n && n.nodeType != 1){
9355 * Gets the previous sibling, skipping text nodes
9356 * @return {HTMLElement} The previous sibling or null
9358 getPrevSibling : function(){
9359 var n = this.dom.previousSibling;
9360 while(n && n.nodeType != 1){
9361 n = n.previousSibling;
9368 * Appends the passed element(s) to this element
9369 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9370 * @return {Roo.Element} this
9372 appendChild: function(el){
9379 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9380 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9381 * automatically generated with the specified attributes.
9382 * @param {HTMLElement} insertBefore (optional) a child element of this element
9383 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9384 * @return {Roo.Element} The new child element
9386 createChild: function(config, insertBefore, returnDom){
9387 config = config || {tag:'div'};
9389 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9391 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9395 * Appends this element to the passed element
9396 * @param {String/HTMLElement/Element} el The new parent element
9397 * @return {Roo.Element} this
9399 appendTo: function(el){
9400 el = Roo.getDom(el);
9401 el.appendChild(this.dom);
9406 * Inserts this element before the passed element in the DOM
9407 * @param {String/HTMLElement/Element} el The element to insert before
9408 * @return {Roo.Element} this
9410 insertBefore: function(el){
9411 el = Roo.getDom(el);
9412 el.parentNode.insertBefore(this.dom, el);
9417 * Inserts this element after the passed element in the DOM
9418 * @param {String/HTMLElement/Element} el The element to insert after
9419 * @return {Roo.Element} this
9421 insertAfter: function(el){
9422 el = Roo.getDom(el);
9423 el.parentNode.insertBefore(this.dom, el.nextSibling);
9428 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9429 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9430 * @return {Roo.Element} The new child
9432 insertFirst: function(el, returnDom){
9434 if(typeof el == 'object' && !el.nodeType){ // dh config
9435 return this.createChild(el, this.dom.firstChild, returnDom);
9437 el = Roo.getDom(el);
9438 this.dom.insertBefore(el, this.dom.firstChild);
9439 return !returnDom ? Roo.get(el) : el;
9444 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9445 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9446 * @param {String} where (optional) 'before' or 'after' defaults to before
9447 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9448 * @return {Roo.Element} the inserted Element
9450 insertSibling: function(el, where, returnDom){
9451 where = where ? where.toLowerCase() : 'before';
9453 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9455 if(typeof el == 'object' && !el.nodeType){ // dh config
9456 if(where == 'after' && !this.dom.nextSibling){
9457 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9459 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9463 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9464 where == 'before' ? this.dom : this.dom.nextSibling);
9473 * Creates and wraps this element with another element
9474 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9475 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9476 * @return {HTMLElement/Element} The newly created wrapper element
9478 wrap: function(config, returnDom){
9480 config = {tag: "div"};
9482 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9483 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9488 * Replaces the passed element with this element
9489 * @param {String/HTMLElement/Element} el The element to replace
9490 * @return {Roo.Element} this
9492 replace: function(el){
9494 this.insertBefore(el);
9500 * Inserts an html fragment into this element
9501 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9502 * @param {String} html The HTML fragment
9503 * @param {Boolean} returnEl True to return an Roo.Element
9504 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9506 insertHtml : function(where, html, returnEl){
9507 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9508 return returnEl ? Roo.get(el) : el;
9512 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9513 * @param {Object} o The object with the attributes
9514 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9515 * @return {Roo.Element} this
9517 set : function(o, useSet){
9519 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9521 if(attr == "style" || typeof o[attr] == "function") { continue; }
9523 el.className = o["cls"];
9526 el.setAttribute(attr, o[attr]);
9533 Roo.DomHelper.applyStyles(el, o.style);
9539 * Convenience method for constructing a KeyMap
9540 * @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:
9541 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9542 * @param {Function} fn The function to call
9543 * @param {Object} scope (optional) The scope of the function
9544 * @return {Roo.KeyMap} The KeyMap created
9546 addKeyListener : function(key, fn, scope){
9548 if(typeof key != "object" || key instanceof Array){
9564 return new Roo.KeyMap(this, config);
9568 * Creates a KeyMap for this element
9569 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9570 * @return {Roo.KeyMap} The KeyMap created
9572 addKeyMap : function(config){
9573 return new Roo.KeyMap(this, config);
9577 * Returns true if this element is scrollable.
9580 isScrollable : function(){
9582 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9586 * 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().
9587 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9588 * @param {Number} value The new scroll value
9589 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9590 * @return {Element} this
9593 scrollTo : function(side, value, animate){
9594 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9596 this.dom[prop] = value;
9598 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9599 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9605 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9606 * within this element's scrollable range.
9607 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9608 * @param {Number} distance How far to scroll the element in pixels
9609 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9610 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9611 * was scrolled as far as it could go.
9613 scroll : function(direction, distance, animate){
9614 if(!this.isScrollable()){
9618 var l = el.scrollLeft, t = el.scrollTop;
9619 var w = el.scrollWidth, h = el.scrollHeight;
9620 var cw = el.clientWidth, ch = el.clientHeight;
9621 direction = direction.toLowerCase();
9622 var scrolled = false;
9623 var a = this.preanim(arguments, 2);
9628 var v = Math.min(l + distance, w-cw);
9629 this.scrollTo("left", v, a);
9636 var v = Math.max(l - distance, 0);
9637 this.scrollTo("left", v, a);
9645 var v = Math.max(t - distance, 0);
9646 this.scrollTo("top", v, a);
9654 var v = Math.min(t + distance, h-ch);
9655 this.scrollTo("top", v, a);
9664 * Translates the passed page coordinates into left/top css values for this element
9665 * @param {Number/Array} x The page x or an array containing [x, y]
9666 * @param {Number} y The page y
9667 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9669 translatePoints : function(x, y){
9670 if(typeof x == 'object' || x instanceof Array){
9673 var p = this.getStyle('position');
9674 var o = this.getXY();
9676 var l = parseInt(this.getStyle('left'), 10);
9677 var t = parseInt(this.getStyle('top'), 10);
9680 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9683 t = (p == "relative") ? 0 : this.dom.offsetTop;
9686 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9690 * Returns the current scroll position of the element.
9691 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9693 getScroll : function(){
9694 var d = this.dom, doc = document;
9695 if(d == doc || d == doc.body){
9696 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9697 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9698 return {left: l, top: t};
9700 return {left: d.scrollLeft, top: d.scrollTop};
9705 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9706 * are convert to standard 6 digit hex color.
9707 * @param {String} attr The css attribute
9708 * @param {String} defaultValue The default value to use when a valid color isn't found
9709 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9712 getColor : function(attr, defaultValue, prefix){
9713 var v = this.getStyle(attr);
9714 if(!v || v == "transparent" || v == "inherit") {
9715 return defaultValue;
9717 var color = typeof prefix == "undefined" ? "#" : prefix;
9718 if(v.substr(0, 4) == "rgb("){
9719 var rvs = v.slice(4, v.length -1).split(",");
9720 for(var i = 0; i < 3; i++){
9721 var h = parseInt(rvs[i]).toString(16);
9728 if(v.substr(0, 1) == "#"){
9730 for(var i = 1; i < 4; i++){
9731 var c = v.charAt(i);
9734 }else if(v.length == 7){
9735 color += v.substr(1);
9739 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9743 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9744 * gradient background, rounded corners and a 4-way shadow.
9745 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9746 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9747 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9748 * @return {Roo.Element} this
9750 boxWrap : function(cls){
9751 cls = cls || 'x-box';
9752 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9753 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9758 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9759 * @param {String} namespace The namespace in which to look for the attribute
9760 * @param {String} name The attribute name
9761 * @return {String} The attribute value
9763 getAttributeNS : Roo.isIE ? function(ns, name){
9765 var type = typeof d[ns+":"+name];
9766 if(type != 'undefined' && type != 'unknown'){
9767 return d[ns+":"+name];
9770 } : function(ns, name){
9772 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9777 * Sets or Returns the value the dom attribute value
9778 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9779 * @param {String} value (optional) The value to set the attribute to
9780 * @return {String} The attribute value
9782 attr : function(name){
9783 if (arguments.length > 1) {
9784 this.dom.setAttribute(name, arguments[1]);
9785 return arguments[1];
9787 if (typeof(name) == 'object') {
9788 for(var i in name) {
9789 this.attr(i, name[i]);
9795 if (!this.dom.hasAttribute(name)) {
9798 return this.dom.getAttribute(name);
9805 var ep = El.prototype;
9808 * Appends an event handler (Shorthand for addListener)
9809 * @param {String} eventName The type of event to append
9810 * @param {Function} fn The method the event invokes
9811 * @param {Object} scope (optional) The scope (this object) of the fn
9812 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9815 ep.on = ep.addListener;
9817 ep.mon = ep.addListener;
9820 * Removes an event handler from this element (shorthand for removeListener)
9821 * @param {String} eventName the type of event to remove
9822 * @param {Function} fn the method the event invokes
9823 * @return {Roo.Element} this
9826 ep.un = ep.removeListener;
9829 * true to automatically adjust width and height settings for box-model issues (default to true)
9831 ep.autoBoxAdjust = true;
9834 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9837 El.addUnits = function(v, defaultUnit){
9838 if(v === "" || v == "auto"){
9841 if(v === undefined){
9844 if(typeof v == "number" || !El.unitPattern.test(v)){
9845 return v + (defaultUnit || 'px');
9850 // special markup used throughout Roo when box wrapping elements
9851 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>';
9853 * Visibility mode constant - Use visibility to hide element
9859 * Visibility mode constant - Use display to hide element
9865 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9866 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9867 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9879 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9880 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9881 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9882 * @return {Element} The Element object
9885 El.get = function(el){
9887 if(!el){ return null; }
9888 if(typeof el == "string"){ // element id
9889 if(!(elm = document.getElementById(el))){
9892 if(ex = El.cache[el]){
9895 ex = El.cache[el] = new El(elm);
9898 }else if(el.tagName){ // dom element
9902 if(ex = El.cache[id]){
9905 ex = El.cache[id] = new El(el);
9908 }else if(el instanceof El){
9910 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9911 // catch case where it hasn't been appended
9912 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9915 }else if(el.isComposite){
9917 }else if(el instanceof Array){
9918 return El.select(el);
9919 }else if(el == document){
9920 // create a bogus element object representing the document object
9922 var f = function(){};
9923 f.prototype = El.prototype;
9925 docEl.dom = document;
9933 El.uncache = function(el){
9934 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9936 delete El.cache[a[i].id || a[i]];
9942 // Garbage collection - uncache elements/purge listeners on orphaned elements
9943 // so we don't hold a reference and cause the browser to retain them
9944 El.garbageCollect = function(){
9945 if(!Roo.enableGarbageCollector){
9946 clearInterval(El.collectorThread);
9949 for(var eid in El.cache){
9950 var el = El.cache[eid], d = el.dom;
9951 // -------------------------------------------------------
9952 // Determining what is garbage:
9953 // -------------------------------------------------------
9955 // dom node is null, definitely garbage
9956 // -------------------------------------------------------
9958 // no parentNode == direct orphan, definitely garbage
9959 // -------------------------------------------------------
9960 // !d.offsetParent && !document.getElementById(eid)
9961 // display none elements have no offsetParent so we will
9962 // also try to look it up by it's id. However, check
9963 // offsetParent first so we don't do unneeded lookups.
9964 // This enables collection of elements that are not orphans
9965 // directly, but somewhere up the line they have an orphan
9967 // -------------------------------------------------------
9968 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9969 delete El.cache[eid];
9970 if(d && Roo.enableListenerCollection){
9976 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9980 El.Flyweight = function(dom){
9983 El.Flyweight.prototype = El.prototype;
9985 El._flyweights = {};
9987 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9988 * the dom node can be overwritten by other code.
9989 * @param {String/HTMLElement} el The dom node or id
9990 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9991 * prevent conflicts (e.g. internally Roo uses "_internal")
9993 * @return {Element} The shared Element object
9995 El.fly = function(el, named){
9996 named = named || '_global';
9997 el = Roo.getDom(el);
10001 if(!El._flyweights[named]){
10002 El._flyweights[named] = new El.Flyweight();
10004 El._flyweights[named].dom = el;
10005 return El._flyweights[named];
10009 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10010 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10011 * Shorthand of {@link Roo.Element#get}
10012 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10013 * @return {Element} The Element object
10019 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10020 * the dom node can be overwritten by other code.
10021 * Shorthand of {@link Roo.Element#fly}
10022 * @param {String/HTMLElement} el The dom node or id
10023 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10024 * prevent conflicts (e.g. internally Roo uses "_internal")
10026 * @return {Element} The shared Element object
10032 // speedy lookup for elements never to box adjust
10033 var noBoxAdjust = Roo.isStrict ? {
10036 input:1, select:1, textarea:1
10038 if(Roo.isIE || Roo.isGecko){
10039 noBoxAdjust['button'] = 1;
10043 Roo.EventManager.on(window, 'unload', function(){
10045 delete El._flyweights;
10053 Roo.Element.selectorFunction = Roo.DomQuery.select;
10056 Roo.Element.select = function(selector, unique, root){
10058 if(typeof selector == "string"){
10059 els = Roo.Element.selectorFunction(selector, root);
10060 }else if(selector.length !== undefined){
10063 throw "Invalid selector";
10065 if(unique === true){
10066 return new Roo.CompositeElement(els);
10068 return new Roo.CompositeElementLite(els);
10072 * Selects elements based on the passed CSS selector to enable working on them as 1.
10073 * @param {String/Array} selector The CSS selector or an array of elements
10074 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10075 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10076 * @return {CompositeElementLite/CompositeElement}
10080 Roo.select = Roo.Element.select;
10097 * Ext JS Library 1.1.1
10098 * Copyright(c) 2006-2007, Ext JS, LLC.
10100 * Originally Released Under LGPL - original licence link has changed is not relivant.
10103 * <script type="text/javascript">
10108 //Notifies Element that fx methods are available
10109 Roo.enableFx = true;
10113 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10114 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10115 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10116 * Element effects to work.</p><br/>
10118 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10119 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10120 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10121 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10122 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10123 * expected results and should be done with care.</p><br/>
10125 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10126 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10129 ----- -----------------------------
10130 tl The top left corner
10131 t The center of the top edge
10132 tr The top right corner
10133 l The center of the left edge
10134 r The center of the right edge
10135 bl The bottom left corner
10136 b The center of the bottom edge
10137 br The bottom right corner
10139 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10140 * below are common options that can be passed to any Fx method.</b>
10141 * @cfg {Function} callback A function called when the effect is finished
10142 * @cfg {Object} scope The scope of the effect function
10143 * @cfg {String} easing A valid Easing value for the effect
10144 * @cfg {String} afterCls A css class to apply after the effect
10145 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10146 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10147 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10148 * effects that end with the element being visually hidden, ignored otherwise)
10149 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10150 * a function which returns such a specification that will be applied to the Element after the effect finishes
10151 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10152 * @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
10153 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10157 * Slides the element into view. An anchor point can be optionally passed to set the point of
10158 * origin for the slide effect. This function automatically handles wrapping the element with
10159 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10162 // default: slide the element in from the top
10165 // custom: slide the element in from the right with a 2-second duration
10166 el.slideIn('r', { duration: 2 });
10168 // common config options shown with default values
10174 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10175 * @param {Object} options (optional) Object literal with any of the Fx config options
10176 * @return {Roo.Element} The Element
10178 slideIn : function(anchor, o){
10179 var el = this.getFxEl();
10182 el.queueFx(o, function(){
10184 anchor = anchor || "t";
10186 // fix display to visibility
10189 // restore values after effect
10190 var r = this.getFxRestore();
10191 var b = this.getBox();
10192 // fixed size for slide
10196 var wrap = this.fxWrap(r.pos, o, "hidden");
10198 var st = this.dom.style;
10199 st.visibility = "visible";
10200 st.position = "absolute";
10202 // clear out temp styles after slide and unwrap
10203 var after = function(){
10204 el.fxUnwrap(wrap, r.pos, o);
10205 st.width = r.width;
10206 st.height = r.height;
10209 // time to calc the positions
10210 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10212 switch(anchor.toLowerCase()){
10214 wrap.setSize(b.width, 0);
10215 st.left = st.bottom = "0";
10219 wrap.setSize(0, b.height);
10220 st.right = st.top = "0";
10224 wrap.setSize(0, b.height);
10225 wrap.setX(b.right);
10226 st.left = st.top = "0";
10227 a = {width: bw, points: pt};
10230 wrap.setSize(b.width, 0);
10231 wrap.setY(b.bottom);
10232 st.left = st.top = "0";
10233 a = {height: bh, points: pt};
10236 wrap.setSize(0, 0);
10237 st.right = st.bottom = "0";
10238 a = {width: bw, height: bh};
10241 wrap.setSize(0, 0);
10242 wrap.setY(b.y+b.height);
10243 st.right = st.top = "0";
10244 a = {width: bw, height: bh, points: pt};
10247 wrap.setSize(0, 0);
10248 wrap.setXY([b.right, b.bottom]);
10249 st.left = st.top = "0";
10250 a = {width: bw, height: bh, points: pt};
10253 wrap.setSize(0, 0);
10254 wrap.setX(b.x+b.width);
10255 st.left = st.bottom = "0";
10256 a = {width: bw, height: bh, points: pt};
10259 this.dom.style.visibility = "visible";
10262 arguments.callee.anim = wrap.fxanim(a,
10272 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10273 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10274 * 'hidden') but block elements will still take up space in the document. The element must be removed
10275 * from the DOM using the 'remove' config option if desired. This function automatically handles
10276 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10279 // default: slide the element out to the top
10282 // custom: slide the element out to the right with a 2-second duration
10283 el.slideOut('r', { duration: 2 });
10285 // common config options shown with default values
10293 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10294 * @param {Object} options (optional) Object literal with any of the Fx config options
10295 * @return {Roo.Element} The Element
10297 slideOut : function(anchor, o){
10298 var el = this.getFxEl();
10301 el.queueFx(o, function(){
10303 anchor = anchor || "t";
10305 // restore values after effect
10306 var r = this.getFxRestore();
10308 var b = this.getBox();
10309 // fixed size for slide
10313 var wrap = this.fxWrap(r.pos, o, "visible");
10315 var st = this.dom.style;
10316 st.visibility = "visible";
10317 st.position = "absolute";
10321 var after = function(){
10323 el.setDisplayed(false);
10328 el.fxUnwrap(wrap, r.pos, o);
10330 st.width = r.width;
10331 st.height = r.height;
10336 var a, zero = {to: 0};
10337 switch(anchor.toLowerCase()){
10339 st.left = st.bottom = "0";
10340 a = {height: zero};
10343 st.right = st.top = "0";
10347 st.left = st.top = "0";
10348 a = {width: zero, points: {to:[b.right, b.y]}};
10351 st.left = st.top = "0";
10352 a = {height: zero, points: {to:[b.x, b.bottom]}};
10355 st.right = st.bottom = "0";
10356 a = {width: zero, height: zero};
10359 st.right = st.top = "0";
10360 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10363 st.left = st.top = "0";
10364 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10367 st.left = st.bottom = "0";
10368 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10372 arguments.callee.anim = wrap.fxanim(a,
10382 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10383 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10384 * The element must be removed from the DOM using the 'remove' config option if desired.
10390 // common config options shown with default values
10398 * @param {Object} options (optional) Object literal with any of the Fx config options
10399 * @return {Roo.Element} The Element
10401 puff : function(o){
10402 var el = this.getFxEl();
10405 el.queueFx(o, function(){
10406 this.clearOpacity();
10409 // restore values after effect
10410 var r = this.getFxRestore();
10411 var st = this.dom.style;
10413 var after = function(){
10415 el.setDisplayed(false);
10422 el.setPositioning(r.pos);
10423 st.width = r.width;
10424 st.height = r.height;
10429 var width = this.getWidth();
10430 var height = this.getHeight();
10432 arguments.callee.anim = this.fxanim({
10433 width : {to: this.adjustWidth(width * 2)},
10434 height : {to: this.adjustHeight(height * 2)},
10435 points : {by: [-(width * .5), -(height * .5)]},
10437 fontSize: {to:200, unit: "%"}
10448 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10449 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10450 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10456 // all config options shown with default values
10464 * @param {Object} options (optional) Object literal with any of the Fx config options
10465 * @return {Roo.Element} The Element
10467 switchOff : function(o){
10468 var el = this.getFxEl();
10471 el.queueFx(o, function(){
10472 this.clearOpacity();
10475 // restore values after effect
10476 var r = this.getFxRestore();
10477 var st = this.dom.style;
10479 var after = function(){
10481 el.setDisplayed(false);
10487 el.setPositioning(r.pos);
10488 st.width = r.width;
10489 st.height = r.height;
10494 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10495 this.clearOpacity();
10499 points:{by:[0, this.getHeight() * .5]}
10500 }, o, 'motion', 0.3, 'easeIn', after);
10501 }).defer(100, this);
10508 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10509 * changed using the "attr" config option) and then fading back to the original color. If no original
10510 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10513 // default: highlight background to yellow
10516 // custom: highlight foreground text to blue for 2 seconds
10517 el.highlight("0000ff", { attr: 'color', duration: 2 });
10519 // common config options shown with default values
10520 el.highlight("ffff9c", {
10521 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10522 endColor: (current color) or "ffffff",
10527 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10528 * @param {Object} options (optional) Object literal with any of the Fx config options
10529 * @return {Roo.Element} The Element
10531 highlight : function(color, o){
10532 var el = this.getFxEl();
10535 el.queueFx(o, function(){
10536 color = color || "ffff9c";
10537 attr = o.attr || "backgroundColor";
10539 this.clearOpacity();
10542 var origColor = this.getColor(attr);
10543 var restoreColor = this.dom.style[attr];
10544 endColor = (o.endColor || origColor) || "ffffff";
10546 var after = function(){
10547 el.dom.style[attr] = restoreColor;
10552 a[attr] = {from: color, to: endColor};
10553 arguments.callee.anim = this.fxanim(a,
10563 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10566 // default: a single light blue ripple
10569 // custom: 3 red ripples lasting 3 seconds total
10570 el.frame("ff0000", 3, { duration: 3 });
10572 // common config options shown with default values
10573 el.frame("C3DAF9", 1, {
10574 duration: 1 //duration of entire animation (not each individual ripple)
10575 // Note: Easing is not configurable and will be ignored if included
10578 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10579 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10580 * @param {Object} options (optional) Object literal with any of the Fx config options
10581 * @return {Roo.Element} The Element
10583 frame : function(color, count, o){
10584 var el = this.getFxEl();
10587 el.queueFx(o, function(){
10588 color = color || "#C3DAF9";
10589 if(color.length == 6){
10590 color = "#" + color;
10592 count = count || 1;
10593 duration = o.duration || 1;
10596 var b = this.getBox();
10597 var animFn = function(){
10598 var proxy = this.createProxy({
10601 visbility:"hidden",
10602 position:"absolute",
10603 "z-index":"35000", // yee haw
10604 border:"0px solid " + color
10607 var scale = Roo.isBorderBox ? 2 : 1;
10609 top:{from:b.y, to:b.y - 20},
10610 left:{from:b.x, to:b.x - 20},
10611 borderWidth:{from:0, to:10},
10612 opacity:{from:1, to:0},
10613 height:{from:b.height, to:(b.height + (20*scale))},
10614 width:{from:b.width, to:(b.width + (20*scale))}
10615 }, duration, function(){
10619 animFn.defer((duration/2)*1000, this);
10630 * Creates a pause before any subsequent queued effects begin. If there are
10631 * no effects queued after the pause it will have no effect.
10636 * @param {Number} seconds The length of time to pause (in seconds)
10637 * @return {Roo.Element} The Element
10639 pause : function(seconds){
10640 var el = this.getFxEl();
10643 el.queueFx(o, function(){
10644 setTimeout(function(){
10646 }, seconds * 1000);
10652 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10653 * using the "endOpacity" config option.
10656 // default: fade in from opacity 0 to 100%
10659 // custom: fade in from opacity 0 to 75% over 2 seconds
10660 el.fadeIn({ endOpacity: .75, duration: 2});
10662 // common config options shown with default values
10664 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10669 * @param {Object} options (optional) Object literal with any of the Fx config options
10670 * @return {Roo.Element} The Element
10672 fadeIn : function(o){
10673 var el = this.getFxEl();
10675 el.queueFx(o, function(){
10676 this.setOpacity(0);
10678 this.dom.style.visibility = 'visible';
10679 var to = o.endOpacity || 1;
10680 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10681 o, null, .5, "easeOut", function(){
10683 this.clearOpacity();
10692 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10693 * using the "endOpacity" config option.
10696 // default: fade out from the element's current opacity to 0
10699 // custom: fade out from the element's current opacity to 25% over 2 seconds
10700 el.fadeOut({ endOpacity: .25, duration: 2});
10702 // common config options shown with default values
10704 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10711 * @param {Object} options (optional) Object literal with any of the Fx config options
10712 * @return {Roo.Element} The Element
10714 fadeOut : function(o){
10715 var el = this.getFxEl();
10717 el.queueFx(o, function(){
10718 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10719 o, null, .5, "easeOut", function(){
10720 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10721 this.dom.style.display = "none";
10723 this.dom.style.visibility = "hidden";
10725 this.clearOpacity();
10733 * Animates the transition of an element's dimensions from a starting height/width
10734 * to an ending height/width.
10737 // change height and width to 100x100 pixels
10738 el.scale(100, 100);
10740 // common config options shown with default values. The height and width will default to
10741 // the element's existing values if passed as null.
10744 [element's height], {
10749 * @param {Number} width The new width (pass undefined to keep the original width)
10750 * @param {Number} height The new height (pass undefined to keep the original height)
10751 * @param {Object} options (optional) Object literal with any of the Fx config options
10752 * @return {Roo.Element} The Element
10754 scale : function(w, h, o){
10755 this.shift(Roo.apply({}, o, {
10763 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10764 * Any of these properties not specified in the config object will not be changed. This effect
10765 * requires that at least one new dimension, position or opacity setting must be passed in on
10766 * the config object in order for the function to have any effect.
10769 // slide the element horizontally to x position 200 while changing the height and opacity
10770 el.shift({ x: 200, height: 50, opacity: .8 });
10772 // common config options shown with default values.
10774 width: [element's width],
10775 height: [element's height],
10776 x: [element's x position],
10777 y: [element's y position],
10778 opacity: [element's opacity],
10783 * @param {Object} options Object literal with any of the Fx config options
10784 * @return {Roo.Element} The Element
10786 shift : function(o){
10787 var el = this.getFxEl();
10789 el.queueFx(o, function(){
10790 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10791 if(w !== undefined){
10792 a.width = {to: this.adjustWidth(w)};
10794 if(h !== undefined){
10795 a.height = {to: this.adjustHeight(h)};
10797 if(x !== undefined || y !== undefined){
10799 x !== undefined ? x : this.getX(),
10800 y !== undefined ? y : this.getY()
10803 if(op !== undefined){
10804 a.opacity = {to: op};
10806 if(o.xy !== undefined){
10807 a.points = {to: o.xy};
10809 arguments.callee.anim = this.fxanim(a,
10810 o, 'motion', .35, "easeOut", function(){
10818 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10819 * ending point of the effect.
10822 // default: slide the element downward while fading out
10825 // custom: slide the element out to the right with a 2-second duration
10826 el.ghost('r', { duration: 2 });
10828 // common config options shown with default values
10836 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10837 * @param {Object} options (optional) Object literal with any of the Fx config options
10838 * @return {Roo.Element} The Element
10840 ghost : function(anchor, o){
10841 var el = this.getFxEl();
10844 el.queueFx(o, function(){
10845 anchor = anchor || "b";
10847 // restore values after effect
10848 var r = this.getFxRestore();
10849 var w = this.getWidth(),
10850 h = this.getHeight();
10852 var st = this.dom.style;
10854 var after = function(){
10856 el.setDisplayed(false);
10862 el.setPositioning(r.pos);
10863 st.width = r.width;
10864 st.height = r.height;
10869 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10870 switch(anchor.toLowerCase()){
10897 arguments.callee.anim = this.fxanim(a,
10907 * Ensures that all effects queued after syncFx is called on the element are
10908 * run concurrently. This is the opposite of {@link #sequenceFx}.
10909 * @return {Roo.Element} The Element
10911 syncFx : function(){
10912 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10921 * Ensures that all effects queued after sequenceFx is called on the element are
10922 * run in sequence. This is the opposite of {@link #syncFx}.
10923 * @return {Roo.Element} The Element
10925 sequenceFx : function(){
10926 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10928 concurrent : false,
10935 nextFx : function(){
10936 var ef = this.fxQueue[0];
10943 * Returns true if the element has any effects actively running or queued, else returns false.
10944 * @return {Boolean} True if element has active effects, else false
10946 hasActiveFx : function(){
10947 return this.fxQueue && this.fxQueue[0];
10951 * Stops any running effects and clears the element's internal effects queue if it contains
10952 * any additional effects that haven't started yet.
10953 * @return {Roo.Element} The Element
10955 stopFx : function(){
10956 if(this.hasActiveFx()){
10957 var cur = this.fxQueue[0];
10958 if(cur && cur.anim && cur.anim.isAnimated()){
10959 this.fxQueue = [cur]; // clear out others
10960 cur.anim.stop(true);
10967 beforeFx : function(o){
10968 if(this.hasActiveFx() && !o.concurrent){
10979 * Returns true if the element is currently blocking so that no other effect can be queued
10980 * until this effect is finished, else returns false if blocking is not set. This is commonly
10981 * used to ensure that an effect initiated by a user action runs to completion prior to the
10982 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10983 * @return {Boolean} True if blocking, else false
10985 hasFxBlock : function(){
10986 var q = this.fxQueue;
10987 return q && q[0] && q[0].block;
10991 queueFx : function(o, fn){
10995 if(!this.hasFxBlock()){
10996 Roo.applyIf(o, this.fxDefaults);
10998 var run = this.beforeFx(o);
10999 fn.block = o.block;
11000 this.fxQueue.push(fn);
11012 fxWrap : function(pos, o, vis){
11014 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11017 wrapXY = this.getXY();
11019 var div = document.createElement("div");
11020 div.style.visibility = vis;
11021 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11022 wrap.setPositioning(pos);
11023 if(wrap.getStyle("position") == "static"){
11024 wrap.position("relative");
11026 this.clearPositioning('auto');
11028 wrap.dom.appendChild(this.dom);
11030 wrap.setXY(wrapXY);
11037 fxUnwrap : function(wrap, pos, o){
11038 this.clearPositioning();
11039 this.setPositioning(pos);
11041 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11047 getFxRestore : function(){
11048 var st = this.dom.style;
11049 return {pos: this.getPositioning(), width: st.width, height : st.height};
11053 afterFx : function(o){
11055 this.applyStyles(o.afterStyle);
11058 this.addClass(o.afterCls);
11060 if(o.remove === true){
11063 Roo.callback(o.callback, o.scope, [this]);
11065 this.fxQueue.shift();
11071 getFxEl : function(){ // support for composite element fx
11072 return Roo.get(this.dom);
11076 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11077 animType = animType || 'run';
11079 var anim = Roo.lib.Anim[animType](
11081 (opt.duration || defaultDur) || .35,
11082 (opt.easing || defaultEase) || 'easeOut',
11084 Roo.callback(cb, this);
11093 // backwords compat
11094 Roo.Fx.resize = Roo.Fx.scale;
11096 //When included, Roo.Fx is automatically applied to Element so that all basic
11097 //effects are available directly via the Element API
11098 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11100 * Ext JS Library 1.1.1
11101 * Copyright(c) 2006-2007, Ext JS, LLC.
11103 * Originally Released Under LGPL - original licence link has changed is not relivant.
11106 * <script type="text/javascript">
11111 * @class Roo.CompositeElement
11112 * Standard composite class. Creates a Roo.Element for every element in the collection.
11114 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11115 * actions will be performed on all the elements in this collection.</b>
11117 * All methods return <i>this</i> and can be chained.
11119 var els = Roo.select("#some-el div.some-class", true);
11120 // or select directly from an existing element
11121 var el = Roo.get('some-el');
11122 el.select('div.some-class', true);
11124 els.setWidth(100); // all elements become 100 width
11125 els.hide(true); // all elements fade out and hide
11127 els.setWidth(100).hide(true);
11130 Roo.CompositeElement = function(els){
11131 this.elements = [];
11132 this.addElements(els);
11134 Roo.CompositeElement.prototype = {
11136 addElements : function(els){
11140 if(typeof els == "string"){
11141 els = Roo.Element.selectorFunction(els);
11143 var yels = this.elements;
11144 var index = yels.length-1;
11145 for(var i = 0, len = els.length; i < len; i++) {
11146 yels[++index] = Roo.get(els[i]);
11152 * Clears this composite and adds the elements returned by the passed selector.
11153 * @param {String/Array} els A string CSS selector, an array of elements or an element
11154 * @return {CompositeElement} this
11156 fill : function(els){
11157 this.elements = [];
11163 * Filters this composite to only elements that match the passed selector.
11164 * @param {String} selector A string CSS selector
11165 * @param {Boolean} inverse return inverse filter (not matches)
11166 * @return {CompositeElement} this
11168 filter : function(selector, inverse){
11170 inverse = inverse || false;
11171 this.each(function(el){
11172 var match = inverse ? !el.is(selector) : el.is(selector);
11174 els[els.length] = el.dom;
11181 invoke : function(fn, args){
11182 var els = this.elements;
11183 for(var i = 0, len = els.length; i < len; i++) {
11184 Roo.Element.prototype[fn].apply(els[i], args);
11189 * Adds elements to this composite.
11190 * @param {String/Array} els A string CSS selector, an array of elements or an element
11191 * @return {CompositeElement} this
11193 add : function(els){
11194 if(typeof els == "string"){
11195 this.addElements(Roo.Element.selectorFunction(els));
11196 }else if(els.length !== undefined){
11197 this.addElements(els);
11199 this.addElements([els]);
11204 * Calls the passed function passing (el, this, index) for each element in this composite.
11205 * @param {Function} fn The function to call
11206 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11207 * @return {CompositeElement} this
11209 each : function(fn, scope){
11210 var els = this.elements;
11211 for(var i = 0, len = els.length; i < len; i++){
11212 if(fn.call(scope || els[i], els[i], this, i) === false) {
11220 * Returns the Element object at the specified index
11221 * @param {Number} index
11222 * @return {Roo.Element}
11224 item : function(index){
11225 return this.elements[index] || null;
11229 * Returns the first Element
11230 * @return {Roo.Element}
11232 first : function(){
11233 return this.item(0);
11237 * Returns the last Element
11238 * @return {Roo.Element}
11241 return this.item(this.elements.length-1);
11245 * Returns the number of elements in this composite
11248 getCount : function(){
11249 return this.elements.length;
11253 * Returns true if this composite contains the passed element
11256 contains : function(el){
11257 return this.indexOf(el) !== -1;
11261 * Returns true if this composite contains the passed element
11264 indexOf : function(el){
11265 return this.elements.indexOf(Roo.get(el));
11270 * Removes the specified element(s).
11271 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11272 * or an array of any of those.
11273 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11274 * @return {CompositeElement} this
11276 removeElement : function(el, removeDom){
11277 if(el instanceof Array){
11278 for(var i = 0, len = el.length; i < len; i++){
11279 this.removeElement(el[i]);
11283 var index = typeof el == 'number' ? el : this.indexOf(el);
11286 var d = this.elements[index];
11290 d.parentNode.removeChild(d);
11293 this.elements.splice(index, 1);
11299 * Replaces the specified element with the passed element.
11300 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11302 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11303 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11304 * @return {CompositeElement} this
11306 replaceElement : function(el, replacement, domReplace){
11307 var index = typeof el == 'number' ? el : this.indexOf(el);
11310 this.elements[index].replaceWith(replacement);
11312 this.elements.splice(index, 1, Roo.get(replacement))
11319 * Removes all elements.
11321 clear : function(){
11322 this.elements = [];
11326 Roo.CompositeElement.createCall = function(proto, fnName){
11327 if(!proto[fnName]){
11328 proto[fnName] = function(){
11329 return this.invoke(fnName, arguments);
11333 for(var fnName in Roo.Element.prototype){
11334 if(typeof Roo.Element.prototype[fnName] == "function"){
11335 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11341 * Ext JS Library 1.1.1
11342 * Copyright(c) 2006-2007, Ext JS, LLC.
11344 * Originally Released Under LGPL - original licence link has changed is not relivant.
11347 * <script type="text/javascript">
11351 * @class Roo.CompositeElementLite
11352 * @extends Roo.CompositeElement
11353 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11355 var els = Roo.select("#some-el div.some-class");
11356 // or select directly from an existing element
11357 var el = Roo.get('some-el');
11358 el.select('div.some-class');
11360 els.setWidth(100); // all elements become 100 width
11361 els.hide(true); // all elements fade out and hide
11363 els.setWidth(100).hide(true);
11364 </code></pre><br><br>
11365 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11366 * actions will be performed on all the elements in this collection.</b>
11368 Roo.CompositeElementLite = function(els){
11369 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11370 this.el = new Roo.Element.Flyweight();
11372 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11373 addElements : function(els){
11375 if(els instanceof Array){
11376 this.elements = this.elements.concat(els);
11378 var yels = this.elements;
11379 var index = yels.length-1;
11380 for(var i = 0, len = els.length; i < len; i++) {
11381 yels[++index] = els[i];
11387 invoke : function(fn, args){
11388 var els = this.elements;
11390 for(var i = 0, len = els.length; i < len; i++) {
11392 Roo.Element.prototype[fn].apply(el, args);
11397 * Returns a flyweight Element of the dom element object at the specified index
11398 * @param {Number} index
11399 * @return {Roo.Element}
11401 item : function(index){
11402 if(!this.elements[index]){
11405 this.el.dom = this.elements[index];
11409 // fixes scope with flyweight
11410 addListener : function(eventName, handler, scope, opt){
11411 var els = this.elements;
11412 for(var i = 0, len = els.length; i < len; i++) {
11413 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11419 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11420 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11421 * a reference to the dom node, use el.dom.</b>
11422 * @param {Function} fn The function to call
11423 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11424 * @return {CompositeElement} this
11426 each : function(fn, scope){
11427 var els = this.elements;
11429 for(var i = 0, len = els.length; i < len; i++){
11431 if(fn.call(scope || el, el, this, i) === false){
11438 indexOf : function(el){
11439 return this.elements.indexOf(Roo.getDom(el));
11442 replaceElement : function(el, replacement, domReplace){
11443 var index = typeof el == 'number' ? el : this.indexOf(el);
11445 replacement = Roo.getDom(replacement);
11447 var d = this.elements[index];
11448 d.parentNode.insertBefore(replacement, d);
11449 d.parentNode.removeChild(d);
11451 this.elements.splice(index, 1, replacement);
11456 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11460 * Ext JS Library 1.1.1
11461 * Copyright(c) 2006-2007, Ext JS, LLC.
11463 * Originally Released Under LGPL - original licence link has changed is not relivant.
11466 * <script type="text/javascript">
11472 * @class Roo.data.Connection
11473 * @extends Roo.util.Observable
11474 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11475 * either to a configured URL, or to a URL specified at request time.
11477 * Requests made by this class are asynchronous, and will return immediately. No data from
11478 * the server will be available to the statement immediately following the {@link #request} call.
11479 * To process returned data, use a callback in the request options object, or an event listener.
11481 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11482 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11483 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11484 * property and, if present, the IFRAME's XML document as the responseXML property.
11486 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11487 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11488 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11489 * standard DOM methods.
11491 * @param {Object} config a configuration object.
11493 Roo.data.Connection = function(config){
11494 Roo.apply(this, config);
11497 * @event beforerequest
11498 * Fires before a network request is made to retrieve a data object.
11499 * @param {Connection} conn This Connection object.
11500 * @param {Object} options The options config object passed to the {@link #request} method.
11502 "beforerequest" : true,
11504 * @event requestcomplete
11505 * Fires if the request was successfully completed.
11506 * @param {Connection} conn This Connection object.
11507 * @param {Object} response The XHR object containing the response data.
11508 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11509 * @param {Object} options The options config object passed to the {@link #request} method.
11511 "requestcomplete" : true,
11513 * @event requestexception
11514 * Fires if an error HTTP status was returned from the server.
11515 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11516 * @param {Connection} conn This Connection object.
11517 * @param {Object} response The XHR object containing the response data.
11518 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11519 * @param {Object} options The options config object passed to the {@link #request} method.
11521 "requestexception" : true
11523 Roo.data.Connection.superclass.constructor.call(this);
11526 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11528 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11531 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11532 * extra parameters to each request made by this object. (defaults to undefined)
11535 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11536 * to each request made by this object. (defaults to undefined)
11539 * @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)
11542 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11546 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11552 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11555 disableCaching: true,
11558 * Sends an HTTP request to a remote server.
11559 * @param {Object} options An object which may contain the following properties:<ul>
11560 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11561 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11562 * request, a url encoded string or a function to call to get either.</li>
11563 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11564 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11565 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11566 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11567 * <li>options {Object} The parameter to the request call.</li>
11568 * <li>success {Boolean} True if the request succeeded.</li>
11569 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11571 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11572 * The callback is passed the following parameters:<ul>
11573 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11574 * <li>options {Object} The parameter to the request call.</li>
11576 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11577 * The callback is passed the following parameters:<ul>
11578 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11579 * <li>options {Object} The parameter to the request call.</li>
11581 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11582 * for the callback function. Defaults to the browser window.</li>
11583 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11584 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11585 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11586 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11587 * params for the post data. Any params will be appended to the URL.</li>
11588 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11590 * @return {Number} transactionId
11592 request : function(o){
11593 if(this.fireEvent("beforerequest", this, o) !== false){
11596 if(typeof p == "function"){
11597 p = p.call(o.scope||window, o);
11599 if(typeof p == "object"){
11600 p = Roo.urlEncode(o.params);
11602 if(this.extraParams){
11603 var extras = Roo.urlEncode(this.extraParams);
11604 p = p ? (p + '&' + extras) : extras;
11607 var url = o.url || this.url;
11608 if(typeof url == 'function'){
11609 url = url.call(o.scope||window, o);
11613 var form = Roo.getDom(o.form);
11614 url = url || form.action;
11616 var enctype = form.getAttribute("enctype");
11619 return this.doFormDataUpload(o,p,url);
11622 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11623 return this.doFormUpload(o, p, url);
11625 var f = Roo.lib.Ajax.serializeForm(form);
11626 p = p ? (p + '&' + f) : f;
11629 var hs = o.headers;
11630 if(this.defaultHeaders){
11631 hs = Roo.apply(hs || {}, this.defaultHeaders);
11638 success: this.handleResponse,
11639 failure: this.handleFailure,
11641 argument: {options: o},
11642 timeout : o.timeout || this.timeout
11645 var method = o.method||this.method||(p ? "POST" : "GET");
11647 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11648 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11651 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11655 }else if(this.autoAbort !== false){
11659 if((method == 'GET' && p) || o.xmlData){
11660 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11663 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
11664 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11665 Roo.lib.Ajax.useDefaultHeader == true;
11666 return this.transId;
11668 Roo.callback(o.callback, o.scope, [o, null, null]);
11674 * Determine whether this object has a request outstanding.
11675 * @param {Number} transactionId (Optional) defaults to the last transaction
11676 * @return {Boolean} True if there is an outstanding request.
11678 isLoading : function(transId){
11680 return Roo.lib.Ajax.isCallInProgress(transId);
11682 return this.transId ? true : false;
11687 * Aborts any outstanding request.
11688 * @param {Number} transactionId (Optional) defaults to the last transaction
11690 abort : function(transId){
11691 if(transId || this.isLoading()){
11692 Roo.lib.Ajax.abort(transId || this.transId);
11697 handleResponse : function(response){
11698 this.transId = false;
11699 var options = response.argument.options;
11700 response.argument = options ? options.argument : null;
11701 this.fireEvent("requestcomplete", this, response, options);
11702 Roo.callback(options.success, options.scope, [response, options]);
11703 Roo.callback(options.callback, options.scope, [options, true, response]);
11707 handleFailure : function(response, e){
11708 this.transId = false;
11709 var options = response.argument.options;
11710 response.argument = options ? options.argument : null;
11711 this.fireEvent("requestexception", this, response, options, e);
11712 Roo.callback(options.failure, options.scope, [response, options]);
11713 Roo.callback(options.callback, options.scope, [options, false, response]);
11717 doFormUpload : function(o, ps, url){
11719 var frame = document.createElement('iframe');
11722 frame.className = 'x-hidden';
11724 frame.src = Roo.SSL_SECURE_URL;
11726 document.body.appendChild(frame);
11729 document.frames[id].name = id;
11732 var form = Roo.getDom(o.form);
11734 form.method = 'POST';
11735 form.enctype = form.encoding = 'multipart/form-data';
11741 if(ps){ // add dynamic params
11743 ps = Roo.urlDecode(ps, false);
11745 if(ps.hasOwnProperty(k)){
11746 hd = document.createElement('input');
11747 hd.type = 'hidden';
11750 form.appendChild(hd);
11757 var r = { // bogus response object
11762 r.argument = o ? o.argument : null;
11767 doc = frame.contentWindow.document;
11769 doc = (frame.contentDocument || window.frames[id].document);
11771 if(doc && doc.body){
11772 r.responseText = doc.body.innerHTML;
11774 if(doc && doc.XMLDocument){
11775 r.responseXML = doc.XMLDocument;
11777 r.responseXML = doc;
11784 Roo.EventManager.removeListener(frame, 'load', cb, this);
11786 this.fireEvent("requestcomplete", this, r, o);
11787 Roo.callback(o.success, o.scope, [r, o]);
11788 Roo.callback(o.callback, o.scope, [o, true, r]);
11790 setTimeout(function(){document.body.removeChild(frame);}, 100);
11793 Roo.EventManager.on(frame, 'load', cb, this);
11796 if(hiddens){ // remove dynamic params
11797 for(var i = 0, len = hiddens.length; i < len; i++){
11798 form.removeChild(hiddens[i]);
11802 // this is a 'formdata version???'
11805 doFormDataUpload : function(o, ps, url)
11807 var form = Roo.getDom(o.form);
11808 form.enctype = form.encoding = 'multipart/form-data';
11809 var formData = o.formData === true ? new FormData(form) : o.formData;
11812 success: this.handleResponse,
11813 failure: this.handleFailure,
11815 argument: {options: o},
11816 timeout : o.timeout || this.timeout
11819 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11823 }else if(this.autoAbort !== false){
11827 //Roo.lib.Ajax.defaultPostHeader = null;
11828 Roo.lib.Ajax.useDefaultHeader = false;
11829 this.transId = Roo.lib.Ajax.request( "POST", url, cb, o.formData, o);
11830 Roo.lib.Ajax.useDefaultHeader = true;
11838 * Ext JS Library 1.1.1
11839 * Copyright(c) 2006-2007, Ext JS, LLC.
11841 * Originally Released Under LGPL - original licence link has changed is not relivant.
11844 * <script type="text/javascript">
11848 * Global Ajax request class.
11851 * @extends Roo.data.Connection
11854 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11855 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11856 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11857 * @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)
11858 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11859 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11860 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11862 Roo.Ajax = new Roo.data.Connection({
11871 * Serialize the passed form into a url encoded string
11873 * @param {String/HTMLElement} form
11876 serializeForm : function(form){
11877 return Roo.lib.Ajax.serializeForm(form);
11881 * Ext JS Library 1.1.1
11882 * Copyright(c) 2006-2007, Ext JS, LLC.
11884 * Originally Released Under LGPL - original licence link has changed is not relivant.
11887 * <script type="text/javascript">
11892 * @class Roo.UpdateManager
11893 * @extends Roo.util.Observable
11894 * Provides AJAX-style update for Element object.<br><br>
11897 * // Get it from a Roo.Element object
11898 * var el = Roo.get("foo");
11899 * var mgr = el.getUpdateManager();
11900 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11902 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11904 * // or directly (returns the same UpdateManager instance)
11905 * var mgr = new Roo.UpdateManager("myElementId");
11906 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11907 * mgr.on("update", myFcnNeedsToKnow);
11909 // short handed call directly from the element object
11910 Roo.get("foo").load({
11914 text: "Loading Foo..."
11918 * Create new UpdateManager directly.
11919 * @param {String/HTMLElement/Roo.Element} el The element to update
11920 * @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).
11922 Roo.UpdateManager = function(el, forceNew){
11924 if(!forceNew && el.updateManager){
11925 return el.updateManager;
11928 * The Element object
11929 * @type Roo.Element
11933 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11936 this.defaultUrl = null;
11940 * @event beforeupdate
11941 * Fired before an update is made, return false from your handler and the update is cancelled.
11942 * @param {Roo.Element} el
11943 * @param {String/Object/Function} url
11944 * @param {String/Object} params
11946 "beforeupdate": true,
11949 * Fired after successful update is made.
11950 * @param {Roo.Element} el
11951 * @param {Object} oResponseObject The response Object
11956 * Fired on update failure.
11957 * @param {Roo.Element} el
11958 * @param {Object} oResponseObject The response Object
11962 var d = Roo.UpdateManager.defaults;
11964 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11967 this.sslBlankUrl = d.sslBlankUrl;
11969 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11972 this.disableCaching = d.disableCaching;
11974 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11977 this.indicatorText = d.indicatorText;
11979 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11982 this.showLoadIndicator = d.showLoadIndicator;
11984 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11987 this.timeout = d.timeout;
11990 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11993 this.loadScripts = d.loadScripts;
11996 * Transaction object of current executing transaction
11998 this.transaction = null;
12003 this.autoRefreshProcId = null;
12005 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12008 this.refreshDelegate = this.refresh.createDelegate(this);
12010 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12013 this.updateDelegate = this.update.createDelegate(this);
12015 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12018 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12022 this.successDelegate = this.processSuccess.createDelegate(this);
12026 this.failureDelegate = this.processFailure.createDelegate(this);
12028 if(!this.renderer){
12030 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12032 this.renderer = new Roo.UpdateManager.BasicRenderer();
12035 Roo.UpdateManager.superclass.constructor.call(this);
12038 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12040 * Get the Element this UpdateManager is bound to
12041 * @return {Roo.Element} The element
12043 getEl : function(){
12047 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12048 * @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:
12051 url: "your-url.php",<br/>
12052 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12053 callback: yourFunction,<br/>
12054 scope: yourObject, //(optional scope) <br/>
12055 discardUrl: false, <br/>
12056 nocache: false,<br/>
12057 text: "Loading...",<br/>
12059 scripts: false<br/>
12062 * The only required property is url. The optional properties nocache, text and scripts
12063 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12064 * @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}
12065 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12066 * @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.
12068 update : function(url, params, callback, discardUrl){
12069 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12070 var method = this.method,
12072 if(typeof url == "object"){ // must be config object
12075 params = params || cfg.params;
12076 callback = callback || cfg.callback;
12077 discardUrl = discardUrl || cfg.discardUrl;
12078 if(callback && cfg.scope){
12079 callback = callback.createDelegate(cfg.scope);
12081 if(typeof cfg.method != "undefined"){method = cfg.method;};
12082 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12083 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12084 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12085 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12087 this.showLoading();
12089 this.defaultUrl = url;
12091 if(typeof url == "function"){
12092 url = url.call(this);
12095 method = method || (params ? "POST" : "GET");
12096 if(method == "GET"){
12097 url = this.prepareUrl(url);
12100 var o = Roo.apply(cfg ||{}, {
12103 success: this.successDelegate,
12104 failure: this.failureDelegate,
12105 callback: undefined,
12106 timeout: (this.timeout*1000),
12107 argument: {"url": url, "form": null, "callback": callback, "params": params}
12109 Roo.log("updated manager called with timeout of " + o.timeout);
12110 this.transaction = Roo.Ajax.request(o);
12115 * 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.
12116 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12117 * @param {String/HTMLElement} form The form Id or form element
12118 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12119 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12120 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12122 formUpdate : function(form, url, reset, callback){
12123 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12124 if(typeof url == "function"){
12125 url = url.call(this);
12127 form = Roo.getDom(form);
12128 this.transaction = Roo.Ajax.request({
12131 success: this.successDelegate,
12132 failure: this.failureDelegate,
12133 timeout: (this.timeout*1000),
12134 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12136 this.showLoading.defer(1, this);
12141 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12142 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12144 refresh : function(callback){
12145 if(this.defaultUrl == null){
12148 this.update(this.defaultUrl, null, callback, true);
12152 * Set this element to auto refresh.
12153 * @param {Number} interval How often to update (in seconds).
12154 * @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)
12155 * @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}
12156 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12157 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12159 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12161 this.update(url || this.defaultUrl, params, callback, true);
12163 if(this.autoRefreshProcId){
12164 clearInterval(this.autoRefreshProcId);
12166 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12170 * Stop auto refresh on this element.
12172 stopAutoRefresh : function(){
12173 if(this.autoRefreshProcId){
12174 clearInterval(this.autoRefreshProcId);
12175 delete this.autoRefreshProcId;
12179 isAutoRefreshing : function(){
12180 return this.autoRefreshProcId ? true : false;
12183 * Called to update the element to "Loading" state. Override to perform custom action.
12185 showLoading : function(){
12186 if(this.showLoadIndicator){
12187 this.el.update(this.indicatorText);
12192 * Adds unique parameter to query string if disableCaching = true
12195 prepareUrl : function(url){
12196 if(this.disableCaching){
12197 var append = "_dc=" + (new Date().getTime());
12198 if(url.indexOf("?") !== -1){
12199 url += "&" + append;
12201 url += "?" + append;
12210 processSuccess : function(response){
12211 this.transaction = null;
12212 if(response.argument.form && response.argument.reset){
12213 try{ // put in try/catch since some older FF releases had problems with this
12214 response.argument.form.reset();
12217 if(this.loadScripts){
12218 this.renderer.render(this.el, response, this,
12219 this.updateComplete.createDelegate(this, [response]));
12221 this.renderer.render(this.el, response, this);
12222 this.updateComplete(response);
12226 updateComplete : function(response){
12227 this.fireEvent("update", this.el, response);
12228 if(typeof response.argument.callback == "function"){
12229 response.argument.callback(this.el, true, response);
12236 processFailure : function(response){
12237 this.transaction = null;
12238 this.fireEvent("failure", this.el, response);
12239 if(typeof response.argument.callback == "function"){
12240 response.argument.callback(this.el, false, response);
12245 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12246 * @param {Object} renderer The object implementing the render() method
12248 setRenderer : function(renderer){
12249 this.renderer = renderer;
12252 getRenderer : function(){
12253 return this.renderer;
12257 * Set the defaultUrl used for updates
12258 * @param {String/Function} defaultUrl The url or a function to call to get the url
12260 setDefaultUrl : function(defaultUrl){
12261 this.defaultUrl = defaultUrl;
12265 * Aborts the executing transaction
12267 abort : function(){
12268 if(this.transaction){
12269 Roo.Ajax.abort(this.transaction);
12274 * Returns true if an update is in progress
12275 * @return {Boolean}
12277 isUpdating : function(){
12278 if(this.transaction){
12279 return Roo.Ajax.isLoading(this.transaction);
12286 * @class Roo.UpdateManager.defaults
12287 * @static (not really - but it helps the doc tool)
12288 * The defaults collection enables customizing the default properties of UpdateManager
12290 Roo.UpdateManager.defaults = {
12292 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12298 * True to process scripts by default (Defaults to false).
12301 loadScripts : false,
12304 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12307 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12309 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12312 disableCaching : false,
12314 * Whether to show indicatorText when loading (Defaults to true).
12317 showLoadIndicator : true,
12319 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12322 indicatorText : '<div class="loading-indicator">Loading...</div>'
12326 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12328 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12329 * @param {String/HTMLElement/Roo.Element} el The element to update
12330 * @param {String} url The url
12331 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12332 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12335 * @member Roo.UpdateManager
12337 Roo.UpdateManager.updateElement = function(el, url, params, options){
12338 var um = Roo.get(el, true).getUpdateManager();
12339 Roo.apply(um, options);
12340 um.update(url, params, options ? options.callback : null);
12342 // alias for backwards compat
12343 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12345 * @class Roo.UpdateManager.BasicRenderer
12346 * Default Content renderer. Updates the elements innerHTML with the responseText.
12348 Roo.UpdateManager.BasicRenderer = function(){};
12350 Roo.UpdateManager.BasicRenderer.prototype = {
12352 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12353 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12354 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12355 * @param {Roo.Element} el The element being rendered
12356 * @param {Object} response The YUI Connect response object
12357 * @param {UpdateManager} updateManager The calling update manager
12358 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12360 render : function(el, response, updateManager, callback){
12361 el.update(response.responseText, updateManager.loadScripts, callback);
12367 * (c)) Alan Knowles
12373 * @class Roo.DomTemplate
12374 * @extends Roo.Template
12375 * An effort at a dom based template engine..
12377 * Similar to XTemplate, except it uses dom parsing to create the template..
12379 * Supported features:
12384 {a_variable} - output encoded.
12385 {a_variable.format:("Y-m-d")} - call a method on the variable
12386 {a_variable:raw} - unencoded output
12387 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12388 {a_variable:this.method_on_template(...)} - call a method on the template object.
12393 <div roo-for="a_variable or condition.."></div>
12394 <div roo-if="a_variable or condition"></div>
12395 <div roo-exec="some javascript"></div>
12396 <div roo-name="named_template"></div>
12401 Roo.DomTemplate = function()
12403 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12410 Roo.extend(Roo.DomTemplate, Roo.Template, {
12412 * id counter for sub templates.
12416 * flag to indicate if dom parser is inside a pre,
12417 * it will strip whitespace if not.
12422 * The various sub templates
12430 * basic tag replacing syntax
12433 * // you can fake an object call by doing this
12437 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12438 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12440 iterChild : function (node, method) {
12442 var oldPre = this.inPre;
12443 if (node.tagName == 'PRE') {
12446 for( var i = 0; i < node.childNodes.length; i++) {
12447 method.call(this, node.childNodes[i]);
12449 this.inPre = oldPre;
12455 * compile the template
12457 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12460 compile: function()
12464 // covert the html into DOM...
12468 doc = document.implementation.createHTMLDocument("");
12469 doc.documentElement.innerHTML = this.html ;
12470 div = doc.documentElement;
12472 // old IE... - nasty -- it causes all sorts of issues.. with
12473 // images getting pulled from server..
12474 div = document.createElement('div');
12475 div.innerHTML = this.html;
12477 //doc.documentElement.innerHTML = htmlBody
12483 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12485 var tpls = this.tpls;
12487 // create a top level template from the snippet..
12489 //Roo.log(div.innerHTML);
12496 body : div.innerHTML,
12509 Roo.each(tpls, function(tp){
12510 this.compileTpl(tp);
12511 this.tpls[tp.id] = tp;
12514 this.master = tpls[0];
12520 compileNode : function(node, istop) {
12525 // skip anything not a tag..
12526 if (node.nodeType != 1) {
12527 if (node.nodeType == 3 && !this.inPre) {
12528 // reduce white space..
12529 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12552 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12553 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12554 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12555 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12561 // just itterate children..
12562 this.iterChild(node,this.compileNode);
12565 tpl.uid = this.id++;
12566 tpl.value = node.getAttribute('roo-' + tpl.attr);
12567 node.removeAttribute('roo-'+ tpl.attr);
12568 if (tpl.attr != 'name') {
12569 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12570 node.parentNode.replaceChild(placeholder, node);
12573 var placeholder = document.createElement('span');
12574 placeholder.className = 'roo-tpl-' + tpl.value;
12575 node.parentNode.replaceChild(placeholder, node);
12578 // parent now sees '{domtplXXXX}
12579 this.iterChild(node,this.compileNode);
12581 // we should now have node body...
12582 var div = document.createElement('div');
12583 div.appendChild(node);
12585 // this has the unfortunate side effect of converting tagged attributes
12586 // eg. href="{...}" into %7C...%7D
12587 // this has been fixed by searching for those combo's although it's a bit hacky..
12590 tpl.body = div.innerHTML;
12597 switch (tpl.value) {
12598 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12599 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12600 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12605 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12609 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12613 tpl.id = tpl.value; // replace non characters???
12619 this.tpls.push(tpl);
12629 * Compile a segment of the template into a 'sub-template'
12635 compileTpl : function(tpl)
12637 var fm = Roo.util.Format;
12638 var useF = this.disableFormats !== true;
12640 var sep = Roo.isGecko ? "+\n" : ",\n";
12642 var undef = function(str) {
12643 Roo.debug && Roo.log("Property not found :" + str);
12647 //Roo.log(tpl.body);
12651 var fn = function(m, lbrace, name, format, args)
12654 //Roo.log(arguments);
12655 args = args ? args.replace(/\\'/g,"'") : args;
12656 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12657 if (typeof(format) == 'undefined') {
12658 format = 'htmlEncode';
12660 if (format == 'raw' ) {
12664 if(name.substr(0, 6) == 'domtpl'){
12665 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12668 // build an array of options to determine if value is undefined..
12670 // basically get 'xxxx.yyyy' then do
12671 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12672 // (function () { Roo.log("Property not found"); return ''; })() :
12677 Roo.each(name.split('.'), function(st) {
12678 lookfor += (lookfor.length ? '.': '') + st;
12679 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12682 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12685 if(format && useF){
12687 args = args ? ',' + args : "";
12689 if(format.substr(0, 5) != "this."){
12690 format = "fm." + format + '(';
12692 format = 'this.call("'+ format.substr(5) + '", ';
12696 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12699 if (args && args.length) {
12700 // called with xxyx.yuu:(test,test)
12702 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12704 // raw.. - :raw modifier..
12705 return "'"+ sep + udef_st + name + ")"+sep+"'";
12709 // branched to use + in gecko and [].join() in others
12711 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12712 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12715 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12716 body.push(tpl.body.replace(/(\r\n|\n)/g,
12717 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12718 body.push("'].join('');};};");
12719 body = body.join('');
12722 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12724 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12731 * same as applyTemplate, except it's done to one of the subTemplates
12732 * when using named templates, you can do:
12734 * var str = pl.applySubTemplate('your-name', values);
12737 * @param {Number} id of the template
12738 * @param {Object} values to apply to template
12739 * @param {Object} parent (normaly the instance of this object)
12741 applySubTemplate : function(id, values, parent)
12745 var t = this.tpls[id];
12749 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12750 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12754 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12761 if(t.execCall && t.execCall.call(this, values, parent)){
12765 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12771 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12772 parent = t.target ? values : parent;
12773 if(t.forCall && vs instanceof Array){
12775 for(var i = 0, len = vs.length; i < len; i++){
12777 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12779 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12781 //Roo.log(t.compiled);
12785 return buf.join('');
12788 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12793 return t.compiled.call(this, vs, parent);
12795 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12797 //Roo.log(t.compiled);
12805 applyTemplate : function(values){
12806 return this.master.compiled.call(this, values, {});
12807 //var s = this.subs;
12810 apply : function(){
12811 return this.applyTemplate.apply(this, arguments);
12816 Roo.DomTemplate.from = function(el){
12817 el = Roo.getDom(el);
12818 return new Roo.Domtemplate(el.value || el.innerHTML);
12821 * Ext JS Library 1.1.1
12822 * Copyright(c) 2006-2007, Ext JS, LLC.
12824 * Originally Released Under LGPL - original licence link has changed is not relivant.
12827 * <script type="text/javascript">
12831 * @class Roo.util.DelayedTask
12832 * Provides a convenient method of performing setTimeout where a new
12833 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12834 * You can use this class to buffer
12835 * the keypress events for a certain number of milliseconds, and perform only if they stop
12836 * for that amount of time.
12837 * @constructor The parameters to this constructor serve as defaults and are not required.
12838 * @param {Function} fn (optional) The default function to timeout
12839 * @param {Object} scope (optional) The default scope of that timeout
12840 * @param {Array} args (optional) The default Array of arguments
12842 Roo.util.DelayedTask = function(fn, scope, args){
12843 var id = null, d, t;
12845 var call = function(){
12846 var now = new Date().getTime();
12850 fn.apply(scope, args || []);
12854 * Cancels any pending timeout and queues a new one
12855 * @param {Number} delay The milliseconds to delay
12856 * @param {Function} newFn (optional) Overrides function passed to constructor
12857 * @param {Object} newScope (optional) Overrides scope passed to constructor
12858 * @param {Array} newArgs (optional) Overrides args passed to constructor
12860 this.delay = function(delay, newFn, newScope, newArgs){
12861 if(id && delay != d){
12865 t = new Date().getTime();
12867 scope = newScope || scope;
12868 args = newArgs || args;
12870 id = setInterval(call, d);
12875 * Cancel the last queued timeout
12877 this.cancel = function(){
12885 * Ext JS Library 1.1.1
12886 * Copyright(c) 2006-2007, Ext JS, LLC.
12888 * Originally Released Under LGPL - original licence link has changed is not relivant.
12891 * <script type="text/javascript">
12895 Roo.util.TaskRunner = function(interval){
12896 interval = interval || 10;
12897 var tasks = [], removeQueue = [];
12899 var running = false;
12901 var stopThread = function(){
12907 var startThread = function(){
12910 id = setInterval(runTasks, interval);
12914 var removeTask = function(task){
12915 removeQueue.push(task);
12921 var runTasks = function(){
12922 if(removeQueue.length > 0){
12923 for(var i = 0, len = removeQueue.length; i < len; i++){
12924 tasks.remove(removeQueue[i]);
12927 if(tasks.length < 1){
12932 var now = new Date().getTime();
12933 for(var i = 0, len = tasks.length; i < len; ++i){
12935 var itime = now - t.taskRunTime;
12936 if(t.interval <= itime){
12937 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12938 t.taskRunTime = now;
12939 if(rt === false || t.taskRunCount === t.repeat){
12944 if(t.duration && t.duration <= (now - t.taskStartTime)){
12951 * Queues a new task.
12952 * @param {Object} task
12954 this.start = function(task){
12956 task.taskStartTime = new Date().getTime();
12957 task.taskRunTime = 0;
12958 task.taskRunCount = 0;
12963 this.stop = function(task){
12968 this.stopAll = function(){
12970 for(var i = 0, len = tasks.length; i < len; i++){
12971 if(tasks[i].onStop){
12980 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12982 * Ext JS Library 1.1.1
12983 * Copyright(c) 2006-2007, Ext JS, LLC.
12985 * Originally Released Under LGPL - original licence link has changed is not relivant.
12988 * <script type="text/javascript">
12993 * @class Roo.util.MixedCollection
12994 * @extends Roo.util.Observable
12995 * A Collection class that maintains both numeric indexes and keys and exposes events.
12997 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12998 * collection (defaults to false)
12999 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13000 * and return the key value for that item. This is used when available to look up the key on items that
13001 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13002 * equivalent to providing an implementation for the {@link #getKey} method.
13004 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13012 * Fires when the collection is cleared.
13017 * Fires when an item is added to the collection.
13018 * @param {Number} index The index at which the item was added.
13019 * @param {Object} o The item added.
13020 * @param {String} key The key associated with the added item.
13025 * Fires when an item is replaced in the collection.
13026 * @param {String} key he key associated with the new added.
13027 * @param {Object} old The item being replaced.
13028 * @param {Object} new The new item.
13033 * Fires when an item is removed from the collection.
13034 * @param {Object} o The item being removed.
13035 * @param {String} key (optional) The key associated with the removed item.
13040 this.allowFunctions = allowFunctions === true;
13042 this.getKey = keyFn;
13044 Roo.util.MixedCollection.superclass.constructor.call(this);
13047 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13048 allowFunctions : false,
13051 * Adds an item to the collection.
13052 * @param {String} key The key to associate with the item
13053 * @param {Object} o The item to add.
13054 * @return {Object} The item added.
13056 add : function(key, o){
13057 if(arguments.length == 1){
13059 key = this.getKey(o);
13061 if(typeof key == "undefined" || key === null){
13063 this.items.push(o);
13064 this.keys.push(null);
13066 var old = this.map[key];
13068 return this.replace(key, o);
13071 this.items.push(o);
13073 this.keys.push(key);
13075 this.fireEvent("add", this.length-1, o, key);
13080 * MixedCollection has a generic way to fetch keys if you implement getKey.
13083 var mc = new Roo.util.MixedCollection();
13084 mc.add(someEl.dom.id, someEl);
13085 mc.add(otherEl.dom.id, otherEl);
13089 var mc = new Roo.util.MixedCollection();
13090 mc.getKey = function(el){
13096 // or via the constructor
13097 var mc = new Roo.util.MixedCollection(false, function(el){
13103 * @param o {Object} The item for which to find the key.
13104 * @return {Object} The key for the passed item.
13106 getKey : function(o){
13111 * Replaces an item in the collection.
13112 * @param {String} key The key associated with the item to replace, or the item to replace.
13113 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13114 * @return {Object} The new item.
13116 replace : function(key, o){
13117 if(arguments.length == 1){
13119 key = this.getKey(o);
13121 var old = this.item(key);
13122 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13123 return this.add(key, o);
13125 var index = this.indexOfKey(key);
13126 this.items[index] = o;
13128 this.fireEvent("replace", key, old, o);
13133 * Adds all elements of an Array or an Object to the collection.
13134 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13135 * an Array of values, each of which are added to the collection.
13137 addAll : function(objs){
13138 if(arguments.length > 1 || objs instanceof Array){
13139 var args = arguments.length > 1 ? arguments : objs;
13140 for(var i = 0, len = args.length; i < len; i++){
13144 for(var key in objs){
13145 if(this.allowFunctions || typeof objs[key] != "function"){
13146 this.add(key, objs[key]);
13153 * Executes the specified function once for every item in the collection, passing each
13154 * item as the first and only parameter. returning false from the function will stop the iteration.
13155 * @param {Function} fn The function to execute for each item.
13156 * @param {Object} scope (optional) The scope in which to execute the function.
13158 each : function(fn, scope){
13159 var items = [].concat(this.items); // each safe for removal
13160 for(var i = 0, len = items.length; i < len; i++){
13161 if(fn.call(scope || items[i], items[i], i, len) === false){
13168 * Executes the specified function once for every key in the collection, passing each
13169 * key, and its associated item as the first two parameters.
13170 * @param {Function} fn The function to execute for each item.
13171 * @param {Object} scope (optional) The scope in which to execute the function.
13173 eachKey : function(fn, scope){
13174 for(var i = 0, len = this.keys.length; i < len; i++){
13175 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13180 * Returns the first item in the collection which elicits a true return value from the
13181 * passed selection function.
13182 * @param {Function} fn The selection function to execute for each item.
13183 * @param {Object} scope (optional) The scope in which to execute the function.
13184 * @return {Object} The first item in the collection which returned true from the selection function.
13186 find : function(fn, scope){
13187 for(var i = 0, len = this.items.length; i < len; i++){
13188 if(fn.call(scope || window, this.items[i], this.keys[i])){
13189 return this.items[i];
13196 * Inserts an item at the specified index in the collection.
13197 * @param {Number} index The index to insert the item at.
13198 * @param {String} key The key to associate with the new item, or the item itself.
13199 * @param {Object} o (optional) If the second parameter was a key, the new item.
13200 * @return {Object} The item inserted.
13202 insert : function(index, key, o){
13203 if(arguments.length == 2){
13205 key = this.getKey(o);
13207 if(index >= this.length){
13208 return this.add(key, o);
13211 this.items.splice(index, 0, o);
13212 if(typeof key != "undefined" && key != null){
13215 this.keys.splice(index, 0, key);
13216 this.fireEvent("add", index, o, key);
13221 * Removed an item from the collection.
13222 * @param {Object} o The item to remove.
13223 * @return {Object} The item removed.
13225 remove : function(o){
13226 return this.removeAt(this.indexOf(o));
13230 * Remove an item from a specified index in the collection.
13231 * @param {Number} index The index within the collection of the item to remove.
13233 removeAt : function(index){
13234 if(index < this.length && index >= 0){
13236 var o = this.items[index];
13237 this.items.splice(index, 1);
13238 var key = this.keys[index];
13239 if(typeof key != "undefined"){
13240 delete this.map[key];
13242 this.keys.splice(index, 1);
13243 this.fireEvent("remove", o, key);
13248 * Removed an item associated with the passed key fom the collection.
13249 * @param {String} key The key of the item to remove.
13251 removeKey : function(key){
13252 return this.removeAt(this.indexOfKey(key));
13256 * Returns the number of items in the collection.
13257 * @return {Number} the number of items in the collection.
13259 getCount : function(){
13260 return this.length;
13264 * Returns index within the collection of the passed Object.
13265 * @param {Object} o The item to find the index of.
13266 * @return {Number} index of the item.
13268 indexOf : function(o){
13269 if(!this.items.indexOf){
13270 for(var i = 0, len = this.items.length; i < len; i++){
13271 if(this.items[i] == o) {
13277 return this.items.indexOf(o);
13282 * Returns index within the collection of the passed key.
13283 * @param {String} key The key to find the index of.
13284 * @return {Number} index of the key.
13286 indexOfKey : function(key){
13287 if(!this.keys.indexOf){
13288 for(var i = 0, len = this.keys.length; i < len; i++){
13289 if(this.keys[i] == key) {
13295 return this.keys.indexOf(key);
13300 * Returns the item associated with the passed key OR index. Key has priority over index.
13301 * @param {String/Number} key The key or index of the item.
13302 * @return {Object} The item associated with the passed key.
13304 item : function(key){
13305 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13306 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13310 * Returns the item at the specified index.
13311 * @param {Number} index The index of the item.
13314 itemAt : function(index){
13315 return this.items[index];
13319 * Returns the item associated with the passed key.
13320 * @param {String/Number} key The key of the item.
13321 * @return {Object} The item associated with the passed key.
13323 key : function(key){
13324 return this.map[key];
13328 * Returns true if the collection contains the passed Object as an item.
13329 * @param {Object} o The Object to look for in the collection.
13330 * @return {Boolean} True if the collection contains the Object as an item.
13332 contains : function(o){
13333 return this.indexOf(o) != -1;
13337 * Returns true if the collection contains the passed Object as a key.
13338 * @param {String} key The key to look for in the collection.
13339 * @return {Boolean} True if the collection contains the Object as a key.
13341 containsKey : function(key){
13342 return typeof this.map[key] != "undefined";
13346 * Removes all items from the collection.
13348 clear : function(){
13353 this.fireEvent("clear");
13357 * Returns the first item in the collection.
13358 * @return {Object} the first item in the collection..
13360 first : function(){
13361 return this.items[0];
13365 * Returns the last item in the collection.
13366 * @return {Object} the last item in the collection..
13369 return this.items[this.length-1];
13372 _sort : function(property, dir, fn){
13373 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13374 fn = fn || function(a, b){
13377 var c = [], k = this.keys, items = this.items;
13378 for(var i = 0, len = items.length; i < len; i++){
13379 c[c.length] = {key: k[i], value: items[i], index: i};
13381 c.sort(function(a, b){
13382 var v = fn(a[property], b[property]) * dsc;
13384 v = (a.index < b.index ? -1 : 1);
13388 for(var i = 0, len = c.length; i < len; i++){
13389 items[i] = c[i].value;
13392 this.fireEvent("sort", this);
13396 * Sorts this collection with the passed comparison function
13397 * @param {String} direction (optional) "ASC" or "DESC"
13398 * @param {Function} fn (optional) comparison function
13400 sort : function(dir, fn){
13401 this._sort("value", dir, fn);
13405 * Sorts this collection by keys
13406 * @param {String} direction (optional) "ASC" or "DESC"
13407 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13409 keySort : function(dir, fn){
13410 this._sort("key", dir, fn || function(a, b){
13411 return String(a).toUpperCase()-String(b).toUpperCase();
13416 * Returns a range of items in this collection
13417 * @param {Number} startIndex (optional) defaults to 0
13418 * @param {Number} endIndex (optional) default to the last item
13419 * @return {Array} An array of items
13421 getRange : function(start, end){
13422 var items = this.items;
13423 if(items.length < 1){
13426 start = start || 0;
13427 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13430 for(var i = start; i <= end; i++) {
13431 r[r.length] = items[i];
13434 for(var i = start; i >= end; i--) {
13435 r[r.length] = items[i];
13442 * Filter the <i>objects</i> in this collection by a specific property.
13443 * Returns a new collection that has been filtered.
13444 * @param {String} property A property on your objects
13445 * @param {String/RegExp} value Either string that the property values
13446 * should start with or a RegExp to test against the property
13447 * @return {MixedCollection} The new filtered collection
13449 filter : function(property, value){
13450 if(!value.exec){ // not a regex
13451 value = String(value);
13452 if(value.length == 0){
13453 return this.clone();
13455 value = new RegExp("^" + Roo.escapeRe(value), "i");
13457 return this.filterBy(function(o){
13458 return o && value.test(o[property]);
13463 * Filter by a function. * Returns a new collection that has been filtered.
13464 * The passed function will be called with each
13465 * object in the collection. If the function returns true, the value is included
13466 * otherwise it is filtered.
13467 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13468 * @param {Object} scope (optional) The scope of the function (defaults to this)
13469 * @return {MixedCollection} The new filtered collection
13471 filterBy : function(fn, scope){
13472 var r = new Roo.util.MixedCollection();
13473 r.getKey = this.getKey;
13474 var k = this.keys, it = this.items;
13475 for(var i = 0, len = it.length; i < len; i++){
13476 if(fn.call(scope||this, it[i], k[i])){
13477 r.add(k[i], it[i]);
13484 * Creates a duplicate of this collection
13485 * @return {MixedCollection}
13487 clone : function(){
13488 var r = new Roo.util.MixedCollection();
13489 var k = this.keys, it = this.items;
13490 for(var i = 0, len = it.length; i < len; i++){
13491 r.add(k[i], it[i]);
13493 r.getKey = this.getKey;
13498 * Returns the item associated with the passed key or index.
13500 * @param {String/Number} key The key or index of the item.
13501 * @return {Object} The item associated with the passed key.
13503 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13505 * Ext JS Library 1.1.1
13506 * Copyright(c) 2006-2007, Ext JS, LLC.
13508 * Originally Released Under LGPL - original licence link has changed is not relivant.
13511 * <script type="text/javascript">
13514 * @class Roo.util.JSON
13515 * Modified version of Douglas Crockford"s json.js that doesn"t
13516 * mess with the Object prototype
13517 * http://www.json.org/js.html
13520 Roo.util.JSON = new (function(){
13521 var useHasOwn = {}.hasOwnProperty ? true : false;
13523 // crashes Safari in some instances
13524 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13526 var pad = function(n) {
13527 return n < 10 ? "0" + n : n;
13540 var encodeString = function(s){
13541 if (/["\\\x00-\x1f]/.test(s)) {
13542 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13547 c = b.charCodeAt();
13549 Math.floor(c / 16).toString(16) +
13550 (c % 16).toString(16);
13553 return '"' + s + '"';
13556 var encodeArray = function(o){
13557 var a = ["["], b, i, l = o.length, v;
13558 for (i = 0; i < l; i += 1) {
13560 switch (typeof v) {
13569 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13577 var encodeDate = function(o){
13578 return '"' + o.getFullYear() + "-" +
13579 pad(o.getMonth() + 1) + "-" +
13580 pad(o.getDate()) + "T" +
13581 pad(o.getHours()) + ":" +
13582 pad(o.getMinutes()) + ":" +
13583 pad(o.getSeconds()) + '"';
13587 * Encodes an Object, Array or other value
13588 * @param {Mixed} o The variable to encode
13589 * @return {String} The JSON string
13591 this.encode = function(o)
13593 // should this be extended to fully wrap stringify..
13595 if(typeof o == "undefined" || o === null){
13597 }else if(o instanceof Array){
13598 return encodeArray(o);
13599 }else if(o instanceof Date){
13600 return encodeDate(o);
13601 }else if(typeof o == "string"){
13602 return encodeString(o);
13603 }else if(typeof o == "number"){
13604 return isFinite(o) ? String(o) : "null";
13605 }else if(typeof o == "boolean"){
13608 var a = ["{"], b, i, v;
13610 if(!useHasOwn || o.hasOwnProperty(i)) {
13612 switch (typeof v) {
13621 a.push(this.encode(i), ":",
13622 v === null ? "null" : this.encode(v));
13633 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13634 * @param {String} json The JSON string
13635 * @return {Object} The resulting object
13637 this.decode = function(json){
13639 return /** eval:var:json */ eval("(" + json + ')');
13643 * Shorthand for {@link Roo.util.JSON#encode}
13644 * @member Roo encode
13646 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13648 * Shorthand for {@link Roo.util.JSON#decode}
13649 * @member Roo decode
13651 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13654 * Ext JS Library 1.1.1
13655 * Copyright(c) 2006-2007, Ext JS, LLC.
13657 * Originally Released Under LGPL - original licence link has changed is not relivant.
13660 * <script type="text/javascript">
13664 * @class Roo.util.Format
13665 * Reusable data formatting functions
13668 Roo.util.Format = function(){
13669 var trimRe = /^\s+|\s+$/g;
13672 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13673 * @param {String} value The string to truncate
13674 * @param {Number} length The maximum length to allow before truncating
13675 * @return {String} The converted text
13677 ellipsis : function(value, len){
13678 if(value && value.length > len){
13679 return value.substr(0, len-3)+"...";
13685 * Checks a reference and converts it to empty string if it is undefined
13686 * @param {Mixed} value Reference to check
13687 * @return {Mixed} Empty string if converted, otherwise the original value
13689 undef : function(value){
13690 return typeof value != "undefined" ? value : "";
13694 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13695 * @param {String} value The string to encode
13696 * @return {String} The encoded text
13698 htmlEncode : function(value){
13699 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13703 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13704 * @param {String} value The string to decode
13705 * @return {String} The decoded text
13707 htmlDecode : function(value){
13708 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13712 * Trims any whitespace from either side of a string
13713 * @param {String} value The text to trim
13714 * @return {String} The trimmed text
13716 trim : function(value){
13717 return String(value).replace(trimRe, "");
13721 * Returns a substring from within an original string
13722 * @param {String} value The original text
13723 * @param {Number} start The start index of the substring
13724 * @param {Number} length The length of the substring
13725 * @return {String} The substring
13727 substr : function(value, start, length){
13728 return String(value).substr(start, length);
13732 * Converts a string to all lower case letters
13733 * @param {String} value The text to convert
13734 * @return {String} The converted text
13736 lowercase : function(value){
13737 return String(value).toLowerCase();
13741 * Converts a string to all upper case letters
13742 * @param {String} value The text to convert
13743 * @return {String} The converted text
13745 uppercase : function(value){
13746 return String(value).toUpperCase();
13750 * Converts the first character only of a string to upper case
13751 * @param {String} value The text to convert
13752 * @return {String} The converted text
13754 capitalize : function(value){
13755 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13759 call : function(value, fn){
13760 if(arguments.length > 2){
13761 var args = Array.prototype.slice.call(arguments, 2);
13762 args.unshift(value);
13764 return /** eval:var:value */ eval(fn).apply(window, args);
13766 /** eval:var:value */
13767 return /** eval:var:value */ eval(fn).call(window, value);
13773 * safer version of Math.toFixed..??/
13774 * @param {Number/String} value The numeric value to format
13775 * @param {Number/String} value Decimal places
13776 * @return {String} The formatted currency string
13778 toFixed : function(v, n)
13780 // why not use to fixed - precision is buggered???
13782 return Math.round(v-0);
13784 var fact = Math.pow(10,n+1);
13785 v = (Math.round((v-0)*fact))/fact;
13786 var z = (''+fact).substring(2);
13787 if (v == Math.floor(v)) {
13788 return Math.floor(v) + '.' + z;
13791 // now just padd decimals..
13792 var ps = String(v).split('.');
13793 var fd = (ps[1] + z);
13794 var r = fd.substring(0,n);
13795 var rm = fd.substring(n);
13797 return ps[0] + '.' + r;
13799 r*=1; // turn it into a number;
13801 if (String(r).length != n) {
13804 r = String(r).substring(1); // chop the end off.
13807 return ps[0] + '.' + r;
13812 * Format a number as US currency
13813 * @param {Number/String} value The numeric value to format
13814 * @return {String} The formatted currency string
13816 usMoney : function(v){
13817 return '$' + Roo.util.Format.number(v);
13822 * eventually this should probably emulate php's number_format
13823 * @param {Number/String} value The numeric value to format
13824 * @param {Number} decimals number of decimal places
13825 * @param {String} delimiter for thousands (default comma)
13826 * @return {String} The formatted currency string
13828 number : function(v, decimals, thousandsDelimiter)
13830 // multiply and round.
13831 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13832 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13834 var mul = Math.pow(10, decimals);
13835 var zero = String(mul).substring(1);
13836 v = (Math.round((v-0)*mul))/mul;
13838 // if it's '0' number.. then
13840 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13842 var ps = v.split('.');
13845 var r = /(\d+)(\d{3})/;
13848 if(thousandsDelimiter.length != 0) {
13849 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13854 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13855 // does not have decimals
13856 (decimals ? ('.' + zero) : '');
13859 return whole + sub ;
13863 * Parse a value into a formatted date using the specified format pattern.
13864 * @param {Mixed} value The value to format
13865 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13866 * @return {String} The formatted date string
13868 date : function(v, format){
13872 if(!(v instanceof Date)){
13873 v = new Date(Date.parse(v));
13875 return v.dateFormat(format || Roo.util.Format.defaults.date);
13879 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13880 * @param {String} format Any valid date format string
13881 * @return {Function} The date formatting function
13883 dateRenderer : function(format){
13884 return function(v){
13885 return Roo.util.Format.date(v, format);
13890 stripTagsRE : /<\/?[^>]+>/gi,
13893 * Strips all HTML tags
13894 * @param {Mixed} value The text from which to strip tags
13895 * @return {String} The stripped text
13897 stripTags : function(v){
13898 return !v ? v : String(v).replace(this.stripTagsRE, "");
13902 Roo.util.Format.defaults = {
13906 * Ext JS Library 1.1.1
13907 * Copyright(c) 2006-2007, Ext JS, LLC.
13909 * Originally Released Under LGPL - original licence link has changed is not relivant.
13912 * <script type="text/javascript">
13919 * @class Roo.MasterTemplate
13920 * @extends Roo.Template
13921 * Provides a template that can have child templates. The syntax is:
13923 var t = new Roo.MasterTemplate(
13924 '<select name="{name}">',
13925 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13928 t.add('options', {value: 'foo', text: 'bar'});
13929 // or you can add multiple child elements in one shot
13930 t.addAll('options', [
13931 {value: 'foo', text: 'bar'},
13932 {value: 'foo2', text: 'bar2'},
13933 {value: 'foo3', text: 'bar3'}
13935 // then append, applying the master template values
13936 t.append('my-form', {name: 'my-select'});
13938 * A name attribute for the child template is not required if you have only one child
13939 * template or you want to refer to them by index.
13941 Roo.MasterTemplate = function(){
13942 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13943 this.originalHtml = this.html;
13945 var m, re = this.subTemplateRe;
13948 while(m = re.exec(this.html)){
13949 var name = m[1], content = m[2];
13954 tpl : new Roo.Template(content)
13957 st[name] = st[subIndex];
13959 st[subIndex].tpl.compile();
13960 st[subIndex].tpl.call = this.call.createDelegate(this);
13963 this.subCount = subIndex;
13966 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13968 * The regular expression used to match sub templates
13972 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13975 * Applies the passed values to a child template.
13976 * @param {String/Number} name (optional) The name or index of the child template
13977 * @param {Array/Object} values The values to be applied to the template
13978 * @return {MasterTemplate} this
13980 add : function(name, values){
13981 if(arguments.length == 1){
13982 values = arguments[0];
13985 var s = this.subs[name];
13986 s.buffer[s.buffer.length] = s.tpl.apply(values);
13991 * Applies all the passed values to a child template.
13992 * @param {String/Number} name (optional) The name or index of the child template
13993 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13994 * @param {Boolean} reset (optional) True to reset the template first
13995 * @return {MasterTemplate} this
13997 fill : function(name, values, reset){
13999 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14007 for(var i = 0, len = values.length; i < len; i++){
14008 this.add(name, values[i]);
14014 * Resets the template for reuse
14015 * @return {MasterTemplate} this
14017 reset : function(){
14019 for(var i = 0; i < this.subCount; i++){
14025 applyTemplate : function(values){
14027 var replaceIndex = -1;
14028 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14029 return s[++replaceIndex].buffer.join("");
14031 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14034 apply : function(){
14035 return this.applyTemplate.apply(this, arguments);
14038 compile : function(){return this;}
14042 * Alias for fill().
14045 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14047 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14048 * var tpl = Roo.MasterTemplate.from('element-id');
14049 * @param {String/HTMLElement} el
14050 * @param {Object} config
14053 Roo.MasterTemplate.from = function(el, config){
14054 el = Roo.getDom(el);
14055 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14058 * Ext JS Library 1.1.1
14059 * Copyright(c) 2006-2007, Ext JS, LLC.
14061 * Originally Released Under LGPL - original licence link has changed is not relivant.
14064 * <script type="text/javascript">
14069 * @class Roo.util.CSS
14070 * Utility class for manipulating CSS rules
14073 Roo.util.CSS = function(){
14075 var doc = document;
14077 var camelRe = /(-[a-z])/gi;
14078 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14082 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14083 * tag and appended to the HEAD of the document.
14084 * @param {String|Object} cssText The text containing the css rules
14085 * @param {String} id An id to add to the stylesheet for later removal
14086 * @return {StyleSheet}
14088 createStyleSheet : function(cssText, id){
14090 var head = doc.getElementsByTagName("head")[0];
14091 var nrules = doc.createElement("style");
14092 nrules.setAttribute("type", "text/css");
14094 nrules.setAttribute("id", id);
14096 if (typeof(cssText) != 'string') {
14097 // support object maps..
14098 // not sure if this a good idea..
14099 // perhaps it should be merged with the general css handling
14100 // and handle js style props.
14101 var cssTextNew = [];
14102 for(var n in cssText) {
14104 for(var k in cssText[n]) {
14105 citems.push( k + ' : ' +cssText[n][k] + ';' );
14107 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14110 cssText = cssTextNew.join("\n");
14116 head.appendChild(nrules);
14117 ss = nrules.styleSheet;
14118 ss.cssText = cssText;
14121 nrules.appendChild(doc.createTextNode(cssText));
14123 nrules.cssText = cssText;
14125 head.appendChild(nrules);
14126 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14128 this.cacheStyleSheet(ss);
14133 * Removes a style or link tag by id
14134 * @param {String} id The id of the tag
14136 removeStyleSheet : function(id){
14137 var existing = doc.getElementById(id);
14139 existing.parentNode.removeChild(existing);
14144 * Dynamically swaps an existing stylesheet reference for a new one
14145 * @param {String} id The id of an existing link tag to remove
14146 * @param {String} url The href of the new stylesheet to include
14148 swapStyleSheet : function(id, url){
14149 this.removeStyleSheet(id);
14150 var ss = doc.createElement("link");
14151 ss.setAttribute("rel", "stylesheet");
14152 ss.setAttribute("type", "text/css");
14153 ss.setAttribute("id", id);
14154 ss.setAttribute("href", url);
14155 doc.getElementsByTagName("head")[0].appendChild(ss);
14159 * Refresh the rule cache if you have dynamically added stylesheets
14160 * @return {Object} An object (hash) of rules indexed by selector
14162 refreshCache : function(){
14163 return this.getRules(true);
14167 cacheStyleSheet : function(stylesheet){
14171 try{// try catch for cross domain access issue
14172 var ssRules = stylesheet.cssRules || stylesheet.rules;
14173 for(var j = ssRules.length-1; j >= 0; --j){
14174 rules[ssRules[j].selectorText] = ssRules[j];
14180 * Gets all css rules for the document
14181 * @param {Boolean} refreshCache true to refresh the internal cache
14182 * @return {Object} An object (hash) of rules indexed by selector
14184 getRules : function(refreshCache){
14185 if(rules == null || refreshCache){
14187 var ds = doc.styleSheets;
14188 for(var i =0, len = ds.length; i < len; i++){
14190 this.cacheStyleSheet(ds[i]);
14198 * Gets an an individual CSS rule by selector(s)
14199 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14200 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14201 * @return {CSSRule} The CSS rule or null if one is not found
14203 getRule : function(selector, refreshCache){
14204 var rs = this.getRules(refreshCache);
14205 if(!(selector instanceof Array)){
14206 return rs[selector];
14208 for(var i = 0; i < selector.length; i++){
14209 if(rs[selector[i]]){
14210 return rs[selector[i]];
14218 * Updates a rule property
14219 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14220 * @param {String} property The css property
14221 * @param {String} value The new value for the property
14222 * @return {Boolean} true If a rule was found and updated
14224 updateRule : function(selector, property, value){
14225 if(!(selector instanceof Array)){
14226 var rule = this.getRule(selector);
14228 rule.style[property.replace(camelRe, camelFn)] = value;
14232 for(var i = 0; i < selector.length; i++){
14233 if(this.updateRule(selector[i], property, value)){
14243 * Ext JS Library 1.1.1
14244 * Copyright(c) 2006-2007, Ext JS, LLC.
14246 * Originally Released Under LGPL - original licence link has changed is not relivant.
14249 * <script type="text/javascript">
14255 * @class Roo.util.ClickRepeater
14256 * @extends Roo.util.Observable
14258 * A wrapper class which can be applied to any element. Fires a "click" event while the
14259 * mouse is pressed. The interval between firings may be specified in the config but
14260 * defaults to 10 milliseconds.
14262 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14264 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14265 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14266 * Similar to an autorepeat key delay.
14267 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14268 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14269 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14270 * "interval" and "delay" are ignored. "immediate" is honored.
14271 * @cfg {Boolean} preventDefault True to prevent the default click event
14272 * @cfg {Boolean} stopDefault True to stop the default click event
14275 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14276 * 2007-02-02 jvs Renamed to ClickRepeater
14277 * 2007-02-03 jvs Modifications for FF Mac and Safari
14280 * @param {String/HTMLElement/Element} el The element to listen on
14281 * @param {Object} config
14283 Roo.util.ClickRepeater = function(el, config)
14285 this.el = Roo.get(el);
14286 this.el.unselectable();
14288 Roo.apply(this, config);
14293 * Fires when the mouse button is depressed.
14294 * @param {Roo.util.ClickRepeater} this
14296 "mousedown" : true,
14299 * Fires on a specified interval during the time the element is pressed.
14300 * @param {Roo.util.ClickRepeater} this
14305 * Fires when the mouse key is released.
14306 * @param {Roo.util.ClickRepeater} this
14311 this.el.on("mousedown", this.handleMouseDown, this);
14312 if(this.preventDefault || this.stopDefault){
14313 this.el.on("click", function(e){
14314 if(this.preventDefault){
14315 e.preventDefault();
14317 if(this.stopDefault){
14323 // allow inline handler
14325 this.on("click", this.handler, this.scope || this);
14328 Roo.util.ClickRepeater.superclass.constructor.call(this);
14331 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14334 preventDefault : true,
14335 stopDefault : false,
14339 handleMouseDown : function(){
14340 clearTimeout(this.timer);
14342 if(this.pressClass){
14343 this.el.addClass(this.pressClass);
14345 this.mousedownTime = new Date();
14347 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14348 this.el.on("mouseout", this.handleMouseOut, this);
14350 this.fireEvent("mousedown", this);
14351 this.fireEvent("click", this);
14353 this.timer = this.click.defer(this.delay || this.interval, this);
14357 click : function(){
14358 this.fireEvent("click", this);
14359 this.timer = this.click.defer(this.getInterval(), this);
14363 getInterval: function(){
14364 if(!this.accelerate){
14365 return this.interval;
14367 var pressTime = this.mousedownTime.getElapsed();
14368 if(pressTime < 500){
14370 }else if(pressTime < 1700){
14372 }else if(pressTime < 2600){
14374 }else if(pressTime < 3500){
14376 }else if(pressTime < 4400){
14378 }else if(pressTime < 5300){
14380 }else if(pressTime < 6200){
14388 handleMouseOut : function(){
14389 clearTimeout(this.timer);
14390 if(this.pressClass){
14391 this.el.removeClass(this.pressClass);
14393 this.el.on("mouseover", this.handleMouseReturn, this);
14397 handleMouseReturn : function(){
14398 this.el.un("mouseover", this.handleMouseReturn);
14399 if(this.pressClass){
14400 this.el.addClass(this.pressClass);
14406 handleMouseUp : function(){
14407 clearTimeout(this.timer);
14408 this.el.un("mouseover", this.handleMouseReturn);
14409 this.el.un("mouseout", this.handleMouseOut);
14410 Roo.get(document).un("mouseup", this.handleMouseUp);
14411 this.el.removeClass(this.pressClass);
14412 this.fireEvent("mouseup", this);
14416 * Ext JS Library 1.1.1
14417 * Copyright(c) 2006-2007, Ext JS, LLC.
14419 * Originally Released Under LGPL - original licence link has changed is not relivant.
14422 * <script type="text/javascript">
14427 * @class Roo.KeyNav
14428 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14429 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14430 * way to implement custom navigation schemes for any UI component.</p>
14431 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14432 * pageUp, pageDown, del, home, end. Usage:</p>
14434 var nav = new Roo.KeyNav("my-element", {
14435 "left" : function(e){
14436 this.moveLeft(e.ctrlKey);
14438 "right" : function(e){
14439 this.moveRight(e.ctrlKey);
14441 "enter" : function(e){
14448 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14449 * @param {Object} config The config
14451 Roo.KeyNav = function(el, config){
14452 this.el = Roo.get(el);
14453 Roo.apply(this, config);
14454 if(!this.disabled){
14455 this.disabled = true;
14460 Roo.KeyNav.prototype = {
14462 * @cfg {Boolean} disabled
14463 * True to disable this KeyNav instance (defaults to false)
14467 * @cfg {String} defaultEventAction
14468 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14469 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14470 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14472 defaultEventAction: "stopEvent",
14474 * @cfg {Boolean} forceKeyDown
14475 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14476 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14477 * handle keydown instead of keypress.
14479 forceKeyDown : false,
14482 prepareEvent : function(e){
14483 var k = e.getKey();
14484 var h = this.keyToHandler[k];
14485 //if(h && this[h]){
14486 // e.stopPropagation();
14488 if(Roo.isSafari && h && k >= 37 && k <= 40){
14494 relay : function(e){
14495 var k = e.getKey();
14496 var h = this.keyToHandler[k];
14498 if(this.doRelay(e, this[h], h) !== true){
14499 e[this.defaultEventAction]();
14505 doRelay : function(e, h, hname){
14506 return h.call(this.scope || this, e);
14509 // possible handlers
14523 // quick lookup hash
14540 * Enable this KeyNav
14542 enable: function(){
14544 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14545 // the EventObject will normalize Safari automatically
14546 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14547 this.el.on("keydown", this.relay, this);
14549 this.el.on("keydown", this.prepareEvent, this);
14550 this.el.on("keypress", this.relay, this);
14552 this.disabled = false;
14557 * Disable this KeyNav
14559 disable: function(){
14560 if(!this.disabled){
14561 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14562 this.el.un("keydown", this.relay);
14564 this.el.un("keydown", this.prepareEvent);
14565 this.el.un("keypress", this.relay);
14567 this.disabled = true;
14572 * Ext JS Library 1.1.1
14573 * Copyright(c) 2006-2007, Ext JS, LLC.
14575 * Originally Released Under LGPL - original licence link has changed is not relivant.
14578 * <script type="text/javascript">
14583 * @class Roo.KeyMap
14584 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14585 * The constructor accepts the same config object as defined by {@link #addBinding}.
14586 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14587 * combination it will call the function with this signature (if the match is a multi-key
14588 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14589 * A KeyMap can also handle a string representation of keys.<br />
14592 // map one key by key code
14593 var map = new Roo.KeyMap("my-element", {
14594 key: 13, // or Roo.EventObject.ENTER
14599 // map multiple keys to one action by string
14600 var map = new Roo.KeyMap("my-element", {
14606 // map multiple keys to multiple actions by strings and array of codes
14607 var map = new Roo.KeyMap("my-element", [
14610 fn: function(){ alert("Return was pressed"); }
14613 fn: function(){ alert('a, b or c was pressed'); }
14618 fn: function(){ alert('Control + shift + tab was pressed.'); }
14622 * <b>Note: A KeyMap starts enabled</b>
14624 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14625 * @param {Object} config The config (see {@link #addBinding})
14626 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14628 Roo.KeyMap = function(el, config, eventName){
14629 this.el = Roo.get(el);
14630 this.eventName = eventName || "keydown";
14631 this.bindings = [];
14633 this.addBinding(config);
14638 Roo.KeyMap.prototype = {
14640 * True to stop the event from bubbling and prevent the default browser action if the
14641 * key was handled by the KeyMap (defaults to false)
14647 * Add a new binding to this KeyMap. The following config object properties are supported:
14649 Property Type Description
14650 ---------- --------------- ----------------------------------------------------------------------
14651 key String/Array A single keycode or an array of keycodes to handle
14652 shift Boolean True to handle key only when shift is pressed (defaults to false)
14653 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14654 alt Boolean True to handle key only when alt is pressed (defaults to false)
14655 fn Function The function to call when KeyMap finds the expected key combination
14656 scope Object The scope of the callback function
14662 var map = new Roo.KeyMap(document, {
14663 key: Roo.EventObject.ENTER,
14668 //Add a new binding to the existing KeyMap later
14676 * @param {Object/Array} config A single KeyMap config or an array of configs
14678 addBinding : function(config){
14679 if(config instanceof Array){
14680 for(var i = 0, len = config.length; i < len; i++){
14681 this.addBinding(config[i]);
14685 var keyCode = config.key,
14686 shift = config.shift,
14687 ctrl = config.ctrl,
14690 scope = config.scope;
14691 if(typeof keyCode == "string"){
14693 var keyString = keyCode.toUpperCase();
14694 for(var j = 0, len = keyString.length; j < len; j++){
14695 ks.push(keyString.charCodeAt(j));
14699 var keyArray = keyCode instanceof Array;
14700 var handler = function(e){
14701 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14702 var k = e.getKey();
14704 for(var i = 0, len = keyCode.length; i < len; i++){
14705 if(keyCode[i] == k){
14706 if(this.stopEvent){
14709 fn.call(scope || window, k, e);
14715 if(this.stopEvent){
14718 fn.call(scope || window, k, e);
14723 this.bindings.push(handler);
14727 * Shorthand for adding a single key listener
14728 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14729 * following options:
14730 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14731 * @param {Function} fn The function to call
14732 * @param {Object} scope (optional) The scope of the function
14734 on : function(key, fn, scope){
14735 var keyCode, shift, ctrl, alt;
14736 if(typeof key == "object" && !(key instanceof Array)){
14755 handleKeyDown : function(e){
14756 if(this.enabled){ //just in case
14757 var b = this.bindings;
14758 for(var i = 0, len = b.length; i < len; i++){
14759 b[i].call(this, e);
14765 * Returns true if this KeyMap is enabled
14766 * @return {Boolean}
14768 isEnabled : function(){
14769 return this.enabled;
14773 * Enables this KeyMap
14775 enable: function(){
14777 this.el.on(this.eventName, this.handleKeyDown, this);
14778 this.enabled = true;
14783 * Disable this KeyMap
14785 disable: function(){
14787 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14788 this.enabled = false;
14793 * Ext JS Library 1.1.1
14794 * Copyright(c) 2006-2007, Ext JS, LLC.
14796 * Originally Released Under LGPL - original licence link has changed is not relivant.
14799 * <script type="text/javascript">
14804 * @class Roo.util.TextMetrics
14805 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14806 * wide, in pixels, a given block of text will be.
14809 Roo.util.TextMetrics = function(){
14813 * Measures the size of the specified text
14814 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14815 * that can affect the size of the rendered text
14816 * @param {String} text The text to measure
14817 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14818 * in order to accurately measure the text height
14819 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14821 measure : function(el, text, fixedWidth){
14823 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14826 shared.setFixedWidth(fixedWidth || 'auto');
14827 return shared.getSize(text);
14831 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14832 * the overhead of multiple calls to initialize the style properties on each measurement.
14833 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14834 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14835 * in order to accurately measure the text height
14836 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14838 createInstance : function(el, fixedWidth){
14839 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14846 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14847 var ml = new Roo.Element(document.createElement('div'));
14848 document.body.appendChild(ml.dom);
14849 ml.position('absolute');
14850 ml.setLeftTop(-1000, -1000);
14854 ml.setWidth(fixedWidth);
14859 * Returns the size of the specified text based on the internal element's style and width properties
14860 * @memberOf Roo.util.TextMetrics.Instance#
14861 * @param {String} text The text to measure
14862 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14864 getSize : function(text){
14866 var s = ml.getSize();
14872 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14873 * that can affect the size of the rendered text
14874 * @memberOf Roo.util.TextMetrics.Instance#
14875 * @param {String/HTMLElement} el The element, dom node or id
14877 bind : function(el){
14879 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14884 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14885 * to set a fixed width in order to accurately measure the text height.
14886 * @memberOf Roo.util.TextMetrics.Instance#
14887 * @param {Number} width The width to set on the element
14889 setFixedWidth : function(width){
14890 ml.setWidth(width);
14894 * Returns the measured width of the specified text
14895 * @memberOf Roo.util.TextMetrics.Instance#
14896 * @param {String} text The text to measure
14897 * @return {Number} width The width in pixels
14899 getWidth : function(text){
14900 ml.dom.style.width = 'auto';
14901 return this.getSize(text).width;
14905 * Returns the measured height of the specified text. For multiline text, be sure to call
14906 * {@link #setFixedWidth} if necessary.
14907 * @memberOf Roo.util.TextMetrics.Instance#
14908 * @param {String} text The text to measure
14909 * @return {Number} height The height in pixels
14911 getHeight : function(text){
14912 return this.getSize(text).height;
14916 instance.bind(bindTo);
14921 // backwards compat
14922 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14924 * Ext JS Library 1.1.1
14925 * Copyright(c) 2006-2007, Ext JS, LLC.
14927 * Originally Released Under LGPL - original licence link has changed is not relivant.
14930 * <script type="text/javascript">
14934 * @class Roo.state.Provider
14935 * Abstract base class for state provider implementations. This class provides methods
14936 * for encoding and decoding <b>typed</b> variables including dates and defines the
14937 * Provider interface.
14939 Roo.state.Provider = function(){
14941 * @event statechange
14942 * Fires when a state change occurs.
14943 * @param {Provider} this This state provider
14944 * @param {String} key The state key which was changed
14945 * @param {String} value The encoded value for the state
14948 "statechange": true
14951 Roo.state.Provider.superclass.constructor.call(this);
14953 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14955 * Returns the current value for a key
14956 * @param {String} name The key name
14957 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14958 * @return {Mixed} The state data
14960 get : function(name, defaultValue){
14961 return typeof this.state[name] == "undefined" ?
14962 defaultValue : this.state[name];
14966 * Clears a value from the state
14967 * @param {String} name The key name
14969 clear : function(name){
14970 delete this.state[name];
14971 this.fireEvent("statechange", this, name, null);
14975 * Sets the value for a key
14976 * @param {String} name The key name
14977 * @param {Mixed} value The value to set
14979 set : function(name, value){
14980 this.state[name] = value;
14981 this.fireEvent("statechange", this, name, value);
14985 * Decodes a string previously encoded with {@link #encodeValue}.
14986 * @param {String} value The value to decode
14987 * @return {Mixed} The decoded value
14989 decodeValue : function(cookie){
14990 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14991 var matches = re.exec(unescape(cookie));
14992 if(!matches || !matches[1]) {
14993 return; // non state cookie
14995 var type = matches[1];
14996 var v = matches[2];
14999 return parseFloat(v);
15001 return new Date(Date.parse(v));
15006 var values = v.split("^");
15007 for(var i = 0, len = values.length; i < len; i++){
15008 all.push(this.decodeValue(values[i]));
15013 var values = v.split("^");
15014 for(var i = 0, len = values.length; i < len; i++){
15015 var kv = values[i].split("=");
15016 all[kv[0]] = this.decodeValue(kv[1]);
15025 * Encodes a value including type information. Decode with {@link #decodeValue}.
15026 * @param {Mixed} value The value to encode
15027 * @return {String} The encoded value
15029 encodeValue : function(v){
15031 if(typeof v == "number"){
15033 }else if(typeof v == "boolean"){
15034 enc = "b:" + (v ? "1" : "0");
15035 }else if(v instanceof Date){
15036 enc = "d:" + v.toGMTString();
15037 }else if(v instanceof Array){
15039 for(var i = 0, len = v.length; i < len; i++){
15040 flat += this.encodeValue(v[i]);
15046 }else if(typeof v == "object"){
15049 if(typeof v[key] != "function"){
15050 flat += key + "=" + this.encodeValue(v[key]) + "^";
15053 enc = "o:" + flat.substring(0, flat.length-1);
15057 return escape(enc);
15063 * Ext JS Library 1.1.1
15064 * Copyright(c) 2006-2007, Ext JS, LLC.
15066 * Originally Released Under LGPL - original licence link has changed is not relivant.
15069 * <script type="text/javascript">
15072 * @class Roo.state.Manager
15073 * This is the global state manager. By default all components that are "state aware" check this class
15074 * for state information if you don't pass them a custom state provider. In order for this class
15075 * to be useful, it must be initialized with a provider when your application initializes.
15077 // in your initialization function
15079 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15081 // supposed you have a {@link Roo.BorderLayout}
15082 var layout = new Roo.BorderLayout(...);
15083 layout.restoreState();
15084 // or a {Roo.BasicDialog}
15085 var dialog = new Roo.BasicDialog(...);
15086 dialog.restoreState();
15090 Roo.state.Manager = function(){
15091 var provider = new Roo.state.Provider();
15095 * Configures the default state provider for your application
15096 * @param {Provider} stateProvider The state provider to set
15098 setProvider : function(stateProvider){
15099 provider = stateProvider;
15103 * Returns the current value for a key
15104 * @param {String} name The key name
15105 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15106 * @return {Mixed} The state data
15108 get : function(key, defaultValue){
15109 return provider.get(key, defaultValue);
15113 * Sets the value for a key
15114 * @param {String} name The key name
15115 * @param {Mixed} value The state data
15117 set : function(key, value){
15118 provider.set(key, value);
15122 * Clears a value from the state
15123 * @param {String} name The key name
15125 clear : function(key){
15126 provider.clear(key);
15130 * Gets the currently configured state provider
15131 * @return {Provider} The state provider
15133 getProvider : function(){
15140 * Ext JS Library 1.1.1
15141 * Copyright(c) 2006-2007, Ext JS, LLC.
15143 * Originally Released Under LGPL - original licence link has changed is not relivant.
15146 * <script type="text/javascript">
15149 * @class Roo.state.CookieProvider
15150 * @extends Roo.state.Provider
15151 * The default Provider implementation which saves state via cookies.
15154 var cp = new Roo.state.CookieProvider({
15156 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15157 domain: "roojs.com"
15159 Roo.state.Manager.setProvider(cp);
15161 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15162 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15163 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15164 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15165 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15166 * domain the page is running on including the 'www' like 'www.roojs.com')
15167 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15169 * Create a new CookieProvider
15170 * @param {Object} config The configuration object
15172 Roo.state.CookieProvider = function(config){
15173 Roo.state.CookieProvider.superclass.constructor.call(this);
15175 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15176 this.domain = null;
15177 this.secure = false;
15178 Roo.apply(this, config);
15179 this.state = this.readCookies();
15182 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15184 set : function(name, value){
15185 if(typeof value == "undefined" || value === null){
15189 this.setCookie(name, value);
15190 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15194 clear : function(name){
15195 this.clearCookie(name);
15196 Roo.state.CookieProvider.superclass.clear.call(this, name);
15200 readCookies : function(){
15202 var c = document.cookie + ";";
15203 var re = /\s?(.*?)=(.*?);/g;
15205 while((matches = re.exec(c)) != null){
15206 var name = matches[1];
15207 var value = matches[2];
15208 if(name && name.substring(0,3) == "ys-"){
15209 cookies[name.substr(3)] = this.decodeValue(value);
15216 setCookie : function(name, value){
15217 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15218 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15219 ((this.path == null) ? "" : ("; path=" + this.path)) +
15220 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15221 ((this.secure == true) ? "; secure" : "");
15225 clearCookie : function(name){
15226 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15227 ((this.path == null) ? "" : ("; path=" + this.path)) +
15228 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15229 ((this.secure == true) ? "; secure" : "");
15233 * Ext JS Library 1.1.1
15234 * Copyright(c) 2006-2007, Ext JS, LLC.
15236 * Originally Released Under LGPL - original licence link has changed is not relivant.
15239 * <script type="text/javascript">
15244 * @class Roo.ComponentMgr
15245 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15248 Roo.ComponentMgr = function(){
15249 var all = new Roo.util.MixedCollection();
15253 * Registers a component.
15254 * @param {Roo.Component} c The component
15256 register : function(c){
15261 * Unregisters a component.
15262 * @param {Roo.Component} c The component
15264 unregister : function(c){
15269 * Returns a component by id
15270 * @param {String} id The component id
15272 get : function(id){
15273 return all.get(id);
15277 * Registers a function that will be called when a specified component is added to ComponentMgr
15278 * @param {String} id The component id
15279 * @param {Funtction} fn The callback function
15280 * @param {Object} scope The scope of the callback
15282 onAvailable : function(id, fn, scope){
15283 all.on("add", function(index, o){
15285 fn.call(scope || o, o);
15286 all.un("add", fn, scope);
15293 * Ext JS Library 1.1.1
15294 * Copyright(c) 2006-2007, Ext JS, LLC.
15296 * Originally Released Under LGPL - original licence link has changed is not relivant.
15299 * <script type="text/javascript">
15303 * @class Roo.Component
15304 * @extends Roo.util.Observable
15305 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15306 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15307 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15308 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15309 * All visual components (widgets) that require rendering into a layout should subclass Component.
15311 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15312 * 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
15313 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15315 Roo.Component = function(config){
15316 config = config || {};
15317 if(config.tagName || config.dom || typeof config == "string"){ // element object
15318 config = {el: config, id: config.id || config};
15320 this.initialConfig = config;
15322 Roo.apply(this, config);
15326 * Fires after the component is disabled.
15327 * @param {Roo.Component} this
15332 * Fires after the component is enabled.
15333 * @param {Roo.Component} this
15337 * @event beforeshow
15338 * Fires before the component is shown. Return false to stop the show.
15339 * @param {Roo.Component} this
15344 * Fires after the component is shown.
15345 * @param {Roo.Component} this
15349 * @event beforehide
15350 * Fires before the component is hidden. Return false to stop the hide.
15351 * @param {Roo.Component} this
15356 * Fires after the component is hidden.
15357 * @param {Roo.Component} this
15361 * @event beforerender
15362 * Fires before the component is rendered. Return false to stop the render.
15363 * @param {Roo.Component} this
15365 beforerender : true,
15368 * Fires after the component is rendered.
15369 * @param {Roo.Component} this
15373 * @event beforedestroy
15374 * Fires before the component is destroyed. Return false to stop the destroy.
15375 * @param {Roo.Component} this
15377 beforedestroy : true,
15380 * Fires after the component is destroyed.
15381 * @param {Roo.Component} this
15386 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15388 Roo.ComponentMgr.register(this);
15389 Roo.Component.superclass.constructor.call(this);
15390 this.initComponent();
15391 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15392 this.render(this.renderTo);
15393 delete this.renderTo;
15398 Roo.Component.AUTO_ID = 1000;
15400 Roo.extend(Roo.Component, Roo.util.Observable, {
15402 * @scope Roo.Component.prototype
15404 * true if this component is hidden. Read-only.
15409 * true if this component is disabled. Read-only.
15414 * true if this component has been rendered. Read-only.
15418 /** @cfg {String} disableClass
15419 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15421 disabledClass : "x-item-disabled",
15422 /** @cfg {Boolean} allowDomMove
15423 * Whether the component can move the Dom node when rendering (defaults to true).
15425 allowDomMove : true,
15426 /** @cfg {String} hideMode (display|visibility)
15427 * How this component should hidden. Supported values are
15428 * "visibility" (css visibility), "offsets" (negative offset position) and
15429 * "display" (css display) - defaults to "display".
15431 hideMode: 'display',
15434 ctype : "Roo.Component",
15437 * @cfg {String} actionMode
15438 * which property holds the element that used for hide() / show() / disable() / enable()
15444 getActionEl : function(){
15445 return this[this.actionMode];
15448 initComponent : Roo.emptyFn,
15450 * If this is a lazy rendering component, render it to its container element.
15451 * @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.
15453 render : function(container, position){
15459 if(this.fireEvent("beforerender", this) === false){
15463 if(!container && this.el){
15464 this.el = Roo.get(this.el);
15465 container = this.el.dom.parentNode;
15466 this.allowDomMove = false;
15468 this.container = Roo.get(container);
15469 this.rendered = true;
15470 if(position !== undefined){
15471 if(typeof position == 'number'){
15472 position = this.container.dom.childNodes[position];
15474 position = Roo.getDom(position);
15477 this.onRender(this.container, position || null);
15479 this.el.addClass(this.cls);
15483 this.el.applyStyles(this.style);
15486 this.fireEvent("render", this);
15487 this.afterRender(this.container);
15500 // default function is not really useful
15501 onRender : function(ct, position){
15503 this.el = Roo.get(this.el);
15504 if(this.allowDomMove !== false){
15505 ct.dom.insertBefore(this.el.dom, position);
15511 getAutoCreate : function(){
15512 var cfg = typeof this.autoCreate == "object" ?
15513 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15514 if(this.id && !cfg.id){
15521 afterRender : Roo.emptyFn,
15524 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15525 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15527 destroy : function(){
15528 if(this.fireEvent("beforedestroy", this) !== false){
15529 this.purgeListeners();
15530 this.beforeDestroy();
15532 this.el.removeAllListeners();
15534 if(this.actionMode == "container"){
15535 this.container.remove();
15539 Roo.ComponentMgr.unregister(this);
15540 this.fireEvent("destroy", this);
15545 beforeDestroy : function(){
15550 onDestroy : function(){
15555 * Returns the underlying {@link Roo.Element}.
15556 * @return {Roo.Element} The element
15558 getEl : function(){
15563 * Returns the id of this component.
15566 getId : function(){
15571 * Try to focus this component.
15572 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15573 * @return {Roo.Component} this
15575 focus : function(selectText){
15578 if(selectText === true){
15579 this.el.dom.select();
15594 * Disable this component.
15595 * @return {Roo.Component} this
15597 disable : function(){
15601 this.disabled = true;
15602 this.fireEvent("disable", this);
15607 onDisable : function(){
15608 this.getActionEl().addClass(this.disabledClass);
15609 this.el.dom.disabled = true;
15613 * Enable this component.
15614 * @return {Roo.Component} this
15616 enable : function(){
15620 this.disabled = false;
15621 this.fireEvent("enable", this);
15626 onEnable : function(){
15627 this.getActionEl().removeClass(this.disabledClass);
15628 this.el.dom.disabled = false;
15632 * Convenience function for setting disabled/enabled by boolean.
15633 * @param {Boolean} disabled
15635 setDisabled : function(disabled){
15636 this[disabled ? "disable" : "enable"]();
15640 * Show this component.
15641 * @return {Roo.Component} this
15644 if(this.fireEvent("beforeshow", this) !== false){
15645 this.hidden = false;
15649 this.fireEvent("show", this);
15655 onShow : function(){
15656 var ae = this.getActionEl();
15657 if(this.hideMode == 'visibility'){
15658 ae.dom.style.visibility = "visible";
15659 }else if(this.hideMode == 'offsets'){
15660 ae.removeClass('x-hidden');
15662 ae.dom.style.display = "";
15667 * Hide this component.
15668 * @return {Roo.Component} this
15671 if(this.fireEvent("beforehide", this) !== false){
15672 this.hidden = true;
15676 this.fireEvent("hide", this);
15682 onHide : function(){
15683 var ae = this.getActionEl();
15684 if(this.hideMode == 'visibility'){
15685 ae.dom.style.visibility = "hidden";
15686 }else if(this.hideMode == 'offsets'){
15687 ae.addClass('x-hidden');
15689 ae.dom.style.display = "none";
15694 * Convenience function to hide or show this component by boolean.
15695 * @param {Boolean} visible True to show, false to hide
15696 * @return {Roo.Component} this
15698 setVisible: function(visible){
15708 * Returns true if this component is visible.
15710 isVisible : function(){
15711 return this.getActionEl().isVisible();
15714 cloneConfig : function(overrides){
15715 overrides = overrides || {};
15716 var id = overrides.id || Roo.id();
15717 var cfg = Roo.applyIf(overrides, this.initialConfig);
15718 cfg.id = id; // prevent dup id
15719 return new this.constructor(cfg);
15723 * Ext JS Library 1.1.1
15724 * Copyright(c) 2006-2007, Ext JS, LLC.
15726 * Originally Released Under LGPL - original licence link has changed is not relivant.
15729 * <script type="text/javascript">
15733 * @class Roo.BoxComponent
15734 * @extends Roo.Component
15735 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15736 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15737 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15738 * layout containers.
15740 * @param {Roo.Element/String/Object} config The configuration options.
15742 Roo.BoxComponent = function(config){
15743 Roo.Component.call(this, config);
15747 * Fires after the component is resized.
15748 * @param {Roo.Component} this
15749 * @param {Number} adjWidth The box-adjusted width that was set
15750 * @param {Number} adjHeight The box-adjusted height that was set
15751 * @param {Number} rawWidth The width that was originally specified
15752 * @param {Number} rawHeight The height that was originally specified
15757 * Fires after the component is moved.
15758 * @param {Roo.Component} this
15759 * @param {Number} x The new x position
15760 * @param {Number} y The new y position
15766 Roo.extend(Roo.BoxComponent, Roo.Component, {
15767 // private, set in afterRender to signify that the component has been rendered
15769 // private, used to defer height settings to subclasses
15770 deferHeight: false,
15771 /** @cfg {Number} width
15772 * width (optional) size of component
15774 /** @cfg {Number} height
15775 * height (optional) size of component
15779 * Sets the width and height of the component. This method fires the resize event. This method can accept
15780 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15781 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15782 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15783 * @return {Roo.BoxComponent} this
15785 setSize : function(w, h){
15786 // support for standard size objects
15787 if(typeof w == 'object'){
15792 if(!this.boxReady){
15798 // prevent recalcs when not needed
15799 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15802 this.lastSize = {width: w, height: h};
15804 var adj = this.adjustSize(w, h);
15805 var aw = adj.width, ah = adj.height;
15806 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15807 var rz = this.getResizeEl();
15808 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15809 rz.setSize(aw, ah);
15810 }else if(!this.deferHeight && ah !== undefined){
15812 }else if(aw !== undefined){
15815 this.onResize(aw, ah, w, h);
15816 this.fireEvent('resize', this, aw, ah, w, h);
15822 * Gets the current size of the component's underlying element.
15823 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15825 getSize : function(){
15826 return this.el.getSize();
15830 * Gets the current XY position of the component's underlying element.
15831 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15832 * @return {Array} The XY position of the element (e.g., [100, 200])
15834 getPosition : function(local){
15835 if(local === true){
15836 return [this.el.getLeft(true), this.el.getTop(true)];
15838 return this.xy || this.el.getXY();
15842 * Gets the current box measurements of the component's underlying element.
15843 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15844 * @returns {Object} box An object in the format {x, y, width, height}
15846 getBox : function(local){
15847 var s = this.el.getSize();
15849 s.x = this.el.getLeft(true);
15850 s.y = this.el.getTop(true);
15852 var xy = this.xy || this.el.getXY();
15860 * Sets the current box measurements of the component's underlying element.
15861 * @param {Object} box An object in the format {x, y, width, height}
15862 * @returns {Roo.BoxComponent} this
15864 updateBox : function(box){
15865 this.setSize(box.width, box.height);
15866 this.setPagePosition(box.x, box.y);
15871 getResizeEl : function(){
15872 return this.resizeEl || this.el;
15876 getPositionEl : function(){
15877 return this.positionEl || this.el;
15881 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15882 * This method fires the move event.
15883 * @param {Number} left The new left
15884 * @param {Number} top The new top
15885 * @returns {Roo.BoxComponent} this
15887 setPosition : function(x, y){
15890 if(!this.boxReady){
15893 var adj = this.adjustPosition(x, y);
15894 var ax = adj.x, ay = adj.y;
15896 var el = this.getPositionEl();
15897 if(ax !== undefined || ay !== undefined){
15898 if(ax !== undefined && ay !== undefined){
15899 el.setLeftTop(ax, ay);
15900 }else if(ax !== undefined){
15902 }else if(ay !== undefined){
15905 this.onPosition(ax, ay);
15906 this.fireEvent('move', this, ax, ay);
15912 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15913 * This method fires the move event.
15914 * @param {Number} x The new x position
15915 * @param {Number} y The new y position
15916 * @returns {Roo.BoxComponent} this
15918 setPagePosition : function(x, y){
15921 if(!this.boxReady){
15924 if(x === undefined || y === undefined){ // cannot translate undefined points
15927 var p = this.el.translatePoints(x, y);
15928 this.setPosition(p.left, p.top);
15933 onRender : function(ct, position){
15934 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15936 this.resizeEl = Roo.get(this.resizeEl);
15938 if(this.positionEl){
15939 this.positionEl = Roo.get(this.positionEl);
15944 afterRender : function(){
15945 Roo.BoxComponent.superclass.afterRender.call(this);
15946 this.boxReady = true;
15947 this.setSize(this.width, this.height);
15948 if(this.x || this.y){
15949 this.setPosition(this.x, this.y);
15951 if(this.pageX || this.pageY){
15952 this.setPagePosition(this.pageX, this.pageY);
15957 * Force the component's size to recalculate based on the underlying element's current height and width.
15958 * @returns {Roo.BoxComponent} this
15960 syncSize : function(){
15961 delete this.lastSize;
15962 this.setSize(this.el.getWidth(), this.el.getHeight());
15967 * Called after the component is resized, this method is empty by default but can be implemented by any
15968 * subclass that needs to perform custom logic after a resize occurs.
15969 * @param {Number} adjWidth The box-adjusted width that was set
15970 * @param {Number} adjHeight The box-adjusted height that was set
15971 * @param {Number} rawWidth The width that was originally specified
15972 * @param {Number} rawHeight The height that was originally specified
15974 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15979 * Called after the component is moved, this method is empty by default but can be implemented by any
15980 * subclass that needs to perform custom logic after a move occurs.
15981 * @param {Number} x The new x position
15982 * @param {Number} y The new y position
15984 onPosition : function(x, y){
15989 adjustSize : function(w, h){
15990 if(this.autoWidth){
15993 if(this.autoHeight){
15996 return {width : w, height: h};
16000 adjustPosition : function(x, y){
16001 return {x : x, y: y};
16004 * Original code for Roojs - LGPL
16005 * <script type="text/javascript">
16009 * @class Roo.XComponent
16010 * A delayed Element creator...
16011 * Or a way to group chunks of interface together.
16012 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16013 * used in conjunction with XComponent.build() it will create an instance of each element,
16014 * then call addxtype() to build the User interface.
16016 * Mypart.xyx = new Roo.XComponent({
16018 parent : 'Mypart.xyz', // empty == document.element.!!
16022 disabled : function() {}
16024 tree : function() { // return an tree of xtype declared components
16028 xtype : 'NestedLayoutPanel',
16035 * It can be used to build a big heiracy, with parent etc.
16036 * or you can just use this to render a single compoent to a dom element
16037 * MYPART.render(Roo.Element | String(id) | dom_element )
16044 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16045 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16047 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16049 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16050 * - if mulitple topModules exist, the last one is defined as the top module.
16054 * When the top level or multiple modules are to embedded into a existing HTML page,
16055 * the parent element can container '#id' of the element where the module will be drawn.
16059 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16060 * it relies more on a include mechanism, where sub modules are included into an outer page.
16061 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16063 * Bootstrap Roo Included elements
16065 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16066 * hence confusing the component builder as it thinks there are multiple top level elements.
16068 * String Over-ride & Translations
16070 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16071 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16072 * are needed. @see Roo.XComponent.overlayString
16076 * @extends Roo.util.Observable
16078 * @param cfg {Object} configuration of component
16081 Roo.XComponent = function(cfg) {
16082 Roo.apply(this, cfg);
16086 * Fires when this the componnt is built
16087 * @param {Roo.XComponent} c the component
16092 this.region = this.region || 'center'; // default..
16093 Roo.XComponent.register(this);
16094 this.modules = false;
16095 this.el = false; // where the layout goes..
16099 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16102 * The created element (with Roo.factory())
16103 * @type {Roo.Layout}
16109 * for BC - use el in new code
16110 * @type {Roo.Layout}
16116 * for BC - use el in new code
16117 * @type {Roo.Layout}
16122 * @cfg {Function|boolean} disabled
16123 * If this module is disabled by some rule, return true from the funtion
16128 * @cfg {String} parent
16129 * Name of parent element which it get xtype added to..
16134 * @cfg {String} order
16135 * Used to set the order in which elements are created (usefull for multiple tabs)
16140 * @cfg {String} name
16141 * String to display while loading.
16145 * @cfg {String} region
16146 * Region to render component to (defaults to center)
16151 * @cfg {Array} items
16152 * A single item array - the first element is the root of the tree..
16153 * It's done this way to stay compatible with the Xtype system...
16159 * The method that retuns the tree of parts that make up this compoennt
16166 * render element to dom or tree
16167 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16170 render : function(el)
16174 var hp = this.parent ? 1 : 0;
16175 Roo.debug && Roo.log(this);
16177 var tree = this._tree ? this._tree() : this.tree();
16180 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16181 // if parent is a '#.....' string, then let's use that..
16182 var ename = this.parent.substr(1);
16183 this.parent = false;
16184 Roo.debug && Roo.log(ename);
16186 case 'bootstrap-body':
16187 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16188 // this is the BorderLayout standard?
16189 this.parent = { el : true };
16192 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16193 // need to insert stuff...
16195 el : new Roo.bootstrap.layout.Border({
16196 el : document.body,
16202 tabPosition: 'top',
16203 //resizeTabs: true,
16204 alwaysShowTabs: true,
16214 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16215 this.parent = { el : new Roo.bootstrap.Body() };
16216 Roo.debug && Roo.log("setting el to doc body");
16219 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16223 this.parent = { el : true};
16226 el = Roo.get(ename);
16227 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16228 this.parent = { el : true};
16235 if (!el && !this.parent) {
16236 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16241 Roo.debug && Roo.log("EL:");
16242 Roo.debug && Roo.log(el);
16243 Roo.debug && Roo.log("this.parent.el:");
16244 Roo.debug && Roo.log(this.parent.el);
16247 // altertive root elements ??? - we need a better way to indicate these.
16248 var is_alt = Roo.XComponent.is_alt ||
16249 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16250 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16251 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16255 if (!this.parent && is_alt) {
16256 //el = Roo.get(document.body);
16257 this.parent = { el : true };
16262 if (!this.parent) {
16264 Roo.debug && Roo.log("no parent - creating one");
16266 el = el ? Roo.get(el) : false;
16268 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16271 el : new Roo.bootstrap.layout.Border({
16272 el: el || document.body,
16278 tabPosition: 'top',
16279 //resizeTabs: true,
16280 alwaysShowTabs: false,
16283 overflow: 'visible'
16289 // it's a top level one..
16291 el : new Roo.BorderLayout(el || document.body, {
16296 tabPosition: 'top',
16297 //resizeTabs: true,
16298 alwaysShowTabs: el && hp? false : true,
16299 hideTabs: el || !hp ? true : false,
16307 if (!this.parent.el) {
16308 // probably an old style ctor, which has been disabled.
16312 // The 'tree' method is '_tree now'
16314 tree.region = tree.region || this.region;
16315 var is_body = false;
16316 if (this.parent.el === true) {
16317 // bootstrap... - body..
16321 this.parent.el = Roo.factory(tree);
16325 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16326 this.fireEvent('built', this);
16328 this.panel = this.el;
16329 this.layout = this.panel.layout;
16330 this.parentLayout = this.parent.layout || false;
16336 Roo.apply(Roo.XComponent, {
16338 * @property hideProgress
16339 * true to disable the building progress bar.. usefull on single page renders.
16342 hideProgress : false,
16344 * @property buildCompleted
16345 * True when the builder has completed building the interface.
16348 buildCompleted : false,
16351 * @property topModule
16352 * the upper most module - uses document.element as it's constructor.
16359 * @property modules
16360 * array of modules to be created by registration system.
16361 * @type {Array} of Roo.XComponent
16366 * @property elmodules
16367 * array of modules to be created by which use #ID
16368 * @type {Array} of Roo.XComponent
16375 * Is an alternative Root - normally used by bootstrap or other systems,
16376 * where the top element in the tree can wrap 'body'
16377 * @type {boolean} (default false)
16382 * @property build_from_html
16383 * Build elements from html - used by bootstrap HTML stuff
16384 * - this is cleared after build is completed
16385 * @type {boolean} (default false)
16388 build_from_html : false,
16390 * Register components to be built later.
16392 * This solves the following issues
16393 * - Building is not done on page load, but after an authentication process has occured.
16394 * - Interface elements are registered on page load
16395 * - Parent Interface elements may not be loaded before child, so this handles that..
16402 module : 'Pman.Tab.projectMgr',
16404 parent : 'Pman.layout',
16405 disabled : false, // or use a function..
16408 * * @param {Object} details about module
16410 register : function(obj) {
16412 Roo.XComponent.event.fireEvent('register', obj);
16413 switch(typeof(obj.disabled) ) {
16419 if ( obj.disabled() ) {
16425 if (obj.disabled || obj.region == '#disabled') {
16431 this.modules.push(obj);
16435 * convert a string to an object..
16436 * eg. 'AAA.BBB' -> finds AAA.BBB
16440 toObject : function(str)
16442 if (!str || typeof(str) == 'object') {
16445 if (str.substring(0,1) == '#') {
16449 var ar = str.split('.');
16454 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16456 throw "Module not found : " + str;
16460 throw "Module not found : " + str;
16462 Roo.each(ar, function(e) {
16463 if (typeof(o[e]) == 'undefined') {
16464 throw "Module not found : " + str;
16475 * move modules into their correct place in the tree..
16478 preBuild : function ()
16481 Roo.each(this.modules , function (obj)
16483 Roo.XComponent.event.fireEvent('beforebuild', obj);
16485 var opar = obj.parent;
16487 obj.parent = this.toObject(opar);
16489 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16494 Roo.debug && Roo.log("GOT top level module");
16495 Roo.debug && Roo.log(obj);
16496 obj.modules = new Roo.util.MixedCollection(false,
16497 function(o) { return o.order + '' }
16499 this.topModule = obj;
16502 // parent is a string (usually a dom element name..)
16503 if (typeof(obj.parent) == 'string') {
16504 this.elmodules.push(obj);
16507 if (obj.parent.constructor != Roo.XComponent) {
16508 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16510 if (!obj.parent.modules) {
16511 obj.parent.modules = new Roo.util.MixedCollection(false,
16512 function(o) { return o.order + '' }
16515 if (obj.parent.disabled) {
16516 obj.disabled = true;
16518 obj.parent.modules.add(obj);
16523 * make a list of modules to build.
16524 * @return {Array} list of modules.
16527 buildOrder : function()
16530 var cmp = function(a,b) {
16531 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16533 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16534 throw "No top level modules to build";
16537 // make a flat list in order of modules to build.
16538 var mods = this.topModule ? [ this.topModule ] : [];
16541 // elmodules (is a list of DOM based modules )
16542 Roo.each(this.elmodules, function(e) {
16544 if (!this.topModule &&
16545 typeof(e.parent) == 'string' &&
16546 e.parent.substring(0,1) == '#' &&
16547 Roo.get(e.parent.substr(1))
16550 _this.topModule = e;
16556 // add modules to their parents..
16557 var addMod = function(m) {
16558 Roo.debug && Roo.log("build Order: add: " + m.name);
16561 if (m.modules && !m.disabled) {
16562 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16563 m.modules.keySort('ASC', cmp );
16564 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16566 m.modules.each(addMod);
16568 Roo.debug && Roo.log("build Order: no child modules");
16570 // not sure if this is used any more..
16572 m.finalize.name = m.name + " (clean up) ";
16573 mods.push(m.finalize);
16577 if (this.topModule && this.topModule.modules) {
16578 this.topModule.modules.keySort('ASC', cmp );
16579 this.topModule.modules.each(addMod);
16585 * Build the registered modules.
16586 * @param {Object} parent element.
16587 * @param {Function} optional method to call after module has been added.
16591 build : function(opts)
16594 if (typeof(opts) != 'undefined') {
16595 Roo.apply(this,opts);
16599 var mods = this.buildOrder();
16601 //this.allmods = mods;
16602 //Roo.debug && Roo.log(mods);
16604 if (!mods.length) { // should not happen
16605 throw "NO modules!!!";
16609 var msg = "Building Interface...";
16610 // flash it up as modal - so we store the mask!?
16611 if (!this.hideProgress && Roo.MessageBox) {
16612 Roo.MessageBox.show({ title: 'loading' });
16613 Roo.MessageBox.show({
16614 title: "Please wait...",
16624 var total = mods.length;
16627 var progressRun = function() {
16628 if (!mods.length) {
16629 Roo.debug && Roo.log('hide?');
16630 if (!this.hideProgress && Roo.MessageBox) {
16631 Roo.MessageBox.hide();
16633 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16635 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16641 var m = mods.shift();
16644 Roo.debug && Roo.log(m);
16645 // not sure if this is supported any more.. - modules that are are just function
16646 if (typeof(m) == 'function') {
16648 return progressRun.defer(10, _this);
16652 msg = "Building Interface " + (total - mods.length) +
16654 (m.name ? (' - ' + m.name) : '');
16655 Roo.debug && Roo.log(msg);
16656 if (!_this.hideProgress && Roo.MessageBox) {
16657 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16661 // is the module disabled?
16662 var disabled = (typeof(m.disabled) == 'function') ?
16663 m.disabled.call(m.module.disabled) : m.disabled;
16667 return progressRun(); // we do not update the display!
16675 // it's 10 on top level, and 1 on others??? why...
16676 return progressRun.defer(10, _this);
16679 progressRun.defer(1, _this);
16685 * Overlay a set of modified strings onto a component
16686 * This is dependant on our builder exporting the strings and 'named strings' elements.
16688 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
16689 * @param {Object} associative array of 'named' string and it's new value.
16692 overlayStrings : function( component, strings )
16694 if (typeof(component['_named_strings']) == 'undefined') {
16695 throw "ERROR: component does not have _named_strings";
16697 for ( var k in strings ) {
16698 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
16699 if (md !== false) {
16700 component['_strings'][md] = strings[k];
16702 Roo.log('could not find named string: ' + k + ' in');
16703 Roo.log(component);
16718 * wrapper for event.on - aliased later..
16719 * Typically use to register a event handler for register:
16721 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16730 Roo.XComponent.event = new Roo.util.Observable({
16734 * Fires when an Component is registered,
16735 * set the disable property on the Component to stop registration.
16736 * @param {Roo.XComponent} c the component being registerd.
16741 * @event beforebuild
16742 * Fires before each Component is built
16743 * can be used to apply permissions.
16744 * @param {Roo.XComponent} c the component being registerd.
16747 'beforebuild' : true,
16749 * @event buildcomplete
16750 * Fires on the top level element when all elements have been built
16751 * @param {Roo.XComponent} the top level component.
16753 'buildcomplete' : true
16758 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16761 * marked - a markdown parser
16762 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16763 * https://github.com/chjj/marked
16769 * Roo.Markdown - is a very crude wrapper around marked..
16773 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16775 * Note: move the sample code to the bottom of this
16776 * file before uncommenting it.
16781 Roo.Markdown.toHtml = function(text) {
16783 var c = new Roo.Markdown.marked.setOptions({
16784 renderer: new Roo.Markdown.marked.Renderer(),
16795 text = text.replace(/\\\n/g,' ');
16796 return Roo.Markdown.marked(text);
16801 // Wraps all "globals" so that the only thing
16802 // exposed is makeHtml().
16807 * Block-Level Grammar
16812 code: /^( {4}[^\n]+\n*)+/,
16814 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16815 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16817 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16818 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16819 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16820 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16821 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16823 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16827 block.bullet = /(?:[*+-]|\d+\.)/;
16828 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16829 block.item = replace(block.item, 'gm')
16830 (/bull/g, block.bullet)
16833 block.list = replace(block.list)
16834 (/bull/g, block.bullet)
16835 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16836 ('def', '\\n+(?=' + block.def.source + ')')
16839 block.blockquote = replace(block.blockquote)
16843 block._tag = '(?!(?:'
16844 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16845 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16846 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16848 block.html = replace(block.html)
16849 ('comment', /<!--[\s\S]*?-->/)
16850 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16851 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16852 (/tag/g, block._tag)
16855 block.paragraph = replace(block.paragraph)
16857 ('heading', block.heading)
16858 ('lheading', block.lheading)
16859 ('blockquote', block.blockquote)
16860 ('tag', '<' + block._tag)
16865 * Normal Block Grammar
16868 block.normal = merge({}, block);
16871 * GFM Block Grammar
16874 block.gfm = merge({}, block.normal, {
16875 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16877 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16880 block.gfm.paragraph = replace(block.paragraph)
16882 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16883 + block.list.source.replace('\\1', '\\3') + '|')
16887 * GFM + Tables Block Grammar
16890 block.tables = merge({}, block.gfm, {
16891 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16892 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16899 function Lexer(options) {
16901 this.tokens.links = {};
16902 this.options = options || marked.defaults;
16903 this.rules = block.normal;
16905 if (this.options.gfm) {
16906 if (this.options.tables) {
16907 this.rules = block.tables;
16909 this.rules = block.gfm;
16915 * Expose Block Rules
16918 Lexer.rules = block;
16921 * Static Lex Method
16924 Lexer.lex = function(src, options) {
16925 var lexer = new Lexer(options);
16926 return lexer.lex(src);
16933 Lexer.prototype.lex = function(src) {
16935 .replace(/\r\n|\r/g, '\n')
16936 .replace(/\t/g, ' ')
16937 .replace(/\u00a0/g, ' ')
16938 .replace(/\u2424/g, '\n');
16940 return this.token(src, true);
16947 Lexer.prototype.token = function(src, top, bq) {
16948 var src = src.replace(/^ +$/gm, '')
16961 if (cap = this.rules.newline.exec(src)) {
16962 src = src.substring(cap[0].length);
16963 if (cap[0].length > 1) {
16971 if (cap = this.rules.code.exec(src)) {
16972 src = src.substring(cap[0].length);
16973 cap = cap[0].replace(/^ {4}/gm, '');
16976 text: !this.options.pedantic
16977 ? cap.replace(/\n+$/, '')
16984 if (cap = this.rules.fences.exec(src)) {
16985 src = src.substring(cap[0].length);
16995 if (cap = this.rules.heading.exec(src)) {
16996 src = src.substring(cap[0].length);
16999 depth: cap[1].length,
17005 // table no leading pipe (gfm)
17006 if (top && (cap = this.rules.nptable.exec(src))) {
17007 src = src.substring(cap[0].length);
17011 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17012 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17013 cells: cap[3].replace(/\n$/, '').split('\n')
17016 for (i = 0; i < item.align.length; i++) {
17017 if (/^ *-+: *$/.test(item.align[i])) {
17018 item.align[i] = 'right';
17019 } else if (/^ *:-+: *$/.test(item.align[i])) {
17020 item.align[i] = 'center';
17021 } else if (/^ *:-+ *$/.test(item.align[i])) {
17022 item.align[i] = 'left';
17024 item.align[i] = null;
17028 for (i = 0; i < item.cells.length; i++) {
17029 item.cells[i] = item.cells[i].split(/ *\| */);
17032 this.tokens.push(item);
17038 if (cap = this.rules.lheading.exec(src)) {
17039 src = src.substring(cap[0].length);
17042 depth: cap[2] === '=' ? 1 : 2,
17049 if (cap = this.rules.hr.exec(src)) {
17050 src = src.substring(cap[0].length);
17058 if (cap = this.rules.blockquote.exec(src)) {
17059 src = src.substring(cap[0].length);
17062 type: 'blockquote_start'
17065 cap = cap[0].replace(/^ *> ?/gm, '');
17067 // Pass `top` to keep the current
17068 // "toplevel" state. This is exactly
17069 // how markdown.pl works.
17070 this.token(cap, top, true);
17073 type: 'blockquote_end'
17080 if (cap = this.rules.list.exec(src)) {
17081 src = src.substring(cap[0].length);
17085 type: 'list_start',
17086 ordered: bull.length > 1
17089 // Get each top-level item.
17090 cap = cap[0].match(this.rules.item);
17096 for (; i < l; i++) {
17099 // Remove the list item's bullet
17100 // so it is seen as the next token.
17101 space = item.length;
17102 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17104 // Outdent whatever the
17105 // list item contains. Hacky.
17106 if (~item.indexOf('\n ')) {
17107 space -= item.length;
17108 item = !this.options.pedantic
17109 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17110 : item.replace(/^ {1,4}/gm, '');
17113 // Determine whether the next list item belongs here.
17114 // Backpedal if it does not belong in this list.
17115 if (this.options.smartLists && i !== l - 1) {
17116 b = block.bullet.exec(cap[i + 1])[0];
17117 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17118 src = cap.slice(i + 1).join('\n') + src;
17123 // Determine whether item is loose or not.
17124 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17125 // for discount behavior.
17126 loose = next || /\n\n(?!\s*$)/.test(item);
17128 next = item.charAt(item.length - 1) === '\n';
17129 if (!loose) { loose = next; }
17134 ? 'loose_item_start'
17135 : 'list_item_start'
17139 this.token(item, false, bq);
17142 type: 'list_item_end'
17154 if (cap = this.rules.html.exec(src)) {
17155 src = src.substring(cap[0].length);
17157 type: this.options.sanitize
17160 pre: !this.options.sanitizer
17161 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17168 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17169 src = src.substring(cap[0].length);
17170 this.tokens.links[cap[1].toLowerCase()] = {
17178 if (top && (cap = this.rules.table.exec(src))) {
17179 src = src.substring(cap[0].length);
17183 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17184 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17185 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17188 for (i = 0; i < item.align.length; i++) {
17189 if (/^ *-+: *$/.test(item.align[i])) {
17190 item.align[i] = 'right';
17191 } else if (/^ *:-+: *$/.test(item.align[i])) {
17192 item.align[i] = 'center';
17193 } else if (/^ *:-+ *$/.test(item.align[i])) {
17194 item.align[i] = 'left';
17196 item.align[i] = null;
17200 for (i = 0; i < item.cells.length; i++) {
17201 item.cells[i] = item.cells[i]
17202 .replace(/^ *\| *| *\| *$/g, '')
17206 this.tokens.push(item);
17211 // top-level paragraph
17212 if (top && (cap = this.rules.paragraph.exec(src))) {
17213 src = src.substring(cap[0].length);
17216 text: cap[1].charAt(cap[1].length - 1) === '\n'
17217 ? cap[1].slice(0, -1)
17224 if (cap = this.rules.text.exec(src)) {
17225 // Top-level should never reach here.
17226 src = src.substring(cap[0].length);
17236 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17240 return this.tokens;
17244 * Inline-Level Grammar
17248 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17249 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17251 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17252 link: /^!?\[(inside)\]\(href\)/,
17253 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17254 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17255 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17256 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17257 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17258 br: /^ {2,}\n(?!\s*$)/,
17260 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17263 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17264 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17266 inline.link = replace(inline.link)
17267 ('inside', inline._inside)
17268 ('href', inline._href)
17271 inline.reflink = replace(inline.reflink)
17272 ('inside', inline._inside)
17276 * Normal Inline Grammar
17279 inline.normal = merge({}, inline);
17282 * Pedantic Inline Grammar
17285 inline.pedantic = merge({}, inline.normal, {
17286 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17287 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17291 * GFM Inline Grammar
17294 inline.gfm = merge({}, inline.normal, {
17295 escape: replace(inline.escape)('])', '~|])')(),
17296 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17297 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17298 text: replace(inline.text)
17300 ('|', '|https?://|')
17305 * GFM + Line Breaks Inline Grammar
17308 inline.breaks = merge({}, inline.gfm, {
17309 br: replace(inline.br)('{2,}', '*')(),
17310 text: replace(inline.gfm.text)('{2,}', '*')()
17314 * Inline Lexer & Compiler
17317 function InlineLexer(links, options) {
17318 this.options = options || marked.defaults;
17319 this.links = links;
17320 this.rules = inline.normal;
17321 this.renderer = this.options.renderer || new Renderer;
17322 this.renderer.options = this.options;
17326 Error('Tokens array requires a `links` property.');
17329 if (this.options.gfm) {
17330 if (this.options.breaks) {
17331 this.rules = inline.breaks;
17333 this.rules = inline.gfm;
17335 } else if (this.options.pedantic) {
17336 this.rules = inline.pedantic;
17341 * Expose Inline Rules
17344 InlineLexer.rules = inline;
17347 * Static Lexing/Compiling Method
17350 InlineLexer.output = function(src, links, options) {
17351 var inline = new InlineLexer(links, options);
17352 return inline.output(src);
17359 InlineLexer.prototype.output = function(src) {
17368 if (cap = this.rules.escape.exec(src)) {
17369 src = src.substring(cap[0].length);
17375 if (cap = this.rules.autolink.exec(src)) {
17376 src = src.substring(cap[0].length);
17377 if (cap[2] === '@') {
17378 text = cap[1].charAt(6) === ':'
17379 ? this.mangle(cap[1].substring(7))
17380 : this.mangle(cap[1]);
17381 href = this.mangle('mailto:') + text;
17383 text = escape(cap[1]);
17386 out += this.renderer.link(href, null, text);
17391 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17392 src = src.substring(cap[0].length);
17393 text = escape(cap[1]);
17395 out += this.renderer.link(href, null, text);
17400 if (cap = this.rules.tag.exec(src)) {
17401 if (!this.inLink && /^<a /i.test(cap[0])) {
17402 this.inLink = true;
17403 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17404 this.inLink = false;
17406 src = src.substring(cap[0].length);
17407 out += this.options.sanitize
17408 ? this.options.sanitizer
17409 ? this.options.sanitizer(cap[0])
17416 if (cap = this.rules.link.exec(src)) {
17417 src = src.substring(cap[0].length);
17418 this.inLink = true;
17419 out += this.outputLink(cap, {
17423 this.inLink = false;
17428 if ((cap = this.rules.reflink.exec(src))
17429 || (cap = this.rules.nolink.exec(src))) {
17430 src = src.substring(cap[0].length);
17431 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17432 link = this.links[link.toLowerCase()];
17433 if (!link || !link.href) {
17434 out += cap[0].charAt(0);
17435 src = cap[0].substring(1) + src;
17438 this.inLink = true;
17439 out += this.outputLink(cap, link);
17440 this.inLink = false;
17445 if (cap = this.rules.strong.exec(src)) {
17446 src = src.substring(cap[0].length);
17447 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17452 if (cap = this.rules.em.exec(src)) {
17453 src = src.substring(cap[0].length);
17454 out += this.renderer.em(this.output(cap[2] || cap[1]));
17459 if (cap = this.rules.code.exec(src)) {
17460 src = src.substring(cap[0].length);
17461 out += this.renderer.codespan(escape(cap[2], true));
17466 if (cap = this.rules.br.exec(src)) {
17467 src = src.substring(cap[0].length);
17468 out += this.renderer.br();
17473 if (cap = this.rules.del.exec(src)) {
17474 src = src.substring(cap[0].length);
17475 out += this.renderer.del(this.output(cap[1]));
17480 if (cap = this.rules.text.exec(src)) {
17481 src = src.substring(cap[0].length);
17482 out += this.renderer.text(escape(this.smartypants(cap[0])));
17488 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17499 InlineLexer.prototype.outputLink = function(cap, link) {
17500 var href = escape(link.href)
17501 , title = link.title ? escape(link.title) : null;
17503 return cap[0].charAt(0) !== '!'
17504 ? this.renderer.link(href, title, this.output(cap[1]))
17505 : this.renderer.image(href, title, escape(cap[1]));
17509 * Smartypants Transformations
17512 InlineLexer.prototype.smartypants = function(text) {
17513 if (!this.options.smartypants) { return text; }
17516 .replace(/---/g, '\u2014')
17518 .replace(/--/g, '\u2013')
17520 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17521 // closing singles & apostrophes
17522 .replace(/'/g, '\u2019')
17524 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17526 .replace(/"/g, '\u201d')
17528 .replace(/\.{3}/g, '\u2026');
17535 InlineLexer.prototype.mangle = function(text) {
17536 if (!this.options.mangle) { return text; }
17542 for (; i < l; i++) {
17543 ch = text.charCodeAt(i);
17544 if (Math.random() > 0.5) {
17545 ch = 'x' + ch.toString(16);
17547 out += '&#' + ch + ';';
17557 function Renderer(options) {
17558 this.options = options || {};
17561 Renderer.prototype.code = function(code, lang, escaped) {
17562 if (this.options.highlight) {
17563 var out = this.options.highlight(code, lang);
17564 if (out != null && out !== code) {
17569 // hack!!! - it's already escapeD?
17574 return '<pre><code>'
17575 + (escaped ? code : escape(code, true))
17576 + '\n</code></pre>';
17579 return '<pre><code class="'
17580 + this.options.langPrefix
17581 + escape(lang, true)
17583 + (escaped ? code : escape(code, true))
17584 + '\n</code></pre>\n';
17587 Renderer.prototype.blockquote = function(quote) {
17588 return '<blockquote>\n' + quote + '</blockquote>\n';
17591 Renderer.prototype.html = function(html) {
17595 Renderer.prototype.heading = function(text, level, raw) {
17599 + this.options.headerPrefix
17600 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17608 Renderer.prototype.hr = function() {
17609 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17612 Renderer.prototype.list = function(body, ordered) {
17613 var type = ordered ? 'ol' : 'ul';
17614 return '<' + type + '>\n' + body + '</' + type + '>\n';
17617 Renderer.prototype.listitem = function(text) {
17618 return '<li>' + text + '</li>\n';
17621 Renderer.prototype.paragraph = function(text) {
17622 return '<p>' + text + '</p>\n';
17625 Renderer.prototype.table = function(header, body) {
17626 return '<table class="table table-striped">\n'
17636 Renderer.prototype.tablerow = function(content) {
17637 return '<tr>\n' + content + '</tr>\n';
17640 Renderer.prototype.tablecell = function(content, flags) {
17641 var type = flags.header ? 'th' : 'td';
17642 var tag = flags.align
17643 ? '<' + type + ' style="text-align:' + flags.align + '">'
17644 : '<' + type + '>';
17645 return tag + content + '</' + type + '>\n';
17648 // span level renderer
17649 Renderer.prototype.strong = function(text) {
17650 return '<strong>' + text + '</strong>';
17653 Renderer.prototype.em = function(text) {
17654 return '<em>' + text + '</em>';
17657 Renderer.prototype.codespan = function(text) {
17658 return '<code>' + text + '</code>';
17661 Renderer.prototype.br = function() {
17662 return this.options.xhtml ? '<br/>' : '<br>';
17665 Renderer.prototype.del = function(text) {
17666 return '<del>' + text + '</del>';
17669 Renderer.prototype.link = function(href, title, text) {
17670 if (this.options.sanitize) {
17672 var prot = decodeURIComponent(unescape(href))
17673 .replace(/[^\w:]/g, '')
17678 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17682 var out = '<a href="' + href + '"';
17684 out += ' title="' + title + '"';
17686 out += '>' + text + '</a>';
17690 Renderer.prototype.image = function(href, title, text) {
17691 var out = '<img src="' + href + '" alt="' + text + '"';
17693 out += ' title="' + title + '"';
17695 out += this.options.xhtml ? '/>' : '>';
17699 Renderer.prototype.text = function(text) {
17704 * Parsing & Compiling
17707 function Parser(options) {
17710 this.options = options || marked.defaults;
17711 this.options.renderer = this.options.renderer || new Renderer;
17712 this.renderer = this.options.renderer;
17713 this.renderer.options = this.options;
17717 * Static Parse Method
17720 Parser.parse = function(src, options, renderer) {
17721 var parser = new Parser(options, renderer);
17722 return parser.parse(src);
17729 Parser.prototype.parse = function(src) {
17730 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17731 this.tokens = src.reverse();
17734 while (this.next()) {
17745 Parser.prototype.next = function() {
17746 return this.token = this.tokens.pop();
17750 * Preview Next Token
17753 Parser.prototype.peek = function() {
17754 return this.tokens[this.tokens.length - 1] || 0;
17758 * Parse Text Tokens
17761 Parser.prototype.parseText = function() {
17762 var body = this.token.text;
17764 while (this.peek().type === 'text') {
17765 body += '\n' + this.next().text;
17768 return this.inline.output(body);
17772 * Parse Current Token
17775 Parser.prototype.tok = function() {
17776 switch (this.token.type) {
17781 return this.renderer.hr();
17784 return this.renderer.heading(
17785 this.inline.output(this.token.text),
17790 return this.renderer.code(this.token.text,
17792 this.token.escaped);
17805 for (i = 0; i < this.token.header.length; i++) {
17806 flags = { header: true, align: this.token.align[i] };
17807 cell += this.renderer.tablecell(
17808 this.inline.output(this.token.header[i]),
17809 { header: true, align: this.token.align[i] }
17812 header += this.renderer.tablerow(cell);
17814 for (i = 0; i < this.token.cells.length; i++) {
17815 row = this.token.cells[i];
17818 for (j = 0; j < row.length; j++) {
17819 cell += this.renderer.tablecell(
17820 this.inline.output(row[j]),
17821 { header: false, align: this.token.align[j] }
17825 body += this.renderer.tablerow(cell);
17827 return this.renderer.table(header, body);
17829 case 'blockquote_start': {
17832 while (this.next().type !== 'blockquote_end') {
17833 body += this.tok();
17836 return this.renderer.blockquote(body);
17838 case 'list_start': {
17840 , ordered = this.token.ordered;
17842 while (this.next().type !== 'list_end') {
17843 body += this.tok();
17846 return this.renderer.list(body, ordered);
17848 case 'list_item_start': {
17851 while (this.next().type !== 'list_item_end') {
17852 body += this.token.type === 'text'
17857 return this.renderer.listitem(body);
17859 case 'loose_item_start': {
17862 while (this.next().type !== 'list_item_end') {
17863 body += this.tok();
17866 return this.renderer.listitem(body);
17869 var html = !this.token.pre && !this.options.pedantic
17870 ? this.inline.output(this.token.text)
17872 return this.renderer.html(html);
17874 case 'paragraph': {
17875 return this.renderer.paragraph(this.inline.output(this.token.text));
17878 return this.renderer.paragraph(this.parseText());
17887 function escape(html, encode) {
17889 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17890 .replace(/</g, '<')
17891 .replace(/>/g, '>')
17892 .replace(/"/g, '"')
17893 .replace(/'/g, ''');
17896 function unescape(html) {
17897 // explicitly match decimal, hex, and named HTML entities
17898 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17899 n = n.toLowerCase();
17900 if (n === 'colon') { return ':'; }
17901 if (n.charAt(0) === '#') {
17902 return n.charAt(1) === 'x'
17903 ? String.fromCharCode(parseInt(n.substring(2), 16))
17904 : String.fromCharCode(+n.substring(1));
17910 function replace(regex, opt) {
17911 regex = regex.source;
17913 return function self(name, val) {
17914 if (!name) { return new RegExp(regex, opt); }
17915 val = val.source || val;
17916 val = val.replace(/(^|[^\[])\^/g, '$1');
17917 regex = regex.replace(name, val);
17925 function merge(obj) {
17930 for (; i < arguments.length; i++) {
17931 target = arguments[i];
17932 for (key in target) {
17933 if (Object.prototype.hasOwnProperty.call(target, key)) {
17934 obj[key] = target[key];
17947 function marked(src, opt, callback) {
17948 if (callback || typeof opt === 'function') {
17954 opt = merge({}, marked.defaults, opt || {});
17956 var highlight = opt.highlight
17962 tokens = Lexer.lex(src, opt)
17964 return callback(e);
17967 pending = tokens.length;
17969 var done = function(err) {
17971 opt.highlight = highlight;
17972 return callback(err);
17978 out = Parser.parse(tokens, opt);
17983 opt.highlight = highlight;
17987 : callback(null, out);
17990 if (!highlight || highlight.length < 3) {
17994 delete opt.highlight;
17996 if (!pending) { return done(); }
17998 for (; i < tokens.length; i++) {
18000 if (token.type !== 'code') {
18001 return --pending || done();
18003 return highlight(token.text, token.lang, function(err, code) {
18004 if (err) { return done(err); }
18005 if (code == null || code === token.text) {
18006 return --pending || done();
18009 token.escaped = true;
18010 --pending || done();
18018 if (opt) { opt = merge({}, marked.defaults, opt); }
18019 return Parser.parse(Lexer.lex(src, opt), opt);
18021 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18022 if ((opt || marked.defaults).silent) {
18023 return '<p>An error occured:</p><pre>'
18024 + escape(e.message + '', true)
18036 marked.setOptions = function(opt) {
18037 merge(marked.defaults, opt);
18041 marked.defaults = {
18052 langPrefix: 'lang-',
18053 smartypants: false,
18055 renderer: new Renderer,
18063 marked.Parser = Parser;
18064 marked.parser = Parser.parse;
18066 marked.Renderer = Renderer;
18068 marked.Lexer = Lexer;
18069 marked.lexer = Lexer.lex;
18071 marked.InlineLexer = InlineLexer;
18072 marked.inlineLexer = InlineLexer.output;
18074 marked.parse = marked;
18076 Roo.Markdown.marked = marked;
18080 * Ext JS Library 1.1.1
18081 * Copyright(c) 2006-2007, Ext JS, LLC.
18083 * Originally Released Under LGPL - original licence link has changed is not relivant.
18086 * <script type="text/javascript">
18092 * These classes are derivatives of the similarly named classes in the YUI Library.
18093 * The original license:
18094 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18095 * Code licensed under the BSD License:
18096 * http://developer.yahoo.net/yui/license.txt
18101 var Event=Roo.EventManager;
18102 var Dom=Roo.lib.Dom;
18105 * @class Roo.dd.DragDrop
18106 * @extends Roo.util.Observable
18107 * Defines the interface and base operation of items that that can be
18108 * dragged or can be drop targets. It was designed to be extended, overriding
18109 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18110 * Up to three html elements can be associated with a DragDrop instance:
18112 * <li>linked element: the element that is passed into the constructor.
18113 * This is the element which defines the boundaries for interaction with
18114 * other DragDrop objects.</li>
18115 * <li>handle element(s): The drag operation only occurs if the element that
18116 * was clicked matches a handle element. By default this is the linked
18117 * element, but there are times that you will want only a portion of the
18118 * linked element to initiate the drag operation, and the setHandleElId()
18119 * method provides a way to define this.</li>
18120 * <li>drag element: this represents the element that would be moved along
18121 * with the cursor during a drag operation. By default, this is the linked
18122 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18123 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18126 * This class should not be instantiated until the onload event to ensure that
18127 * the associated elements are available.
18128 * The following would define a DragDrop obj that would interact with any
18129 * other DragDrop obj in the "group1" group:
18131 * dd = new Roo.dd.DragDrop("div1", "group1");
18133 * Since none of the event handlers have been implemented, nothing would
18134 * actually happen if you were to run the code above. Normally you would
18135 * override this class or one of the default implementations, but you can
18136 * also override the methods you want on an instance of the class...
18138 * dd.onDragDrop = function(e, id) {
18139 * alert("dd was dropped on " + id);
18143 * @param {String} id of the element that is linked to this instance
18144 * @param {String} sGroup the group of related DragDrop objects
18145 * @param {object} config an object containing configurable attributes
18146 * Valid properties for DragDrop:
18147 * padding, isTarget, maintainOffset, primaryButtonOnly
18149 Roo.dd.DragDrop = function(id, sGroup, config) {
18151 this.init(id, sGroup, config);
18156 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18159 * The id of the element associated with this object. This is what we
18160 * refer to as the "linked element" because the size and position of
18161 * this element is used to determine when the drag and drop objects have
18169 * Configuration attributes passed into the constructor
18176 * The id of the element that will be dragged. By default this is same
18177 * as the linked element , but could be changed to another element. Ex:
18179 * @property dragElId
18186 * the id of the element that initiates the drag operation. By default
18187 * this is the linked element, but could be changed to be a child of this
18188 * element. This lets us do things like only starting the drag when the
18189 * header element within the linked html element is clicked.
18190 * @property handleElId
18197 * An associative array of HTML tags that will be ignored if clicked.
18198 * @property invalidHandleTypes
18199 * @type {string: string}
18201 invalidHandleTypes: null,
18204 * An associative array of ids for elements that will be ignored if clicked
18205 * @property invalidHandleIds
18206 * @type {string: string}
18208 invalidHandleIds: null,
18211 * An indexted array of css class names for elements that will be ignored
18213 * @property invalidHandleClasses
18216 invalidHandleClasses: null,
18219 * The linked element's absolute X position at the time the drag was
18221 * @property startPageX
18228 * The linked element's absolute X position at the time the drag was
18230 * @property startPageY
18237 * The group defines a logical collection of DragDrop objects that are
18238 * related. Instances only get events when interacting with other
18239 * DragDrop object in the same group. This lets us define multiple
18240 * groups using a single DragDrop subclass if we want.
18242 * @type {string: string}
18247 * Individual drag/drop instances can be locked. This will prevent
18248 * onmousedown start drag.
18256 * Lock this instance
18259 lock: function() { this.locked = true; },
18262 * Unlock this instace
18265 unlock: function() { this.locked = false; },
18268 * By default, all insances can be a drop target. This can be disabled by
18269 * setting isTarget to false.
18276 * The padding configured for this drag and drop object for calculating
18277 * the drop zone intersection with this object.
18284 * Cached reference to the linked element
18285 * @property _domRef
18291 * Internal typeof flag
18292 * @property __ygDragDrop
18295 __ygDragDrop: true,
18298 * Set to true when horizontal contraints are applied
18299 * @property constrainX
18306 * Set to true when vertical contraints are applied
18307 * @property constrainY
18314 * The left constraint
18322 * The right constraint
18330 * The up constraint
18339 * The down constraint
18347 * Maintain offsets when we resetconstraints. Set to true when you want
18348 * the position of the element relative to its parent to stay the same
18349 * when the page changes
18351 * @property maintainOffset
18354 maintainOffset: false,
18357 * Array of pixel locations the element will snap to if we specified a
18358 * horizontal graduation/interval. This array is generated automatically
18359 * when you define a tick interval.
18366 * Array of pixel locations the element will snap to if we specified a
18367 * vertical graduation/interval. This array is generated automatically
18368 * when you define a tick interval.
18375 * By default the drag and drop instance will only respond to the primary
18376 * button click (left button for a right-handed mouse). Set to true to
18377 * allow drag and drop to start with any mouse click that is propogated
18379 * @property primaryButtonOnly
18382 primaryButtonOnly: true,
18385 * The availabe property is false until the linked dom element is accessible.
18386 * @property available
18392 * By default, drags can only be initiated if the mousedown occurs in the
18393 * region the linked element is. This is done in part to work around a
18394 * bug in some browsers that mis-report the mousedown if the previous
18395 * mouseup happened outside of the window. This property is set to true
18396 * if outer handles are defined.
18398 * @property hasOuterHandles
18402 hasOuterHandles: false,
18405 * Code that executes immediately before the startDrag event
18406 * @method b4StartDrag
18409 b4StartDrag: function(x, y) { },
18412 * Abstract method called after a drag/drop object is clicked
18413 * and the drag or mousedown time thresholds have beeen met.
18414 * @method startDrag
18415 * @param {int} X click location
18416 * @param {int} Y click location
18418 startDrag: function(x, y) { /* override this */ },
18421 * Code that executes immediately before the onDrag event
18425 b4Drag: function(e) { },
18428 * Abstract method called during the onMouseMove event while dragging an
18431 * @param {Event} e the mousemove event
18433 onDrag: function(e) { /* override this */ },
18436 * Abstract method called when this element fist begins hovering over
18437 * another DragDrop obj
18438 * @method onDragEnter
18439 * @param {Event} e the mousemove event
18440 * @param {String|DragDrop[]} id In POINT mode, the element
18441 * id this is hovering over. In INTERSECT mode, an array of one or more
18442 * dragdrop items being hovered over.
18444 onDragEnter: function(e, id) { /* override this */ },
18447 * Code that executes immediately before the onDragOver event
18448 * @method b4DragOver
18451 b4DragOver: function(e) { },
18454 * Abstract method called when this element is hovering over another
18456 * @method onDragOver
18457 * @param {Event} e the mousemove event
18458 * @param {String|DragDrop[]} id In POINT mode, the element
18459 * id this is hovering over. In INTERSECT mode, an array of dd items
18460 * being hovered over.
18462 onDragOver: function(e, id) { /* override this */ },
18465 * Code that executes immediately before the onDragOut event
18466 * @method b4DragOut
18469 b4DragOut: function(e) { },
18472 * Abstract method called when we are no longer hovering over an element
18473 * @method onDragOut
18474 * @param {Event} e the mousemove event
18475 * @param {String|DragDrop[]} id In POINT mode, the element
18476 * id this was hovering over. In INTERSECT mode, an array of dd items
18477 * that the mouse is no longer over.
18479 onDragOut: function(e, id) { /* override this */ },
18482 * Code that executes immediately before the onDragDrop event
18483 * @method b4DragDrop
18486 b4DragDrop: function(e) { },
18489 * Abstract method called when this item is dropped on another DragDrop
18491 * @method onDragDrop
18492 * @param {Event} e the mouseup event
18493 * @param {String|DragDrop[]} id In POINT mode, the element
18494 * id this was dropped on. In INTERSECT mode, an array of dd items this
18497 onDragDrop: function(e, id) { /* override this */ },
18500 * Abstract method called when this item is dropped on an area with no
18502 * @method onInvalidDrop
18503 * @param {Event} e the mouseup event
18505 onInvalidDrop: function(e) { /* override this */ },
18508 * Code that executes immediately before the endDrag event
18509 * @method b4EndDrag
18512 b4EndDrag: function(e) { },
18515 * Fired when we are done dragging the object
18517 * @param {Event} e the mouseup event
18519 endDrag: function(e) { /* override this */ },
18522 * Code executed immediately before the onMouseDown event
18523 * @method b4MouseDown
18524 * @param {Event} e the mousedown event
18527 b4MouseDown: function(e) { },
18530 * Event handler that fires when a drag/drop obj gets a mousedown
18531 * @method onMouseDown
18532 * @param {Event} e the mousedown event
18534 onMouseDown: function(e) { /* override this */ },
18537 * Event handler that fires when a drag/drop obj gets a mouseup
18538 * @method onMouseUp
18539 * @param {Event} e the mouseup event
18541 onMouseUp: function(e) { /* override this */ },
18544 * Override the onAvailable method to do what is needed after the initial
18545 * position was determined.
18546 * @method onAvailable
18548 onAvailable: function () {
18552 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18555 defaultPadding : {left:0, right:0, top:0, bottom:0},
18558 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18562 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18563 { dragElId: "existingProxyDiv" });
18564 dd.startDrag = function(){
18565 this.constrainTo("parent-id");
18568 * Or you can initalize it using the {@link Roo.Element} object:
18570 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18571 startDrag : function(){
18572 this.constrainTo("parent-id");
18576 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18577 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18578 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18579 * an object containing the sides to pad. For example: {right:10, bottom:10}
18580 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18582 constrainTo : function(constrainTo, pad, inContent){
18583 if(typeof pad == "number"){
18584 pad = {left: pad, right:pad, top:pad, bottom:pad};
18586 pad = pad || this.defaultPadding;
18587 var b = Roo.get(this.getEl()).getBox();
18588 var ce = Roo.get(constrainTo);
18589 var s = ce.getScroll();
18590 var c, cd = ce.dom;
18591 if(cd == document.body){
18592 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18595 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18599 var topSpace = b.y - c.y;
18600 var leftSpace = b.x - c.x;
18602 this.resetConstraints();
18603 this.setXConstraint(leftSpace - (pad.left||0), // left
18604 c.width - leftSpace - b.width - (pad.right||0) //right
18606 this.setYConstraint(topSpace - (pad.top||0), //top
18607 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18612 * Returns a reference to the linked element
18614 * @return {HTMLElement} the html element
18616 getEl: function() {
18617 if (!this._domRef) {
18618 this._domRef = Roo.getDom(this.id);
18621 return this._domRef;
18625 * Returns a reference to the actual element to drag. By default this is
18626 * the same as the html element, but it can be assigned to another
18627 * element. An example of this can be found in Roo.dd.DDProxy
18628 * @method getDragEl
18629 * @return {HTMLElement} the html element
18631 getDragEl: function() {
18632 return Roo.getDom(this.dragElId);
18636 * Sets up the DragDrop object. Must be called in the constructor of any
18637 * Roo.dd.DragDrop subclass
18639 * @param id the id of the linked element
18640 * @param {String} sGroup the group of related items
18641 * @param {object} config configuration attributes
18643 init: function(id, sGroup, config) {
18644 this.initTarget(id, sGroup, config);
18645 if (!Roo.isTouch) {
18646 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18648 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18649 // Event.on(this.id, "selectstart", Event.preventDefault);
18653 * Initializes Targeting functionality only... the object does not
18654 * get a mousedown handler.
18655 * @method initTarget
18656 * @param id the id of the linked element
18657 * @param {String} sGroup the group of related items
18658 * @param {object} config configuration attributes
18660 initTarget: function(id, sGroup, config) {
18662 // configuration attributes
18663 this.config = config || {};
18665 // create a local reference to the drag and drop manager
18666 this.DDM = Roo.dd.DDM;
18667 // initialize the groups array
18670 // assume that we have an element reference instead of an id if the
18671 // parameter is not a string
18672 if (typeof id !== "string") {
18679 // add to an interaction group
18680 this.addToGroup((sGroup) ? sGroup : "default");
18682 // We don't want to register this as the handle with the manager
18683 // so we just set the id rather than calling the setter.
18684 this.handleElId = id;
18686 // the linked element is the element that gets dragged by default
18687 this.setDragElId(id);
18689 // by default, clicked anchors will not start drag operations.
18690 this.invalidHandleTypes = { A: "A" };
18691 this.invalidHandleIds = {};
18692 this.invalidHandleClasses = [];
18694 this.applyConfig();
18696 this.handleOnAvailable();
18700 * Applies the configuration parameters that were passed into the constructor.
18701 * This is supposed to happen at each level through the inheritance chain. So
18702 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18703 * DragDrop in order to get all of the parameters that are available in
18705 * @method applyConfig
18707 applyConfig: function() {
18709 // configurable properties:
18710 // padding, isTarget, maintainOffset, primaryButtonOnly
18711 this.padding = this.config.padding || [0, 0, 0, 0];
18712 this.isTarget = (this.config.isTarget !== false);
18713 this.maintainOffset = (this.config.maintainOffset);
18714 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18719 * Executed when the linked element is available
18720 * @method handleOnAvailable
18723 handleOnAvailable: function() {
18724 this.available = true;
18725 this.resetConstraints();
18726 this.onAvailable();
18730 * Configures the padding for the target zone in px. Effectively expands
18731 * (or reduces) the virtual object size for targeting calculations.
18732 * Supports css-style shorthand; if only one parameter is passed, all sides
18733 * will have that padding, and if only two are passed, the top and bottom
18734 * will have the first param, the left and right the second.
18735 * @method setPadding
18736 * @param {int} iTop Top pad
18737 * @param {int} iRight Right pad
18738 * @param {int} iBot Bot pad
18739 * @param {int} iLeft Left pad
18741 setPadding: function(iTop, iRight, iBot, iLeft) {
18742 // this.padding = [iLeft, iRight, iTop, iBot];
18743 if (!iRight && 0 !== iRight) {
18744 this.padding = [iTop, iTop, iTop, iTop];
18745 } else if (!iBot && 0 !== iBot) {
18746 this.padding = [iTop, iRight, iTop, iRight];
18748 this.padding = [iTop, iRight, iBot, iLeft];
18753 * Stores the initial placement of the linked element.
18754 * @method setInitialPosition
18755 * @param {int} diffX the X offset, default 0
18756 * @param {int} diffY the Y offset, default 0
18758 setInitPosition: function(diffX, diffY) {
18759 var el = this.getEl();
18761 if (!this.DDM.verifyEl(el)) {
18765 var dx = diffX || 0;
18766 var dy = diffY || 0;
18768 var p = Dom.getXY( el );
18770 this.initPageX = p[0] - dx;
18771 this.initPageY = p[1] - dy;
18773 this.lastPageX = p[0];
18774 this.lastPageY = p[1];
18777 this.setStartPosition(p);
18781 * Sets the start position of the element. This is set when the obj
18782 * is initialized, the reset when a drag is started.
18783 * @method setStartPosition
18784 * @param pos current position (from previous lookup)
18787 setStartPosition: function(pos) {
18788 var p = pos || Dom.getXY( this.getEl() );
18789 this.deltaSetXY = null;
18791 this.startPageX = p[0];
18792 this.startPageY = p[1];
18796 * Add this instance to a group of related drag/drop objects. All
18797 * instances belong to at least one group, and can belong to as many
18798 * groups as needed.
18799 * @method addToGroup
18800 * @param sGroup {string} the name of the group
18802 addToGroup: function(sGroup) {
18803 this.groups[sGroup] = true;
18804 this.DDM.regDragDrop(this, sGroup);
18808 * Remove's this instance from the supplied interaction group
18809 * @method removeFromGroup
18810 * @param {string} sGroup The group to drop
18812 removeFromGroup: function(sGroup) {
18813 if (this.groups[sGroup]) {
18814 delete this.groups[sGroup];
18817 this.DDM.removeDDFromGroup(this, sGroup);
18821 * Allows you to specify that an element other than the linked element
18822 * will be moved with the cursor during a drag
18823 * @method setDragElId
18824 * @param id {string} the id of the element that will be used to initiate the drag
18826 setDragElId: function(id) {
18827 this.dragElId = id;
18831 * Allows you to specify a child of the linked element that should be
18832 * used to initiate the drag operation. An example of this would be if
18833 * you have a content div with text and links. Clicking anywhere in the
18834 * content area would normally start the drag operation. Use this method
18835 * to specify that an element inside of the content div is the element
18836 * that starts the drag operation.
18837 * @method setHandleElId
18838 * @param id {string} the id of the element that will be used to
18839 * initiate the drag.
18841 setHandleElId: function(id) {
18842 if (typeof id !== "string") {
18845 this.handleElId = id;
18846 this.DDM.regHandle(this.id, id);
18850 * Allows you to set an element outside of the linked element as a drag
18852 * @method setOuterHandleElId
18853 * @param id the id of the element that will be used to initiate the drag
18855 setOuterHandleElId: function(id) {
18856 if (typeof id !== "string") {
18859 Event.on(id, "mousedown",
18860 this.handleMouseDown, this);
18861 this.setHandleElId(id);
18863 this.hasOuterHandles = true;
18867 * Remove all drag and drop hooks for this element
18870 unreg: function() {
18871 Event.un(this.id, "mousedown",
18872 this.handleMouseDown);
18873 Event.un(this.id, "touchstart",
18874 this.handleMouseDown);
18875 this._domRef = null;
18876 this.DDM._remove(this);
18879 destroy : function(){
18884 * Returns true if this instance is locked, or the drag drop mgr is locked
18885 * (meaning that all drag/drop is disabled on the page.)
18887 * @return {boolean} true if this obj or all drag/drop is locked, else
18890 isLocked: function() {
18891 return (this.DDM.isLocked() || this.locked);
18895 * Fired when this object is clicked
18896 * @method handleMouseDown
18898 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18901 handleMouseDown: function(e, oDD){
18903 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18904 //Roo.log('not touch/ button !=0');
18907 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18908 return; // double touch..
18912 if (this.isLocked()) {
18913 //Roo.log('locked');
18917 this.DDM.refreshCache(this.groups);
18918 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18919 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18920 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18921 //Roo.log('no outer handes or not over target');
18924 // Roo.log('check validator');
18925 if (this.clickValidator(e)) {
18926 // Roo.log('validate success');
18927 // set the initial element position
18928 this.setStartPosition();
18931 this.b4MouseDown(e);
18932 this.onMouseDown(e);
18934 this.DDM.handleMouseDown(e, this);
18936 this.DDM.stopEvent(e);
18944 clickValidator: function(e) {
18945 var target = e.getTarget();
18946 return ( this.isValidHandleChild(target) &&
18947 (this.id == this.handleElId ||
18948 this.DDM.handleWasClicked(target, this.id)) );
18952 * Allows you to specify a tag name that should not start a drag operation
18953 * when clicked. This is designed to facilitate embedding links within a
18954 * drag handle that do something other than start the drag.
18955 * @method addInvalidHandleType
18956 * @param {string} tagName the type of element to exclude
18958 addInvalidHandleType: function(tagName) {
18959 var type = tagName.toUpperCase();
18960 this.invalidHandleTypes[type] = type;
18964 * Lets you to specify an element id for a child of a drag handle
18965 * that should not initiate a drag
18966 * @method addInvalidHandleId
18967 * @param {string} id the element id of the element you wish to ignore
18969 addInvalidHandleId: function(id) {
18970 if (typeof id !== "string") {
18973 this.invalidHandleIds[id] = id;
18977 * Lets you specify a css class of elements that will not initiate a drag
18978 * @method addInvalidHandleClass
18979 * @param {string} cssClass the class of the elements you wish to ignore
18981 addInvalidHandleClass: function(cssClass) {
18982 this.invalidHandleClasses.push(cssClass);
18986 * Unsets an excluded tag name set by addInvalidHandleType
18987 * @method removeInvalidHandleType
18988 * @param {string} tagName the type of element to unexclude
18990 removeInvalidHandleType: function(tagName) {
18991 var type = tagName.toUpperCase();
18992 // this.invalidHandleTypes[type] = null;
18993 delete this.invalidHandleTypes[type];
18997 * Unsets an invalid handle id
18998 * @method removeInvalidHandleId
18999 * @param {string} id the id of the element to re-enable
19001 removeInvalidHandleId: function(id) {
19002 if (typeof id !== "string") {
19005 delete this.invalidHandleIds[id];
19009 * Unsets an invalid css class
19010 * @method removeInvalidHandleClass
19011 * @param {string} cssClass the class of the element(s) you wish to
19014 removeInvalidHandleClass: function(cssClass) {
19015 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19016 if (this.invalidHandleClasses[i] == cssClass) {
19017 delete this.invalidHandleClasses[i];
19023 * Checks the tag exclusion list to see if this click should be ignored
19024 * @method isValidHandleChild
19025 * @param {HTMLElement} node the HTMLElement to evaluate
19026 * @return {boolean} true if this is a valid tag type, false if not
19028 isValidHandleChild: function(node) {
19031 // var n = (node.nodeName == "#text") ? node.parentNode : node;
19034 nodeName = node.nodeName.toUpperCase();
19036 nodeName = node.nodeName;
19038 valid = valid && !this.invalidHandleTypes[nodeName];
19039 valid = valid && !this.invalidHandleIds[node.id];
19041 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19042 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19051 * Create the array of horizontal tick marks if an interval was specified
19052 * in setXConstraint().
19053 * @method setXTicks
19056 setXTicks: function(iStartX, iTickSize) {
19058 this.xTickSize = iTickSize;
19062 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19064 this.xTicks[this.xTicks.length] = i;
19069 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19071 this.xTicks[this.xTicks.length] = i;
19076 this.xTicks.sort(this.DDM.numericSort) ;
19080 * Create the array of vertical tick marks if an interval was specified in
19081 * setYConstraint().
19082 * @method setYTicks
19085 setYTicks: function(iStartY, iTickSize) {
19087 this.yTickSize = iTickSize;
19091 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19093 this.yTicks[this.yTicks.length] = i;
19098 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19100 this.yTicks[this.yTicks.length] = i;
19105 this.yTicks.sort(this.DDM.numericSort) ;
19109 * By default, the element can be dragged any place on the screen. Use
19110 * this method to limit the horizontal travel of the element. Pass in
19111 * 0,0 for the parameters if you want to lock the drag to the y axis.
19112 * @method setXConstraint
19113 * @param {int} iLeft the number of pixels the element can move to the left
19114 * @param {int} iRight the number of pixels the element can move to the
19116 * @param {int} iTickSize optional parameter for specifying that the
19118 * should move iTickSize pixels at a time.
19120 setXConstraint: function(iLeft, iRight, iTickSize) {
19121 this.leftConstraint = iLeft;
19122 this.rightConstraint = iRight;
19124 this.minX = this.initPageX - iLeft;
19125 this.maxX = this.initPageX + iRight;
19126 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19128 this.constrainX = true;
19132 * Clears any constraints applied to this instance. Also clears ticks
19133 * since they can't exist independent of a constraint at this time.
19134 * @method clearConstraints
19136 clearConstraints: function() {
19137 this.constrainX = false;
19138 this.constrainY = false;
19143 * Clears any tick interval defined for this instance
19144 * @method clearTicks
19146 clearTicks: function() {
19147 this.xTicks = null;
19148 this.yTicks = null;
19149 this.xTickSize = 0;
19150 this.yTickSize = 0;
19154 * By default, the element can be dragged any place on the screen. Set
19155 * this to limit the vertical travel of the element. Pass in 0,0 for the
19156 * parameters if you want to lock the drag to the x axis.
19157 * @method setYConstraint
19158 * @param {int} iUp the number of pixels the element can move up
19159 * @param {int} iDown the number of pixels the element can move down
19160 * @param {int} iTickSize optional parameter for specifying that the
19161 * element should move iTickSize pixels at a time.
19163 setYConstraint: function(iUp, iDown, iTickSize) {
19164 this.topConstraint = iUp;
19165 this.bottomConstraint = iDown;
19167 this.minY = this.initPageY - iUp;
19168 this.maxY = this.initPageY + iDown;
19169 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19171 this.constrainY = true;
19176 * resetConstraints must be called if you manually reposition a dd element.
19177 * @method resetConstraints
19178 * @param {boolean} maintainOffset
19180 resetConstraints: function() {
19183 // Maintain offsets if necessary
19184 if (this.initPageX || this.initPageX === 0) {
19185 // figure out how much this thing has moved
19186 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19187 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19189 this.setInitPosition(dx, dy);
19191 // This is the first time we have detected the element's position
19193 this.setInitPosition();
19196 if (this.constrainX) {
19197 this.setXConstraint( this.leftConstraint,
19198 this.rightConstraint,
19202 if (this.constrainY) {
19203 this.setYConstraint( this.topConstraint,
19204 this.bottomConstraint,
19210 * Normally the drag element is moved pixel by pixel, but we can specify
19211 * that it move a number of pixels at a time. This method resolves the
19212 * location when we have it set up like this.
19214 * @param {int} val where we want to place the object
19215 * @param {int[]} tickArray sorted array of valid points
19216 * @return {int} the closest tick
19219 getTick: function(val, tickArray) {
19222 // If tick interval is not defined, it is effectively 1 pixel,
19223 // so we return the value passed to us.
19225 } else if (tickArray[0] >= val) {
19226 // The value is lower than the first tick, so we return the first
19228 return tickArray[0];
19230 for (var i=0, len=tickArray.length; i<len; ++i) {
19232 if (tickArray[next] && tickArray[next] >= val) {
19233 var diff1 = val - tickArray[i];
19234 var diff2 = tickArray[next] - val;
19235 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19239 // The value is larger than the last tick, so we return the last
19241 return tickArray[tickArray.length - 1];
19248 * @return {string} string representation of the dd obj
19250 toString: function() {
19251 return ("DragDrop " + this.id);
19259 * Ext JS Library 1.1.1
19260 * Copyright(c) 2006-2007, Ext JS, LLC.
19262 * Originally Released Under LGPL - original licence link has changed is not relivant.
19265 * <script type="text/javascript">
19270 * The drag and drop utility provides a framework for building drag and drop
19271 * applications. In addition to enabling drag and drop for specific elements,
19272 * the drag and drop elements are tracked by the manager class, and the
19273 * interactions between the various elements are tracked during the drag and
19274 * the implementing code is notified about these important moments.
19277 // Only load the library once. Rewriting the manager class would orphan
19278 // existing drag and drop instances.
19279 if (!Roo.dd.DragDropMgr) {
19282 * @class Roo.dd.DragDropMgr
19283 * DragDropMgr is a singleton that tracks the element interaction for
19284 * all DragDrop items in the window. Generally, you will not call
19285 * this class directly, but it does have helper methods that could
19286 * be useful in your DragDrop implementations.
19289 Roo.dd.DragDropMgr = function() {
19291 var Event = Roo.EventManager;
19296 * Two dimensional Array of registered DragDrop objects. The first
19297 * dimension is the DragDrop item group, the second the DragDrop
19300 * @type {string: string}
19307 * Array of element ids defined as drag handles. Used to determine
19308 * if the element that generated the mousedown event is actually the
19309 * handle and not the html element itself.
19310 * @property handleIds
19311 * @type {string: string}
19318 * the DragDrop object that is currently being dragged
19319 * @property dragCurrent
19327 * the DragDrop object(s) that are being hovered over
19328 * @property dragOvers
19336 * the X distance between the cursor and the object being dragged
19345 * the Y distance between the cursor and the object being dragged
19354 * Flag to determine if we should prevent the default behavior of the
19355 * events we define. By default this is true, but this can be set to
19356 * false if you need the default behavior (not recommended)
19357 * @property preventDefault
19361 preventDefault: true,
19364 * Flag to determine if we should stop the propagation of the events
19365 * we generate. This is true by default but you may want to set it to
19366 * false if the html element contains other features that require the
19368 * @property stopPropagation
19372 stopPropagation: true,
19375 * Internal flag that is set to true when drag and drop has been
19377 * @property initialized
19384 * All drag and drop can be disabled.
19392 * Called the first time an element is registered.
19398 this.initialized = true;
19402 * In point mode, drag and drop interaction is defined by the
19403 * location of the cursor during the drag/drop
19411 * In intersect mode, drag and drop interactio nis defined by the
19412 * overlap of two or more drag and drop objects.
19413 * @property INTERSECT
19420 * The current drag and drop mode. Default: POINT
19428 * Runs method on all drag and drop objects
19429 * @method _execOnAll
19433 _execOnAll: function(sMethod, args) {
19434 for (var i in this.ids) {
19435 for (var j in this.ids[i]) {
19436 var oDD = this.ids[i][j];
19437 if (! this.isTypeOfDD(oDD)) {
19440 oDD[sMethod].apply(oDD, args);
19446 * Drag and drop initialization. Sets up the global event handlers
19451 _onLoad: function() {
19455 if (!Roo.isTouch) {
19456 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19457 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19459 Event.on(document, "touchend", this.handleMouseUp, this, true);
19460 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19462 Event.on(window, "unload", this._onUnload, this, true);
19463 Event.on(window, "resize", this._onResize, this, true);
19464 // Event.on(window, "mouseout", this._test);
19469 * Reset constraints on all drag and drop objs
19470 * @method _onResize
19474 _onResize: function(e) {
19475 this._execOnAll("resetConstraints", []);
19479 * Lock all drag and drop functionality
19483 lock: function() { this.locked = true; },
19486 * Unlock all drag and drop functionality
19490 unlock: function() { this.locked = false; },
19493 * Is drag and drop locked?
19495 * @return {boolean} True if drag and drop is locked, false otherwise.
19498 isLocked: function() { return this.locked; },
19501 * Location cache that is set for all drag drop objects when a drag is
19502 * initiated, cleared when the drag is finished.
19503 * @property locationCache
19510 * Set useCache to false if you want to force object the lookup of each
19511 * drag and drop linked element constantly during a drag.
19512 * @property useCache
19519 * The number of pixels that the mouse needs to move after the
19520 * mousedown before the drag is initiated. Default=3;
19521 * @property clickPixelThresh
19525 clickPixelThresh: 3,
19528 * The number of milliseconds after the mousedown event to initiate the
19529 * drag if we don't get a mouseup event. Default=1000
19530 * @property clickTimeThresh
19534 clickTimeThresh: 350,
19537 * Flag that indicates that either the drag pixel threshold or the
19538 * mousdown time threshold has been met
19539 * @property dragThreshMet
19544 dragThreshMet: false,
19547 * Timeout used for the click time threshold
19548 * @property clickTimeout
19553 clickTimeout: null,
19556 * The X position of the mousedown event stored for later use when a
19557 * drag threshold is met.
19566 * The Y position of the mousedown event stored for later use when a
19567 * drag threshold is met.
19576 * Each DragDrop instance must be registered with the DragDropMgr.
19577 * This is executed in DragDrop.init()
19578 * @method regDragDrop
19579 * @param {DragDrop} oDD the DragDrop object to register
19580 * @param {String} sGroup the name of the group this element belongs to
19583 regDragDrop: function(oDD, sGroup) {
19584 if (!this.initialized) { this.init(); }
19586 if (!this.ids[sGroup]) {
19587 this.ids[sGroup] = {};
19589 this.ids[sGroup][oDD.id] = oDD;
19593 * Removes the supplied dd instance from the supplied group. Executed
19594 * by DragDrop.removeFromGroup, so don't call this function directly.
19595 * @method removeDDFromGroup
19599 removeDDFromGroup: function(oDD, sGroup) {
19600 if (!this.ids[sGroup]) {
19601 this.ids[sGroup] = {};
19604 var obj = this.ids[sGroup];
19605 if (obj && obj[oDD.id]) {
19606 delete obj[oDD.id];
19611 * Unregisters a drag and drop item. This is executed in
19612 * DragDrop.unreg, use that method instead of calling this directly.
19617 _remove: function(oDD) {
19618 for (var g in oDD.groups) {
19619 if (g && this.ids[g][oDD.id]) {
19620 delete this.ids[g][oDD.id];
19623 delete this.handleIds[oDD.id];
19627 * Each DragDrop handle element must be registered. This is done
19628 * automatically when executing DragDrop.setHandleElId()
19629 * @method regHandle
19630 * @param {String} sDDId the DragDrop id this element is a handle for
19631 * @param {String} sHandleId the id of the element that is the drag
19635 regHandle: function(sDDId, sHandleId) {
19636 if (!this.handleIds[sDDId]) {
19637 this.handleIds[sDDId] = {};
19639 this.handleIds[sDDId][sHandleId] = sHandleId;
19643 * Utility function to determine if a given element has been
19644 * registered as a drag drop item.
19645 * @method isDragDrop
19646 * @param {String} id the element id to check
19647 * @return {boolean} true if this element is a DragDrop item,
19651 isDragDrop: function(id) {
19652 return ( this.getDDById(id) ) ? true : false;
19656 * Returns the drag and drop instances that are in all groups the
19657 * passed in instance belongs to.
19658 * @method getRelated
19659 * @param {DragDrop} p_oDD the obj to get related data for
19660 * @param {boolean} bTargetsOnly if true, only return targetable objs
19661 * @return {DragDrop[]} the related instances
19664 getRelated: function(p_oDD, bTargetsOnly) {
19666 for (var i in p_oDD.groups) {
19667 for (j in this.ids[i]) {
19668 var dd = this.ids[i][j];
19669 if (! this.isTypeOfDD(dd)) {
19672 if (!bTargetsOnly || dd.isTarget) {
19673 oDDs[oDDs.length] = dd;
19682 * Returns true if the specified dd target is a legal target for
19683 * the specifice drag obj
19684 * @method isLegalTarget
19685 * @param {DragDrop} the drag obj
19686 * @param {DragDrop} the target
19687 * @return {boolean} true if the target is a legal target for the
19691 isLegalTarget: function (oDD, oTargetDD) {
19692 var targets = this.getRelated(oDD, true);
19693 for (var i=0, len=targets.length;i<len;++i) {
19694 if (targets[i].id == oTargetDD.id) {
19703 * My goal is to be able to transparently determine if an object is
19704 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19705 * returns "object", oDD.constructor.toString() always returns
19706 * "DragDrop" and not the name of the subclass. So for now it just
19707 * evaluates a well-known variable in DragDrop.
19708 * @method isTypeOfDD
19709 * @param {Object} the object to evaluate
19710 * @return {boolean} true if typeof oDD = DragDrop
19713 isTypeOfDD: function (oDD) {
19714 return (oDD && oDD.__ygDragDrop);
19718 * Utility function to determine if a given element has been
19719 * registered as a drag drop handle for the given Drag Drop object.
19721 * @param {String} id the element id to check
19722 * @return {boolean} true if this element is a DragDrop handle, false
19726 isHandle: function(sDDId, sHandleId) {
19727 return ( this.handleIds[sDDId] &&
19728 this.handleIds[sDDId][sHandleId] );
19732 * Returns the DragDrop instance for a given id
19733 * @method getDDById
19734 * @param {String} id the id of the DragDrop object
19735 * @return {DragDrop} the drag drop object, null if it is not found
19738 getDDById: function(id) {
19739 for (var i in this.ids) {
19740 if (this.ids[i][id]) {
19741 return this.ids[i][id];
19748 * Fired after a registered DragDrop object gets the mousedown event.
19749 * Sets up the events required to track the object being dragged
19750 * @method handleMouseDown
19751 * @param {Event} e the event
19752 * @param oDD the DragDrop object being dragged
19756 handleMouseDown: function(e, oDD) {
19758 Roo.QuickTips.disable();
19760 this.currentTarget = e.getTarget();
19762 this.dragCurrent = oDD;
19764 var el = oDD.getEl();
19766 // track start position
19767 this.startX = e.getPageX();
19768 this.startY = e.getPageY();
19770 this.deltaX = this.startX - el.offsetLeft;
19771 this.deltaY = this.startY - el.offsetTop;
19773 this.dragThreshMet = false;
19775 this.clickTimeout = setTimeout(
19777 var DDM = Roo.dd.DDM;
19778 DDM.startDrag(DDM.startX, DDM.startY);
19780 this.clickTimeThresh );
19784 * Fired when either the drag pixel threshol or the mousedown hold
19785 * time threshold has been met.
19786 * @method startDrag
19787 * @param x {int} the X position of the original mousedown
19788 * @param y {int} the Y position of the original mousedown
19791 startDrag: function(x, y) {
19792 clearTimeout(this.clickTimeout);
19793 if (this.dragCurrent) {
19794 this.dragCurrent.b4StartDrag(x, y);
19795 this.dragCurrent.startDrag(x, y);
19797 this.dragThreshMet = true;
19801 * Internal function to handle the mouseup event. Will be invoked
19802 * from the context of the document.
19803 * @method handleMouseUp
19804 * @param {Event} e the event
19808 handleMouseUp: function(e) {
19811 Roo.QuickTips.enable();
19813 if (! this.dragCurrent) {
19817 clearTimeout(this.clickTimeout);
19819 if (this.dragThreshMet) {
19820 this.fireEvents(e, true);
19830 * Utility to stop event propagation and event default, if these
19831 * features are turned on.
19832 * @method stopEvent
19833 * @param {Event} e the event as returned by this.getEvent()
19836 stopEvent: function(e){
19837 if(this.stopPropagation) {
19838 e.stopPropagation();
19841 if (this.preventDefault) {
19842 e.preventDefault();
19847 * Internal function to clean up event handlers after the drag
19848 * operation is complete
19850 * @param {Event} e the event
19854 stopDrag: function(e) {
19855 // Fire the drag end event for the item that was dragged
19856 if (this.dragCurrent) {
19857 if (this.dragThreshMet) {
19858 this.dragCurrent.b4EndDrag(e);
19859 this.dragCurrent.endDrag(e);
19862 this.dragCurrent.onMouseUp(e);
19865 this.dragCurrent = null;
19866 this.dragOvers = {};
19870 * Internal function to handle the mousemove event. Will be invoked
19871 * from the context of the html element.
19873 * @TODO figure out what we can do about mouse events lost when the
19874 * user drags objects beyond the window boundary. Currently we can
19875 * detect this in internet explorer by verifying that the mouse is
19876 * down during the mousemove event. Firefox doesn't give us the
19877 * button state on the mousemove event.
19878 * @method handleMouseMove
19879 * @param {Event} e the event
19883 handleMouseMove: function(e) {
19884 if (! this.dragCurrent) {
19888 // var button = e.which || e.button;
19890 // check for IE mouseup outside of page boundary
19891 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19893 return this.handleMouseUp(e);
19896 if (!this.dragThreshMet) {
19897 var diffX = Math.abs(this.startX - e.getPageX());
19898 var diffY = Math.abs(this.startY - e.getPageY());
19899 if (diffX > this.clickPixelThresh ||
19900 diffY > this.clickPixelThresh) {
19901 this.startDrag(this.startX, this.startY);
19905 if (this.dragThreshMet) {
19906 this.dragCurrent.b4Drag(e);
19907 this.dragCurrent.onDrag(e);
19908 if(!this.dragCurrent.moveOnly){
19909 this.fireEvents(e, false);
19919 * Iterates over all of the DragDrop elements to find ones we are
19920 * hovering over or dropping on
19921 * @method fireEvents
19922 * @param {Event} e the event
19923 * @param {boolean} isDrop is this a drop op or a mouseover op?
19927 fireEvents: function(e, isDrop) {
19928 var dc = this.dragCurrent;
19930 // If the user did the mouse up outside of the window, we could
19931 // get here even though we have ended the drag.
19932 if (!dc || dc.isLocked()) {
19936 var pt = e.getPoint();
19938 // cache the previous dragOver array
19944 var enterEvts = [];
19946 // Check to see if the object(s) we were hovering over is no longer
19947 // being hovered over so we can fire the onDragOut event
19948 for (var i in this.dragOvers) {
19950 var ddo = this.dragOvers[i];
19952 if (! this.isTypeOfDD(ddo)) {
19956 if (! this.isOverTarget(pt, ddo, this.mode)) {
19957 outEvts.push( ddo );
19960 oldOvers[i] = true;
19961 delete this.dragOvers[i];
19964 for (var sGroup in dc.groups) {
19966 if ("string" != typeof sGroup) {
19970 for (i in this.ids[sGroup]) {
19971 var oDD = this.ids[sGroup][i];
19972 if (! this.isTypeOfDD(oDD)) {
19976 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19977 if (this.isOverTarget(pt, oDD, this.mode)) {
19978 // look for drop interactions
19980 dropEvts.push( oDD );
19981 // look for drag enter and drag over interactions
19984 // initial drag over: dragEnter fires
19985 if (!oldOvers[oDD.id]) {
19986 enterEvts.push( oDD );
19987 // subsequent drag overs: dragOver fires
19989 overEvts.push( oDD );
19992 this.dragOvers[oDD.id] = oDD;
20000 if (outEvts.length) {
20001 dc.b4DragOut(e, outEvts);
20002 dc.onDragOut(e, outEvts);
20005 if (enterEvts.length) {
20006 dc.onDragEnter(e, enterEvts);
20009 if (overEvts.length) {
20010 dc.b4DragOver(e, overEvts);
20011 dc.onDragOver(e, overEvts);
20014 if (dropEvts.length) {
20015 dc.b4DragDrop(e, dropEvts);
20016 dc.onDragDrop(e, dropEvts);
20020 // fire dragout events
20022 for (i=0, len=outEvts.length; i<len; ++i) {
20023 dc.b4DragOut(e, outEvts[i].id);
20024 dc.onDragOut(e, outEvts[i].id);
20027 // fire enter events
20028 for (i=0,len=enterEvts.length; i<len; ++i) {
20029 // dc.b4DragEnter(e, oDD.id);
20030 dc.onDragEnter(e, enterEvts[i].id);
20033 // fire over events
20034 for (i=0,len=overEvts.length; i<len; ++i) {
20035 dc.b4DragOver(e, overEvts[i].id);
20036 dc.onDragOver(e, overEvts[i].id);
20039 // fire drop events
20040 for (i=0, len=dropEvts.length; i<len; ++i) {
20041 dc.b4DragDrop(e, dropEvts[i].id);
20042 dc.onDragDrop(e, dropEvts[i].id);
20047 // notify about a drop that did not find a target
20048 if (isDrop && !dropEvts.length) {
20049 dc.onInvalidDrop(e);
20055 * Helper function for getting the best match from the list of drag
20056 * and drop objects returned by the drag and drop events when we are
20057 * in INTERSECT mode. It returns either the first object that the
20058 * cursor is over, or the object that has the greatest overlap with
20059 * the dragged element.
20060 * @method getBestMatch
20061 * @param {DragDrop[]} dds The array of drag and drop objects
20063 * @return {DragDrop} The best single match
20066 getBestMatch: function(dds) {
20068 // Return null if the input is not what we expect
20069 //if (!dds || !dds.length || dds.length == 0) {
20071 // If there is only one item, it wins
20072 //} else if (dds.length == 1) {
20074 var len = dds.length;
20079 // Loop through the targeted items
20080 for (var i=0; i<len; ++i) {
20082 // If the cursor is over the object, it wins. If the
20083 // cursor is over multiple matches, the first one we come
20085 if (dd.cursorIsOver) {
20088 // Otherwise the object with the most overlap wins
20091 winner.overlap.getArea() < dd.overlap.getArea()) {
20102 * Refreshes the cache of the top-left and bottom-right points of the
20103 * drag and drop objects in the specified group(s). This is in the
20104 * format that is stored in the drag and drop instance, so typical
20107 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20111 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20113 * @TODO this really should be an indexed array. Alternatively this
20114 * method could accept both.
20115 * @method refreshCache
20116 * @param {Object} groups an associative array of groups to refresh
20119 refreshCache: function(groups) {
20120 for (var sGroup in groups) {
20121 if ("string" != typeof sGroup) {
20124 for (var i in this.ids[sGroup]) {
20125 var oDD = this.ids[sGroup][i];
20127 if (this.isTypeOfDD(oDD)) {
20128 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20129 var loc = this.getLocation(oDD);
20131 this.locationCache[oDD.id] = loc;
20133 delete this.locationCache[oDD.id];
20134 // this will unregister the drag and drop object if
20135 // the element is not in a usable state
20144 * This checks to make sure an element exists and is in the DOM. The
20145 * main purpose is to handle cases where innerHTML is used to remove
20146 * drag and drop objects from the DOM. IE provides an 'unspecified
20147 * error' when trying to access the offsetParent of such an element
20149 * @param {HTMLElement} el the element to check
20150 * @return {boolean} true if the element looks usable
20153 verifyEl: function(el) {
20158 parent = el.offsetParent;
20161 parent = el.offsetParent;
20172 * Returns a Region object containing the drag and drop element's position
20173 * and size, including the padding configured for it
20174 * @method getLocation
20175 * @param {DragDrop} oDD the drag and drop object to get the
20177 * @return {Roo.lib.Region} a Region object representing the total area
20178 * the element occupies, including any padding
20179 * the instance is configured for.
20182 getLocation: function(oDD) {
20183 if (! this.isTypeOfDD(oDD)) {
20187 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20190 pos= Roo.lib.Dom.getXY(el);
20198 x2 = x1 + el.offsetWidth;
20200 y2 = y1 + el.offsetHeight;
20202 t = y1 - oDD.padding[0];
20203 r = x2 + oDD.padding[1];
20204 b = y2 + oDD.padding[2];
20205 l = x1 - oDD.padding[3];
20207 return new Roo.lib.Region( t, r, b, l );
20211 * Checks the cursor location to see if it over the target
20212 * @method isOverTarget
20213 * @param {Roo.lib.Point} pt The point to evaluate
20214 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20215 * @return {boolean} true if the mouse is over the target
20219 isOverTarget: function(pt, oTarget, intersect) {
20220 // use cache if available
20221 var loc = this.locationCache[oTarget.id];
20222 if (!loc || !this.useCache) {
20223 loc = this.getLocation(oTarget);
20224 this.locationCache[oTarget.id] = loc;
20232 oTarget.cursorIsOver = loc.contains( pt );
20234 // DragDrop is using this as a sanity check for the initial mousedown
20235 // in this case we are done. In POINT mode, if the drag obj has no
20236 // contraints, we are also done. Otherwise we need to evaluate the
20237 // location of the target as related to the actual location of the
20238 // dragged element.
20239 var dc = this.dragCurrent;
20240 if (!dc || !dc.getTargetCoord ||
20241 (!intersect && !dc.constrainX && !dc.constrainY)) {
20242 return oTarget.cursorIsOver;
20245 oTarget.overlap = null;
20247 // Get the current location of the drag element, this is the
20248 // location of the mouse event less the delta that represents
20249 // where the original mousedown happened on the element. We
20250 // need to consider constraints and ticks as well.
20251 var pos = dc.getTargetCoord(pt.x, pt.y);
20253 var el = dc.getDragEl();
20254 var curRegion = new Roo.lib.Region( pos.y,
20255 pos.x + el.offsetWidth,
20256 pos.y + el.offsetHeight,
20259 var overlap = curRegion.intersect(loc);
20262 oTarget.overlap = overlap;
20263 return (intersect) ? true : oTarget.cursorIsOver;
20270 * unload event handler
20271 * @method _onUnload
20275 _onUnload: function(e, me) {
20276 Roo.dd.DragDropMgr.unregAll();
20280 * Cleans up the drag and drop events and objects.
20285 unregAll: function() {
20287 if (this.dragCurrent) {
20289 this.dragCurrent = null;
20292 this._execOnAll("unreg", []);
20294 for (i in this.elementCache) {
20295 delete this.elementCache[i];
20298 this.elementCache = {};
20303 * A cache of DOM elements
20304 * @property elementCache
20311 * Get the wrapper for the DOM element specified
20312 * @method getElWrapper
20313 * @param {String} id the id of the element to get
20314 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20316 * @deprecated This wrapper isn't that useful
20319 getElWrapper: function(id) {
20320 var oWrapper = this.elementCache[id];
20321 if (!oWrapper || !oWrapper.el) {
20322 oWrapper = this.elementCache[id] =
20323 new this.ElementWrapper(Roo.getDom(id));
20329 * Returns the actual DOM element
20330 * @method getElement
20331 * @param {String} id the id of the elment to get
20332 * @return {Object} The element
20333 * @deprecated use Roo.getDom instead
20336 getElement: function(id) {
20337 return Roo.getDom(id);
20341 * Returns the style property for the DOM element (i.e.,
20342 * document.getElById(id).style)
20344 * @param {String} id the id of the elment to get
20345 * @return {Object} The style property of the element
20346 * @deprecated use Roo.getDom instead
20349 getCss: function(id) {
20350 var el = Roo.getDom(id);
20351 return (el) ? el.style : null;
20355 * Inner class for cached elements
20356 * @class DragDropMgr.ElementWrapper
20361 ElementWrapper: function(el) {
20366 this.el = el || null;
20371 this.id = this.el && el.id;
20373 * A reference to the style property
20376 this.css = this.el && el.style;
20380 * Returns the X position of an html element
20382 * @param el the element for which to get the position
20383 * @return {int} the X coordinate
20385 * @deprecated use Roo.lib.Dom.getX instead
20388 getPosX: function(el) {
20389 return Roo.lib.Dom.getX(el);
20393 * Returns the Y position of an html element
20395 * @param el the element for which to get the position
20396 * @return {int} the Y coordinate
20397 * @deprecated use Roo.lib.Dom.getY instead
20400 getPosY: function(el) {
20401 return Roo.lib.Dom.getY(el);
20405 * Swap two nodes. In IE, we use the native method, for others we
20406 * emulate the IE behavior
20408 * @param n1 the first node to swap
20409 * @param n2 the other node to swap
20412 swapNode: function(n1, n2) {
20416 var p = n2.parentNode;
20417 var s = n2.nextSibling;
20420 p.insertBefore(n1, n2);
20421 } else if (n2 == n1.nextSibling) {
20422 p.insertBefore(n2, n1);
20424 n1.parentNode.replaceChild(n2, n1);
20425 p.insertBefore(n1, s);
20431 * Returns the current scroll position
20432 * @method getScroll
20436 getScroll: function () {
20437 var t, l, dde=document.documentElement, db=document.body;
20438 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20440 l = dde.scrollLeft;
20447 return { top: t, left: l };
20451 * Returns the specified element style property
20453 * @param {HTMLElement} el the element
20454 * @param {string} styleProp the style property
20455 * @return {string} The value of the style property
20456 * @deprecated use Roo.lib.Dom.getStyle
20459 getStyle: function(el, styleProp) {
20460 return Roo.fly(el).getStyle(styleProp);
20464 * Gets the scrollTop
20465 * @method getScrollTop
20466 * @return {int} the document's scrollTop
20469 getScrollTop: function () { return this.getScroll().top; },
20472 * Gets the scrollLeft
20473 * @method getScrollLeft
20474 * @return {int} the document's scrollTop
20477 getScrollLeft: function () { return this.getScroll().left; },
20480 * Sets the x/y position of an element to the location of the
20483 * @param {HTMLElement} moveEl The element to move
20484 * @param {HTMLElement} targetEl The position reference element
20487 moveToEl: function (moveEl, targetEl) {
20488 var aCoord = Roo.lib.Dom.getXY(targetEl);
20489 Roo.lib.Dom.setXY(moveEl, aCoord);
20493 * Numeric array sort function
20494 * @method numericSort
20497 numericSort: function(a, b) { return (a - b); },
20501 * @property _timeoutCount
20508 * Trying to make the load order less important. Without this we get
20509 * an error if this file is loaded before the Event Utility.
20510 * @method _addListeners
20514 _addListeners: function() {
20515 var DDM = Roo.dd.DDM;
20516 if ( Roo.lib.Event && document ) {
20519 if (DDM._timeoutCount > 2000) {
20521 setTimeout(DDM._addListeners, 10);
20522 if (document && document.body) {
20523 DDM._timeoutCount += 1;
20530 * Recursively searches the immediate parent and all child nodes for
20531 * the handle element in order to determine wheter or not it was
20533 * @method handleWasClicked
20534 * @param node the html element to inspect
20537 handleWasClicked: function(node, id) {
20538 if (this.isHandle(id, node.id)) {
20541 // check to see if this is a text node child of the one we want
20542 var p = node.parentNode;
20545 if (this.isHandle(id, p.id)) {
20560 // shorter alias, save a few bytes
20561 Roo.dd.DDM = Roo.dd.DragDropMgr;
20562 Roo.dd.DDM._addListeners();
20566 * Ext JS Library 1.1.1
20567 * Copyright(c) 2006-2007, Ext JS, LLC.
20569 * Originally Released Under LGPL - original licence link has changed is not relivant.
20572 * <script type="text/javascript">
20577 * A DragDrop implementation where the linked element follows the
20578 * mouse cursor during a drag.
20579 * @extends Roo.dd.DragDrop
20581 * @param {String} id the id of the linked element
20582 * @param {String} sGroup the group of related DragDrop items
20583 * @param {object} config an object containing configurable attributes
20584 * Valid properties for DD:
20587 Roo.dd.DD = function(id, sGroup, config) {
20589 this.init(id, sGroup, config);
20593 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20596 * When set to true, the utility automatically tries to scroll the browser
20597 * window wehn a drag and drop element is dragged near the viewport boundary.
20598 * Defaults to true.
20605 * Sets the pointer offset to the distance between the linked element's top
20606 * left corner and the location the element was clicked
20607 * @method autoOffset
20608 * @param {int} iPageX the X coordinate of the click
20609 * @param {int} iPageY the Y coordinate of the click
20611 autoOffset: function(iPageX, iPageY) {
20612 var x = iPageX - this.startPageX;
20613 var y = iPageY - this.startPageY;
20614 this.setDelta(x, y);
20618 * Sets the pointer offset. You can call this directly to force the
20619 * offset to be in a particular location (e.g., pass in 0,0 to set it
20620 * to the center of the object)
20622 * @param {int} iDeltaX the distance from the left
20623 * @param {int} iDeltaY the distance from the top
20625 setDelta: function(iDeltaX, iDeltaY) {
20626 this.deltaX = iDeltaX;
20627 this.deltaY = iDeltaY;
20631 * Sets the drag element to the location of the mousedown or click event,
20632 * maintaining the cursor location relative to the location on the element
20633 * that was clicked. Override this if you want to place the element in a
20634 * location other than where the cursor is.
20635 * @method setDragElPos
20636 * @param {int} iPageX the X coordinate of the mousedown or drag event
20637 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20639 setDragElPos: function(iPageX, iPageY) {
20640 // the first time we do this, we are going to check to make sure
20641 // the element has css positioning
20643 var el = this.getDragEl();
20644 this.alignElWithMouse(el, iPageX, iPageY);
20648 * Sets the element to the location of the mousedown or click event,
20649 * maintaining the cursor location relative to the location on the element
20650 * that was clicked. Override this if you want to place the element in a
20651 * location other than where the cursor is.
20652 * @method alignElWithMouse
20653 * @param {HTMLElement} el the element to move
20654 * @param {int} iPageX the X coordinate of the mousedown or drag event
20655 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20657 alignElWithMouse: function(el, iPageX, iPageY) {
20658 var oCoord = this.getTargetCoord(iPageX, iPageY);
20659 var fly = el.dom ? el : Roo.fly(el);
20660 if (!this.deltaSetXY) {
20661 var aCoord = [oCoord.x, oCoord.y];
20663 var newLeft = fly.getLeft(true);
20664 var newTop = fly.getTop(true);
20665 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20667 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20670 this.cachePosition(oCoord.x, oCoord.y);
20671 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20676 * Saves the most recent position so that we can reset the constraints and
20677 * tick marks on-demand. We need to know this so that we can calculate the
20678 * number of pixels the element is offset from its original position.
20679 * @method cachePosition
20680 * @param iPageX the current x position (optional, this just makes it so we
20681 * don't have to look it up again)
20682 * @param iPageY the current y position (optional, this just makes it so we
20683 * don't have to look it up again)
20685 cachePosition: function(iPageX, iPageY) {
20687 this.lastPageX = iPageX;
20688 this.lastPageY = iPageY;
20690 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20691 this.lastPageX = aCoord[0];
20692 this.lastPageY = aCoord[1];
20697 * Auto-scroll the window if the dragged object has been moved beyond the
20698 * visible window boundary.
20699 * @method autoScroll
20700 * @param {int} x the drag element's x position
20701 * @param {int} y the drag element's y position
20702 * @param {int} h the height of the drag element
20703 * @param {int} w the width of the drag element
20706 autoScroll: function(x, y, h, w) {
20709 // The client height
20710 var clientH = Roo.lib.Dom.getViewWidth();
20712 // The client width
20713 var clientW = Roo.lib.Dom.getViewHeight();
20715 // The amt scrolled down
20716 var st = this.DDM.getScrollTop();
20718 // The amt scrolled right
20719 var sl = this.DDM.getScrollLeft();
20721 // Location of the bottom of the element
20724 // Location of the right of the element
20727 // The distance from the cursor to the bottom of the visible area,
20728 // adjusted so that we don't scroll if the cursor is beyond the
20729 // element drag constraints
20730 var toBot = (clientH + st - y - this.deltaY);
20732 // The distance from the cursor to the right of the visible area
20733 var toRight = (clientW + sl - x - this.deltaX);
20736 // How close to the edge the cursor must be before we scroll
20737 // var thresh = (document.all) ? 100 : 40;
20740 // How many pixels to scroll per autoscroll op. This helps to reduce
20741 // clunky scrolling. IE is more sensitive about this ... it needs this
20742 // value to be higher.
20743 var scrAmt = (document.all) ? 80 : 30;
20745 // Scroll down if we are near the bottom of the visible page and the
20746 // obj extends below the crease
20747 if ( bot > clientH && toBot < thresh ) {
20748 window.scrollTo(sl, st + scrAmt);
20751 // Scroll up if the window is scrolled down and the top of the object
20752 // goes above the top border
20753 if ( y < st && st > 0 && y - st < thresh ) {
20754 window.scrollTo(sl, st - scrAmt);
20757 // Scroll right if the obj is beyond the right border and the cursor is
20758 // near the border.
20759 if ( right > clientW && toRight < thresh ) {
20760 window.scrollTo(sl + scrAmt, st);
20763 // Scroll left if the window has been scrolled to the right and the obj
20764 // extends past the left border
20765 if ( x < sl && sl > 0 && x - sl < thresh ) {
20766 window.scrollTo(sl - scrAmt, st);
20772 * Finds the location the element should be placed if we want to move
20773 * it to where the mouse location less the click offset would place us.
20774 * @method getTargetCoord
20775 * @param {int} iPageX the X coordinate of the click
20776 * @param {int} iPageY the Y coordinate of the click
20777 * @return an object that contains the coordinates (Object.x and Object.y)
20780 getTargetCoord: function(iPageX, iPageY) {
20783 var x = iPageX - this.deltaX;
20784 var y = iPageY - this.deltaY;
20786 if (this.constrainX) {
20787 if (x < this.minX) { x = this.minX; }
20788 if (x > this.maxX) { x = this.maxX; }
20791 if (this.constrainY) {
20792 if (y < this.minY) { y = this.minY; }
20793 if (y > this.maxY) { y = this.maxY; }
20796 x = this.getTick(x, this.xTicks);
20797 y = this.getTick(y, this.yTicks);
20804 * Sets up config options specific to this class. Overrides
20805 * Roo.dd.DragDrop, but all versions of this method through the
20806 * inheritance chain are called
20808 applyConfig: function() {
20809 Roo.dd.DD.superclass.applyConfig.call(this);
20810 this.scroll = (this.config.scroll !== false);
20814 * Event that fires prior to the onMouseDown event. Overrides
20817 b4MouseDown: function(e) {
20818 // this.resetConstraints();
20819 this.autoOffset(e.getPageX(),
20824 * Event that fires prior to the onDrag event. Overrides
20827 b4Drag: function(e) {
20828 this.setDragElPos(e.getPageX(),
20832 toString: function() {
20833 return ("DD " + this.id);
20836 //////////////////////////////////////////////////////////////////////////
20837 // Debugging ygDragDrop events that can be overridden
20838 //////////////////////////////////////////////////////////////////////////
20840 startDrag: function(x, y) {
20843 onDrag: function(e) {
20846 onDragEnter: function(e, id) {
20849 onDragOver: function(e, id) {
20852 onDragOut: function(e, id) {
20855 onDragDrop: function(e, id) {
20858 endDrag: function(e) {
20865 * Ext JS Library 1.1.1
20866 * Copyright(c) 2006-2007, Ext JS, LLC.
20868 * Originally Released Under LGPL - original licence link has changed is not relivant.
20871 * <script type="text/javascript">
20875 * @class Roo.dd.DDProxy
20876 * A DragDrop implementation that inserts an empty, bordered div into
20877 * the document that follows the cursor during drag operations. At the time of
20878 * the click, the frame div is resized to the dimensions of the linked html
20879 * element, and moved to the exact location of the linked element.
20881 * References to the "frame" element refer to the single proxy element that
20882 * was created to be dragged in place of all DDProxy elements on the
20885 * @extends Roo.dd.DD
20887 * @param {String} id the id of the linked html element
20888 * @param {String} sGroup the group of related DragDrop objects
20889 * @param {object} config an object containing configurable attributes
20890 * Valid properties for DDProxy in addition to those in DragDrop:
20891 * resizeFrame, centerFrame, dragElId
20893 Roo.dd.DDProxy = function(id, sGroup, config) {
20895 this.init(id, sGroup, config);
20901 * The default drag frame div id
20902 * @property Roo.dd.DDProxy.dragElId
20906 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20908 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20911 * By default we resize the drag frame to be the same size as the element
20912 * we want to drag (this is to get the frame effect). We can turn it off
20913 * if we want a different behavior.
20914 * @property resizeFrame
20920 * By default the frame is positioned exactly where the drag element is, so
20921 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20922 * you do not have constraints on the obj is to have the drag frame centered
20923 * around the cursor. Set centerFrame to true for this effect.
20924 * @property centerFrame
20927 centerFrame: false,
20930 * Creates the proxy element if it does not yet exist
20931 * @method createFrame
20933 createFrame: function() {
20935 var body = document.body;
20937 if (!body || !body.firstChild) {
20938 setTimeout( function() { self.createFrame(); }, 50 );
20942 var div = this.getDragEl();
20945 div = document.createElement("div");
20946 div.id = this.dragElId;
20949 s.position = "absolute";
20950 s.visibility = "hidden";
20952 s.border = "2px solid #aaa";
20955 // appendChild can blow up IE if invoked prior to the window load event
20956 // while rendering a table. It is possible there are other scenarios
20957 // that would cause this to happen as well.
20958 body.insertBefore(div, body.firstChild);
20963 * Initialization for the drag frame element. Must be called in the
20964 * constructor of all subclasses
20965 * @method initFrame
20967 initFrame: function() {
20968 this.createFrame();
20971 applyConfig: function() {
20972 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20974 this.resizeFrame = (this.config.resizeFrame !== false);
20975 this.centerFrame = (this.config.centerFrame);
20976 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20980 * Resizes the drag frame to the dimensions of the clicked object, positions
20981 * it over the object, and finally displays it
20982 * @method showFrame
20983 * @param {int} iPageX X click position
20984 * @param {int} iPageY Y click position
20987 showFrame: function(iPageX, iPageY) {
20988 var el = this.getEl();
20989 var dragEl = this.getDragEl();
20990 var s = dragEl.style;
20992 this._resizeProxy();
20994 if (this.centerFrame) {
20995 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20996 Math.round(parseInt(s.height, 10)/2) );
20999 this.setDragElPos(iPageX, iPageY);
21001 Roo.fly(dragEl).show();
21005 * The proxy is automatically resized to the dimensions of the linked
21006 * element when a drag is initiated, unless resizeFrame is set to false
21007 * @method _resizeProxy
21010 _resizeProxy: function() {
21011 if (this.resizeFrame) {
21012 var el = this.getEl();
21013 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21017 // overrides Roo.dd.DragDrop
21018 b4MouseDown: function(e) {
21019 var x = e.getPageX();
21020 var y = e.getPageY();
21021 this.autoOffset(x, y);
21022 this.setDragElPos(x, y);
21025 // overrides Roo.dd.DragDrop
21026 b4StartDrag: function(x, y) {
21027 // show the drag frame
21028 this.showFrame(x, y);
21031 // overrides Roo.dd.DragDrop
21032 b4EndDrag: function(e) {
21033 Roo.fly(this.getDragEl()).hide();
21036 // overrides Roo.dd.DragDrop
21037 // By default we try to move the element to the last location of the frame.
21038 // This is so that the default behavior mirrors that of Roo.dd.DD.
21039 endDrag: function(e) {
21041 var lel = this.getEl();
21042 var del = this.getDragEl();
21044 // Show the drag frame briefly so we can get its position
21045 del.style.visibility = "";
21048 // Hide the linked element before the move to get around a Safari
21050 lel.style.visibility = "hidden";
21051 Roo.dd.DDM.moveToEl(lel, del);
21052 del.style.visibility = "hidden";
21053 lel.style.visibility = "";
21058 beforeMove : function(){
21062 afterDrag : function(){
21066 toString: function() {
21067 return ("DDProxy " + this.id);
21073 * Ext JS Library 1.1.1
21074 * Copyright(c) 2006-2007, Ext JS, LLC.
21076 * Originally Released Under LGPL - original licence link has changed is not relivant.
21079 * <script type="text/javascript">
21083 * @class Roo.dd.DDTarget
21084 * A DragDrop implementation that does not move, but can be a drop
21085 * target. You would get the same result by simply omitting implementation
21086 * for the event callbacks, but this way we reduce the processing cost of the
21087 * event listener and the callbacks.
21088 * @extends Roo.dd.DragDrop
21090 * @param {String} id the id of the element that is a drop target
21091 * @param {String} sGroup the group of related DragDrop objects
21092 * @param {object} config an object containing configurable attributes
21093 * Valid properties for DDTarget in addition to those in
21097 Roo.dd.DDTarget = function(id, sGroup, config) {
21099 this.initTarget(id, sGroup, config);
21101 if (config && (config.listeners || config.events)) {
21102 Roo.dd.DragDrop.superclass.constructor.call(this, {
21103 listeners : config.listeners || {},
21104 events : config.events || {}
21109 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21110 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21111 toString: function() {
21112 return ("DDTarget " + this.id);
21117 * Ext JS Library 1.1.1
21118 * Copyright(c) 2006-2007, Ext JS, LLC.
21120 * Originally Released Under LGPL - original licence link has changed is not relivant.
21123 * <script type="text/javascript">
21128 * @class Roo.dd.ScrollManager
21129 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21130 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21133 Roo.dd.ScrollManager = function(){
21134 var ddm = Roo.dd.DragDropMgr;
21141 var onStop = function(e){
21146 var triggerRefresh = function(){
21147 if(ddm.dragCurrent){
21148 ddm.refreshCache(ddm.dragCurrent.groups);
21152 var doScroll = function(){
21153 if(ddm.dragCurrent){
21154 var dds = Roo.dd.ScrollManager;
21156 if(proc.el.scroll(proc.dir, dds.increment)){
21160 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21165 var clearProc = function(){
21167 clearInterval(proc.id);
21174 var startProc = function(el, dir){
21175 Roo.log('scroll startproc');
21179 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21182 var onFire = function(e, isDrop){
21184 if(isDrop || !ddm.dragCurrent){ return; }
21185 var dds = Roo.dd.ScrollManager;
21186 if(!dragEl || dragEl != ddm.dragCurrent){
21187 dragEl = ddm.dragCurrent;
21188 // refresh regions on drag start
21189 dds.refreshCache();
21192 var xy = Roo.lib.Event.getXY(e);
21193 var pt = new Roo.lib.Point(xy[0], xy[1]);
21194 for(var id in els){
21195 var el = els[id], r = el._region;
21196 if(r && r.contains(pt) && el.isScrollable()){
21197 if(r.bottom - pt.y <= dds.thresh){
21199 startProc(el, "down");
21202 }else if(r.right - pt.x <= dds.thresh){
21204 startProc(el, "left");
21207 }else if(pt.y - r.top <= dds.thresh){
21209 startProc(el, "up");
21212 }else if(pt.x - r.left <= dds.thresh){
21214 startProc(el, "right");
21223 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21224 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21228 * Registers new overflow element(s) to auto scroll
21229 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21231 register : function(el){
21232 if(el instanceof Array){
21233 for(var i = 0, len = el.length; i < len; i++) {
21234 this.register(el[i]);
21240 Roo.dd.ScrollManager.els = els;
21244 * Unregisters overflow element(s) so they are no longer scrolled
21245 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21247 unregister : function(el){
21248 if(el instanceof Array){
21249 for(var i = 0, len = el.length; i < len; i++) {
21250 this.unregister(el[i]);
21259 * The number of pixels from the edge of a container the pointer needs to be to
21260 * trigger scrolling (defaults to 25)
21266 * The number of pixels to scroll in each scroll increment (defaults to 50)
21272 * The frequency of scrolls in milliseconds (defaults to 500)
21278 * True to animate the scroll (defaults to true)
21284 * The animation duration in seconds -
21285 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21291 * Manually trigger a cache refresh.
21293 refreshCache : function(){
21294 for(var id in els){
21295 if(typeof els[id] == 'object'){ // for people extending the object prototype
21296 els[id]._region = els[id].getRegion();
21303 * Ext JS Library 1.1.1
21304 * Copyright(c) 2006-2007, Ext JS, LLC.
21306 * Originally Released Under LGPL - original licence link has changed is not relivant.
21309 * <script type="text/javascript">
21314 * @class Roo.dd.Registry
21315 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21316 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21319 Roo.dd.Registry = function(){
21322 var autoIdSeed = 0;
21324 var getId = function(el, autogen){
21325 if(typeof el == "string"){
21329 if(!id && autogen !== false){
21330 id = "roodd-" + (++autoIdSeed);
21338 * Register a drag drop element
21339 * @param {String|HTMLElement} element The id or DOM node to register
21340 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21341 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21342 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21343 * populated in the data object (if applicable):
21345 Value Description<br />
21346 --------- ------------------------------------------<br />
21347 handles Array of DOM nodes that trigger dragging<br />
21348 for the element being registered<br />
21349 isHandle True if the element passed in triggers<br />
21350 dragging itself, else false
21353 register : function(el, data){
21355 if(typeof el == "string"){
21356 el = document.getElementById(el);
21359 elements[getId(el)] = data;
21360 if(data.isHandle !== false){
21361 handles[data.ddel.id] = data;
21364 var hs = data.handles;
21365 for(var i = 0, len = hs.length; i < len; i++){
21366 handles[getId(hs[i])] = data;
21372 * Unregister a drag drop element
21373 * @param {String|HTMLElement} element The id or DOM node to unregister
21375 unregister : function(el){
21376 var id = getId(el, false);
21377 var data = elements[id];
21379 delete elements[id];
21381 var hs = data.handles;
21382 for(var i = 0, len = hs.length; i < len; i++){
21383 delete handles[getId(hs[i], false)];
21390 * Returns the handle registered for a DOM Node by id
21391 * @param {String|HTMLElement} id The DOM node or id to look up
21392 * @return {Object} handle The custom handle data
21394 getHandle : function(id){
21395 if(typeof id != "string"){ // must be element?
21398 return handles[id];
21402 * Returns the handle that is registered for the DOM node that is the target of the event
21403 * @param {Event} e The event
21404 * @return {Object} handle The custom handle data
21406 getHandleFromEvent : function(e){
21407 var t = Roo.lib.Event.getTarget(e);
21408 return t ? handles[t.id] : null;
21412 * Returns a custom data object that is registered for a DOM node by id
21413 * @param {String|HTMLElement} id The DOM node or id to look up
21414 * @return {Object} data The custom data
21416 getTarget : function(id){
21417 if(typeof id != "string"){ // must be element?
21420 return elements[id];
21424 * Returns a custom data object that is registered for the DOM node that is the target of the event
21425 * @param {Event} e The event
21426 * @return {Object} data The custom data
21428 getTargetFromEvent : function(e){
21429 var t = Roo.lib.Event.getTarget(e);
21430 return t ? elements[t.id] || handles[t.id] : null;
21435 * Ext JS Library 1.1.1
21436 * Copyright(c) 2006-2007, Ext JS, LLC.
21438 * Originally Released Under LGPL - original licence link has changed is not relivant.
21441 * <script type="text/javascript">
21446 * @class Roo.dd.StatusProxy
21447 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21448 * default drag proxy used by all Roo.dd components.
21450 * @param {Object} config
21452 Roo.dd.StatusProxy = function(config){
21453 Roo.apply(this, config);
21454 this.id = this.id || Roo.id();
21455 this.el = new Roo.Layer({
21457 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21458 {tag: "div", cls: "x-dd-drop-icon"},
21459 {tag: "div", cls: "x-dd-drag-ghost"}
21462 shadow: !config || config.shadow !== false
21464 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21465 this.dropStatus = this.dropNotAllowed;
21468 Roo.dd.StatusProxy.prototype = {
21470 * @cfg {String} dropAllowed
21471 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21473 dropAllowed : "x-dd-drop-ok",
21475 * @cfg {String} dropNotAllowed
21476 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21478 dropNotAllowed : "x-dd-drop-nodrop",
21481 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21482 * over the current target element.
21483 * @param {String} cssClass The css class for the new drop status indicator image
21485 setStatus : function(cssClass){
21486 cssClass = cssClass || this.dropNotAllowed;
21487 if(this.dropStatus != cssClass){
21488 this.el.replaceClass(this.dropStatus, cssClass);
21489 this.dropStatus = cssClass;
21494 * Resets the status indicator to the default dropNotAllowed value
21495 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21497 reset : function(clearGhost){
21498 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21499 this.dropStatus = this.dropNotAllowed;
21501 this.ghost.update("");
21506 * Updates the contents of the ghost element
21507 * @param {String} html The html that will replace the current innerHTML of the ghost element
21509 update : function(html){
21510 if(typeof html == "string"){
21511 this.ghost.update(html);
21513 this.ghost.update("");
21514 html.style.margin = "0";
21515 this.ghost.dom.appendChild(html);
21517 // ensure float = none set?? cant remember why though.
21518 var el = this.ghost.dom.firstChild;
21520 Roo.fly(el).setStyle('float', 'none');
21525 * Returns the underlying proxy {@link Roo.Layer}
21526 * @return {Roo.Layer} el
21528 getEl : function(){
21533 * Returns the ghost element
21534 * @return {Roo.Element} el
21536 getGhost : function(){
21542 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21544 hide : function(clear){
21552 * Stops the repair animation if it's currently running
21555 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21561 * Displays this proxy
21568 * Force the Layer to sync its shadow and shim positions to the element
21575 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21576 * invalid drop operation by the item being dragged.
21577 * @param {Array} xy The XY position of the element ([x, y])
21578 * @param {Function} callback The function to call after the repair is complete
21579 * @param {Object} scope The scope in which to execute the callback
21581 repair : function(xy, callback, scope){
21582 this.callback = callback;
21583 this.scope = scope;
21584 if(xy && this.animRepair !== false){
21585 this.el.addClass("x-dd-drag-repair");
21586 this.el.hideUnders(true);
21587 this.anim = this.el.shift({
21588 duration: this.repairDuration || .5,
21592 callback: this.afterRepair,
21596 this.afterRepair();
21601 afterRepair : function(){
21603 if(typeof this.callback == "function"){
21604 this.callback.call(this.scope || this);
21606 this.callback = null;
21611 * Ext JS Library 1.1.1
21612 * Copyright(c) 2006-2007, Ext JS, LLC.
21614 * Originally Released Under LGPL - original licence link has changed is not relivant.
21617 * <script type="text/javascript">
21621 * @class Roo.dd.DragSource
21622 * @extends Roo.dd.DDProxy
21623 * A simple class that provides the basic implementation needed to make any element draggable.
21625 * @param {String/HTMLElement/Element} el The container element
21626 * @param {Object} config
21628 Roo.dd.DragSource = function(el, config){
21629 this.el = Roo.get(el);
21630 this.dragData = {};
21632 Roo.apply(this, config);
21635 this.proxy = new Roo.dd.StatusProxy();
21638 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21639 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21641 this.dragging = false;
21644 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21646 * @cfg {String} dropAllowed
21647 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21649 dropAllowed : "x-dd-drop-ok",
21651 * @cfg {String} dropNotAllowed
21652 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21654 dropNotAllowed : "x-dd-drop-nodrop",
21657 * Returns the data object associated with this drag source
21658 * @return {Object} data An object containing arbitrary data
21660 getDragData : function(e){
21661 return this.dragData;
21665 onDragEnter : function(e, id){
21666 var target = Roo.dd.DragDropMgr.getDDById(id);
21667 this.cachedTarget = target;
21668 if(this.beforeDragEnter(target, e, id) !== false){
21669 if(target.isNotifyTarget){
21670 var status = target.notifyEnter(this, e, this.dragData);
21671 this.proxy.setStatus(status);
21673 this.proxy.setStatus(this.dropAllowed);
21676 if(this.afterDragEnter){
21678 * An empty function by default, but provided so that you can perform a custom action
21679 * when the dragged item enters the drop target by providing an implementation.
21680 * @param {Roo.dd.DragDrop} target The drop target
21681 * @param {Event} e The event object
21682 * @param {String} id The id of the dragged element
21683 * @method afterDragEnter
21685 this.afterDragEnter(target, e, id);
21691 * An empty function by default, but provided so that you can perform a custom action
21692 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21693 * @param {Roo.dd.DragDrop} target The drop target
21694 * @param {Event} e The event object
21695 * @param {String} id The id of the dragged element
21696 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21698 beforeDragEnter : function(target, e, id){
21703 alignElWithMouse: function() {
21704 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21709 onDragOver : function(e, id){
21710 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21711 if(this.beforeDragOver(target, e, id) !== false){
21712 if(target.isNotifyTarget){
21713 var status = target.notifyOver(this, e, this.dragData);
21714 this.proxy.setStatus(status);
21717 if(this.afterDragOver){
21719 * An empty function by default, but provided so that you can perform a custom action
21720 * while the dragged item is over the drop target by providing an implementation.
21721 * @param {Roo.dd.DragDrop} target The drop target
21722 * @param {Event} e The event object
21723 * @param {String} id The id of the dragged element
21724 * @method afterDragOver
21726 this.afterDragOver(target, e, id);
21732 * An empty function by default, but provided so that you can perform a custom action
21733 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21734 * @param {Roo.dd.DragDrop} target The drop target
21735 * @param {Event} e The event object
21736 * @param {String} id The id of the dragged element
21737 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21739 beforeDragOver : function(target, e, id){
21744 onDragOut : function(e, id){
21745 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21746 if(this.beforeDragOut(target, e, id) !== false){
21747 if(target.isNotifyTarget){
21748 target.notifyOut(this, e, this.dragData);
21750 this.proxy.reset();
21751 if(this.afterDragOut){
21753 * An empty function by default, but provided so that you can perform a custom action
21754 * after the dragged item is dragged out of the target without dropping.
21755 * @param {Roo.dd.DragDrop} target The drop target
21756 * @param {Event} e The event object
21757 * @param {String} id The id of the dragged element
21758 * @method afterDragOut
21760 this.afterDragOut(target, e, id);
21763 this.cachedTarget = null;
21767 * An empty function by default, but provided so that you can perform a custom action before the dragged
21768 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21769 * @param {Roo.dd.DragDrop} target The drop target
21770 * @param {Event} e The event object
21771 * @param {String} id The id of the dragged element
21772 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21774 beforeDragOut : function(target, e, id){
21779 onDragDrop : function(e, id){
21780 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21781 if(this.beforeDragDrop(target, e, id) !== false){
21782 if(target.isNotifyTarget){
21783 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21784 this.onValidDrop(target, e, id);
21786 this.onInvalidDrop(target, e, id);
21789 this.onValidDrop(target, e, id);
21792 if(this.afterDragDrop){
21794 * An empty function by default, but provided so that you can perform a custom action
21795 * after a valid drag drop has occurred by providing an implementation.
21796 * @param {Roo.dd.DragDrop} target The drop target
21797 * @param {Event} e The event object
21798 * @param {String} id The id of the dropped element
21799 * @method afterDragDrop
21801 this.afterDragDrop(target, e, id);
21804 delete this.cachedTarget;
21808 * An empty function by default, but provided so that you can perform a custom action before the dragged
21809 * item is dropped onto the target and optionally cancel the onDragDrop.
21810 * @param {Roo.dd.DragDrop} target The drop target
21811 * @param {Event} e The event object
21812 * @param {String} id The id of the dragged element
21813 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21815 beforeDragDrop : function(target, e, id){
21820 onValidDrop : function(target, e, id){
21822 if(this.afterValidDrop){
21824 * An empty function by default, but provided so that you can perform a custom action
21825 * after a valid drop has occurred by providing an implementation.
21826 * @param {Object} target The target DD
21827 * @param {Event} e The event object
21828 * @param {String} id The id of the dropped element
21829 * @method afterInvalidDrop
21831 this.afterValidDrop(target, e, id);
21836 getRepairXY : function(e, data){
21837 return this.el.getXY();
21841 onInvalidDrop : function(target, e, id){
21842 this.beforeInvalidDrop(target, e, id);
21843 if(this.cachedTarget){
21844 if(this.cachedTarget.isNotifyTarget){
21845 this.cachedTarget.notifyOut(this, e, this.dragData);
21847 this.cacheTarget = null;
21849 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21851 if(this.afterInvalidDrop){
21853 * An empty function by default, but provided so that you can perform a custom action
21854 * after an invalid drop has occurred by providing an implementation.
21855 * @param {Event} e The event object
21856 * @param {String} id The id of the dropped element
21857 * @method afterInvalidDrop
21859 this.afterInvalidDrop(e, id);
21864 afterRepair : function(){
21866 this.el.highlight(this.hlColor || "c3daf9");
21868 this.dragging = false;
21872 * An empty function by default, but provided so that you can perform a custom action after an invalid
21873 * drop has occurred.
21874 * @param {Roo.dd.DragDrop} target The drop target
21875 * @param {Event} e The event object
21876 * @param {String} id The id of the dragged element
21877 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21879 beforeInvalidDrop : function(target, e, id){
21884 handleMouseDown : function(e){
21885 if(this.dragging) {
21888 var data = this.getDragData(e);
21889 if(data && this.onBeforeDrag(data, e) !== false){
21890 this.dragData = data;
21892 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21897 * An empty function by default, but provided so that you can perform a custom action before the initial
21898 * drag event begins and optionally cancel it.
21899 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21900 * @param {Event} e The event object
21901 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21903 onBeforeDrag : function(data, e){
21908 * An empty function by default, but provided so that you can perform a custom action once the initial
21909 * drag event has begun. The drag cannot be canceled from this function.
21910 * @param {Number} x The x position of the click on the dragged object
21911 * @param {Number} y The y position of the click on the dragged object
21913 onStartDrag : Roo.emptyFn,
21915 // private - YUI override
21916 startDrag : function(x, y){
21917 this.proxy.reset();
21918 this.dragging = true;
21919 this.proxy.update("");
21920 this.onInitDrag(x, y);
21925 onInitDrag : function(x, y){
21926 var clone = this.el.dom.cloneNode(true);
21927 clone.id = Roo.id(); // prevent duplicate ids
21928 this.proxy.update(clone);
21929 this.onStartDrag(x, y);
21934 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21935 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21937 getProxy : function(){
21942 * Hides the drag source's {@link Roo.dd.StatusProxy}
21944 hideProxy : function(){
21946 this.proxy.reset(true);
21947 this.dragging = false;
21951 triggerCacheRefresh : function(){
21952 Roo.dd.DDM.refreshCache(this.groups);
21955 // private - override to prevent hiding
21956 b4EndDrag: function(e) {
21959 // private - override to prevent moving
21960 endDrag : function(e){
21961 this.onEndDrag(this.dragData, e);
21965 onEndDrag : function(data, e){
21968 // private - pin to cursor
21969 autoOffset : function(x, y) {
21970 this.setDelta(-12, -20);
21974 * Ext JS Library 1.1.1
21975 * Copyright(c) 2006-2007, Ext JS, LLC.
21977 * Originally Released Under LGPL - original licence link has changed is not relivant.
21980 * <script type="text/javascript">
21985 * @class Roo.dd.DropTarget
21986 * @extends Roo.dd.DDTarget
21987 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21988 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21990 * @param {String/HTMLElement/Element} el The container element
21991 * @param {Object} config
21993 Roo.dd.DropTarget = function(el, config){
21994 this.el = Roo.get(el);
21996 var listeners = false; ;
21997 if (config && config.listeners) {
21998 listeners= config.listeners;
21999 delete config.listeners;
22001 Roo.apply(this, config);
22003 if(this.containerScroll){
22004 Roo.dd.ScrollManager.register(this.el);
22008 * @scope Roo.dd.DropTarget
22013 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22014 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
22015 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
22017 * IMPORTANT : it should set this.overClass and this.dropAllowed
22019 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22020 * @param {Event} e The event
22021 * @param {Object} data An object containing arbitrary data supplied by the drag source
22027 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22028 * This method will be called on every mouse movement while the drag source is over the drop target.
22029 * This default implementation simply returns the dropAllowed config value.
22031 * IMPORTANT : it should set this.dropAllowed
22033 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22034 * @param {Event} e The event
22035 * @param {Object} data An object containing arbitrary data supplied by the drag source
22041 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22042 * out of the target without dropping. This default implementation simply removes the CSS class specified by
22043 * overClass (if any) from the drop element.
22045 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22046 * @param {Event} e The event
22047 * @param {Object} data An object containing arbitrary data supplied by the drag source
22053 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22054 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22055 * implementation that does something to process the drop event and returns true so that the drag source's
22056 * repair action does not run.
22058 * IMPORTANT : it should set this.success
22060 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22061 * @param {Event} e The event
22062 * @param {Object} data An object containing arbitrary data supplied by the drag source
22068 Roo.dd.DropTarget.superclass.constructor.call( this,
22070 this.ddGroup || this.group,
22073 listeners : listeners || {}
22081 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22083 * @cfg {String} overClass
22084 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22087 * @cfg {String} ddGroup
22088 * The drag drop group to handle drop events for
22092 * @cfg {String} dropAllowed
22093 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22095 dropAllowed : "x-dd-drop-ok",
22097 * @cfg {String} dropNotAllowed
22098 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22100 dropNotAllowed : "x-dd-drop-nodrop",
22102 * @cfg {boolean} success
22103 * set this after drop listener..
22107 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22108 * if the drop point is valid for over/enter..
22115 isNotifyTarget : true,
22120 notifyEnter : function(dd, e, data)
22123 this.fireEvent('enter', dd, e, data);
22124 if(this.overClass){
22125 this.el.addClass(this.overClass);
22127 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22128 this.valid ? this.dropAllowed : this.dropNotAllowed
22135 notifyOver : function(dd, e, data)
22138 this.fireEvent('over', dd, e, data);
22139 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22140 this.valid ? this.dropAllowed : this.dropNotAllowed
22147 notifyOut : function(dd, e, data)
22149 this.fireEvent('out', dd, e, data);
22150 if(this.overClass){
22151 this.el.removeClass(this.overClass);
22158 notifyDrop : function(dd, e, data)
22160 this.success = false;
22161 this.fireEvent('drop', dd, e, data);
22162 return this.success;
22166 * Ext JS Library 1.1.1
22167 * Copyright(c) 2006-2007, Ext JS, LLC.
22169 * Originally Released Under LGPL - original licence link has changed is not relivant.
22172 * <script type="text/javascript">
22177 * @class Roo.dd.DragZone
22178 * @extends Roo.dd.DragSource
22179 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22180 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22182 * @param {String/HTMLElement/Element} el The container element
22183 * @param {Object} config
22185 Roo.dd.DragZone = function(el, config){
22186 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22187 if(this.containerScroll){
22188 Roo.dd.ScrollManager.register(this.el);
22192 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22194 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22195 * for auto scrolling during drag operations.
22198 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22199 * method after a failed drop (defaults to "c3daf9" - light blue)
22203 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22204 * for a valid target to drag based on the mouse down. Override this method
22205 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22206 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22207 * @param {EventObject} e The mouse down event
22208 * @return {Object} The dragData
22210 getDragData : function(e){
22211 return Roo.dd.Registry.getHandleFromEvent(e);
22215 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22216 * this.dragData.ddel
22217 * @param {Number} x The x position of the click on the dragged object
22218 * @param {Number} y The y position of the click on the dragged object
22219 * @return {Boolean} true to continue the drag, false to cancel
22221 onInitDrag : function(x, y){
22222 this.proxy.update(this.dragData.ddel.cloneNode(true));
22223 this.onStartDrag(x, y);
22228 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22230 afterRepair : function(){
22232 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22234 this.dragging = false;
22238 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22239 * the XY of this.dragData.ddel
22240 * @param {EventObject} e The mouse up event
22241 * @return {Array} The xy location (e.g. [100, 200])
22243 getRepairXY : function(e){
22244 return Roo.Element.fly(this.dragData.ddel).getXY();
22248 * Ext JS Library 1.1.1
22249 * Copyright(c) 2006-2007, Ext JS, LLC.
22251 * Originally Released Under LGPL - original licence link has changed is not relivant.
22254 * <script type="text/javascript">
22257 * @class Roo.dd.DropZone
22258 * @extends Roo.dd.DropTarget
22259 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22260 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22262 * @param {String/HTMLElement/Element} el The container element
22263 * @param {Object} config
22265 Roo.dd.DropZone = function(el, config){
22266 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22269 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22271 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22272 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22273 * provide your own custom lookup.
22274 * @param {Event} e The event
22275 * @return {Object} data The custom data
22277 getTargetFromEvent : function(e){
22278 return Roo.dd.Registry.getTargetFromEvent(e);
22282 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22283 * that it has registered. This method has no default implementation and should be overridden to provide
22284 * node-specific processing if necessary.
22285 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22286 * {@link #getTargetFromEvent} for this node)
22287 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22288 * @param {Event} e The event
22289 * @param {Object} data An object containing arbitrary data supplied by the drag source
22291 onNodeEnter : function(n, dd, e, data){
22296 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22297 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22298 * overridden to provide the proper feedback.
22299 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22300 * {@link #getTargetFromEvent} for this node)
22301 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22302 * @param {Event} e The event
22303 * @param {Object} data An object containing arbitrary data supplied by the drag source
22304 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22305 * underlying {@link Roo.dd.StatusProxy} can be updated
22307 onNodeOver : function(n, dd, e, data){
22308 return this.dropAllowed;
22312 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22313 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22314 * node-specific processing if necessary.
22315 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22316 * {@link #getTargetFromEvent} for this node)
22317 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22318 * @param {Event} e The event
22319 * @param {Object} data An object containing arbitrary data supplied by the drag source
22321 onNodeOut : function(n, dd, e, data){
22326 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22327 * the drop node. The default implementation returns false, so it should be overridden to provide the
22328 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22329 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22330 * {@link #getTargetFromEvent} for this node)
22331 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22332 * @param {Event} e The event
22333 * @param {Object} data An object containing arbitrary data supplied by the drag source
22334 * @return {Boolean} True if the drop was valid, else false
22336 onNodeDrop : function(n, dd, e, data){
22341 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22342 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22343 * it should be overridden to provide the proper feedback if necessary.
22344 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22345 * @param {Event} e The event
22346 * @param {Object} data An object containing arbitrary data supplied by the drag source
22347 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22348 * underlying {@link Roo.dd.StatusProxy} can be updated
22350 onContainerOver : function(dd, e, data){
22351 return this.dropNotAllowed;
22355 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22356 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22357 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22358 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22359 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22360 * @param {Event} e The event
22361 * @param {Object} data An object containing arbitrary data supplied by the drag source
22362 * @return {Boolean} True if the drop was valid, else false
22364 onContainerDrop : function(dd, e, data){
22369 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22370 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22371 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22372 * you should override this method and provide a custom implementation.
22373 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22374 * @param {Event} e The event
22375 * @param {Object} data An object containing arbitrary data supplied by the drag source
22376 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22377 * underlying {@link Roo.dd.StatusProxy} can be updated
22379 notifyEnter : function(dd, e, data){
22380 return this.dropNotAllowed;
22384 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22385 * This method will be called on every mouse movement while the drag source is over the drop zone.
22386 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22387 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22388 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22389 * registered node, it will call {@link #onContainerOver}.
22390 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22391 * @param {Event} e The event
22392 * @param {Object} data An object containing arbitrary data supplied by the drag source
22393 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22394 * underlying {@link Roo.dd.StatusProxy} can be updated
22396 notifyOver : function(dd, e, data){
22397 var n = this.getTargetFromEvent(e);
22398 if(!n){ // not over valid drop target
22399 if(this.lastOverNode){
22400 this.onNodeOut(this.lastOverNode, dd, e, data);
22401 this.lastOverNode = null;
22403 return this.onContainerOver(dd, e, data);
22405 if(this.lastOverNode != n){
22406 if(this.lastOverNode){
22407 this.onNodeOut(this.lastOverNode, dd, e, data);
22409 this.onNodeEnter(n, dd, e, data);
22410 this.lastOverNode = n;
22412 return this.onNodeOver(n, dd, e, data);
22416 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22417 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22418 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22419 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22420 * @param {Event} e The event
22421 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22423 notifyOut : function(dd, e, data){
22424 if(this.lastOverNode){
22425 this.onNodeOut(this.lastOverNode, dd, e, data);
22426 this.lastOverNode = null;
22431 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22432 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22433 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22434 * otherwise it will call {@link #onContainerDrop}.
22435 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22436 * @param {Event} e The event
22437 * @param {Object} data An object containing arbitrary data supplied by the drag source
22438 * @return {Boolean} True if the drop was valid, else false
22440 notifyDrop : function(dd, e, data){
22441 if(this.lastOverNode){
22442 this.onNodeOut(this.lastOverNode, dd, e, data);
22443 this.lastOverNode = null;
22445 var n = this.getTargetFromEvent(e);
22447 this.onNodeDrop(n, dd, e, data) :
22448 this.onContainerDrop(dd, e, data);
22452 triggerCacheRefresh : function(){
22453 Roo.dd.DDM.refreshCache(this.groups);
22457 * Ext JS Library 1.1.1
22458 * Copyright(c) 2006-2007, Ext JS, LLC.
22460 * Originally Released Under LGPL - original licence link has changed is not relivant.
22463 * <script type="text/javascript">
22468 * @class Roo.data.SortTypes
22470 * Defines the default sorting (casting?) comparison functions used when sorting data.
22472 Roo.data.SortTypes = {
22474 * Default sort that does nothing
22475 * @param {Mixed} s The value being converted
22476 * @return {Mixed} The comparison value
22478 none : function(s){
22483 * The regular expression used to strip tags
22487 stripTagsRE : /<\/?[^>]+>/gi,
22490 * Strips all HTML tags to sort on text only
22491 * @param {Mixed} s The value being converted
22492 * @return {String} The comparison value
22494 asText : function(s){
22495 return String(s).replace(this.stripTagsRE, "");
22499 * Strips all HTML tags to sort on text only - Case insensitive
22500 * @param {Mixed} s The value being converted
22501 * @return {String} The comparison value
22503 asUCText : function(s){
22504 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22508 * Case insensitive string
22509 * @param {Mixed} s The value being converted
22510 * @return {String} The comparison value
22512 asUCString : function(s) {
22513 return String(s).toUpperCase();
22518 * @param {Mixed} s The value being converted
22519 * @return {Number} The comparison value
22521 asDate : function(s) {
22525 if(s instanceof Date){
22526 return s.getTime();
22528 return Date.parse(String(s));
22533 * @param {Mixed} s The value being converted
22534 * @return {Float} The comparison value
22536 asFloat : function(s) {
22537 var val = parseFloat(String(s).replace(/,/g, ""));
22546 * @param {Mixed} s The value being converted
22547 * @return {Number} The comparison value
22549 asInt : function(s) {
22550 var val = parseInt(String(s).replace(/,/g, ""));
22558 * Ext JS Library 1.1.1
22559 * Copyright(c) 2006-2007, Ext JS, LLC.
22561 * Originally Released Under LGPL - original licence link has changed is not relivant.
22564 * <script type="text/javascript">
22568 * @class Roo.data.Record
22569 * Instances of this class encapsulate both record <em>definition</em> information, and record
22570 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22571 * to access Records cached in an {@link Roo.data.Store} object.<br>
22573 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22574 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22577 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22579 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22580 * {@link #create}. The parameters are the same.
22581 * @param {Array} data An associative Array of data values keyed by the field name.
22582 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22583 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22584 * not specified an integer id is generated.
22586 Roo.data.Record = function(data, id){
22587 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22592 * Generate a constructor for a specific record layout.
22593 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22594 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22595 * Each field definition object may contain the following properties: <ul>
22596 * <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,
22597 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22598 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22599 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22600 * is being used, then this is a string containing the javascript expression to reference the data relative to
22601 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22602 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22603 * this may be omitted.</p></li>
22604 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22605 * <ul><li>auto (Default, implies no conversion)</li>
22610 * <li>date</li></ul></p></li>
22611 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22612 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22613 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22614 * by the Reader into an object that will be stored in the Record. It is passed the
22615 * following parameters:<ul>
22616 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22618 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22620 * <br>usage:<br><pre><code>
22621 var TopicRecord = Roo.data.Record.create(
22622 {name: 'title', mapping: 'topic_title'},
22623 {name: 'author', mapping: 'username'},
22624 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22625 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22626 {name: 'lastPoster', mapping: 'user2'},
22627 {name: 'excerpt', mapping: 'post_text'}
22630 var myNewRecord = new TopicRecord({
22631 title: 'Do my job please',
22634 lastPost: new Date(),
22635 lastPoster: 'Animal',
22636 excerpt: 'No way dude!'
22638 myStore.add(myNewRecord);
22643 Roo.data.Record.create = function(o){
22644 var f = function(){
22645 f.superclass.constructor.apply(this, arguments);
22647 Roo.extend(f, Roo.data.Record);
22648 var p = f.prototype;
22649 p.fields = new Roo.util.MixedCollection(false, function(field){
22652 for(var i = 0, len = o.length; i < len; i++){
22653 p.fields.add(new Roo.data.Field(o[i]));
22655 f.getField = function(name){
22656 return p.fields.get(name);
22661 Roo.data.Record.AUTO_ID = 1000;
22662 Roo.data.Record.EDIT = 'edit';
22663 Roo.data.Record.REJECT = 'reject';
22664 Roo.data.Record.COMMIT = 'commit';
22666 Roo.data.Record.prototype = {
22668 * Readonly flag - true if this record has been modified.
22677 join : function(store){
22678 this.store = store;
22682 * Set the named field to the specified value.
22683 * @param {String} name The name of the field to set.
22684 * @param {Object} value The value to set the field to.
22686 set : function(name, value){
22687 if(this.data[name] == value){
22691 if(!this.modified){
22692 this.modified = {};
22694 if(typeof this.modified[name] == 'undefined'){
22695 this.modified[name] = this.data[name];
22697 this.data[name] = value;
22698 if(!this.editing && this.store){
22699 this.store.afterEdit(this);
22704 * Get the value of the named field.
22705 * @param {String} name The name of the field to get the value of.
22706 * @return {Object} The value of the field.
22708 get : function(name){
22709 return this.data[name];
22713 beginEdit : function(){
22714 this.editing = true;
22715 this.modified = {};
22719 cancelEdit : function(){
22720 this.editing = false;
22721 delete this.modified;
22725 endEdit : function(){
22726 this.editing = false;
22727 if(this.dirty && this.store){
22728 this.store.afterEdit(this);
22733 * Usually called by the {@link Roo.data.Store} which owns the Record.
22734 * Rejects all changes made to the Record since either creation, or the last commit operation.
22735 * Modified fields are reverted to their original values.
22737 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22738 * of reject operations.
22740 reject : function(){
22741 var m = this.modified;
22743 if(typeof m[n] != "function"){
22744 this.data[n] = m[n];
22747 this.dirty = false;
22748 delete this.modified;
22749 this.editing = false;
22751 this.store.afterReject(this);
22756 * Usually called by the {@link Roo.data.Store} which owns the Record.
22757 * Commits all changes made to the Record since either creation, or the last commit operation.
22759 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22760 * of commit operations.
22762 commit : function(){
22763 this.dirty = false;
22764 delete this.modified;
22765 this.editing = false;
22767 this.store.afterCommit(this);
22772 hasError : function(){
22773 return this.error != null;
22777 clearError : function(){
22782 * Creates a copy of this record.
22783 * @param {String} id (optional) A new record id if you don't want to use this record's id
22786 copy : function(newId) {
22787 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22791 * Ext JS Library 1.1.1
22792 * Copyright(c) 2006-2007, Ext JS, LLC.
22794 * Originally Released Under LGPL - original licence link has changed is not relivant.
22797 * <script type="text/javascript">
22803 * @class Roo.data.Store
22804 * @extends Roo.util.Observable
22805 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22806 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22808 * 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
22809 * has no knowledge of the format of the data returned by the Proxy.<br>
22811 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22812 * instances from the data object. These records are cached and made available through accessor functions.
22814 * Creates a new Store.
22815 * @param {Object} config A config object containing the objects needed for the Store to access data,
22816 * and read the data into Records.
22818 Roo.data.Store = function(config){
22819 this.data = new Roo.util.MixedCollection(false);
22820 this.data.getKey = function(o){
22823 this.baseParams = {};
22825 this.paramNames = {
22830 "multisort" : "_multisort"
22833 if(config && config.data){
22834 this.inlineData = config.data;
22835 delete config.data;
22838 Roo.apply(this, config);
22840 if(this.reader){ // reader passed
22841 this.reader = Roo.factory(this.reader, Roo.data);
22842 this.reader.xmodule = this.xmodule || false;
22843 if(!this.recordType){
22844 this.recordType = this.reader.recordType;
22846 if(this.reader.onMetaChange){
22847 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22851 if(this.recordType){
22852 this.fields = this.recordType.prototype.fields;
22854 this.modified = [];
22858 * @event datachanged
22859 * Fires when the data cache has changed, and a widget which is using this Store
22860 * as a Record cache should refresh its view.
22861 * @param {Store} this
22863 datachanged : true,
22865 * @event metachange
22866 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22867 * @param {Store} this
22868 * @param {Object} meta The JSON metadata
22873 * Fires when Records have been added to the Store
22874 * @param {Store} this
22875 * @param {Roo.data.Record[]} records The array of Records added
22876 * @param {Number} index The index at which the record(s) were added
22881 * Fires when a Record has been removed from the Store
22882 * @param {Store} this
22883 * @param {Roo.data.Record} record The Record that was removed
22884 * @param {Number} index The index at which the record was removed
22889 * Fires when a Record has been updated
22890 * @param {Store} this
22891 * @param {Roo.data.Record} record The Record that was updated
22892 * @param {String} operation The update operation being performed. Value may be one of:
22894 Roo.data.Record.EDIT
22895 Roo.data.Record.REJECT
22896 Roo.data.Record.COMMIT
22902 * Fires when the data cache has been cleared.
22903 * @param {Store} this
22907 * @event beforeload
22908 * Fires before a request is made for a new data object. If the beforeload handler returns false
22909 * the load action will be canceled.
22910 * @param {Store} this
22911 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22915 * @event beforeloadadd
22916 * Fires after a new set of Records has been loaded.
22917 * @param {Store} this
22918 * @param {Roo.data.Record[]} records The Records that were loaded
22919 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22921 beforeloadadd : true,
22924 * Fires after a new set of Records has been loaded, before they are added to the store.
22925 * @param {Store} this
22926 * @param {Roo.data.Record[]} records The Records that were loaded
22927 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22928 * @params {Object} return from reader
22932 * @event loadexception
22933 * Fires if an exception occurs in the Proxy during loading.
22934 * Called with the signature of the Proxy's "loadexception" event.
22935 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22938 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22939 * @param {Object} load options
22940 * @param {Object} jsonData from your request (normally this contains the Exception)
22942 loadexception : true
22946 this.proxy = Roo.factory(this.proxy, Roo.data);
22947 this.proxy.xmodule = this.xmodule || false;
22948 this.relayEvents(this.proxy, ["loadexception"]);
22950 this.sortToggle = {};
22951 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22953 Roo.data.Store.superclass.constructor.call(this);
22955 if(this.inlineData){
22956 this.loadData(this.inlineData);
22957 delete this.inlineData;
22961 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22963 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22964 * without a remote query - used by combo/forms at present.
22968 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22971 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22974 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22975 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22978 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22979 * on any HTTP request
22982 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22985 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22989 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22990 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22992 remoteSort : false,
22995 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22996 * loaded or when a record is removed. (defaults to false).
22998 pruneModifiedRecords : false,
23001 lastOptions : null,
23004 * Add Records to the Store and fires the add event.
23005 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23007 add : function(records){
23008 records = [].concat(records);
23009 for(var i = 0, len = records.length; i < len; i++){
23010 records[i].join(this);
23012 var index = this.data.length;
23013 this.data.addAll(records);
23014 this.fireEvent("add", this, records, index);
23018 * Remove a Record from the Store and fires the remove event.
23019 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
23021 remove : function(record){
23022 var index = this.data.indexOf(record);
23023 this.data.removeAt(index);
23025 if(this.pruneModifiedRecords){
23026 this.modified.remove(record);
23028 this.fireEvent("remove", this, record, index);
23032 * Remove all Records from the Store and fires the clear event.
23034 removeAll : function(){
23036 if(this.pruneModifiedRecords){
23037 this.modified = [];
23039 this.fireEvent("clear", this);
23043 * Inserts Records to the Store at the given index and fires the add event.
23044 * @param {Number} index The start index at which to insert the passed Records.
23045 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23047 insert : function(index, records){
23048 records = [].concat(records);
23049 for(var i = 0, len = records.length; i < len; i++){
23050 this.data.insert(index, records[i]);
23051 records[i].join(this);
23053 this.fireEvent("add", this, records, index);
23057 * Get the index within the cache of the passed Record.
23058 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
23059 * @return {Number} The index of the passed Record. Returns -1 if not found.
23061 indexOf : function(record){
23062 return this.data.indexOf(record);
23066 * Get the index within the cache of the Record with the passed id.
23067 * @param {String} id The id of the Record to find.
23068 * @return {Number} The index of the Record. Returns -1 if not found.
23070 indexOfId : function(id){
23071 return this.data.indexOfKey(id);
23075 * Get the Record with the specified id.
23076 * @param {String} id The id of the Record to find.
23077 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
23079 getById : function(id){
23080 return this.data.key(id);
23084 * Get the Record at the specified index.
23085 * @param {Number} index The index of the Record to find.
23086 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
23088 getAt : function(index){
23089 return this.data.itemAt(index);
23093 * Returns a range of Records between specified indices.
23094 * @param {Number} startIndex (optional) The starting index (defaults to 0)
23095 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
23096 * @return {Roo.data.Record[]} An array of Records
23098 getRange : function(start, end){
23099 return this.data.getRange(start, end);
23103 storeOptions : function(o){
23104 o = Roo.apply({}, o);
23107 this.lastOptions = o;
23111 * Loads the Record cache from the configured Proxy using the configured Reader.
23113 * If using remote paging, then the first load call must specify the <em>start</em>
23114 * and <em>limit</em> properties in the options.params property to establish the initial
23115 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23117 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23118 * and this call will return before the new data has been loaded. Perform any post-processing
23119 * in a callback function, or in a "load" event handler.</strong>
23121 * @param {Object} options An object containing properties which control loading options:<ul>
23122 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23123 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23124 * passed the following arguments:<ul>
23125 * <li>r : Roo.data.Record[]</li>
23126 * <li>options: Options object from the load call</li>
23127 * <li>success: Boolean success indicator</li></ul></li>
23128 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23129 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23132 load : function(options){
23133 options = options || {};
23134 if(this.fireEvent("beforeload", this, options) !== false){
23135 this.storeOptions(options);
23136 var p = Roo.apply(options.params || {}, this.baseParams);
23137 // if meta was not loaded from remote source.. try requesting it.
23138 if (!this.reader.metaFromRemote) {
23139 p._requestMeta = 1;
23141 if(this.sortInfo && this.remoteSort){
23142 var pn = this.paramNames;
23143 p[pn["sort"]] = this.sortInfo.field;
23144 p[pn["dir"]] = this.sortInfo.direction;
23146 if (this.multiSort) {
23147 var pn = this.paramNames;
23148 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23151 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23156 * Reloads the Record cache from the configured Proxy using the configured Reader and
23157 * the options from the last load operation performed.
23158 * @param {Object} options (optional) An object containing properties which may override the options
23159 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23160 * the most recently used options are reused).
23162 reload : function(options){
23163 this.load(Roo.applyIf(options||{}, this.lastOptions));
23167 // Called as a callback by the Reader during a load operation.
23168 loadRecords : function(o, options, success){
23169 if(!o || success === false){
23170 if(success !== false){
23171 this.fireEvent("load", this, [], options, o);
23173 if(options.callback){
23174 options.callback.call(options.scope || this, [], options, false);
23178 // if data returned failure - throw an exception.
23179 if (o.success === false) {
23180 // show a message if no listener is registered.
23181 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23182 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23184 // loadmask wil be hooked into this..
23185 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23188 var r = o.records, t = o.totalRecords || r.length;
23190 this.fireEvent("beforeloadadd", this, r, options, o);
23192 if(!options || options.add !== true){
23193 if(this.pruneModifiedRecords){
23194 this.modified = [];
23196 for(var i = 0, len = r.length; i < len; i++){
23200 this.data = this.snapshot;
23201 delete this.snapshot;
23204 this.data.addAll(r);
23205 this.totalLength = t;
23207 this.fireEvent("datachanged", this);
23209 this.totalLength = Math.max(t, this.data.length+r.length);
23213 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23215 var e = new Roo.data.Record({});
23217 e.set(this.parent.displayField, this.parent.emptyTitle);
23218 e.set(this.parent.valueField, '');
23223 this.fireEvent("load", this, r, options, o);
23224 if(options.callback){
23225 options.callback.call(options.scope || this, r, options, true);
23231 * Loads data from a passed data block. A Reader which understands the format of the data
23232 * must have been configured in the constructor.
23233 * @param {Object} data The data block from which to read the Records. The format of the data expected
23234 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23235 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23237 loadData : function(o, append){
23238 var r = this.reader.readRecords(o);
23239 this.loadRecords(r, {add: append}, true);
23243 * Gets the number of cached records.
23245 * <em>If using paging, this may not be the total size of the dataset. If the data object
23246 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23247 * the data set size</em>
23249 getCount : function(){
23250 return this.data.length || 0;
23254 * Gets the total number of records in the dataset as returned by the server.
23256 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23257 * the dataset size</em>
23259 getTotalCount : function(){
23260 return this.totalLength || 0;
23264 * Returns the sort state of the Store as an object with two properties:
23266 field {String} The name of the field by which the Records are sorted
23267 direction {String} The sort order, "ASC" or "DESC"
23270 getSortState : function(){
23271 return this.sortInfo;
23275 applySort : function(){
23276 if(this.sortInfo && !this.remoteSort){
23277 var s = this.sortInfo, f = s.field;
23278 var st = this.fields.get(f).sortType;
23279 var fn = function(r1, r2){
23280 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23281 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23283 this.data.sort(s.direction, fn);
23284 if(this.snapshot && this.snapshot != this.data){
23285 this.snapshot.sort(s.direction, fn);
23291 * Sets the default sort column and order to be used by the next load operation.
23292 * @param {String} fieldName The name of the field to sort by.
23293 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23295 setDefaultSort : function(field, dir){
23296 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23300 * Sort the Records.
23301 * If remote sorting is used, the sort is performed on the server, and the cache is
23302 * reloaded. If local sorting is used, the cache is sorted internally.
23303 * @param {String} fieldName The name of the field to sort by.
23304 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23306 sort : function(fieldName, dir){
23307 var f = this.fields.get(fieldName);
23309 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23311 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23312 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23317 this.sortToggle[f.name] = dir;
23318 this.sortInfo = {field: f.name, direction: dir};
23319 if(!this.remoteSort){
23321 this.fireEvent("datachanged", this);
23323 this.load(this.lastOptions);
23328 * Calls the specified function for each of the Records in the cache.
23329 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23330 * Returning <em>false</em> aborts and exits the iteration.
23331 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23333 each : function(fn, scope){
23334 this.data.each(fn, scope);
23338 * Gets all records modified since the last commit. Modified records are persisted across load operations
23339 * (e.g., during paging).
23340 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23342 getModifiedRecords : function(){
23343 return this.modified;
23347 createFilterFn : function(property, value, anyMatch){
23348 if(!value.exec){ // not a regex
23349 value = String(value);
23350 if(value.length == 0){
23353 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23355 return function(r){
23356 return value.test(r.data[property]);
23361 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23362 * @param {String} property A field on your records
23363 * @param {Number} start The record index to start at (defaults to 0)
23364 * @param {Number} end The last record index to include (defaults to length - 1)
23365 * @return {Number} The sum
23367 sum : function(property, start, end){
23368 var rs = this.data.items, v = 0;
23369 start = start || 0;
23370 end = (end || end === 0) ? end : rs.length-1;
23372 for(var i = start; i <= end; i++){
23373 v += (rs[i].data[property] || 0);
23379 * Filter the records by a specified property.
23380 * @param {String} field A field on your records
23381 * @param {String/RegExp} value Either a string that the field
23382 * should start with or a RegExp to test against the field
23383 * @param {Boolean} anyMatch True to match any part not just the beginning
23385 filter : function(property, value, anyMatch){
23386 var fn = this.createFilterFn(property, value, anyMatch);
23387 return fn ? this.filterBy(fn) : this.clearFilter();
23391 * Filter by a function. The specified function will be called with each
23392 * record in this data source. If the function returns true the record is included,
23393 * otherwise it is filtered.
23394 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23395 * @param {Object} scope (optional) The scope of the function (defaults to this)
23397 filterBy : function(fn, scope){
23398 this.snapshot = this.snapshot || this.data;
23399 this.data = this.queryBy(fn, scope||this);
23400 this.fireEvent("datachanged", this);
23404 * Query the records by a specified property.
23405 * @param {String} field A field on your records
23406 * @param {String/RegExp} value Either a string that the field
23407 * should start with or a RegExp to test against the field
23408 * @param {Boolean} anyMatch True to match any part not just the beginning
23409 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23411 query : function(property, value, anyMatch){
23412 var fn = this.createFilterFn(property, value, anyMatch);
23413 return fn ? this.queryBy(fn) : this.data.clone();
23417 * Query by a function. The specified function will be called with each
23418 * record in this data source. If the function returns true the record is included
23420 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23421 * @param {Object} scope (optional) The scope of the function (defaults to this)
23422 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23424 queryBy : function(fn, scope){
23425 var data = this.snapshot || this.data;
23426 return data.filterBy(fn, scope||this);
23430 * Collects unique values for a particular dataIndex from this store.
23431 * @param {String} dataIndex The property to collect
23432 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23433 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23434 * @return {Array} An array of the unique values
23436 collect : function(dataIndex, allowNull, bypassFilter){
23437 var d = (bypassFilter === true && this.snapshot) ?
23438 this.snapshot.items : this.data.items;
23439 var v, sv, r = [], l = {};
23440 for(var i = 0, len = d.length; i < len; i++){
23441 v = d[i].data[dataIndex];
23443 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23452 * Revert to a view of the Record cache with no filtering applied.
23453 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23455 clearFilter : function(suppressEvent){
23456 if(this.snapshot && this.snapshot != this.data){
23457 this.data = this.snapshot;
23458 delete this.snapshot;
23459 if(suppressEvent !== true){
23460 this.fireEvent("datachanged", this);
23466 afterEdit : function(record){
23467 if(this.modified.indexOf(record) == -1){
23468 this.modified.push(record);
23470 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23474 afterReject : function(record){
23475 this.modified.remove(record);
23476 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23480 afterCommit : function(record){
23481 this.modified.remove(record);
23482 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23486 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23487 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23489 commitChanges : function(){
23490 var m = this.modified.slice(0);
23491 this.modified = [];
23492 for(var i = 0, len = m.length; i < len; i++){
23498 * Cancel outstanding changes on all changed records.
23500 rejectChanges : function(){
23501 var m = this.modified.slice(0);
23502 this.modified = [];
23503 for(var i = 0, len = m.length; i < len; i++){
23508 onMetaChange : function(meta, rtype, o){
23509 this.recordType = rtype;
23510 this.fields = rtype.prototype.fields;
23511 delete this.snapshot;
23512 this.sortInfo = meta.sortInfo || this.sortInfo;
23513 this.modified = [];
23514 this.fireEvent('metachange', this, this.reader.meta);
23517 moveIndex : function(data, type)
23519 var index = this.indexOf(data);
23521 var newIndex = index + type;
23525 this.insert(newIndex, data);
23530 * Ext JS Library 1.1.1
23531 * Copyright(c) 2006-2007, Ext JS, LLC.
23533 * Originally Released Under LGPL - original licence link has changed is not relivant.
23536 * <script type="text/javascript">
23540 * @class Roo.data.SimpleStore
23541 * @extends Roo.data.Store
23542 * Small helper class to make creating Stores from Array data easier.
23543 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23544 * @cfg {Array} fields An array of field definition objects, or field name strings.
23545 * @cfg {Array} data The multi-dimensional array of data
23547 * @param {Object} config
23549 Roo.data.SimpleStore = function(config){
23550 Roo.data.SimpleStore.superclass.constructor.call(this, {
23552 reader: new Roo.data.ArrayReader({
23555 Roo.data.Record.create(config.fields)
23557 proxy : new Roo.data.MemoryProxy(config.data)
23561 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23563 * Ext JS Library 1.1.1
23564 * Copyright(c) 2006-2007, Ext JS, LLC.
23566 * Originally Released Under LGPL - original licence link has changed is not relivant.
23569 * <script type="text/javascript">
23574 * @extends Roo.data.Store
23575 * @class Roo.data.JsonStore
23576 * Small helper class to make creating Stores for JSON data easier. <br/>
23578 var store = new Roo.data.JsonStore({
23579 url: 'get-images.php',
23581 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23584 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23585 * JsonReader and HttpProxy (unless inline data is provided).</b>
23586 * @cfg {Array} fields An array of field definition objects, or field name strings.
23588 * @param {Object} config
23590 Roo.data.JsonStore = function(c){
23591 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23592 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23593 reader: new Roo.data.JsonReader(c, c.fields)
23596 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23598 * Ext JS Library 1.1.1
23599 * Copyright(c) 2006-2007, Ext JS, LLC.
23601 * Originally Released Under LGPL - original licence link has changed is not relivant.
23604 * <script type="text/javascript">
23608 Roo.data.Field = function(config){
23609 if(typeof config == "string"){
23610 config = {name: config};
23612 Roo.apply(this, config);
23615 this.type = "auto";
23618 var st = Roo.data.SortTypes;
23619 // named sortTypes are supported, here we look them up
23620 if(typeof this.sortType == "string"){
23621 this.sortType = st[this.sortType];
23624 // set default sortType for strings and dates
23625 if(!this.sortType){
23628 this.sortType = st.asUCString;
23631 this.sortType = st.asDate;
23634 this.sortType = st.none;
23639 var stripRe = /[\$,%]/g;
23641 // prebuilt conversion function for this field, instead of
23642 // switching every time we're reading a value
23644 var cv, dateFormat = this.dateFormat;
23649 cv = function(v){ return v; };
23652 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23656 return v !== undefined && v !== null && v !== '' ?
23657 parseInt(String(v).replace(stripRe, ""), 10) : '';
23662 return v !== undefined && v !== null && v !== '' ?
23663 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23668 cv = function(v){ return v === true || v === "true" || v == 1; };
23675 if(v instanceof Date){
23679 if(dateFormat == "timestamp"){
23680 return new Date(v*1000);
23682 return Date.parseDate(v, dateFormat);
23684 var parsed = Date.parse(v);
23685 return parsed ? new Date(parsed) : null;
23694 Roo.data.Field.prototype = {
23702 * Ext JS Library 1.1.1
23703 * Copyright(c) 2006-2007, Ext JS, LLC.
23705 * Originally Released Under LGPL - original licence link has changed is not relivant.
23708 * <script type="text/javascript">
23711 // Base class for reading structured data from a data source. This class is intended to be
23712 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23715 * @class Roo.data.DataReader
23716 * Base class for reading structured data from a data source. This class is intended to be
23717 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23720 Roo.data.DataReader = function(meta, recordType){
23724 this.recordType = recordType instanceof Array ?
23725 Roo.data.Record.create(recordType) : recordType;
23728 Roo.data.DataReader.prototype = {
23730 * Create an empty record
23731 * @param {Object} data (optional) - overlay some values
23732 * @return {Roo.data.Record} record created.
23734 newRow : function(d) {
23736 this.recordType.prototype.fields.each(function(c) {
23738 case 'int' : da[c.name] = 0; break;
23739 case 'date' : da[c.name] = new Date(); break;
23740 case 'float' : da[c.name] = 0.0; break;
23741 case 'boolean' : da[c.name] = false; break;
23742 default : da[c.name] = ""; break;
23746 return new this.recordType(Roo.apply(da, d));
23751 * Ext JS Library 1.1.1
23752 * Copyright(c) 2006-2007, Ext JS, LLC.
23754 * Originally Released Under LGPL - original licence link has changed is not relivant.
23757 * <script type="text/javascript">
23761 * @class Roo.data.DataProxy
23762 * @extends Roo.data.Observable
23763 * This class is an abstract base class for implementations which provide retrieval of
23764 * unformatted data objects.<br>
23766 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23767 * (of the appropriate type which knows how to parse the data object) to provide a block of
23768 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23770 * Custom implementations must implement the load method as described in
23771 * {@link Roo.data.HttpProxy#load}.
23773 Roo.data.DataProxy = function(){
23776 * @event beforeload
23777 * Fires before a network request is made to retrieve a data object.
23778 * @param {Object} This DataProxy object.
23779 * @param {Object} params The params parameter to the load function.
23784 * Fires before the load method's callback is called.
23785 * @param {Object} This DataProxy object.
23786 * @param {Object} o The data object.
23787 * @param {Object} arg The callback argument object passed to the load function.
23791 * @event loadexception
23792 * Fires if an Exception occurs during data retrieval.
23793 * @param {Object} This DataProxy object.
23794 * @param {Object} o The data object.
23795 * @param {Object} arg The callback argument object passed to the load function.
23796 * @param {Object} e The Exception.
23798 loadexception : true
23800 Roo.data.DataProxy.superclass.constructor.call(this);
23803 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23806 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23810 * Ext JS Library 1.1.1
23811 * Copyright(c) 2006-2007, Ext JS, LLC.
23813 * Originally Released Under LGPL - original licence link has changed is not relivant.
23816 * <script type="text/javascript">
23819 * @class Roo.data.MemoryProxy
23820 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23821 * to the Reader when its load method is called.
23823 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23825 Roo.data.MemoryProxy = function(data){
23829 Roo.data.MemoryProxy.superclass.constructor.call(this);
23833 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23836 * Load data from the requested source (in this case an in-memory
23837 * data object passed to the constructor), read the data object into
23838 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23839 * process that block using the passed callback.
23840 * @param {Object} params This parameter is not used by the MemoryProxy class.
23841 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23842 * object into a block of Roo.data.Records.
23843 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23844 * The function must be passed <ul>
23845 * <li>The Record block object</li>
23846 * <li>The "arg" argument from the load function</li>
23847 * <li>A boolean success indicator</li>
23849 * @param {Object} scope The scope in which to call the callback
23850 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23852 load : function(params, reader, callback, scope, arg){
23853 params = params || {};
23856 result = reader.readRecords(params.data ? params.data :this.data);
23858 this.fireEvent("loadexception", this, arg, null, e);
23859 callback.call(scope, null, arg, false);
23862 callback.call(scope, result, arg, true);
23866 update : function(params, records){
23871 * Ext JS Library 1.1.1
23872 * Copyright(c) 2006-2007, Ext JS, LLC.
23874 * Originally Released Under LGPL - original licence link has changed is not relivant.
23877 * <script type="text/javascript">
23880 * @class Roo.data.HttpProxy
23881 * @extends Roo.data.DataProxy
23882 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23883 * configured to reference a certain URL.<br><br>
23885 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23886 * from which the running page was served.<br><br>
23888 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23890 * Be aware that to enable the browser to parse an XML document, the server must set
23891 * the Content-Type header in the HTTP response to "text/xml".
23893 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23894 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23895 * will be used to make the request.
23897 Roo.data.HttpProxy = function(conn){
23898 Roo.data.HttpProxy.superclass.constructor.call(this);
23899 // is conn a conn config or a real conn?
23901 this.useAjax = !conn || !conn.events;
23905 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23906 // thse are take from connection...
23909 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23912 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23913 * extra parameters to each request made by this object. (defaults to undefined)
23916 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23917 * to each request made by this object. (defaults to undefined)
23920 * @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)
23923 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23926 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23932 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23936 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23937 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23938 * a finer-grained basis than the DataProxy events.
23940 getConnection : function(){
23941 return this.useAjax ? Roo.Ajax : this.conn;
23945 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23946 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23947 * process that block using the passed callback.
23948 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23949 * for the request to the remote server.
23950 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23951 * object into a block of Roo.data.Records.
23952 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23953 * The function must be passed <ul>
23954 * <li>The Record block object</li>
23955 * <li>The "arg" argument from the load function</li>
23956 * <li>A boolean success indicator</li>
23958 * @param {Object} scope The scope in which to call the callback
23959 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23961 load : function(params, reader, callback, scope, arg){
23962 if(this.fireEvent("beforeload", this, params) !== false){
23964 params : params || {},
23966 callback : callback,
23971 callback : this.loadResponse,
23975 Roo.applyIf(o, this.conn);
23976 if(this.activeRequest){
23977 Roo.Ajax.abort(this.activeRequest);
23979 this.activeRequest = Roo.Ajax.request(o);
23981 this.conn.request(o);
23984 callback.call(scope||this, null, arg, false);
23989 loadResponse : function(o, success, response){
23990 delete this.activeRequest;
23992 this.fireEvent("loadexception", this, o, response);
23993 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23998 result = o.reader.read(response);
24000 this.fireEvent("loadexception", this, o, response, e);
24001 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24005 this.fireEvent("load", this, o, o.request.arg);
24006 o.request.callback.call(o.request.scope, result, o.request.arg, true);
24010 update : function(dataSet){
24015 updateResponse : function(dataSet){
24020 * Ext JS Library 1.1.1
24021 * Copyright(c) 2006-2007, Ext JS, LLC.
24023 * Originally Released Under LGPL - original licence link has changed is not relivant.
24026 * <script type="text/javascript">
24030 * @class Roo.data.ScriptTagProxy
24031 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
24032 * other than the originating domain of the running page.<br><br>
24034 * <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
24035 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
24037 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
24038 * source code that is used as the source inside a <script> tag.<br><br>
24040 * In order for the browser to process the returned data, the server must wrap the data object
24041 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
24042 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
24043 * depending on whether the callback name was passed:
24046 boolean scriptTag = false;
24047 String cb = request.getParameter("callback");
24050 response.setContentType("text/javascript");
24052 response.setContentType("application/x-json");
24054 Writer out = response.getWriter();
24056 out.write(cb + "(");
24058 out.print(dataBlock.toJsonString());
24065 * @param {Object} config A configuration object.
24067 Roo.data.ScriptTagProxy = function(config){
24068 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24069 Roo.apply(this, config);
24070 this.head = document.getElementsByTagName("head")[0];
24073 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24075 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24077 * @cfg {String} url The URL from which to request the data object.
24080 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24084 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24085 * the server the name of the callback function set up by the load call to process the returned data object.
24086 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24087 * javascript output which calls this named function passing the data object as its only parameter.
24089 callbackParam : "callback",
24091 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24092 * name to the request.
24097 * Load data from the configured URL, read the data object into
24098 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24099 * process that block using the passed callback.
24100 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24101 * for the request to the remote server.
24102 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24103 * object into a block of Roo.data.Records.
24104 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24105 * The function must be passed <ul>
24106 * <li>The Record block object</li>
24107 * <li>The "arg" argument from the load function</li>
24108 * <li>A boolean success indicator</li>
24110 * @param {Object} scope The scope in which to call the callback
24111 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24113 load : function(params, reader, callback, scope, arg){
24114 if(this.fireEvent("beforeload", this, params) !== false){
24116 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24118 var url = this.url;
24119 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24121 url += "&_dc=" + (new Date().getTime());
24123 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24126 cb : "stcCallback"+transId,
24127 scriptId : "stcScript"+transId,
24131 callback : callback,
24137 window[trans.cb] = function(o){
24138 conn.handleResponse(o, trans);
24141 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24143 if(this.autoAbort !== false){
24147 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24149 var script = document.createElement("script");
24150 script.setAttribute("src", url);
24151 script.setAttribute("type", "text/javascript");
24152 script.setAttribute("id", trans.scriptId);
24153 this.head.appendChild(script);
24155 this.trans = trans;
24157 callback.call(scope||this, null, arg, false);
24162 isLoading : function(){
24163 return this.trans ? true : false;
24167 * Abort the current server request.
24169 abort : function(){
24170 if(this.isLoading()){
24171 this.destroyTrans(this.trans);
24176 destroyTrans : function(trans, isLoaded){
24177 this.head.removeChild(document.getElementById(trans.scriptId));
24178 clearTimeout(trans.timeoutId);
24180 window[trans.cb] = undefined;
24182 delete window[trans.cb];
24185 // if hasn't been loaded, wait for load to remove it to prevent script error
24186 window[trans.cb] = function(){
24187 window[trans.cb] = undefined;
24189 delete window[trans.cb];
24196 handleResponse : function(o, trans){
24197 this.trans = false;
24198 this.destroyTrans(trans, true);
24201 result = trans.reader.readRecords(o);
24203 this.fireEvent("loadexception", this, o, trans.arg, e);
24204 trans.callback.call(trans.scope||window, null, trans.arg, false);
24207 this.fireEvent("load", this, o, trans.arg);
24208 trans.callback.call(trans.scope||window, result, trans.arg, true);
24212 handleFailure : function(trans){
24213 this.trans = false;
24214 this.destroyTrans(trans, false);
24215 this.fireEvent("loadexception", this, null, trans.arg);
24216 trans.callback.call(trans.scope||window, null, trans.arg, false);
24220 * Ext JS Library 1.1.1
24221 * Copyright(c) 2006-2007, Ext JS, LLC.
24223 * Originally Released Under LGPL - original licence link has changed is not relivant.
24226 * <script type="text/javascript">
24230 * @class Roo.data.JsonReader
24231 * @extends Roo.data.DataReader
24232 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24233 * based on mappings in a provided Roo.data.Record constructor.
24235 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24236 * in the reply previously.
24241 var RecordDef = Roo.data.Record.create([
24242 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24243 {name: 'occupation'} // This field will use "occupation" as the mapping.
24245 var myReader = new Roo.data.JsonReader({
24246 totalProperty: "results", // The property which contains the total dataset size (optional)
24247 root: "rows", // The property which contains an Array of row objects
24248 id: "id" // The property within each row object that provides an ID for the record (optional)
24252 * This would consume a JSON file like this:
24254 { 'results': 2, 'rows': [
24255 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24256 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24259 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24260 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24261 * paged from the remote server.
24262 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24263 * @cfg {String} root name of the property which contains the Array of row objects.
24264 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24265 * @cfg {Array} fields Array of field definition objects
24267 * Create a new JsonReader
24268 * @param {Object} meta Metadata configuration options
24269 * @param {Object} recordType Either an Array of field definition objects,
24270 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24272 Roo.data.JsonReader = function(meta, recordType){
24275 // set some defaults:
24276 Roo.applyIf(meta, {
24277 totalProperty: 'total',
24278 successProperty : 'success',
24283 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24285 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24288 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24289 * Used by Store query builder to append _requestMeta to params.
24292 metaFromRemote : false,
24294 * This method is only used by a DataProxy which has retrieved data from a remote server.
24295 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24296 * @return {Object} data A data block which is used by an Roo.data.Store object as
24297 * a cache of Roo.data.Records.
24299 read : function(response){
24300 var json = response.responseText;
24302 var o = /* eval:var:o */ eval("("+json+")");
24304 throw {message: "JsonReader.read: Json object not found"};
24310 this.metaFromRemote = true;
24311 this.meta = o.metaData;
24312 this.recordType = Roo.data.Record.create(o.metaData.fields);
24313 this.onMetaChange(this.meta, this.recordType, o);
24315 return this.readRecords(o);
24318 // private function a store will implement
24319 onMetaChange : function(meta, recordType, o){
24326 simpleAccess: function(obj, subsc) {
24333 getJsonAccessor: function(){
24335 return function(expr) {
24337 return(re.test(expr))
24338 ? new Function("obj", "return obj." + expr)
24343 return Roo.emptyFn;
24348 * Create a data block containing Roo.data.Records from an XML document.
24349 * @param {Object} o An object which contains an Array of row objects in the property specified
24350 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24351 * which contains the total size of the dataset.
24352 * @return {Object} data A data block which is used by an Roo.data.Store object as
24353 * a cache of Roo.data.Records.
24355 readRecords : function(o){
24357 * After any data loads, the raw JSON data is available for further custom processing.
24361 var s = this.meta, Record = this.recordType,
24362 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24364 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24366 if(s.totalProperty) {
24367 this.getTotal = this.getJsonAccessor(s.totalProperty);
24369 if(s.successProperty) {
24370 this.getSuccess = this.getJsonAccessor(s.successProperty);
24372 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24374 var g = this.getJsonAccessor(s.id);
24375 this.getId = function(rec) {
24377 return (r === undefined || r === "") ? null : r;
24380 this.getId = function(){return null;};
24383 for(var jj = 0; jj < fl; jj++){
24385 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24386 this.ef[jj] = this.getJsonAccessor(map);
24390 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24391 if(s.totalProperty){
24392 var vt = parseInt(this.getTotal(o), 10);
24397 if(s.successProperty){
24398 var vs = this.getSuccess(o);
24399 if(vs === false || vs === 'false'){
24404 for(var i = 0; i < c; i++){
24407 var id = this.getId(n);
24408 for(var j = 0; j < fl; j++){
24410 var v = this.ef[j](n);
24412 Roo.log('missing convert for ' + f.name);
24416 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24418 var record = new Record(values, id);
24420 records[i] = record;
24426 totalRecords : totalRecords
24431 * Ext JS Library 1.1.1
24432 * Copyright(c) 2006-2007, Ext JS, LLC.
24434 * Originally Released Under LGPL - original licence link has changed is not relivant.
24437 * <script type="text/javascript">
24441 * @class Roo.data.XmlReader
24442 * @extends Roo.data.DataReader
24443 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24444 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24446 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24447 * header in the HTTP response must be set to "text/xml".</em>
24451 var RecordDef = Roo.data.Record.create([
24452 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24453 {name: 'occupation'} // This field will use "occupation" as the mapping.
24455 var myReader = new Roo.data.XmlReader({
24456 totalRecords: "results", // The element which contains the total dataset size (optional)
24457 record: "row", // The repeated element which contains row information
24458 id: "id" // The element within the row that provides an ID for the record (optional)
24462 * This would consume an XML file like this:
24466 <results>2</results>
24469 <name>Bill</name>
24470 <occupation>Gardener</occupation>
24474 <name>Ben</name>
24475 <occupation>Horticulturalist</occupation>
24479 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24480 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24481 * paged from the remote server.
24482 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24483 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24484 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24485 * a record identifier value.
24487 * Create a new XmlReader
24488 * @param {Object} meta Metadata configuration options
24489 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24490 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24491 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24493 Roo.data.XmlReader = function(meta, recordType){
24495 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24497 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24499 * This method is only used by a DataProxy which has retrieved data from a remote server.
24500 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24501 * to contain a method called 'responseXML' that returns an XML document object.
24502 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24503 * a cache of Roo.data.Records.
24505 read : function(response){
24506 var doc = response.responseXML;
24508 throw {message: "XmlReader.read: XML Document not available"};
24510 return this.readRecords(doc);
24514 * Create a data block containing Roo.data.Records from an XML document.
24515 * @param {Object} doc A parsed XML document.
24516 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24517 * a cache of Roo.data.Records.
24519 readRecords : function(doc){
24521 * After any data loads/reads, the raw XML Document is available for further custom processing.
24522 * @type XMLDocument
24524 this.xmlData = doc;
24525 var root = doc.documentElement || doc;
24526 var q = Roo.DomQuery;
24527 var recordType = this.recordType, fields = recordType.prototype.fields;
24528 var sid = this.meta.id;
24529 var totalRecords = 0, success = true;
24530 if(this.meta.totalRecords){
24531 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24534 if(this.meta.success){
24535 var sv = q.selectValue(this.meta.success, root, true);
24536 success = sv !== false && sv !== 'false';
24539 var ns = q.select(this.meta.record, root);
24540 for(var i = 0, len = ns.length; i < len; i++) {
24543 var id = sid ? q.selectValue(sid, n) : undefined;
24544 for(var j = 0, jlen = fields.length; j < jlen; j++){
24545 var f = fields.items[j];
24546 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24548 values[f.name] = v;
24550 var record = new recordType(values, id);
24552 records[records.length] = record;
24558 totalRecords : totalRecords || records.length
24563 * Ext JS Library 1.1.1
24564 * Copyright(c) 2006-2007, Ext JS, LLC.
24566 * Originally Released Under LGPL - original licence link has changed is not relivant.
24569 * <script type="text/javascript">
24573 * @class Roo.data.ArrayReader
24574 * @extends Roo.data.DataReader
24575 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24576 * Each element of that Array represents a row of data fields. The
24577 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24578 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24582 var RecordDef = Roo.data.Record.create([
24583 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24584 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24586 var myReader = new Roo.data.ArrayReader({
24587 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24591 * This would consume an Array like this:
24593 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24597 * Create a new JsonReader
24598 * @param {Object} meta Metadata configuration options.
24599 * @param {Object|Array} recordType Either an Array of field definition objects
24601 * @cfg {Array} fields Array of field definition objects
24602 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24603 * as specified to {@link Roo.data.Record#create},
24604 * or an {@link Roo.data.Record} object
24607 * created using {@link Roo.data.Record#create}.
24609 Roo.data.ArrayReader = function(meta, recordType){
24612 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24615 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24617 * Create a data block containing Roo.data.Records from an XML document.
24618 * @param {Object} o An Array of row objects which represents the dataset.
24619 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
24620 * a cache of Roo.data.Records.
24622 readRecords : function(o)
24624 var sid = this.meta ? this.meta.id : null;
24625 var recordType = this.recordType, fields = recordType.prototype.fields;
24628 for(var i = 0; i < root.length; i++){
24631 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24632 for(var j = 0, jlen = fields.length; j < jlen; j++){
24633 var f = fields.items[j];
24634 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24635 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24637 values[f.name] = v;
24639 var record = new recordType(values, id);
24641 records[records.length] = record;
24645 totalRecords : records.length
24650 * Ext JS Library 1.1.1
24651 * Copyright(c) 2006-2007, Ext JS, LLC.
24653 * Originally Released Under LGPL - original licence link has changed is not relivant.
24656 * <script type="text/javascript">
24661 * @class Roo.data.Tree
24662 * @extends Roo.util.Observable
24663 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24664 * in the tree have most standard DOM functionality.
24666 * @param {Node} root (optional) The root node
24668 Roo.data.Tree = function(root){
24669 this.nodeHash = {};
24671 * The root node for this tree
24676 this.setRootNode(root);
24681 * Fires when a new child node is appended to a node in this tree.
24682 * @param {Tree} tree The owner tree
24683 * @param {Node} parent The parent node
24684 * @param {Node} node The newly appended node
24685 * @param {Number} index The index of the newly appended node
24690 * Fires when a child node is removed from a node in this tree.
24691 * @param {Tree} tree The owner tree
24692 * @param {Node} parent The parent node
24693 * @param {Node} node The child node removed
24698 * Fires when a node is moved to a new location in the tree
24699 * @param {Tree} tree The owner tree
24700 * @param {Node} node The node moved
24701 * @param {Node} oldParent The old parent of this node
24702 * @param {Node} newParent The new parent of this node
24703 * @param {Number} index The index it was moved to
24708 * Fires when a new child node is inserted in a node in this tree.
24709 * @param {Tree} tree The owner tree
24710 * @param {Node} parent The parent node
24711 * @param {Node} node The child node inserted
24712 * @param {Node} refNode The child node the node was inserted before
24716 * @event beforeappend
24717 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24718 * @param {Tree} tree The owner tree
24719 * @param {Node} parent The parent node
24720 * @param {Node} node The child node to be appended
24722 "beforeappend" : true,
24724 * @event beforeremove
24725 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24726 * @param {Tree} tree The owner tree
24727 * @param {Node} parent The parent node
24728 * @param {Node} node The child node to be removed
24730 "beforeremove" : true,
24732 * @event beforemove
24733 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24734 * @param {Tree} tree The owner tree
24735 * @param {Node} node The node being moved
24736 * @param {Node} oldParent The parent of the node
24737 * @param {Node} newParent The new parent the node is moving to
24738 * @param {Number} index The index it is being moved to
24740 "beforemove" : true,
24742 * @event beforeinsert
24743 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24744 * @param {Tree} tree The owner tree
24745 * @param {Node} parent The parent node
24746 * @param {Node} node The child node to be inserted
24747 * @param {Node} refNode The child node the node is being inserted before
24749 "beforeinsert" : true
24752 Roo.data.Tree.superclass.constructor.call(this);
24755 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24756 pathSeparator: "/",
24758 proxyNodeEvent : function(){
24759 return this.fireEvent.apply(this, arguments);
24763 * Returns the root node for this tree.
24766 getRootNode : function(){
24771 * Sets the root node for this tree.
24772 * @param {Node} node
24775 setRootNode : function(node){
24777 node.ownerTree = this;
24778 node.isRoot = true;
24779 this.registerNode(node);
24784 * Gets a node in this tree by its id.
24785 * @param {String} id
24788 getNodeById : function(id){
24789 return this.nodeHash[id];
24792 registerNode : function(node){
24793 this.nodeHash[node.id] = node;
24796 unregisterNode : function(node){
24797 delete this.nodeHash[node.id];
24800 toString : function(){
24801 return "[Tree"+(this.id?" "+this.id:"")+"]";
24806 * @class Roo.data.Node
24807 * @extends Roo.util.Observable
24808 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24809 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24811 * @param {Object} attributes The attributes/config for the node
24813 Roo.data.Node = function(attributes){
24815 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24818 this.attributes = attributes || {};
24819 this.leaf = this.attributes.leaf;
24821 * The node id. @type String
24823 this.id = this.attributes.id;
24825 this.id = Roo.id(null, "ynode-");
24826 this.attributes.id = this.id;
24831 * All child nodes of this node. @type Array
24833 this.childNodes = [];
24834 if(!this.childNodes.indexOf){ // indexOf is a must
24835 this.childNodes.indexOf = function(o){
24836 for(var i = 0, len = this.length; i < len; i++){
24845 * The parent node for this node. @type Node
24847 this.parentNode = null;
24849 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24851 this.firstChild = null;
24853 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24855 this.lastChild = null;
24857 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24859 this.previousSibling = null;
24861 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24863 this.nextSibling = null;
24868 * Fires when a new child node is appended
24869 * @param {Tree} tree The owner tree
24870 * @param {Node} this This node
24871 * @param {Node} node The newly appended node
24872 * @param {Number} index The index of the newly appended node
24877 * Fires when a child node is removed
24878 * @param {Tree} tree The owner tree
24879 * @param {Node} this This node
24880 * @param {Node} node The removed node
24885 * Fires when this node is moved to a new location in the tree
24886 * @param {Tree} tree The owner tree
24887 * @param {Node} this This node
24888 * @param {Node} oldParent The old parent of this node
24889 * @param {Node} newParent The new parent of this node
24890 * @param {Number} index The index it was moved to
24895 * Fires when a new child node is inserted.
24896 * @param {Tree} tree The owner tree
24897 * @param {Node} this This node
24898 * @param {Node} node The child node inserted
24899 * @param {Node} refNode The child node the node was inserted before
24903 * @event beforeappend
24904 * Fires before a new child is appended, return false to cancel the append.
24905 * @param {Tree} tree The owner tree
24906 * @param {Node} this This node
24907 * @param {Node} node The child node to be appended
24909 "beforeappend" : true,
24911 * @event beforeremove
24912 * Fires before a child is removed, return false to cancel the remove.
24913 * @param {Tree} tree The owner tree
24914 * @param {Node} this This node
24915 * @param {Node} node The child node to be removed
24917 "beforeremove" : true,
24919 * @event beforemove
24920 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24921 * @param {Tree} tree The owner tree
24922 * @param {Node} this This node
24923 * @param {Node} oldParent The parent of this node
24924 * @param {Node} newParent The new parent this node is moving to
24925 * @param {Number} index The index it is being moved to
24927 "beforemove" : true,
24929 * @event beforeinsert
24930 * Fires before a new child is inserted, return false to cancel the insert.
24931 * @param {Tree} tree The owner tree
24932 * @param {Node} this This node
24933 * @param {Node} node The child node to be inserted
24934 * @param {Node} refNode The child node the node is being inserted before
24936 "beforeinsert" : true
24938 this.listeners = this.attributes.listeners;
24939 Roo.data.Node.superclass.constructor.call(this);
24942 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24943 fireEvent : function(evtName){
24944 // first do standard event for this node
24945 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24948 // then bubble it up to the tree if the event wasn't cancelled
24949 var ot = this.getOwnerTree();
24951 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24959 * Returns true if this node is a leaf
24960 * @return {Boolean}
24962 isLeaf : function(){
24963 return this.leaf === true;
24967 setFirstChild : function(node){
24968 this.firstChild = node;
24972 setLastChild : function(node){
24973 this.lastChild = node;
24978 * Returns true if this node is the last child of its parent
24979 * @return {Boolean}
24981 isLast : function(){
24982 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24986 * Returns true if this node is the first child of its parent
24987 * @return {Boolean}
24989 isFirst : function(){
24990 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24993 hasChildNodes : function(){
24994 return !this.isLeaf() && this.childNodes.length > 0;
24998 * Insert node(s) as the last child node of this node.
24999 * @param {Node/Array} node The node or Array of nodes to append
25000 * @return {Node} The appended node if single append, or null if an array was passed
25002 appendChild : function(node){
25004 if(node instanceof Array){
25006 }else if(arguments.length > 1){
25010 // if passed an array or multiple args do them one by one
25012 for(var i = 0, len = multi.length; i < len; i++) {
25013 this.appendChild(multi[i]);
25016 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
25019 var index = this.childNodes.length;
25020 var oldParent = node.parentNode;
25021 // it's a move, make sure we move it cleanly
25023 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
25026 oldParent.removeChild(node);
25029 index = this.childNodes.length;
25031 this.setFirstChild(node);
25033 this.childNodes.push(node);
25034 node.parentNode = this;
25035 var ps = this.childNodes[index-1];
25037 node.previousSibling = ps;
25038 ps.nextSibling = node;
25040 node.previousSibling = null;
25042 node.nextSibling = null;
25043 this.setLastChild(node);
25044 node.setOwnerTree(this.getOwnerTree());
25045 this.fireEvent("append", this.ownerTree, this, node, index);
25046 if(this.ownerTree) {
25047 this.ownerTree.fireEvent("appendnode", this, node, index);
25050 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25057 * Removes a child node from this node.
25058 * @param {Node} node The node to remove
25059 * @return {Node} The removed node
25061 removeChild : function(node){
25062 var index = this.childNodes.indexOf(node);
25066 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25070 // remove it from childNodes collection
25071 this.childNodes.splice(index, 1);
25074 if(node.previousSibling){
25075 node.previousSibling.nextSibling = node.nextSibling;
25077 if(node.nextSibling){
25078 node.nextSibling.previousSibling = node.previousSibling;
25081 // update child refs
25082 if(this.firstChild == node){
25083 this.setFirstChild(node.nextSibling);
25085 if(this.lastChild == node){
25086 this.setLastChild(node.previousSibling);
25089 node.setOwnerTree(null);
25090 // clear any references from the node
25091 node.parentNode = null;
25092 node.previousSibling = null;
25093 node.nextSibling = null;
25094 this.fireEvent("remove", this.ownerTree, this, node);
25099 * Inserts the first node before the second node in this nodes childNodes collection.
25100 * @param {Node} node The node to insert
25101 * @param {Node} refNode The node to insert before (if null the node is appended)
25102 * @return {Node} The inserted node
25104 insertBefore : function(node, refNode){
25105 if(!refNode){ // like standard Dom, refNode can be null for append
25106 return this.appendChild(node);
25109 if(node == refNode){
25113 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25116 var index = this.childNodes.indexOf(refNode);
25117 var oldParent = node.parentNode;
25118 var refIndex = index;
25120 // when moving internally, indexes will change after remove
25121 if(oldParent == this && this.childNodes.indexOf(node) < index){
25125 // it's a move, make sure we move it cleanly
25127 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25130 oldParent.removeChild(node);
25133 this.setFirstChild(node);
25135 this.childNodes.splice(refIndex, 0, node);
25136 node.parentNode = this;
25137 var ps = this.childNodes[refIndex-1];
25139 node.previousSibling = ps;
25140 ps.nextSibling = node;
25142 node.previousSibling = null;
25144 node.nextSibling = refNode;
25145 refNode.previousSibling = node;
25146 node.setOwnerTree(this.getOwnerTree());
25147 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25149 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25155 * Returns the child node at the specified index.
25156 * @param {Number} index
25159 item : function(index){
25160 return this.childNodes[index];
25164 * Replaces one child node in this node with another.
25165 * @param {Node} newChild The replacement node
25166 * @param {Node} oldChild The node to replace
25167 * @return {Node} The replaced node
25169 replaceChild : function(newChild, oldChild){
25170 this.insertBefore(newChild, oldChild);
25171 this.removeChild(oldChild);
25176 * Returns the index of a child node
25177 * @param {Node} node
25178 * @return {Number} The index of the node or -1 if it was not found
25180 indexOf : function(child){
25181 return this.childNodes.indexOf(child);
25185 * Returns the tree this node is in.
25188 getOwnerTree : function(){
25189 // if it doesn't have one, look for one
25190 if(!this.ownerTree){
25194 this.ownerTree = p.ownerTree;
25200 return this.ownerTree;
25204 * Returns depth of this node (the root node has a depth of 0)
25207 getDepth : function(){
25210 while(p.parentNode){
25218 setOwnerTree : function(tree){
25219 // if it's move, we need to update everyone
25220 if(tree != this.ownerTree){
25221 if(this.ownerTree){
25222 this.ownerTree.unregisterNode(this);
25224 this.ownerTree = tree;
25225 var cs = this.childNodes;
25226 for(var i = 0, len = cs.length; i < len; i++) {
25227 cs[i].setOwnerTree(tree);
25230 tree.registerNode(this);
25236 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25237 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25238 * @return {String} The path
25240 getPath : function(attr){
25241 attr = attr || "id";
25242 var p = this.parentNode;
25243 var b = [this.attributes[attr]];
25245 b.unshift(p.attributes[attr]);
25248 var sep = this.getOwnerTree().pathSeparator;
25249 return sep + b.join(sep);
25253 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25254 * function call will be the scope provided or the current node. The arguments to the function
25255 * will be the args provided or the current node. If the function returns false at any point,
25256 * the bubble is stopped.
25257 * @param {Function} fn The function to call
25258 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25259 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25261 bubble : function(fn, scope, args){
25264 if(fn.call(scope || p, args || p) === false){
25272 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25273 * function call will be the scope provided or the current node. The arguments to the function
25274 * will be the args provided or the current node. If the function returns false at any point,
25275 * the cascade is stopped on that branch.
25276 * @param {Function} fn The function to call
25277 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25278 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25280 cascade : function(fn, scope, args){
25281 if(fn.call(scope || this, args || this) !== false){
25282 var cs = this.childNodes;
25283 for(var i = 0, len = cs.length; i < len; i++) {
25284 cs[i].cascade(fn, scope, args);
25290 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25291 * function call will be the scope provided or the current node. The arguments to the function
25292 * will be the args provided or the current node. If the function returns false at any point,
25293 * the iteration stops.
25294 * @param {Function} fn The function to call
25295 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25296 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25298 eachChild : function(fn, scope, args){
25299 var cs = this.childNodes;
25300 for(var i = 0, len = cs.length; i < len; i++) {
25301 if(fn.call(scope || this, args || cs[i]) === false){
25308 * Finds the first child that has the attribute with the specified value.
25309 * @param {String} attribute The attribute name
25310 * @param {Mixed} value The value to search for
25311 * @return {Node} The found child or null if none was found
25313 findChild : function(attribute, value){
25314 var cs = this.childNodes;
25315 for(var i = 0, len = cs.length; i < len; i++) {
25316 if(cs[i].attributes[attribute] == value){
25324 * Finds the first child by a custom function. The child matches if the function passed
25326 * @param {Function} fn
25327 * @param {Object} scope (optional)
25328 * @return {Node} The found child or null if none was found
25330 findChildBy : function(fn, scope){
25331 var cs = this.childNodes;
25332 for(var i = 0, len = cs.length; i < len; i++) {
25333 if(fn.call(scope||cs[i], cs[i]) === true){
25341 * Sorts this nodes children using the supplied sort function
25342 * @param {Function} fn
25343 * @param {Object} scope (optional)
25345 sort : function(fn, scope){
25346 var cs = this.childNodes;
25347 var len = cs.length;
25349 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25351 for(var i = 0; i < len; i++){
25353 n.previousSibling = cs[i-1];
25354 n.nextSibling = cs[i+1];
25356 this.setFirstChild(n);
25359 this.setLastChild(n);
25366 * Returns true if this node is an ancestor (at any point) of the passed node.
25367 * @param {Node} node
25368 * @return {Boolean}
25370 contains : function(node){
25371 return node.isAncestor(this);
25375 * Returns true if the passed node is an ancestor (at any point) of this node.
25376 * @param {Node} node
25377 * @return {Boolean}
25379 isAncestor : function(node){
25380 var p = this.parentNode;
25390 toString : function(){
25391 return "[Node"+(this.id?" "+this.id:"")+"]";
25395 * Ext JS Library 1.1.1
25396 * Copyright(c) 2006-2007, Ext JS, LLC.
25398 * Originally Released Under LGPL - original licence link has changed is not relivant.
25401 * <script type="text/javascript">
25406 * @extends Roo.Element
25407 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25408 * automatic maintaining of shadow/shim positions.
25409 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25410 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25411 * you can pass a string with a CSS class name. False turns off the shadow.
25412 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25413 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25414 * @cfg {String} cls CSS class to add to the element
25415 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25416 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25418 * @param {Object} config An object with config options.
25419 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25422 Roo.Layer = function(config, existingEl){
25423 config = config || {};
25424 var dh = Roo.DomHelper;
25425 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25427 this.dom = Roo.getDom(existingEl);
25430 var o = config.dh || {tag: "div", cls: "x-layer"};
25431 this.dom = dh.append(pel, o);
25434 this.addClass(config.cls);
25436 this.constrain = config.constrain !== false;
25437 this.visibilityMode = Roo.Element.VISIBILITY;
25439 this.id = this.dom.id = config.id;
25441 this.id = Roo.id(this.dom);
25443 this.zindex = config.zindex || this.getZIndex();
25444 this.position("absolute", this.zindex);
25446 this.shadowOffset = config.shadowOffset || 4;
25447 this.shadow = new Roo.Shadow({
25448 offset : this.shadowOffset,
25449 mode : config.shadow
25452 this.shadowOffset = 0;
25454 this.useShim = config.shim !== false && Roo.useShims;
25455 this.useDisplay = config.useDisplay;
25459 var supr = Roo.Element.prototype;
25461 // shims are shared among layer to keep from having 100 iframes
25464 Roo.extend(Roo.Layer, Roo.Element, {
25466 getZIndex : function(){
25467 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25470 getShim : function(){
25477 var shim = shims.shift();
25479 shim = this.createShim();
25480 shim.enableDisplayMode('block');
25481 shim.dom.style.display = 'none';
25482 shim.dom.style.visibility = 'visible';
25484 var pn = this.dom.parentNode;
25485 if(shim.dom.parentNode != pn){
25486 pn.insertBefore(shim.dom, this.dom);
25488 shim.setStyle('z-index', this.getZIndex()-2);
25493 hideShim : function(){
25495 this.shim.setDisplayed(false);
25496 shims.push(this.shim);
25501 disableShadow : function(){
25503 this.shadowDisabled = true;
25504 this.shadow.hide();
25505 this.lastShadowOffset = this.shadowOffset;
25506 this.shadowOffset = 0;
25510 enableShadow : function(show){
25512 this.shadowDisabled = false;
25513 this.shadowOffset = this.lastShadowOffset;
25514 delete this.lastShadowOffset;
25522 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25523 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25524 sync : function(doShow){
25525 var sw = this.shadow;
25526 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25527 var sh = this.getShim();
25529 var w = this.getWidth(),
25530 h = this.getHeight();
25532 var l = this.getLeft(true),
25533 t = this.getTop(true);
25535 if(sw && !this.shadowDisabled){
25536 if(doShow && !sw.isVisible()){
25539 sw.realign(l, t, w, h);
25545 // fit the shim behind the shadow, so it is shimmed too
25546 var a = sw.adjusts, s = sh.dom.style;
25547 s.left = (Math.min(l, l+a.l))+"px";
25548 s.top = (Math.min(t, t+a.t))+"px";
25549 s.width = (w+a.w)+"px";
25550 s.height = (h+a.h)+"px";
25557 sh.setLeftTop(l, t);
25564 destroy : function(){
25567 this.shadow.hide();
25569 this.removeAllListeners();
25570 var pn = this.dom.parentNode;
25572 pn.removeChild(this.dom);
25574 Roo.Element.uncache(this.id);
25577 remove : function(){
25582 beginUpdate : function(){
25583 this.updating = true;
25587 endUpdate : function(){
25588 this.updating = false;
25593 hideUnders : function(negOffset){
25595 this.shadow.hide();
25601 constrainXY : function(){
25602 if(this.constrain){
25603 var vw = Roo.lib.Dom.getViewWidth(),
25604 vh = Roo.lib.Dom.getViewHeight();
25605 var s = Roo.get(document).getScroll();
25607 var xy = this.getXY();
25608 var x = xy[0], y = xy[1];
25609 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25610 // only move it if it needs it
25612 // first validate right/bottom
25613 if((x + w) > vw+s.left){
25614 x = vw - w - this.shadowOffset;
25617 if((y + h) > vh+s.top){
25618 y = vh - h - this.shadowOffset;
25621 // then make sure top/left isn't negative
25632 var ay = this.avoidY;
25633 if(y <= ay && (y+h) >= ay){
25639 supr.setXY.call(this, xy);
25645 isVisible : function(){
25646 return this.visible;
25650 showAction : function(){
25651 this.visible = true; // track visibility to prevent getStyle calls
25652 if(this.useDisplay === true){
25653 this.setDisplayed("");
25654 }else if(this.lastXY){
25655 supr.setXY.call(this, this.lastXY);
25656 }else if(this.lastLT){
25657 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25662 hideAction : function(){
25663 this.visible = false;
25664 if(this.useDisplay === true){
25665 this.setDisplayed(false);
25667 this.setLeftTop(-10000,-10000);
25671 // overridden Element method
25672 setVisible : function(v, a, d, c, e){
25677 var cb = function(){
25682 }.createDelegate(this);
25683 supr.setVisible.call(this, true, true, d, cb, e);
25686 this.hideUnders(true);
25695 }.createDelegate(this);
25697 supr.setVisible.call(this, v, a, d, cb, e);
25706 storeXY : function(xy){
25707 delete this.lastLT;
25711 storeLeftTop : function(left, top){
25712 delete this.lastXY;
25713 this.lastLT = [left, top];
25717 beforeFx : function(){
25718 this.beforeAction();
25719 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25723 afterFx : function(){
25724 Roo.Layer.superclass.afterFx.apply(this, arguments);
25725 this.sync(this.isVisible());
25729 beforeAction : function(){
25730 if(!this.updating && this.shadow){
25731 this.shadow.hide();
25735 // overridden Element method
25736 setLeft : function(left){
25737 this.storeLeftTop(left, this.getTop(true));
25738 supr.setLeft.apply(this, arguments);
25742 setTop : function(top){
25743 this.storeLeftTop(this.getLeft(true), top);
25744 supr.setTop.apply(this, arguments);
25748 setLeftTop : function(left, top){
25749 this.storeLeftTop(left, top);
25750 supr.setLeftTop.apply(this, arguments);
25754 setXY : function(xy, a, d, c, e){
25756 this.beforeAction();
25758 var cb = this.createCB(c);
25759 supr.setXY.call(this, xy, a, d, cb, e);
25766 createCB : function(c){
25777 // overridden Element method
25778 setX : function(x, a, d, c, e){
25779 this.setXY([x, this.getY()], a, d, c, e);
25782 // overridden Element method
25783 setY : function(y, a, d, c, e){
25784 this.setXY([this.getX(), y], a, d, c, e);
25787 // overridden Element method
25788 setSize : function(w, h, a, d, c, e){
25789 this.beforeAction();
25790 var cb = this.createCB(c);
25791 supr.setSize.call(this, w, h, a, d, cb, e);
25797 // overridden Element method
25798 setWidth : function(w, a, d, c, e){
25799 this.beforeAction();
25800 var cb = this.createCB(c);
25801 supr.setWidth.call(this, w, a, d, cb, e);
25807 // overridden Element method
25808 setHeight : function(h, a, d, c, e){
25809 this.beforeAction();
25810 var cb = this.createCB(c);
25811 supr.setHeight.call(this, h, a, d, cb, e);
25817 // overridden Element method
25818 setBounds : function(x, y, w, h, a, d, c, e){
25819 this.beforeAction();
25820 var cb = this.createCB(c);
25822 this.storeXY([x, y]);
25823 supr.setXY.call(this, [x, y]);
25824 supr.setSize.call(this, w, h, a, d, cb, e);
25827 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25833 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25834 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25835 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25836 * @param {Number} zindex The new z-index to set
25837 * @return {this} The Layer
25839 setZIndex : function(zindex){
25840 this.zindex = zindex;
25841 this.setStyle("z-index", zindex + 2);
25843 this.shadow.setZIndex(zindex + 1);
25846 this.shim.setStyle("z-index", zindex);
25852 * Ext JS Library 1.1.1
25853 * Copyright(c) 2006-2007, Ext JS, LLC.
25855 * Originally Released Under LGPL - original licence link has changed is not relivant.
25858 * <script type="text/javascript">
25863 * @class Roo.Shadow
25864 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25865 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25866 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25868 * Create a new Shadow
25869 * @param {Object} config The config object
25871 Roo.Shadow = function(config){
25872 Roo.apply(this, config);
25873 if(typeof this.mode != "string"){
25874 this.mode = this.defaultMode;
25876 var o = this.offset, a = {h: 0};
25877 var rad = Math.floor(this.offset/2);
25878 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25884 a.l -= this.offset + rad;
25885 a.t -= this.offset + rad;
25896 a.l -= (this.offset - rad);
25897 a.t -= this.offset + rad;
25899 a.w -= (this.offset - rad)*2;
25910 a.l -= (this.offset - rad);
25911 a.t -= (this.offset - rad);
25913 a.w -= (this.offset + rad + 1);
25914 a.h -= (this.offset + rad);
25923 Roo.Shadow.prototype = {
25925 * @cfg {String} mode
25926 * The shadow display mode. Supports the following options:<br />
25927 * sides: Shadow displays on both sides and bottom only<br />
25928 * frame: Shadow displays equally on all four sides<br />
25929 * drop: Traditional bottom-right drop shadow (default)
25932 * @cfg {String} offset
25933 * The number of pixels to offset the shadow from the element (defaults to 4)
25938 defaultMode: "drop",
25941 * Displays the shadow under the target element
25942 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25944 show : function(target){
25945 target = Roo.get(target);
25947 this.el = Roo.Shadow.Pool.pull();
25948 if(this.el.dom.nextSibling != target.dom){
25949 this.el.insertBefore(target);
25952 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25954 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25957 target.getLeft(true),
25958 target.getTop(true),
25962 this.el.dom.style.display = "block";
25966 * Returns true if the shadow is visible, else false
25968 isVisible : function(){
25969 return this.el ? true : false;
25973 * Direct alignment when values are already available. Show must be called at least once before
25974 * calling this method to ensure it is initialized.
25975 * @param {Number} left The target element left position
25976 * @param {Number} top The target element top position
25977 * @param {Number} width The target element width
25978 * @param {Number} height The target element height
25980 realign : function(l, t, w, h){
25984 var a = this.adjusts, d = this.el.dom, s = d.style;
25986 s.left = (l+a.l)+"px";
25987 s.top = (t+a.t)+"px";
25988 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25990 if(s.width != sws || s.height != shs){
25994 var cn = d.childNodes;
25995 var sww = Math.max(0, (sw-12))+"px";
25996 cn[0].childNodes[1].style.width = sww;
25997 cn[1].childNodes[1].style.width = sww;
25998 cn[2].childNodes[1].style.width = sww;
25999 cn[1].style.height = Math.max(0, (sh-12))+"px";
26005 * Hides this shadow
26009 this.el.dom.style.display = "none";
26010 Roo.Shadow.Pool.push(this.el);
26016 * Adjust the z-index of this shadow
26017 * @param {Number} zindex The new z-index
26019 setZIndex : function(z){
26022 this.el.setStyle("z-index", z);
26027 // Private utility class that manages the internal Shadow cache
26028 Roo.Shadow.Pool = function(){
26030 var markup = Roo.isIE ?
26031 '<div class="x-ie-shadow"></div>' :
26032 '<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>';
26035 var sh = p.shift();
26037 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
26038 sh.autoBoxAdjust = false;
26043 push : function(sh){
26049 * Ext JS Library 1.1.1
26050 * Copyright(c) 2006-2007, Ext JS, LLC.
26052 * Originally Released Under LGPL - original licence link has changed is not relivant.
26055 * <script type="text/javascript">
26060 * @class Roo.SplitBar
26061 * @extends Roo.util.Observable
26062 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26066 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26067 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26068 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26069 split.minSize = 100;
26070 split.maxSize = 600;
26071 split.animate = true;
26072 split.on('moved', splitterMoved);
26075 * Create a new SplitBar
26076 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26077 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26078 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26079 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26080 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26081 position of the SplitBar).
26083 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26086 this.el = Roo.get(dragElement, true);
26087 this.el.dom.unselectable = "on";
26089 this.resizingEl = Roo.get(resizingElement, true);
26093 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26094 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26097 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26100 * The minimum size of the resizing element. (Defaults to 0)
26106 * The maximum size of the resizing element. (Defaults to 2000)
26109 this.maxSize = 2000;
26112 * Whether to animate the transition to the new size
26115 this.animate = false;
26118 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26121 this.useShim = false;
26126 if(!existingProxy){
26128 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26130 this.proxy = Roo.get(existingProxy).dom;
26133 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26136 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26139 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26142 this.dragSpecs = {};
26145 * @private The adapter to use to positon and resize elements
26147 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26148 this.adapter.init(this);
26150 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26152 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26153 this.el.addClass("x-splitbar-h");
26156 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26157 this.el.addClass("x-splitbar-v");
26163 * Fires when the splitter is moved (alias for {@link #event-moved})
26164 * @param {Roo.SplitBar} this
26165 * @param {Number} newSize the new width or height
26170 * Fires when the splitter is moved
26171 * @param {Roo.SplitBar} this
26172 * @param {Number} newSize the new width or height
26176 * @event beforeresize
26177 * Fires before the splitter is dragged
26178 * @param {Roo.SplitBar} this
26180 "beforeresize" : true,
26182 "beforeapply" : true
26185 Roo.util.Observable.call(this);
26188 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26189 onStartProxyDrag : function(x, y){
26190 this.fireEvent("beforeresize", this);
26192 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26194 o.enableDisplayMode("block");
26195 // all splitbars share the same overlay
26196 Roo.SplitBar.prototype.overlay = o;
26198 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26199 this.overlay.show();
26200 Roo.get(this.proxy).setDisplayed("block");
26201 var size = this.adapter.getElementSize(this);
26202 this.activeMinSize = this.getMinimumSize();;
26203 this.activeMaxSize = this.getMaximumSize();;
26204 var c1 = size - this.activeMinSize;
26205 var c2 = Math.max(this.activeMaxSize - size, 0);
26206 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26207 this.dd.resetConstraints();
26208 this.dd.setXConstraint(
26209 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26210 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26212 this.dd.setYConstraint(0, 0);
26214 this.dd.resetConstraints();
26215 this.dd.setXConstraint(0, 0);
26216 this.dd.setYConstraint(
26217 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26218 this.placement == Roo.SplitBar.TOP ? c2 : c1
26221 this.dragSpecs.startSize = size;
26222 this.dragSpecs.startPoint = [x, y];
26223 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26227 * @private Called after the drag operation by the DDProxy
26229 onEndProxyDrag : function(e){
26230 Roo.get(this.proxy).setDisplayed(false);
26231 var endPoint = Roo.lib.Event.getXY(e);
26233 this.overlay.hide();
26236 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26237 newSize = this.dragSpecs.startSize +
26238 (this.placement == Roo.SplitBar.LEFT ?
26239 endPoint[0] - this.dragSpecs.startPoint[0] :
26240 this.dragSpecs.startPoint[0] - endPoint[0]
26243 newSize = this.dragSpecs.startSize +
26244 (this.placement == Roo.SplitBar.TOP ?
26245 endPoint[1] - this.dragSpecs.startPoint[1] :
26246 this.dragSpecs.startPoint[1] - endPoint[1]
26249 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26250 if(newSize != this.dragSpecs.startSize){
26251 if(this.fireEvent('beforeapply', this, newSize) !== false){
26252 this.adapter.setElementSize(this, newSize);
26253 this.fireEvent("moved", this, newSize);
26254 this.fireEvent("resize", this, newSize);
26260 * Get the adapter this SplitBar uses
26261 * @return The adapter object
26263 getAdapter : function(){
26264 return this.adapter;
26268 * Set the adapter this SplitBar uses
26269 * @param {Object} adapter A SplitBar adapter object
26271 setAdapter : function(adapter){
26272 this.adapter = adapter;
26273 this.adapter.init(this);
26277 * Gets the minimum size for the resizing element
26278 * @return {Number} The minimum size
26280 getMinimumSize : function(){
26281 return this.minSize;
26285 * Sets the minimum size for the resizing element
26286 * @param {Number} minSize The minimum size
26288 setMinimumSize : function(minSize){
26289 this.minSize = minSize;
26293 * Gets the maximum size for the resizing element
26294 * @return {Number} The maximum size
26296 getMaximumSize : function(){
26297 return this.maxSize;
26301 * Sets the maximum size for the resizing element
26302 * @param {Number} maxSize The maximum size
26304 setMaximumSize : function(maxSize){
26305 this.maxSize = maxSize;
26309 * Sets the initialize size for the resizing element
26310 * @param {Number} size The initial size
26312 setCurrentSize : function(size){
26313 var oldAnimate = this.animate;
26314 this.animate = false;
26315 this.adapter.setElementSize(this, size);
26316 this.animate = oldAnimate;
26320 * Destroy this splitbar.
26321 * @param {Boolean} removeEl True to remove the element
26323 destroy : function(removeEl){
26325 this.shim.remove();
26328 this.proxy.parentNode.removeChild(this.proxy);
26336 * @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.
26338 Roo.SplitBar.createProxy = function(dir){
26339 var proxy = new Roo.Element(document.createElement("div"));
26340 proxy.unselectable();
26341 var cls = 'x-splitbar-proxy';
26342 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26343 document.body.appendChild(proxy.dom);
26348 * @class Roo.SplitBar.BasicLayoutAdapter
26349 * Default Adapter. It assumes the splitter and resizing element are not positioned
26350 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26352 Roo.SplitBar.BasicLayoutAdapter = function(){
26355 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26356 // do nothing for now
26357 init : function(s){
26361 * Called before drag operations to get the current size of the resizing element.
26362 * @param {Roo.SplitBar} s The SplitBar using this adapter
26364 getElementSize : function(s){
26365 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26366 return s.resizingEl.getWidth();
26368 return s.resizingEl.getHeight();
26373 * Called after drag operations to set the size of the resizing element.
26374 * @param {Roo.SplitBar} s The SplitBar using this adapter
26375 * @param {Number} newSize The new size to set
26376 * @param {Function} onComplete A function to be invoked when resizing is complete
26378 setElementSize : function(s, newSize, onComplete){
26379 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26381 s.resizingEl.setWidth(newSize);
26383 onComplete(s, newSize);
26386 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26391 s.resizingEl.setHeight(newSize);
26393 onComplete(s, newSize);
26396 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26403 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26404 * @extends Roo.SplitBar.BasicLayoutAdapter
26405 * Adapter that moves the splitter element to align with the resized sizing element.
26406 * Used with an absolute positioned SplitBar.
26407 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26408 * document.body, make sure you assign an id to the body element.
26410 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26411 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26412 this.container = Roo.get(container);
26415 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26416 init : function(s){
26417 this.basic.init(s);
26420 getElementSize : function(s){
26421 return this.basic.getElementSize(s);
26424 setElementSize : function(s, newSize, onComplete){
26425 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26428 moveSplitter : function(s){
26429 var yes = Roo.SplitBar;
26430 switch(s.placement){
26432 s.el.setX(s.resizingEl.getRight());
26435 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26438 s.el.setY(s.resizingEl.getBottom());
26441 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26448 * Orientation constant - Create a vertical SplitBar
26452 Roo.SplitBar.VERTICAL = 1;
26455 * Orientation constant - Create a horizontal SplitBar
26459 Roo.SplitBar.HORIZONTAL = 2;
26462 * Placement constant - The resizing element is to the left of the splitter element
26466 Roo.SplitBar.LEFT = 1;
26469 * Placement constant - The resizing element is to the right of the splitter element
26473 Roo.SplitBar.RIGHT = 2;
26476 * Placement constant - The resizing element is positioned above the splitter element
26480 Roo.SplitBar.TOP = 3;
26483 * Placement constant - The resizing element is positioned under splitter element
26487 Roo.SplitBar.BOTTOM = 4;
26490 * Ext JS Library 1.1.1
26491 * Copyright(c) 2006-2007, Ext JS, LLC.
26493 * Originally Released Under LGPL - original licence link has changed is not relivant.
26496 * <script type="text/javascript">
26501 * @extends Roo.util.Observable
26502 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26503 * This class also supports single and multi selection modes. <br>
26504 * Create a data model bound view:
26506 var store = new Roo.data.Store(...);
26508 var view = new Roo.View({
26510 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26512 singleSelect: true,
26513 selectedClass: "ydataview-selected",
26517 // listen for node click?
26518 view.on("click", function(vw, index, node, e){
26519 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26523 dataModel.load("foobar.xml");
26525 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26527 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26528 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26530 * Note: old style constructor is still suported (container, template, config)
26533 * Create a new View
26534 * @param {Object} config The config object
26537 Roo.View = function(config, depreciated_tpl, depreciated_config){
26539 this.parent = false;
26541 if (typeof(depreciated_tpl) == 'undefined') {
26542 // new way.. - universal constructor.
26543 Roo.apply(this, config);
26544 this.el = Roo.get(this.el);
26547 this.el = Roo.get(config);
26548 this.tpl = depreciated_tpl;
26549 Roo.apply(this, depreciated_config);
26551 this.wrapEl = this.el.wrap().wrap();
26552 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26555 if(typeof(this.tpl) == "string"){
26556 this.tpl = new Roo.Template(this.tpl);
26558 // support xtype ctors..
26559 this.tpl = new Roo.factory(this.tpl, Roo);
26563 this.tpl.compile();
26568 * @event beforeclick
26569 * Fires before a click is processed. Returns false to cancel the default action.
26570 * @param {Roo.View} this
26571 * @param {Number} index The index of the target node
26572 * @param {HTMLElement} node The target node
26573 * @param {Roo.EventObject} e The raw event object
26575 "beforeclick" : true,
26578 * Fires when a template node is clicked.
26579 * @param {Roo.View} this
26580 * @param {Number} index The index of the target node
26581 * @param {HTMLElement} node The target node
26582 * @param {Roo.EventObject} e The raw event object
26587 * Fires when a template node is double clicked.
26588 * @param {Roo.View} this
26589 * @param {Number} index The index of the target node
26590 * @param {HTMLElement} node The target node
26591 * @param {Roo.EventObject} e The raw event object
26595 * @event contextmenu
26596 * Fires when a template node is right clicked.
26597 * @param {Roo.View} this
26598 * @param {Number} index The index of the target node
26599 * @param {HTMLElement} node The target node
26600 * @param {Roo.EventObject} e The raw event object
26602 "contextmenu" : true,
26604 * @event selectionchange
26605 * Fires when the selected nodes change.
26606 * @param {Roo.View} this
26607 * @param {Array} selections Array of the selected nodes
26609 "selectionchange" : true,
26612 * @event beforeselect
26613 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26614 * @param {Roo.View} this
26615 * @param {HTMLElement} node The node to be selected
26616 * @param {Array} selections Array of currently selected nodes
26618 "beforeselect" : true,
26620 * @event preparedata
26621 * Fires on every row to render, to allow you to change the data.
26622 * @param {Roo.View} this
26623 * @param {Object} data to be rendered (change this)
26625 "preparedata" : true
26633 "click": this.onClick,
26634 "dblclick": this.onDblClick,
26635 "contextmenu": this.onContextMenu,
26639 this.selections = [];
26641 this.cmp = new Roo.CompositeElementLite([]);
26643 this.store = Roo.factory(this.store, Roo.data);
26644 this.setStore(this.store, true);
26647 if ( this.footer && this.footer.xtype) {
26649 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26651 this.footer.dataSource = this.store;
26652 this.footer.container = fctr;
26653 this.footer = Roo.factory(this.footer, Roo);
26654 fctr.insertFirst(this.el);
26656 // this is a bit insane - as the paging toolbar seems to detach the el..
26657 // dom.parentNode.parentNode.parentNode
26658 // they get detached?
26662 Roo.View.superclass.constructor.call(this);
26667 Roo.extend(Roo.View, Roo.util.Observable, {
26670 * @cfg {Roo.data.Store} store Data store to load data from.
26675 * @cfg {String|Roo.Element} el The container element.
26680 * @cfg {String|Roo.Template} tpl The template used by this View
26684 * @cfg {String} dataName the named area of the template to use as the data area
26685 * Works with domtemplates roo-name="name"
26689 * @cfg {String} selectedClass The css class to add to selected nodes
26691 selectedClass : "x-view-selected",
26693 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26698 * @cfg {String} text to display on mask (default Loading)
26702 * @cfg {Boolean} multiSelect Allow multiple selection
26704 multiSelect : false,
26706 * @cfg {Boolean} singleSelect Allow single selection
26708 singleSelect: false,
26711 * @cfg {Boolean} toggleSelect - selecting
26713 toggleSelect : false,
26716 * @cfg {Boolean} tickable - selecting
26721 * Returns the element this view is bound to.
26722 * @return {Roo.Element}
26724 getEl : function(){
26725 return this.wrapEl;
26731 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26733 refresh : function(){
26734 //Roo.log('refresh');
26737 // if we are using something like 'domtemplate', then
26738 // the what gets used is:
26739 // t.applySubtemplate(NAME, data, wrapping data..)
26740 // the outer template then get' applied with
26741 // the store 'extra data'
26742 // and the body get's added to the
26743 // roo-name="data" node?
26744 // <span class='roo-tpl-{name}'></span> ?????
26748 this.clearSelections();
26749 this.el.update("");
26751 var records = this.store.getRange();
26752 if(records.length < 1) {
26754 // is this valid?? = should it render a template??
26756 this.el.update(this.emptyText);
26760 if (this.dataName) {
26761 this.el.update(t.apply(this.store.meta)); //????
26762 el = this.el.child('.roo-tpl-' + this.dataName);
26765 for(var i = 0, len = records.length; i < len; i++){
26766 var data = this.prepareData(records[i].data, i, records[i]);
26767 this.fireEvent("preparedata", this, data, i, records[i]);
26769 var d = Roo.apply({}, data);
26772 Roo.apply(d, {'roo-id' : Roo.id()});
26776 Roo.each(this.parent.item, function(item){
26777 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26780 Roo.apply(d, {'roo-data-checked' : 'checked'});
26784 html[html.length] = Roo.util.Format.trim(
26786 t.applySubtemplate(this.dataName, d, this.store.meta) :
26793 el.update(html.join(""));
26794 this.nodes = el.dom.childNodes;
26795 this.updateIndexes(0);
26800 * Function to override to reformat the data that is sent to
26801 * the template for each node.
26802 * DEPRICATED - use the preparedata event handler.
26803 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26804 * a JSON object for an UpdateManager bound view).
26806 prepareData : function(data, index, record)
26808 this.fireEvent("preparedata", this, data, index, record);
26812 onUpdate : function(ds, record){
26813 // Roo.log('on update');
26814 this.clearSelections();
26815 var index = this.store.indexOf(record);
26816 var n = this.nodes[index];
26817 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26818 n.parentNode.removeChild(n);
26819 this.updateIndexes(index, index);
26825 onAdd : function(ds, records, index)
26827 //Roo.log(['on Add', ds, records, index] );
26828 this.clearSelections();
26829 if(this.nodes.length == 0){
26833 var n = this.nodes[index];
26834 for(var i = 0, len = records.length; i < len; i++){
26835 var d = this.prepareData(records[i].data, i, records[i]);
26837 this.tpl.insertBefore(n, d);
26840 this.tpl.append(this.el, d);
26843 this.updateIndexes(index);
26846 onRemove : function(ds, record, index){
26847 // Roo.log('onRemove');
26848 this.clearSelections();
26849 var el = this.dataName ?
26850 this.el.child('.roo-tpl-' + this.dataName) :
26853 el.dom.removeChild(this.nodes[index]);
26854 this.updateIndexes(index);
26858 * Refresh an individual node.
26859 * @param {Number} index
26861 refreshNode : function(index){
26862 this.onUpdate(this.store, this.store.getAt(index));
26865 updateIndexes : function(startIndex, endIndex){
26866 var ns = this.nodes;
26867 startIndex = startIndex || 0;
26868 endIndex = endIndex || ns.length - 1;
26869 for(var i = startIndex; i <= endIndex; i++){
26870 ns[i].nodeIndex = i;
26875 * Changes the data store this view uses and refresh the view.
26876 * @param {Store} store
26878 setStore : function(store, initial){
26879 if(!initial && this.store){
26880 this.store.un("datachanged", this.refresh);
26881 this.store.un("add", this.onAdd);
26882 this.store.un("remove", this.onRemove);
26883 this.store.un("update", this.onUpdate);
26884 this.store.un("clear", this.refresh);
26885 this.store.un("beforeload", this.onBeforeLoad);
26886 this.store.un("load", this.onLoad);
26887 this.store.un("loadexception", this.onLoad);
26891 store.on("datachanged", this.refresh, this);
26892 store.on("add", this.onAdd, this);
26893 store.on("remove", this.onRemove, this);
26894 store.on("update", this.onUpdate, this);
26895 store.on("clear", this.refresh, this);
26896 store.on("beforeload", this.onBeforeLoad, this);
26897 store.on("load", this.onLoad, this);
26898 store.on("loadexception", this.onLoad, this);
26906 * onbeforeLoad - masks the loading area.
26909 onBeforeLoad : function(store,opts)
26911 //Roo.log('onBeforeLoad');
26913 this.el.update("");
26915 this.el.mask(this.mask ? this.mask : "Loading" );
26917 onLoad : function ()
26924 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26925 * @param {HTMLElement} node
26926 * @return {HTMLElement} The template node
26928 findItemFromChild : function(node){
26929 var el = this.dataName ?
26930 this.el.child('.roo-tpl-' + this.dataName,true) :
26933 if(!node || node.parentNode == el){
26936 var p = node.parentNode;
26937 while(p && p != el){
26938 if(p.parentNode == el){
26947 onClick : function(e){
26948 var item = this.findItemFromChild(e.getTarget());
26950 var index = this.indexOf(item);
26951 if(this.onItemClick(item, index, e) !== false){
26952 this.fireEvent("click", this, index, item, e);
26955 this.clearSelections();
26960 onContextMenu : function(e){
26961 var item = this.findItemFromChild(e.getTarget());
26963 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26968 onDblClick : function(e){
26969 var item = this.findItemFromChild(e.getTarget());
26971 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26975 onItemClick : function(item, index, e)
26977 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26980 if (this.toggleSelect) {
26981 var m = this.isSelected(item) ? 'unselect' : 'select';
26984 _t[m](item, true, false);
26987 if(this.multiSelect || this.singleSelect){
26988 if(this.multiSelect && e.shiftKey && this.lastSelection){
26989 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26991 this.select(item, this.multiSelect && e.ctrlKey);
26992 this.lastSelection = item;
26995 if(!this.tickable){
26996 e.preventDefault();
27004 * Get the number of selected nodes.
27007 getSelectionCount : function(){
27008 return this.selections.length;
27012 * Get the currently selected nodes.
27013 * @return {Array} An array of HTMLElements
27015 getSelectedNodes : function(){
27016 return this.selections;
27020 * Get the indexes of the selected nodes.
27023 getSelectedIndexes : function(){
27024 var indexes = [], s = this.selections;
27025 for(var i = 0, len = s.length; i < len; i++){
27026 indexes.push(s[i].nodeIndex);
27032 * Clear all selections
27033 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
27035 clearSelections : function(suppressEvent){
27036 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
27037 this.cmp.elements = this.selections;
27038 this.cmp.removeClass(this.selectedClass);
27039 this.selections = [];
27040 if(!suppressEvent){
27041 this.fireEvent("selectionchange", this, this.selections);
27047 * Returns true if the passed node is selected
27048 * @param {HTMLElement/Number} node The node or node index
27049 * @return {Boolean}
27051 isSelected : function(node){
27052 var s = this.selections;
27056 node = this.getNode(node);
27057 return s.indexOf(node) !== -1;
27062 * @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
27063 * @param {Boolean} keepExisting (optional) true to keep existing selections
27064 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27066 select : function(nodeInfo, keepExisting, suppressEvent){
27067 if(nodeInfo instanceof Array){
27069 this.clearSelections(true);
27071 for(var i = 0, len = nodeInfo.length; i < len; i++){
27072 this.select(nodeInfo[i], true, true);
27076 var node = this.getNode(nodeInfo);
27077 if(!node || this.isSelected(node)){
27078 return; // already selected.
27081 this.clearSelections(true);
27084 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27085 Roo.fly(node).addClass(this.selectedClass);
27086 this.selections.push(node);
27087 if(!suppressEvent){
27088 this.fireEvent("selectionchange", this, this.selections);
27096 * @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
27097 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27098 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27100 unselect : function(nodeInfo, keepExisting, suppressEvent)
27102 if(nodeInfo instanceof Array){
27103 Roo.each(this.selections, function(s) {
27104 this.unselect(s, nodeInfo);
27108 var node = this.getNode(nodeInfo);
27109 if(!node || !this.isSelected(node)){
27110 //Roo.log("not selected");
27111 return; // not selected.
27115 Roo.each(this.selections, function(s) {
27117 Roo.fly(node).removeClass(this.selectedClass);
27124 this.selections= ns;
27125 this.fireEvent("selectionchange", this, this.selections);
27129 * Gets a template node.
27130 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27131 * @return {HTMLElement} The node or null if it wasn't found
27133 getNode : function(nodeInfo){
27134 if(typeof nodeInfo == "string"){
27135 return document.getElementById(nodeInfo);
27136 }else if(typeof nodeInfo == "number"){
27137 return this.nodes[nodeInfo];
27143 * Gets a range template nodes.
27144 * @param {Number} startIndex
27145 * @param {Number} endIndex
27146 * @return {Array} An array of nodes
27148 getNodes : function(start, end){
27149 var ns = this.nodes;
27150 start = start || 0;
27151 end = typeof end == "undefined" ? ns.length - 1 : end;
27154 for(var i = start; i <= end; i++){
27158 for(var i = start; i >= end; i--){
27166 * Finds the index of the passed node
27167 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27168 * @return {Number} The index of the node or -1
27170 indexOf : function(node){
27171 node = this.getNode(node);
27172 if(typeof node.nodeIndex == "number"){
27173 return node.nodeIndex;
27175 var ns = this.nodes;
27176 for(var i = 0, len = ns.length; i < len; i++){
27186 * Ext JS Library 1.1.1
27187 * Copyright(c) 2006-2007, Ext JS, LLC.
27189 * Originally Released Under LGPL - original licence link has changed is not relivant.
27192 * <script type="text/javascript">
27196 * @class Roo.JsonView
27197 * @extends Roo.View
27198 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27200 var view = new Roo.JsonView({
27201 container: "my-element",
27202 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27207 // listen for node click?
27208 view.on("click", function(vw, index, node, e){
27209 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27212 // direct load of JSON data
27213 view.load("foobar.php");
27215 // Example from my blog list
27216 var tpl = new Roo.Template(
27217 '<div class="entry">' +
27218 '<a class="entry-title" href="{link}">{title}</a>' +
27219 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27220 "</div><hr />"
27223 var moreView = new Roo.JsonView({
27224 container : "entry-list",
27228 moreView.on("beforerender", this.sortEntries, this);
27230 url: "/blog/get-posts.php",
27231 params: "allposts=true",
27232 text: "Loading Blog Entries..."
27236 * Note: old code is supported with arguments : (container, template, config)
27240 * Create a new JsonView
27242 * @param {Object} config The config object
27245 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27248 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27250 var um = this.el.getUpdateManager();
27251 um.setRenderer(this);
27252 um.on("update", this.onLoad, this);
27253 um.on("failure", this.onLoadException, this);
27256 * @event beforerender
27257 * Fires before rendering of the downloaded JSON data.
27258 * @param {Roo.JsonView} this
27259 * @param {Object} data The JSON data loaded
27263 * Fires when data is loaded.
27264 * @param {Roo.JsonView} this
27265 * @param {Object} data The JSON data loaded
27266 * @param {Object} response The raw Connect response object
27269 * @event loadexception
27270 * Fires when loading fails.
27271 * @param {Roo.JsonView} this
27272 * @param {Object} response The raw Connect response object
27275 'beforerender' : true,
27277 'loadexception' : true
27280 Roo.extend(Roo.JsonView, Roo.View, {
27282 * @type {String} The root property in the loaded JSON object that contains the data
27287 * Refreshes the view.
27289 refresh : function(){
27290 this.clearSelections();
27291 this.el.update("");
27293 var o = this.jsonData;
27294 if(o && o.length > 0){
27295 for(var i = 0, len = o.length; i < len; i++){
27296 var data = this.prepareData(o[i], i, o);
27297 html[html.length] = this.tpl.apply(data);
27300 html.push(this.emptyText);
27302 this.el.update(html.join(""));
27303 this.nodes = this.el.dom.childNodes;
27304 this.updateIndexes(0);
27308 * 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.
27309 * @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:
27312 url: "your-url.php",
27313 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27314 callback: yourFunction,
27315 scope: yourObject, //(optional scope)
27318 text: "Loading...",
27323 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27324 * 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.
27325 * @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}
27326 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27327 * @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.
27330 var um = this.el.getUpdateManager();
27331 um.update.apply(um, arguments);
27334 // note - render is a standard framework call...
27335 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27336 render : function(el, response){
27338 this.clearSelections();
27339 this.el.update("");
27342 if (response != '') {
27343 o = Roo.util.JSON.decode(response.responseText);
27346 o = o[this.jsonRoot];
27352 * The current JSON data or null
27355 this.beforeRender();
27360 * Get the number of records in the current JSON dataset
27363 getCount : function(){
27364 return this.jsonData ? this.jsonData.length : 0;
27368 * Returns the JSON object for the specified node(s)
27369 * @param {HTMLElement/Array} node The node or an array of nodes
27370 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27371 * you get the JSON object for the node
27373 getNodeData : function(node){
27374 if(node instanceof Array){
27376 for(var i = 0, len = node.length; i < len; i++){
27377 data.push(this.getNodeData(node[i]));
27381 return this.jsonData[this.indexOf(node)] || null;
27384 beforeRender : function(){
27385 this.snapshot = this.jsonData;
27387 this.sort.apply(this, this.sortInfo);
27389 this.fireEvent("beforerender", this, this.jsonData);
27392 onLoad : function(el, o){
27393 this.fireEvent("load", this, this.jsonData, o);
27396 onLoadException : function(el, o){
27397 this.fireEvent("loadexception", this, o);
27401 * Filter the data by a specific property.
27402 * @param {String} property A property on your JSON objects
27403 * @param {String/RegExp} value Either string that the property values
27404 * should start with, or a RegExp to test against the property
27406 filter : function(property, value){
27409 var ss = this.snapshot;
27410 if(typeof value == "string"){
27411 var vlen = value.length;
27413 this.clearFilter();
27416 value = value.toLowerCase();
27417 for(var i = 0, len = ss.length; i < len; i++){
27419 if(o[property].substr(0, vlen).toLowerCase() == value){
27423 } else if(value.exec){ // regex?
27424 for(var i = 0, len = ss.length; i < len; i++){
27426 if(value.test(o[property])){
27433 this.jsonData = data;
27439 * Filter by a function. The passed function will be called with each
27440 * object in the current dataset. If the function returns true the value is kept,
27441 * otherwise it is filtered.
27442 * @param {Function} fn
27443 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27445 filterBy : function(fn, scope){
27448 var ss = this.snapshot;
27449 for(var i = 0, len = ss.length; i < len; i++){
27451 if(fn.call(scope || this, o)){
27455 this.jsonData = data;
27461 * Clears the current filter.
27463 clearFilter : function(){
27464 if(this.snapshot && this.jsonData != this.snapshot){
27465 this.jsonData = this.snapshot;
27472 * Sorts the data for this view and refreshes it.
27473 * @param {String} property A property on your JSON objects to sort on
27474 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27475 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27477 sort : function(property, dir, sortType){
27478 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27481 var dsc = dir && dir.toLowerCase() == "desc";
27482 var f = function(o1, o2){
27483 var v1 = sortType ? sortType(o1[p]) : o1[p];
27484 var v2 = sortType ? sortType(o2[p]) : o2[p];
27487 return dsc ? +1 : -1;
27488 } else if(v1 > v2){
27489 return dsc ? -1 : +1;
27494 this.jsonData.sort(f);
27496 if(this.jsonData != this.snapshot){
27497 this.snapshot.sort(f);
27503 * Ext JS Library 1.1.1
27504 * Copyright(c) 2006-2007, Ext JS, LLC.
27506 * Originally Released Under LGPL - original licence link has changed is not relivant.
27509 * <script type="text/javascript">
27514 * @class Roo.ColorPalette
27515 * @extends Roo.Component
27516 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27517 * Here's an example of typical usage:
27519 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27520 cp.render('my-div');
27522 cp.on('select', function(palette, selColor){
27523 // do something with selColor
27527 * Create a new ColorPalette
27528 * @param {Object} config The config object
27530 Roo.ColorPalette = function(config){
27531 Roo.ColorPalette.superclass.constructor.call(this, config);
27535 * Fires when a color is selected
27536 * @param {ColorPalette} this
27537 * @param {String} color The 6-digit color hex code (without the # symbol)
27543 this.on("select", this.handler, this.scope, true);
27546 Roo.extend(Roo.ColorPalette, Roo.Component, {
27548 * @cfg {String} itemCls
27549 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27551 itemCls : "x-color-palette",
27553 * @cfg {String} value
27554 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27555 * the hex codes are case-sensitive.
27558 clickEvent:'click',
27560 ctype: "Roo.ColorPalette",
27563 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27565 allowReselect : false,
27568 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27569 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27570 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27571 * of colors with the width setting until the box is symmetrical.</p>
27572 * <p>You can override individual colors if needed:</p>
27574 var cp = new Roo.ColorPalette();
27575 cp.colors[0] = "FF0000"; // change the first box to red
27578 Or you can provide a custom array of your own for complete control:
27580 var cp = new Roo.ColorPalette();
27581 cp.colors = ["000000", "993300", "333300"];
27586 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27587 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27588 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27589 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27590 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27594 onRender : function(container, position){
27595 var t = new Roo.MasterTemplate(
27596 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27598 var c = this.colors;
27599 for(var i = 0, len = c.length; i < len; i++){
27602 var el = document.createElement("div");
27603 el.className = this.itemCls;
27605 container.dom.insertBefore(el, position);
27606 this.el = Roo.get(el);
27607 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27608 if(this.clickEvent != 'click'){
27609 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27614 afterRender : function(){
27615 Roo.ColorPalette.superclass.afterRender.call(this);
27617 var s = this.value;
27624 handleClick : function(e, t){
27625 e.preventDefault();
27626 if(!this.disabled){
27627 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27628 this.select(c.toUpperCase());
27633 * Selects the specified color in the palette (fires the select event)
27634 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27636 select : function(color){
27637 color = color.replace("#", "");
27638 if(color != this.value || this.allowReselect){
27641 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27643 el.child("a.color-"+color).addClass("x-color-palette-sel");
27644 this.value = color;
27645 this.fireEvent("select", this, color);
27650 * Ext JS Library 1.1.1
27651 * Copyright(c) 2006-2007, Ext JS, LLC.
27653 * Originally Released Under LGPL - original licence link has changed is not relivant.
27656 * <script type="text/javascript">
27660 * @class Roo.DatePicker
27661 * @extends Roo.Component
27662 * Simple date picker class.
27664 * Create a new DatePicker
27665 * @param {Object} config The config object
27667 Roo.DatePicker = function(config){
27668 Roo.DatePicker.superclass.constructor.call(this, config);
27670 this.value = config && config.value ?
27671 config.value.clearTime() : new Date().clearTime();
27676 * Fires when a date is selected
27677 * @param {DatePicker} this
27678 * @param {Date} date The selected date
27682 * @event monthchange
27683 * Fires when the displayed month changes
27684 * @param {DatePicker} this
27685 * @param {Date} date The selected month
27687 'monthchange': true
27691 this.on("select", this.handler, this.scope || this);
27693 // build the disabledDatesRE
27694 if(!this.disabledDatesRE && this.disabledDates){
27695 var dd = this.disabledDates;
27697 for(var i = 0; i < dd.length; i++){
27699 if(i != dd.length-1) {
27703 this.disabledDatesRE = new RegExp(re + ")");
27707 Roo.extend(Roo.DatePicker, Roo.Component, {
27709 * @cfg {String} todayText
27710 * The text to display on the button that selects the current date (defaults to "Today")
27712 todayText : "Today",
27714 * @cfg {String} okText
27715 * The text to display on the ok button
27717 okText : " OK ", //   to give the user extra clicking room
27719 * @cfg {String} cancelText
27720 * The text to display on the cancel button
27722 cancelText : "Cancel",
27724 * @cfg {String} todayTip
27725 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27727 todayTip : "{0} (Spacebar)",
27729 * @cfg {Date} minDate
27730 * Minimum allowable date (JavaScript date object, defaults to null)
27734 * @cfg {Date} maxDate
27735 * Maximum allowable date (JavaScript date object, defaults to null)
27739 * @cfg {String} minText
27740 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27742 minText : "This date is before the minimum date",
27744 * @cfg {String} maxText
27745 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27747 maxText : "This date is after the maximum date",
27749 * @cfg {String} format
27750 * The default date format string which can be overriden for localization support. The format must be
27751 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27755 * @cfg {Array} disabledDays
27756 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27758 disabledDays : null,
27760 * @cfg {String} disabledDaysText
27761 * The tooltip to display when the date falls on a disabled day (defaults to "")
27763 disabledDaysText : "",
27765 * @cfg {RegExp} disabledDatesRE
27766 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27768 disabledDatesRE : null,
27770 * @cfg {String} disabledDatesText
27771 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27773 disabledDatesText : "",
27775 * @cfg {Boolean} constrainToViewport
27776 * True to constrain the date picker to the viewport (defaults to true)
27778 constrainToViewport : true,
27780 * @cfg {Array} monthNames
27781 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27783 monthNames : Date.monthNames,
27785 * @cfg {Array} dayNames
27786 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27788 dayNames : Date.dayNames,
27790 * @cfg {String} nextText
27791 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27793 nextText: 'Next Month (Control+Right)',
27795 * @cfg {String} prevText
27796 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27798 prevText: 'Previous Month (Control+Left)',
27800 * @cfg {String} monthYearText
27801 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27803 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27805 * @cfg {Number} startDay
27806 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27810 * @cfg {Bool} showClear
27811 * Show a clear button (usefull for date form elements that can be blank.)
27817 * Sets the value of the date field
27818 * @param {Date} value The date to set
27820 setValue : function(value){
27821 var old = this.value;
27823 if (typeof(value) == 'string') {
27825 value = Date.parseDate(value, this.format);
27828 value = new Date();
27831 this.value = value.clearTime(true);
27833 this.update(this.value);
27838 * Gets the current selected value of the date field
27839 * @return {Date} The selected date
27841 getValue : function(){
27846 focus : function(){
27848 this.update(this.activeDate);
27853 onRender : function(container, position){
27856 '<table cellspacing="0">',
27857 '<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>',
27858 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27859 var dn = this.dayNames;
27860 for(var i = 0; i < 7; i++){
27861 var d = this.startDay+i;
27865 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27867 m[m.length] = "</tr></thead><tbody><tr>";
27868 for(var i = 0; i < 42; i++) {
27869 if(i % 7 == 0 && i != 0){
27870 m[m.length] = "</tr><tr>";
27872 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27874 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27875 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27877 var el = document.createElement("div");
27878 el.className = "x-date-picker";
27879 el.innerHTML = m.join("");
27881 container.dom.insertBefore(el, position);
27883 this.el = Roo.get(el);
27884 this.eventEl = Roo.get(el.firstChild);
27886 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27887 handler: this.showPrevMonth,
27889 preventDefault:true,
27893 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27894 handler: this.showNextMonth,
27896 preventDefault:true,
27900 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27902 this.monthPicker = this.el.down('div.x-date-mp');
27903 this.monthPicker.enableDisplayMode('block');
27905 var kn = new Roo.KeyNav(this.eventEl, {
27906 "left" : function(e){
27908 this.showPrevMonth() :
27909 this.update(this.activeDate.add("d", -1));
27912 "right" : function(e){
27914 this.showNextMonth() :
27915 this.update(this.activeDate.add("d", 1));
27918 "up" : function(e){
27920 this.showNextYear() :
27921 this.update(this.activeDate.add("d", -7));
27924 "down" : function(e){
27926 this.showPrevYear() :
27927 this.update(this.activeDate.add("d", 7));
27930 "pageUp" : function(e){
27931 this.showNextMonth();
27934 "pageDown" : function(e){
27935 this.showPrevMonth();
27938 "enter" : function(e){
27939 e.stopPropagation();
27946 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27948 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27950 this.el.unselectable();
27952 this.cells = this.el.select("table.x-date-inner tbody td");
27953 this.textNodes = this.el.query("table.x-date-inner tbody span");
27955 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27957 tooltip: this.monthYearText
27960 this.mbtn.on('click', this.showMonthPicker, this);
27961 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27964 var today = (new Date()).dateFormat(this.format);
27966 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27967 if (this.showClear) {
27968 baseTb.add( new Roo.Toolbar.Fill());
27971 text: String.format(this.todayText, today),
27972 tooltip: String.format(this.todayTip, today),
27973 handler: this.selectToday,
27977 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27980 if (this.showClear) {
27982 baseTb.add( new Roo.Toolbar.Fill());
27985 cls: 'x-btn-icon x-btn-clear',
27986 handler: function() {
27988 this.fireEvent("select", this, '');
27998 this.update(this.value);
28001 createMonthPicker : function(){
28002 if(!this.monthPicker.dom.firstChild){
28003 var buf = ['<table border="0" cellspacing="0">'];
28004 for(var i = 0; i < 6; i++){
28006 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
28007 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
28009 '<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>' :
28010 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
28014 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
28016 '</button><button type="button" class="x-date-mp-cancel">',
28018 '</button></td></tr>',
28021 this.monthPicker.update(buf.join(''));
28022 this.monthPicker.on('click', this.onMonthClick, this);
28023 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
28025 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
28026 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
28028 this.mpMonths.each(function(m, a, i){
28031 m.dom.xmonth = 5 + Math.round(i * .5);
28033 m.dom.xmonth = Math.round((i-1) * .5);
28039 showMonthPicker : function(){
28040 this.createMonthPicker();
28041 var size = this.el.getSize();
28042 this.monthPicker.setSize(size);
28043 this.monthPicker.child('table').setSize(size);
28045 this.mpSelMonth = (this.activeDate || this.value).getMonth();
28046 this.updateMPMonth(this.mpSelMonth);
28047 this.mpSelYear = (this.activeDate || this.value).getFullYear();
28048 this.updateMPYear(this.mpSelYear);
28050 this.monthPicker.slideIn('t', {duration:.2});
28053 updateMPYear : function(y){
28055 var ys = this.mpYears.elements;
28056 for(var i = 1; i <= 10; i++){
28057 var td = ys[i-1], y2;
28059 y2 = y + Math.round(i * .5);
28060 td.firstChild.innerHTML = y2;
28063 y2 = y - (5-Math.round(i * .5));
28064 td.firstChild.innerHTML = y2;
28067 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28071 updateMPMonth : function(sm){
28072 this.mpMonths.each(function(m, a, i){
28073 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28077 selectMPMonth: function(m){
28081 onMonthClick : function(e, t){
28083 var el = new Roo.Element(t), pn;
28084 if(el.is('button.x-date-mp-cancel')){
28085 this.hideMonthPicker();
28087 else if(el.is('button.x-date-mp-ok')){
28088 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28089 this.hideMonthPicker();
28091 else if(pn = el.up('td.x-date-mp-month', 2)){
28092 this.mpMonths.removeClass('x-date-mp-sel');
28093 pn.addClass('x-date-mp-sel');
28094 this.mpSelMonth = pn.dom.xmonth;
28096 else if(pn = el.up('td.x-date-mp-year', 2)){
28097 this.mpYears.removeClass('x-date-mp-sel');
28098 pn.addClass('x-date-mp-sel');
28099 this.mpSelYear = pn.dom.xyear;
28101 else if(el.is('a.x-date-mp-prev')){
28102 this.updateMPYear(this.mpyear-10);
28104 else if(el.is('a.x-date-mp-next')){
28105 this.updateMPYear(this.mpyear+10);
28109 onMonthDblClick : function(e, t){
28111 var el = new Roo.Element(t), pn;
28112 if(pn = el.up('td.x-date-mp-month', 2)){
28113 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28114 this.hideMonthPicker();
28116 else if(pn = el.up('td.x-date-mp-year', 2)){
28117 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28118 this.hideMonthPicker();
28122 hideMonthPicker : function(disableAnim){
28123 if(this.monthPicker){
28124 if(disableAnim === true){
28125 this.monthPicker.hide();
28127 this.monthPicker.slideOut('t', {duration:.2});
28133 showPrevMonth : function(e){
28134 this.update(this.activeDate.add("mo", -1));
28138 showNextMonth : function(e){
28139 this.update(this.activeDate.add("mo", 1));
28143 showPrevYear : function(){
28144 this.update(this.activeDate.add("y", -1));
28148 showNextYear : function(){
28149 this.update(this.activeDate.add("y", 1));
28153 handleMouseWheel : function(e){
28154 var delta = e.getWheelDelta();
28156 this.showPrevMonth();
28158 } else if(delta < 0){
28159 this.showNextMonth();
28165 handleDateClick : function(e, t){
28167 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28168 this.setValue(new Date(t.dateValue));
28169 this.fireEvent("select", this, this.value);
28174 selectToday : function(){
28175 this.setValue(new Date().clearTime());
28176 this.fireEvent("select", this, this.value);
28180 update : function(date)
28182 var vd = this.activeDate;
28183 this.activeDate = date;
28185 var t = date.getTime();
28186 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28187 this.cells.removeClass("x-date-selected");
28188 this.cells.each(function(c){
28189 if(c.dom.firstChild.dateValue == t){
28190 c.addClass("x-date-selected");
28191 setTimeout(function(){
28192 try{c.dom.firstChild.focus();}catch(e){}
28201 var days = date.getDaysInMonth();
28202 var firstOfMonth = date.getFirstDateOfMonth();
28203 var startingPos = firstOfMonth.getDay()-this.startDay;
28205 if(startingPos <= this.startDay){
28209 var pm = date.add("mo", -1);
28210 var prevStart = pm.getDaysInMonth()-startingPos;
28212 var cells = this.cells.elements;
28213 var textEls = this.textNodes;
28214 days += startingPos;
28216 // convert everything to numbers so it's fast
28217 var day = 86400000;
28218 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28219 var today = new Date().clearTime().getTime();
28220 var sel = date.clearTime().getTime();
28221 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28222 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28223 var ddMatch = this.disabledDatesRE;
28224 var ddText = this.disabledDatesText;
28225 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28226 var ddaysText = this.disabledDaysText;
28227 var format = this.format;
28229 var setCellClass = function(cal, cell){
28231 var t = d.getTime();
28232 cell.firstChild.dateValue = t;
28234 cell.className += " x-date-today";
28235 cell.title = cal.todayText;
28238 cell.className += " x-date-selected";
28239 setTimeout(function(){
28240 try{cell.firstChild.focus();}catch(e){}
28245 cell.className = " x-date-disabled";
28246 cell.title = cal.minText;
28250 cell.className = " x-date-disabled";
28251 cell.title = cal.maxText;
28255 if(ddays.indexOf(d.getDay()) != -1){
28256 cell.title = ddaysText;
28257 cell.className = " x-date-disabled";
28260 if(ddMatch && format){
28261 var fvalue = d.dateFormat(format);
28262 if(ddMatch.test(fvalue)){
28263 cell.title = ddText.replace("%0", fvalue);
28264 cell.className = " x-date-disabled";
28270 for(; i < startingPos; i++) {
28271 textEls[i].innerHTML = (++prevStart);
28272 d.setDate(d.getDate()+1);
28273 cells[i].className = "x-date-prevday";
28274 setCellClass(this, cells[i]);
28276 for(; i < days; i++){
28277 intDay = i - startingPos + 1;
28278 textEls[i].innerHTML = (intDay);
28279 d.setDate(d.getDate()+1);
28280 cells[i].className = "x-date-active";
28281 setCellClass(this, cells[i]);
28284 for(; i < 42; i++) {
28285 textEls[i].innerHTML = (++extraDays);
28286 d.setDate(d.getDate()+1);
28287 cells[i].className = "x-date-nextday";
28288 setCellClass(this, cells[i]);
28291 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28292 this.fireEvent('monthchange', this, date);
28294 if(!this.internalRender){
28295 var main = this.el.dom.firstChild;
28296 var w = main.offsetWidth;
28297 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28298 Roo.fly(main).setWidth(w);
28299 this.internalRender = true;
28300 // opera does not respect the auto grow header center column
28301 // then, after it gets a width opera refuses to recalculate
28302 // without a second pass
28303 if(Roo.isOpera && !this.secondPass){
28304 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28305 this.secondPass = true;
28306 this.update.defer(10, this, [date]);
28314 * Ext JS Library 1.1.1
28315 * Copyright(c) 2006-2007, Ext JS, LLC.
28317 * Originally Released Under LGPL - original licence link has changed is not relivant.
28320 * <script type="text/javascript">
28323 * @class Roo.TabPanel
28324 * @extends Roo.util.Observable
28325 * A lightweight tab container.
28329 // basic tabs 1, built from existing content
28330 var tabs = new Roo.TabPanel("tabs1");
28331 tabs.addTab("script", "View Script");
28332 tabs.addTab("markup", "View Markup");
28333 tabs.activate("script");
28335 // more advanced tabs, built from javascript
28336 var jtabs = new Roo.TabPanel("jtabs");
28337 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28339 // set up the UpdateManager
28340 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28341 var updater = tab2.getUpdateManager();
28342 updater.setDefaultUrl("ajax1.htm");
28343 tab2.on('activate', updater.refresh, updater, true);
28345 // Use setUrl for Ajax loading
28346 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28347 tab3.setUrl("ajax2.htm", null, true);
28350 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28353 jtabs.activate("jtabs-1");
28356 * Create a new TabPanel.
28357 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28358 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28360 Roo.TabPanel = function(container, config){
28362 * The container element for this TabPanel.
28363 * @type Roo.Element
28365 this.el = Roo.get(container, true);
28367 if(typeof config == "boolean"){
28368 this.tabPosition = config ? "bottom" : "top";
28370 Roo.apply(this, config);
28373 if(this.tabPosition == "bottom"){
28374 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28375 this.el.addClass("x-tabs-bottom");
28377 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28378 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28379 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28381 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28383 if(this.tabPosition != "bottom"){
28384 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28385 * @type Roo.Element
28387 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28388 this.el.addClass("x-tabs-top");
28392 this.bodyEl.setStyle("position", "relative");
28394 this.active = null;
28395 this.activateDelegate = this.activate.createDelegate(this);
28400 * Fires when the active tab changes
28401 * @param {Roo.TabPanel} this
28402 * @param {Roo.TabPanelItem} activePanel The new active tab
28406 * @event beforetabchange
28407 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28408 * @param {Roo.TabPanel} this
28409 * @param {Object} e Set cancel to true on this object to cancel the tab change
28410 * @param {Roo.TabPanelItem} tab The tab being changed to
28412 "beforetabchange" : true
28415 Roo.EventManager.onWindowResize(this.onResize, this);
28416 this.cpad = this.el.getPadding("lr");
28417 this.hiddenCount = 0;
28420 // toolbar on the tabbar support...
28421 if (this.toolbar) {
28422 var tcfg = this.toolbar;
28423 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28424 this.toolbar = new Roo.Toolbar(tcfg);
28425 if (Roo.isSafari) {
28426 var tbl = tcfg.container.child('table', true);
28427 tbl.setAttribute('width', '100%');
28434 Roo.TabPanel.superclass.constructor.call(this);
28437 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28439 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28441 tabPosition : "top",
28443 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28445 currentTabWidth : 0,
28447 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28451 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28455 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28457 preferredTabWidth : 175,
28459 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28461 resizeTabs : false,
28463 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28465 monitorResize : true,
28467 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28472 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28473 * @param {String} id The id of the div to use <b>or create</b>
28474 * @param {String} text The text for the tab
28475 * @param {String} content (optional) Content to put in the TabPanelItem body
28476 * @param {Boolean} closable (optional) True to create a close icon on the tab
28477 * @return {Roo.TabPanelItem} The created TabPanelItem
28479 addTab : function(id, text, content, closable){
28480 var item = new Roo.TabPanelItem(this, id, text, closable);
28481 this.addTabItem(item);
28483 item.setContent(content);
28489 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28490 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28491 * @return {Roo.TabPanelItem}
28493 getTab : function(id){
28494 return this.items[id];
28498 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28499 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28501 hideTab : function(id){
28502 var t = this.items[id];
28505 this.hiddenCount++;
28506 this.autoSizeTabs();
28511 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28512 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28514 unhideTab : function(id){
28515 var t = this.items[id];
28517 t.setHidden(false);
28518 this.hiddenCount--;
28519 this.autoSizeTabs();
28524 * Adds an existing {@link Roo.TabPanelItem}.
28525 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28527 addTabItem : function(item){
28528 this.items[item.id] = item;
28529 this.items.push(item);
28530 if(this.resizeTabs){
28531 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28532 this.autoSizeTabs();
28539 * Removes a {@link Roo.TabPanelItem}.
28540 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28542 removeTab : function(id){
28543 var items = this.items;
28544 var tab = items[id];
28545 if(!tab) { return; }
28546 var index = items.indexOf(tab);
28547 if(this.active == tab && items.length > 1){
28548 var newTab = this.getNextAvailable(index);
28553 this.stripEl.dom.removeChild(tab.pnode.dom);
28554 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28555 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28557 items.splice(index, 1);
28558 delete this.items[tab.id];
28559 tab.fireEvent("close", tab);
28560 tab.purgeListeners();
28561 this.autoSizeTabs();
28564 getNextAvailable : function(start){
28565 var items = this.items;
28567 // look for a next tab that will slide over to
28568 // replace the one being removed
28569 while(index < items.length){
28570 var item = items[++index];
28571 if(item && !item.isHidden()){
28575 // if one isn't found select the previous tab (on the left)
28578 var item = items[--index];
28579 if(item && !item.isHidden()){
28587 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28588 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28590 disableTab : function(id){
28591 var tab = this.items[id];
28592 if(tab && this.active != tab){
28598 * Enables a {@link Roo.TabPanelItem} that is disabled.
28599 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28601 enableTab : function(id){
28602 var tab = this.items[id];
28607 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28608 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28609 * @return {Roo.TabPanelItem} The TabPanelItem.
28611 activate : function(id){
28612 var tab = this.items[id];
28616 if(tab == this.active || tab.disabled){
28620 this.fireEvent("beforetabchange", this, e, tab);
28621 if(e.cancel !== true && !tab.disabled){
28623 this.active.hide();
28625 this.active = this.items[id];
28626 this.active.show();
28627 this.fireEvent("tabchange", this, this.active);
28633 * Gets the active {@link Roo.TabPanelItem}.
28634 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28636 getActiveTab : function(){
28637 return this.active;
28641 * Updates the tab body element to fit the height of the container element
28642 * for overflow scrolling
28643 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28645 syncHeight : function(targetHeight){
28646 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28647 var bm = this.bodyEl.getMargins();
28648 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28649 this.bodyEl.setHeight(newHeight);
28653 onResize : function(){
28654 if(this.monitorResize){
28655 this.autoSizeTabs();
28660 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28662 beginUpdate : function(){
28663 this.updating = true;
28667 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28669 endUpdate : function(){
28670 this.updating = false;
28671 this.autoSizeTabs();
28675 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28677 autoSizeTabs : function(){
28678 var count = this.items.length;
28679 var vcount = count - this.hiddenCount;
28680 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28683 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28684 var availWidth = Math.floor(w / vcount);
28685 var b = this.stripBody;
28686 if(b.getWidth() > w){
28687 var tabs = this.items;
28688 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28689 if(availWidth < this.minTabWidth){
28690 /*if(!this.sleft){ // incomplete scrolling code
28691 this.createScrollButtons();
28694 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28697 if(this.currentTabWidth < this.preferredTabWidth){
28698 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28704 * Returns the number of tabs in this TabPanel.
28707 getCount : function(){
28708 return this.items.length;
28712 * Resizes all the tabs to the passed width
28713 * @param {Number} The new width
28715 setTabWidth : function(width){
28716 this.currentTabWidth = width;
28717 for(var i = 0, len = this.items.length; i < len; i++) {
28718 if(!this.items[i].isHidden()) {
28719 this.items[i].setWidth(width);
28725 * Destroys this TabPanel
28726 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28728 destroy : function(removeEl){
28729 Roo.EventManager.removeResizeListener(this.onResize, this);
28730 for(var i = 0, len = this.items.length; i < len; i++){
28731 this.items[i].purgeListeners();
28733 if(removeEl === true){
28734 this.el.update("");
28741 * @class Roo.TabPanelItem
28742 * @extends Roo.util.Observable
28743 * Represents an individual item (tab plus body) in a TabPanel.
28744 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28745 * @param {String} id The id of this TabPanelItem
28746 * @param {String} text The text for the tab of this TabPanelItem
28747 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28749 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28751 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28752 * @type Roo.TabPanel
28754 this.tabPanel = tabPanel;
28756 * The id for this TabPanelItem
28761 this.disabled = false;
28765 this.loaded = false;
28766 this.closable = closable;
28769 * The body element for this TabPanelItem.
28770 * @type Roo.Element
28772 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28773 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28774 this.bodyEl.setStyle("display", "block");
28775 this.bodyEl.setStyle("zoom", "1");
28778 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28780 this.el = Roo.get(els.el, true);
28781 this.inner = Roo.get(els.inner, true);
28782 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28783 this.pnode = Roo.get(els.el.parentNode, true);
28784 this.el.on("mousedown", this.onTabMouseDown, this);
28785 this.el.on("click", this.onTabClick, this);
28788 var c = Roo.get(els.close, true);
28789 c.dom.title = this.closeText;
28790 c.addClassOnOver("close-over");
28791 c.on("click", this.closeClick, this);
28797 * Fires when this tab becomes the active tab.
28798 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28799 * @param {Roo.TabPanelItem} this
28803 * @event beforeclose
28804 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28805 * @param {Roo.TabPanelItem} this
28806 * @param {Object} e Set cancel to true on this object to cancel the close.
28808 "beforeclose": true,
28811 * Fires when this tab is closed.
28812 * @param {Roo.TabPanelItem} this
28816 * @event deactivate
28817 * Fires when this tab is no longer the active tab.
28818 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28819 * @param {Roo.TabPanelItem} this
28821 "deactivate" : true
28823 this.hidden = false;
28825 Roo.TabPanelItem.superclass.constructor.call(this);
28828 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28829 purgeListeners : function(){
28830 Roo.util.Observable.prototype.purgeListeners.call(this);
28831 this.el.removeAllListeners();
28834 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28837 this.pnode.addClass("on");
28840 this.tabPanel.stripWrap.repaint();
28842 this.fireEvent("activate", this.tabPanel, this);
28846 * Returns true if this tab is the active tab.
28847 * @return {Boolean}
28849 isActive : function(){
28850 return this.tabPanel.getActiveTab() == this;
28854 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28857 this.pnode.removeClass("on");
28859 this.fireEvent("deactivate", this.tabPanel, this);
28862 hideAction : function(){
28863 this.bodyEl.hide();
28864 this.bodyEl.setStyle("position", "absolute");
28865 this.bodyEl.setLeft("-20000px");
28866 this.bodyEl.setTop("-20000px");
28869 showAction : function(){
28870 this.bodyEl.setStyle("position", "relative");
28871 this.bodyEl.setTop("");
28872 this.bodyEl.setLeft("");
28873 this.bodyEl.show();
28877 * Set the tooltip for the tab.
28878 * @param {String} tooltip The tab's tooltip
28880 setTooltip : function(text){
28881 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28882 this.textEl.dom.qtip = text;
28883 this.textEl.dom.removeAttribute('title');
28885 this.textEl.dom.title = text;
28889 onTabClick : function(e){
28890 e.preventDefault();
28891 this.tabPanel.activate(this.id);
28894 onTabMouseDown : function(e){
28895 e.preventDefault();
28896 this.tabPanel.activate(this.id);
28899 getWidth : function(){
28900 return this.inner.getWidth();
28903 setWidth : function(width){
28904 var iwidth = width - this.pnode.getPadding("lr");
28905 this.inner.setWidth(iwidth);
28906 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28907 this.pnode.setWidth(width);
28911 * Show or hide the tab
28912 * @param {Boolean} hidden True to hide or false to show.
28914 setHidden : function(hidden){
28915 this.hidden = hidden;
28916 this.pnode.setStyle("display", hidden ? "none" : "");
28920 * Returns true if this tab is "hidden"
28921 * @return {Boolean}
28923 isHidden : function(){
28924 return this.hidden;
28928 * Returns the text for this tab
28931 getText : function(){
28935 autoSize : function(){
28936 //this.el.beginMeasure();
28937 this.textEl.setWidth(1);
28939 * #2804 [new] Tabs in Roojs
28940 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28942 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28943 //this.el.endMeasure();
28947 * Sets the text for the tab (Note: this also sets the tooltip text)
28948 * @param {String} text The tab's text and tooltip
28950 setText : function(text){
28952 this.textEl.update(text);
28953 this.setTooltip(text);
28954 if(!this.tabPanel.resizeTabs){
28959 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28961 activate : function(){
28962 this.tabPanel.activate(this.id);
28966 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28968 disable : function(){
28969 if(this.tabPanel.active != this){
28970 this.disabled = true;
28971 this.pnode.addClass("disabled");
28976 * Enables this TabPanelItem if it was previously disabled.
28978 enable : function(){
28979 this.disabled = false;
28980 this.pnode.removeClass("disabled");
28984 * Sets the content for this TabPanelItem.
28985 * @param {String} content The content
28986 * @param {Boolean} loadScripts true to look for and load scripts
28988 setContent : function(content, loadScripts){
28989 this.bodyEl.update(content, loadScripts);
28993 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28994 * @return {Roo.UpdateManager} The UpdateManager
28996 getUpdateManager : function(){
28997 return this.bodyEl.getUpdateManager();
29001 * Set a URL to be used to load the content for this TabPanelItem.
29002 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
29003 * @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)
29004 * @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)
29005 * @return {Roo.UpdateManager} The UpdateManager
29007 setUrl : function(url, params, loadOnce){
29008 if(this.refreshDelegate){
29009 this.un('activate', this.refreshDelegate);
29011 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
29012 this.on("activate", this.refreshDelegate);
29013 return this.bodyEl.getUpdateManager();
29017 _handleRefresh : function(url, params, loadOnce){
29018 if(!loadOnce || !this.loaded){
29019 var updater = this.bodyEl.getUpdateManager();
29020 updater.update(url, params, this._setLoaded.createDelegate(this));
29025 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
29026 * Will fail silently if the setUrl method has not been called.
29027 * This does not activate the panel, just updates its content.
29029 refresh : function(){
29030 if(this.refreshDelegate){
29031 this.loaded = false;
29032 this.refreshDelegate();
29037 _setLoaded : function(){
29038 this.loaded = true;
29042 closeClick : function(e){
29045 this.fireEvent("beforeclose", this, o);
29046 if(o.cancel !== true){
29047 this.tabPanel.removeTab(this.id);
29051 * The text displayed in the tooltip for the close icon.
29054 closeText : "Close this tab"
29058 Roo.TabPanel.prototype.createStrip = function(container){
29059 var strip = document.createElement("div");
29060 strip.className = "x-tabs-wrap";
29061 container.appendChild(strip);
29065 Roo.TabPanel.prototype.createStripList = function(strip){
29066 // div wrapper for retard IE
29067 // returns the "tr" element.
29068 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29069 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29070 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29071 return strip.firstChild.firstChild.firstChild.firstChild;
29074 Roo.TabPanel.prototype.createBody = function(container){
29075 var body = document.createElement("div");
29076 Roo.id(body, "tab-body");
29077 Roo.fly(body).addClass("x-tabs-body");
29078 container.appendChild(body);
29082 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29083 var body = Roo.getDom(id);
29085 body = document.createElement("div");
29088 Roo.fly(body).addClass("x-tabs-item-body");
29089 bodyEl.insertBefore(body, bodyEl.firstChild);
29093 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29094 var td = document.createElement("td");
29095 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29096 //stripEl.appendChild(td);
29098 td.className = "x-tabs-closable";
29099 if(!this.closeTpl){
29100 this.closeTpl = new Roo.Template(
29101 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29102 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29103 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29106 var el = this.closeTpl.overwrite(td, {"text": text});
29107 var close = el.getElementsByTagName("div")[0];
29108 var inner = el.getElementsByTagName("em")[0];
29109 return {"el": el, "close": close, "inner": inner};
29112 this.tabTpl = new Roo.Template(
29113 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29114 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29117 var el = this.tabTpl.overwrite(td, {"text": text});
29118 var inner = el.getElementsByTagName("em")[0];
29119 return {"el": el, "inner": inner};
29123 * Ext JS Library 1.1.1
29124 * Copyright(c) 2006-2007, Ext JS, LLC.
29126 * Originally Released Under LGPL - original licence link has changed is not relivant.
29129 * <script type="text/javascript">
29133 * @class Roo.Button
29134 * @extends Roo.util.Observable
29135 * Simple Button class
29136 * @cfg {String} text The button text
29137 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29138 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29139 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29140 * @cfg {Object} scope The scope of the handler
29141 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29142 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29143 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29144 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29145 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29146 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29147 applies if enableToggle = true)
29148 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29149 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29150 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29152 * Create a new button
29153 * @param {Object} config The config object
29155 Roo.Button = function(renderTo, config)
29159 renderTo = config.renderTo || false;
29162 Roo.apply(this, config);
29166 * Fires when this button is clicked
29167 * @param {Button} this
29168 * @param {EventObject} e The click event
29173 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29174 * @param {Button} this
29175 * @param {Boolean} pressed
29180 * Fires when the mouse hovers over the button
29181 * @param {Button} this
29182 * @param {Event} e The event object
29184 'mouseover' : true,
29187 * Fires when the mouse exits the button
29188 * @param {Button} this
29189 * @param {Event} e The event object
29194 * Fires when the button is rendered
29195 * @param {Button} this
29200 this.menu = Roo.menu.MenuMgr.get(this.menu);
29202 // register listeners first!! - so render can be captured..
29203 Roo.util.Observable.call(this);
29205 this.render(renderTo);
29211 Roo.extend(Roo.Button, Roo.util.Observable, {
29217 * Read-only. True if this button is hidden
29222 * Read-only. True if this button is disabled
29227 * Read-only. True if this button is pressed (only if enableToggle = true)
29233 * @cfg {Number} tabIndex
29234 * The DOM tabIndex for this button (defaults to undefined)
29236 tabIndex : undefined,
29239 * @cfg {Boolean} enableToggle
29240 * True to enable pressed/not pressed toggling (defaults to false)
29242 enableToggle: false,
29244 * @cfg {Mixed} menu
29245 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29249 * @cfg {String} menuAlign
29250 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29252 menuAlign : "tl-bl?",
29255 * @cfg {String} iconCls
29256 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29258 iconCls : undefined,
29260 * @cfg {String} type
29261 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29266 menuClassTarget: 'tr',
29269 * @cfg {String} clickEvent
29270 * The type of event to map to the button's event handler (defaults to 'click')
29272 clickEvent : 'click',
29275 * @cfg {Boolean} handleMouseEvents
29276 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29278 handleMouseEvents : true,
29281 * @cfg {String} tooltipType
29282 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29284 tooltipType : 'qtip',
29287 * @cfg {String} cls
29288 * A CSS class to apply to the button's main element.
29292 * @cfg {Roo.Template} template (Optional)
29293 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29294 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29295 * require code modifications if required elements (e.g. a button) aren't present.
29299 render : function(renderTo){
29301 if(this.hideParent){
29302 this.parentEl = Roo.get(renderTo);
29304 if(!this.dhconfig){
29305 if(!this.template){
29306 if(!Roo.Button.buttonTemplate){
29307 // hideous table template
29308 Roo.Button.buttonTemplate = new Roo.Template(
29309 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29310 '<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>',
29311 "</tr></tbody></table>");
29313 this.template = Roo.Button.buttonTemplate;
29315 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29316 var btnEl = btn.child("button:first");
29317 btnEl.on('focus', this.onFocus, this);
29318 btnEl.on('blur', this.onBlur, this);
29320 btn.addClass(this.cls);
29323 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29326 btnEl.addClass(this.iconCls);
29328 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29331 if(this.tabIndex !== undefined){
29332 btnEl.dom.tabIndex = this.tabIndex;
29335 if(typeof this.tooltip == 'object'){
29336 Roo.QuickTips.tips(Roo.apply({
29340 btnEl.dom[this.tooltipType] = this.tooltip;
29344 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29348 this.el.dom.id = this.el.id = this.id;
29351 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29352 this.menu.on("show", this.onMenuShow, this);
29353 this.menu.on("hide", this.onMenuHide, this);
29355 btn.addClass("x-btn");
29356 if(Roo.isIE && !Roo.isIE7){
29357 this.autoWidth.defer(1, this);
29361 if(this.handleMouseEvents){
29362 btn.on("mouseover", this.onMouseOver, this);
29363 btn.on("mouseout", this.onMouseOut, this);
29364 btn.on("mousedown", this.onMouseDown, this);
29366 btn.on(this.clickEvent, this.onClick, this);
29367 //btn.on("mouseup", this.onMouseUp, this);
29374 Roo.ButtonToggleMgr.register(this);
29376 this.el.addClass("x-btn-pressed");
29379 var repeater = new Roo.util.ClickRepeater(btn,
29380 typeof this.repeat == "object" ? this.repeat : {}
29382 repeater.on("click", this.onClick, this);
29385 this.fireEvent('render', this);
29389 * Returns the button's underlying element
29390 * @return {Roo.Element} The element
29392 getEl : function(){
29397 * Destroys this Button and removes any listeners.
29399 destroy : function(){
29400 Roo.ButtonToggleMgr.unregister(this);
29401 this.el.removeAllListeners();
29402 this.purgeListeners();
29407 autoWidth : function(){
29409 this.el.setWidth("auto");
29410 if(Roo.isIE7 && Roo.isStrict){
29411 var ib = this.el.child('button');
29412 if(ib && ib.getWidth() > 20){
29414 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29419 this.el.beginMeasure();
29421 if(this.el.getWidth() < this.minWidth){
29422 this.el.setWidth(this.minWidth);
29425 this.el.endMeasure();
29432 * Assigns this button's click handler
29433 * @param {Function} handler The function to call when the button is clicked
29434 * @param {Object} scope (optional) Scope for the function passed in
29436 setHandler : function(handler, scope){
29437 this.handler = handler;
29438 this.scope = scope;
29442 * Sets this button's text
29443 * @param {String} text The button text
29445 setText : function(text){
29448 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29454 * Gets the text for this button
29455 * @return {String} The button text
29457 getText : function(){
29465 this.hidden = false;
29467 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29475 this.hidden = true;
29477 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29482 * Convenience function for boolean show/hide
29483 * @param {Boolean} visible True to show, false to hide
29485 setVisible: function(visible){
29494 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29495 * @param {Boolean} state (optional) Force a particular state
29497 toggle : function(state){
29498 state = state === undefined ? !this.pressed : state;
29499 if(state != this.pressed){
29501 this.el.addClass("x-btn-pressed");
29502 this.pressed = true;
29503 this.fireEvent("toggle", this, true);
29505 this.el.removeClass("x-btn-pressed");
29506 this.pressed = false;
29507 this.fireEvent("toggle", this, false);
29509 if(this.toggleHandler){
29510 this.toggleHandler.call(this.scope || this, this, state);
29518 focus : function(){
29519 this.el.child('button:first').focus();
29523 * Disable this button
29525 disable : function(){
29527 this.el.addClass("x-btn-disabled");
29529 this.disabled = true;
29533 * Enable this button
29535 enable : function(){
29537 this.el.removeClass("x-btn-disabled");
29539 this.disabled = false;
29543 * Convenience function for boolean enable/disable
29544 * @param {Boolean} enabled True to enable, false to disable
29546 setDisabled : function(v){
29547 this[v !== true ? "enable" : "disable"]();
29551 onClick : function(e)
29554 e.preventDefault();
29559 if(!this.disabled){
29560 if(this.enableToggle){
29563 if(this.menu && !this.menu.isVisible()){
29564 this.menu.show(this.el, this.menuAlign);
29566 this.fireEvent("click", this, e);
29568 this.el.removeClass("x-btn-over");
29569 this.handler.call(this.scope || this, this, e);
29574 onMouseOver : function(e){
29575 if(!this.disabled){
29576 this.el.addClass("x-btn-over");
29577 this.fireEvent('mouseover', this, e);
29581 onMouseOut : function(e){
29582 if(!e.within(this.el, true)){
29583 this.el.removeClass("x-btn-over");
29584 this.fireEvent('mouseout', this, e);
29588 onFocus : function(e){
29589 if(!this.disabled){
29590 this.el.addClass("x-btn-focus");
29594 onBlur : function(e){
29595 this.el.removeClass("x-btn-focus");
29598 onMouseDown : function(e){
29599 if(!this.disabled && e.button == 0){
29600 this.el.addClass("x-btn-click");
29601 Roo.get(document).on('mouseup', this.onMouseUp, this);
29605 onMouseUp : function(e){
29607 this.el.removeClass("x-btn-click");
29608 Roo.get(document).un('mouseup', this.onMouseUp, this);
29612 onMenuShow : function(e){
29613 this.el.addClass("x-btn-menu-active");
29616 onMenuHide : function(e){
29617 this.el.removeClass("x-btn-menu-active");
29621 // Private utility class used by Button
29622 Roo.ButtonToggleMgr = function(){
29625 function toggleGroup(btn, state){
29627 var g = groups[btn.toggleGroup];
29628 for(var i = 0, l = g.length; i < l; i++){
29630 g[i].toggle(false);
29637 register : function(btn){
29638 if(!btn.toggleGroup){
29641 var g = groups[btn.toggleGroup];
29643 g = groups[btn.toggleGroup] = [];
29646 btn.on("toggle", toggleGroup);
29649 unregister : function(btn){
29650 if(!btn.toggleGroup){
29653 var g = groups[btn.toggleGroup];
29656 btn.un("toggle", toggleGroup);
29662 * Ext JS Library 1.1.1
29663 * Copyright(c) 2006-2007, Ext JS, LLC.
29665 * Originally Released Under LGPL - original licence link has changed is not relivant.
29668 * <script type="text/javascript">
29672 * @class Roo.SplitButton
29673 * @extends Roo.Button
29674 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29675 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29676 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29677 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29678 * @cfg {String} arrowTooltip The title attribute of the arrow
29680 * Create a new menu button
29681 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29682 * @param {Object} config The config object
29684 Roo.SplitButton = function(renderTo, config){
29685 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29687 * @event arrowclick
29688 * Fires when this button's arrow is clicked
29689 * @param {SplitButton} this
29690 * @param {EventObject} e The click event
29692 this.addEvents({"arrowclick":true});
29695 Roo.extend(Roo.SplitButton, Roo.Button, {
29696 render : function(renderTo){
29697 // this is one sweet looking template!
29698 var tpl = new Roo.Template(
29699 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29700 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29701 '<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>',
29702 "</tbody></table></td><td>",
29703 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29704 '<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>',
29705 "</tbody></table></td></tr></table>"
29707 var btn = tpl.append(renderTo, [this.text, this.type], true);
29708 var btnEl = btn.child("button");
29710 btn.addClass(this.cls);
29713 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29716 btnEl.addClass(this.iconCls);
29718 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29722 if(this.handleMouseEvents){
29723 btn.on("mouseover", this.onMouseOver, this);
29724 btn.on("mouseout", this.onMouseOut, this);
29725 btn.on("mousedown", this.onMouseDown, this);
29726 btn.on("mouseup", this.onMouseUp, this);
29728 btn.on(this.clickEvent, this.onClick, this);
29730 if(typeof this.tooltip == 'object'){
29731 Roo.QuickTips.tips(Roo.apply({
29735 btnEl.dom[this.tooltipType] = this.tooltip;
29738 if(this.arrowTooltip){
29739 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29748 this.el.addClass("x-btn-pressed");
29750 if(Roo.isIE && !Roo.isIE7){
29751 this.autoWidth.defer(1, this);
29756 this.menu.on("show", this.onMenuShow, this);
29757 this.menu.on("hide", this.onMenuHide, this);
29759 this.fireEvent('render', this);
29763 autoWidth : function(){
29765 var tbl = this.el.child("table:first");
29766 var tbl2 = this.el.child("table:last");
29767 this.el.setWidth("auto");
29768 tbl.setWidth("auto");
29769 if(Roo.isIE7 && Roo.isStrict){
29770 var ib = this.el.child('button:first');
29771 if(ib && ib.getWidth() > 20){
29773 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29778 this.el.beginMeasure();
29780 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29781 tbl.setWidth(this.minWidth-tbl2.getWidth());
29784 this.el.endMeasure();
29787 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29791 * Sets this button's click handler
29792 * @param {Function} handler The function to call when the button is clicked
29793 * @param {Object} scope (optional) Scope for the function passed above
29795 setHandler : function(handler, scope){
29796 this.handler = handler;
29797 this.scope = scope;
29801 * Sets this button's arrow click handler
29802 * @param {Function} handler The function to call when the arrow is clicked
29803 * @param {Object} scope (optional) Scope for the function passed above
29805 setArrowHandler : function(handler, scope){
29806 this.arrowHandler = handler;
29807 this.scope = scope;
29813 focus : function(){
29815 this.el.child("button:first").focus();
29820 onClick : function(e){
29821 e.preventDefault();
29822 if(!this.disabled){
29823 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29824 if(this.menu && !this.menu.isVisible()){
29825 this.menu.show(this.el, this.menuAlign);
29827 this.fireEvent("arrowclick", this, e);
29828 if(this.arrowHandler){
29829 this.arrowHandler.call(this.scope || this, this, e);
29832 this.fireEvent("click", this, e);
29834 this.handler.call(this.scope || this, this, e);
29840 onMouseDown : function(e){
29841 if(!this.disabled){
29842 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29846 onMouseUp : function(e){
29847 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29852 // backwards compat
29853 Roo.MenuButton = Roo.SplitButton;/*
29855 * Ext JS Library 1.1.1
29856 * Copyright(c) 2006-2007, Ext JS, LLC.
29858 * Originally Released Under LGPL - original licence link has changed is not relivant.
29861 * <script type="text/javascript">
29865 * @class Roo.Toolbar
29866 * Basic Toolbar class.
29868 * Creates a new Toolbar
29869 * @param {Object} container The config object
29871 Roo.Toolbar = function(container, buttons, config)
29873 /// old consturctor format still supported..
29874 if(container instanceof Array){ // omit the container for later rendering
29875 buttons = container;
29879 if (typeof(container) == 'object' && container.xtype) {
29880 config = container;
29881 container = config.container;
29882 buttons = config.buttons || []; // not really - use items!!
29885 if (config && config.items) {
29886 xitems = config.items;
29887 delete config.items;
29889 Roo.apply(this, config);
29890 this.buttons = buttons;
29893 this.render(container);
29895 this.xitems = xitems;
29896 Roo.each(xitems, function(b) {
29902 Roo.Toolbar.prototype = {
29904 * @cfg {Array} items
29905 * array of button configs or elements to add (will be converted to a MixedCollection)
29909 * @cfg {String/HTMLElement/Element} container
29910 * The id or element that will contain the toolbar
29913 render : function(ct){
29914 this.el = Roo.get(ct);
29916 this.el.addClass(this.cls);
29918 // using a table allows for vertical alignment
29919 // 100% width is needed by Safari...
29920 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29921 this.tr = this.el.child("tr", true);
29923 this.items = new Roo.util.MixedCollection(false, function(o){
29924 return o.id || ("item" + (++autoId));
29927 this.add.apply(this, this.buttons);
29928 delete this.buttons;
29933 * Adds element(s) to the toolbar -- this function takes a variable number of
29934 * arguments of mixed type and adds them to the toolbar.
29935 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29937 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29938 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29939 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29940 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29941 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29942 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29943 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29944 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29945 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29947 * @param {Mixed} arg2
29948 * @param {Mixed} etc.
29951 var a = arguments, l = a.length;
29952 for(var i = 0; i < l; i++){
29957 _add : function(el) {
29960 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29963 if (el.applyTo){ // some kind of form field
29964 return this.addField(el);
29966 if (el.render){ // some kind of Toolbar.Item
29967 return this.addItem(el);
29969 if (typeof el == "string"){ // string
29970 if(el == "separator" || el == "-"){
29971 return this.addSeparator();
29974 return this.addSpacer();
29977 return this.addFill();
29979 return this.addText(el);
29982 if(el.tagName){ // element
29983 return this.addElement(el);
29985 if(typeof el == "object"){ // must be button config?
29986 return this.addButton(el);
29988 // and now what?!?!
29994 * Add an Xtype element
29995 * @param {Object} xtype Xtype Object
29996 * @return {Object} created Object
29998 addxtype : function(e){
29999 return this.add(e);
30003 * Returns the Element for this toolbar.
30004 * @return {Roo.Element}
30006 getEl : function(){
30012 * @return {Roo.Toolbar.Item} The separator item
30014 addSeparator : function(){
30015 return this.addItem(new Roo.Toolbar.Separator());
30019 * Adds a spacer element
30020 * @return {Roo.Toolbar.Spacer} The spacer item
30022 addSpacer : function(){
30023 return this.addItem(new Roo.Toolbar.Spacer());
30027 * Adds a fill element that forces subsequent additions to the right side of the toolbar
30028 * @return {Roo.Toolbar.Fill} The fill item
30030 addFill : function(){
30031 return this.addItem(new Roo.Toolbar.Fill());
30035 * Adds any standard HTML element to the toolbar
30036 * @param {String/HTMLElement/Element} el The element or id of the element to add
30037 * @return {Roo.Toolbar.Item} The element's item
30039 addElement : function(el){
30040 return this.addItem(new Roo.Toolbar.Item(el));
30043 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
30044 * @type Roo.util.MixedCollection
30049 * Adds any Toolbar.Item or subclass
30050 * @param {Roo.Toolbar.Item} item
30051 * @return {Roo.Toolbar.Item} The item
30053 addItem : function(item){
30054 var td = this.nextBlock();
30056 this.items.add(item);
30061 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30062 * @param {Object/Array} config A button config or array of configs
30063 * @return {Roo.Toolbar.Button/Array}
30065 addButton : function(config){
30066 if(config instanceof Array){
30068 for(var i = 0, len = config.length; i < len; i++) {
30069 buttons.push(this.addButton(config[i]));
30074 if(!(config instanceof Roo.Toolbar.Button)){
30076 new Roo.Toolbar.SplitButton(config) :
30077 new Roo.Toolbar.Button(config);
30079 var td = this.nextBlock();
30086 * Adds text to the toolbar
30087 * @param {String} text The text to add
30088 * @return {Roo.Toolbar.Item} The element's item
30090 addText : function(text){
30091 return this.addItem(new Roo.Toolbar.TextItem(text));
30095 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30096 * @param {Number} index The index where the item is to be inserted
30097 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30098 * @return {Roo.Toolbar.Button/Item}
30100 insertButton : function(index, item){
30101 if(item instanceof Array){
30103 for(var i = 0, len = item.length; i < len; i++) {
30104 buttons.push(this.insertButton(index + i, item[i]));
30108 if (!(item instanceof Roo.Toolbar.Button)){
30109 item = new Roo.Toolbar.Button(item);
30111 var td = document.createElement("td");
30112 this.tr.insertBefore(td, this.tr.childNodes[index]);
30114 this.items.insert(index, item);
30119 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30120 * @param {Object} config
30121 * @return {Roo.Toolbar.Item} The element's item
30123 addDom : function(config, returnEl){
30124 var td = this.nextBlock();
30125 Roo.DomHelper.overwrite(td, config);
30126 var ti = new Roo.Toolbar.Item(td.firstChild);
30128 this.items.add(ti);
30133 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30134 * @type Roo.util.MixedCollection
30139 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30140 * Note: the field should not have been rendered yet. For a field that has already been
30141 * rendered, use {@link #addElement}.
30142 * @param {Roo.form.Field} field
30143 * @return {Roo.ToolbarItem}
30147 addField : function(field) {
30148 if (!this.fields) {
30150 this.fields = new Roo.util.MixedCollection(false, function(o){
30151 return o.id || ("item" + (++autoId));
30156 var td = this.nextBlock();
30158 var ti = new Roo.Toolbar.Item(td.firstChild);
30160 this.items.add(ti);
30161 this.fields.add(field);
30172 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30173 this.el.child('div').hide();
30181 this.el.child('div').show();
30185 nextBlock : function(){
30186 var td = document.createElement("td");
30187 this.tr.appendChild(td);
30192 destroy : function(){
30193 if(this.items){ // rendered?
30194 Roo.destroy.apply(Roo, this.items.items);
30196 if(this.fields){ // rendered?
30197 Roo.destroy.apply(Roo, this.fields.items);
30199 Roo.Element.uncache(this.el, this.tr);
30204 * @class Roo.Toolbar.Item
30205 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30207 * Creates a new Item
30208 * @param {HTMLElement} el
30210 Roo.Toolbar.Item = function(el){
30212 if (typeof (el.xtype) != 'undefined') {
30217 this.el = Roo.getDom(el);
30218 this.id = Roo.id(this.el);
30219 this.hidden = false;
30224 * Fires when the button is rendered
30225 * @param {Button} this
30229 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30231 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30232 //Roo.Toolbar.Item.prototype = {
30235 * Get this item's HTML Element
30236 * @return {HTMLElement}
30238 getEl : function(){
30243 render : function(td){
30246 td.appendChild(this.el);
30248 this.fireEvent('render', this);
30252 * Removes and destroys this item.
30254 destroy : function(){
30255 this.td.parentNode.removeChild(this.td);
30262 this.hidden = false;
30263 this.td.style.display = "";
30270 this.hidden = true;
30271 this.td.style.display = "none";
30275 * Convenience function for boolean show/hide.
30276 * @param {Boolean} visible true to show/false to hide
30278 setVisible: function(visible){
30287 * Try to focus this item.
30289 focus : function(){
30290 Roo.fly(this.el).focus();
30294 * Disables this item.
30296 disable : function(){
30297 Roo.fly(this.td).addClass("x-item-disabled");
30298 this.disabled = true;
30299 this.el.disabled = true;
30303 * Enables this item.
30305 enable : function(){
30306 Roo.fly(this.td).removeClass("x-item-disabled");
30307 this.disabled = false;
30308 this.el.disabled = false;
30314 * @class Roo.Toolbar.Separator
30315 * @extends Roo.Toolbar.Item
30316 * A simple toolbar separator class
30318 * Creates a new Separator
30320 Roo.Toolbar.Separator = function(cfg){
30322 var s = document.createElement("span");
30323 s.className = "ytb-sep";
30328 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30330 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30331 enable:Roo.emptyFn,
30332 disable:Roo.emptyFn,
30337 * @class Roo.Toolbar.Spacer
30338 * @extends Roo.Toolbar.Item
30339 * A simple element that adds extra horizontal space to a toolbar.
30341 * Creates a new Spacer
30343 Roo.Toolbar.Spacer = function(cfg){
30344 var s = document.createElement("div");
30345 s.className = "ytb-spacer";
30349 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30351 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30352 enable:Roo.emptyFn,
30353 disable:Roo.emptyFn,
30358 * @class Roo.Toolbar.Fill
30359 * @extends Roo.Toolbar.Spacer
30360 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30362 * Creates a new Spacer
30364 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30366 render : function(td){
30367 td.style.width = '100%';
30368 Roo.Toolbar.Fill.superclass.render.call(this, td);
30373 * @class Roo.Toolbar.TextItem
30374 * @extends Roo.Toolbar.Item
30375 * A simple class that renders text directly into a toolbar.
30377 * Creates a new TextItem
30378 * @param {String} text
30380 Roo.Toolbar.TextItem = function(cfg){
30381 var text = cfg || "";
30382 if (typeof(cfg) == 'object') {
30383 text = cfg.text || "";
30387 var s = document.createElement("span");
30388 s.className = "ytb-text";
30389 s.innerHTML = text;
30394 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30396 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30399 enable:Roo.emptyFn,
30400 disable:Roo.emptyFn,
30405 * @class Roo.Toolbar.Button
30406 * @extends Roo.Button
30407 * A button that renders into a toolbar.
30409 * Creates a new Button
30410 * @param {Object} config A standard {@link Roo.Button} config object
30412 Roo.Toolbar.Button = function(config){
30413 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30415 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30416 render : function(td){
30418 Roo.Toolbar.Button.superclass.render.call(this, td);
30422 * Removes and destroys this button
30424 destroy : function(){
30425 Roo.Toolbar.Button.superclass.destroy.call(this);
30426 this.td.parentNode.removeChild(this.td);
30430 * Shows this button
30433 this.hidden = false;
30434 this.td.style.display = "";
30438 * Hides this button
30441 this.hidden = true;
30442 this.td.style.display = "none";
30446 * Disables this item
30448 disable : function(){
30449 Roo.fly(this.td).addClass("x-item-disabled");
30450 this.disabled = true;
30454 * Enables this item
30456 enable : function(){
30457 Roo.fly(this.td).removeClass("x-item-disabled");
30458 this.disabled = false;
30461 // backwards compat
30462 Roo.ToolbarButton = Roo.Toolbar.Button;
30465 * @class Roo.Toolbar.SplitButton
30466 * @extends Roo.SplitButton
30467 * A menu button that renders into a toolbar.
30469 * Creates a new SplitButton
30470 * @param {Object} config A standard {@link Roo.SplitButton} config object
30472 Roo.Toolbar.SplitButton = function(config){
30473 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30475 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30476 render : function(td){
30478 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30482 * Removes and destroys this button
30484 destroy : function(){
30485 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30486 this.td.parentNode.removeChild(this.td);
30490 * Shows this button
30493 this.hidden = false;
30494 this.td.style.display = "";
30498 * Hides this button
30501 this.hidden = true;
30502 this.td.style.display = "none";
30506 // backwards compat
30507 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30509 * Ext JS Library 1.1.1
30510 * Copyright(c) 2006-2007, Ext JS, LLC.
30512 * Originally Released Under LGPL - original licence link has changed is not relivant.
30515 * <script type="text/javascript">
30519 * @class Roo.PagingToolbar
30520 * @extends Roo.Toolbar
30521 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30523 * Create a new PagingToolbar
30524 * @param {Object} config The config object
30526 Roo.PagingToolbar = function(el, ds, config)
30528 // old args format still supported... - xtype is prefered..
30529 if (typeof(el) == 'object' && el.xtype) {
30530 // created from xtype...
30532 ds = el.dataSource;
30533 el = config.container;
30536 if (config.items) {
30537 items = config.items;
30541 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30544 this.renderButtons(this.el);
30547 // supprot items array.
30549 Roo.each(items, function(e) {
30550 this.add(Roo.factory(e));
30555 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30557 * @cfg {Roo.data.Store} dataSource
30558 * The underlying data store providing the paged data
30561 * @cfg {String/HTMLElement/Element} container
30562 * container The id or element that will contain the toolbar
30565 * @cfg {Boolean} displayInfo
30566 * True to display the displayMsg (defaults to false)
30569 * @cfg {Number} pageSize
30570 * The number of records to display per page (defaults to 20)
30574 * @cfg {String} displayMsg
30575 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30577 displayMsg : 'Displaying {0} - {1} of {2}',
30579 * @cfg {String} emptyMsg
30580 * The message to display when no records are found (defaults to "No data to display")
30582 emptyMsg : 'No data to display',
30584 * Customizable piece of the default paging text (defaults to "Page")
30587 beforePageText : "Page",
30589 * Customizable piece of the default paging text (defaults to "of %0")
30592 afterPageText : "of {0}",
30594 * Customizable piece of the default paging text (defaults to "First Page")
30597 firstText : "First Page",
30599 * Customizable piece of the default paging text (defaults to "Previous Page")
30602 prevText : "Previous Page",
30604 * Customizable piece of the default paging text (defaults to "Next Page")
30607 nextText : "Next Page",
30609 * Customizable piece of the default paging text (defaults to "Last Page")
30612 lastText : "Last Page",
30614 * Customizable piece of the default paging text (defaults to "Refresh")
30617 refreshText : "Refresh",
30620 renderButtons : function(el){
30621 Roo.PagingToolbar.superclass.render.call(this, el);
30622 this.first = this.addButton({
30623 tooltip: this.firstText,
30624 cls: "x-btn-icon x-grid-page-first",
30626 handler: this.onClick.createDelegate(this, ["first"])
30628 this.prev = this.addButton({
30629 tooltip: this.prevText,
30630 cls: "x-btn-icon x-grid-page-prev",
30632 handler: this.onClick.createDelegate(this, ["prev"])
30634 //this.addSeparator();
30635 this.add(this.beforePageText);
30636 this.field = Roo.get(this.addDom({
30641 cls: "x-grid-page-number"
30643 this.field.on("keydown", this.onPagingKeydown, this);
30644 this.field.on("focus", function(){this.dom.select();});
30645 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30646 this.field.setHeight(18);
30647 //this.addSeparator();
30648 this.next = this.addButton({
30649 tooltip: this.nextText,
30650 cls: "x-btn-icon x-grid-page-next",
30652 handler: this.onClick.createDelegate(this, ["next"])
30654 this.last = this.addButton({
30655 tooltip: this.lastText,
30656 cls: "x-btn-icon x-grid-page-last",
30658 handler: this.onClick.createDelegate(this, ["last"])
30660 //this.addSeparator();
30661 this.loading = this.addButton({
30662 tooltip: this.refreshText,
30663 cls: "x-btn-icon x-grid-loading",
30664 handler: this.onClick.createDelegate(this, ["refresh"])
30667 if(this.displayInfo){
30668 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30673 updateInfo : function(){
30674 if(this.displayEl){
30675 var count = this.ds.getCount();
30676 var msg = count == 0 ?
30680 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30682 this.displayEl.update(msg);
30687 onLoad : function(ds, r, o){
30688 this.cursor = o.params ? o.params.start : 0;
30689 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30691 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30692 this.field.dom.value = ap;
30693 this.first.setDisabled(ap == 1);
30694 this.prev.setDisabled(ap == 1);
30695 this.next.setDisabled(ap == ps);
30696 this.last.setDisabled(ap == ps);
30697 this.loading.enable();
30702 getPageData : function(){
30703 var total = this.ds.getTotalCount();
30706 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30707 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30712 onLoadError : function(){
30713 this.loading.enable();
30717 onPagingKeydown : function(e){
30718 var k = e.getKey();
30719 var d = this.getPageData();
30721 var v = this.field.dom.value, pageNum;
30722 if(!v || isNaN(pageNum = parseInt(v, 10))){
30723 this.field.dom.value = d.activePage;
30726 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30727 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30730 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))
30732 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30733 this.field.dom.value = pageNum;
30734 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30737 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30739 var v = this.field.dom.value, pageNum;
30740 var increment = (e.shiftKey) ? 10 : 1;
30741 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30744 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30745 this.field.dom.value = d.activePage;
30748 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30750 this.field.dom.value = parseInt(v, 10) + increment;
30751 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30752 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30759 beforeLoad : function(){
30761 this.loading.disable();
30766 onClick : function(which){
30770 ds.load({params:{start: 0, limit: this.pageSize}});
30773 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30776 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30779 var total = ds.getTotalCount();
30780 var extra = total % this.pageSize;
30781 var lastStart = extra ? (total - extra) : total-this.pageSize;
30782 ds.load({params:{start: lastStart, limit: this.pageSize}});
30785 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30791 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30792 * @param {Roo.data.Store} store The data store to unbind
30794 unbind : function(ds){
30795 ds.un("beforeload", this.beforeLoad, this);
30796 ds.un("load", this.onLoad, this);
30797 ds.un("loadexception", this.onLoadError, this);
30798 ds.un("remove", this.updateInfo, this);
30799 ds.un("add", this.updateInfo, this);
30800 this.ds = undefined;
30804 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30805 * @param {Roo.data.Store} store The data store to bind
30807 bind : function(ds){
30808 ds.on("beforeload", this.beforeLoad, this);
30809 ds.on("load", this.onLoad, this);
30810 ds.on("loadexception", this.onLoadError, this);
30811 ds.on("remove", this.updateInfo, this);
30812 ds.on("add", this.updateInfo, this);
30817 * Ext JS Library 1.1.1
30818 * Copyright(c) 2006-2007, Ext JS, LLC.
30820 * Originally Released Under LGPL - original licence link has changed is not relivant.
30823 * <script type="text/javascript">
30827 * @class Roo.Resizable
30828 * @extends Roo.util.Observable
30829 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30830 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30831 * 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
30832 * the element will be wrapped for you automatically.</p>
30833 * <p>Here is the list of valid resize handles:</p>
30836 ------ -------------------
30845 'hd' horizontal drag
30848 * <p>Here's an example showing the creation of a typical Resizable:</p>
30850 var resizer = new Roo.Resizable("element-id", {
30858 resizer.on("resize", myHandler);
30860 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30861 * resizer.east.setDisplayed(false);</p>
30862 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30863 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30864 * resize operation's new size (defaults to [0, 0])
30865 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30866 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30867 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30868 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30869 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30870 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30871 * @cfg {Number} width The width of the element in pixels (defaults to null)
30872 * @cfg {Number} height The height of the element in pixels (defaults to null)
30873 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30874 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30875 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30876 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30877 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30878 * in favor of the handles config option (defaults to false)
30879 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30880 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30881 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30882 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30883 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30884 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30885 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30886 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30887 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30888 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30889 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30891 * Create a new resizable component
30892 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30893 * @param {Object} config configuration options
30895 Roo.Resizable = function(el, config)
30897 this.el = Roo.get(el);
30899 if(config && config.wrap){
30900 config.resizeChild = this.el;
30901 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30902 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30903 this.el.setStyle("overflow", "hidden");
30904 this.el.setPositioning(config.resizeChild.getPositioning());
30905 config.resizeChild.clearPositioning();
30906 if(!config.width || !config.height){
30907 var csize = config.resizeChild.getSize();
30908 this.el.setSize(csize.width, csize.height);
30910 if(config.pinned && !config.adjustments){
30911 config.adjustments = "auto";
30915 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30916 this.proxy.unselectable();
30917 this.proxy.enableDisplayMode('block');
30919 Roo.apply(this, config);
30922 this.disableTrackOver = true;
30923 this.el.addClass("x-resizable-pinned");
30925 // if the element isn't positioned, make it relative
30926 var position = this.el.getStyle("position");
30927 if(position != "absolute" && position != "fixed"){
30928 this.el.setStyle("position", "relative");
30930 if(!this.handles){ // no handles passed, must be legacy style
30931 this.handles = 's,e,se';
30932 if(this.multiDirectional){
30933 this.handles += ',n,w';
30936 if(this.handles == "all"){
30937 this.handles = "n s e w ne nw se sw";
30939 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30940 var ps = Roo.Resizable.positions;
30941 for(var i = 0, len = hs.length; i < len; i++){
30942 if(hs[i] && ps[hs[i]]){
30943 var pos = ps[hs[i]];
30944 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30948 this.corner = this.southeast;
30950 // updateBox = the box can move..
30951 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30952 this.updateBox = true;
30955 this.activeHandle = null;
30957 if(this.resizeChild){
30958 if(typeof this.resizeChild == "boolean"){
30959 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30961 this.resizeChild = Roo.get(this.resizeChild, true);
30965 if(this.adjustments == "auto"){
30966 var rc = this.resizeChild;
30967 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30968 if(rc && (hw || hn)){
30969 rc.position("relative");
30970 rc.setLeft(hw ? hw.el.getWidth() : 0);
30971 rc.setTop(hn ? hn.el.getHeight() : 0);
30973 this.adjustments = [
30974 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30975 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30979 if(this.draggable){
30980 this.dd = this.dynamic ?
30981 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30982 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30988 * @event beforeresize
30989 * Fired before resize is allowed. Set enabled to false to cancel resize.
30990 * @param {Roo.Resizable} this
30991 * @param {Roo.EventObject} e The mousedown event
30993 "beforeresize" : true,
30996 * Fired a resizing.
30997 * @param {Roo.Resizable} this
30998 * @param {Number} x The new x position
30999 * @param {Number} y The new y position
31000 * @param {Number} w The new w width
31001 * @param {Number} h The new h hight
31002 * @param {Roo.EventObject} e The mouseup event
31007 * Fired after a resize.
31008 * @param {Roo.Resizable} this
31009 * @param {Number} width The new width
31010 * @param {Number} height The new height
31011 * @param {Roo.EventObject} e The mouseup event
31016 if(this.width !== null && this.height !== null){
31017 this.resizeTo(this.width, this.height);
31019 this.updateChildSize();
31022 this.el.dom.style.zoom = 1;
31024 Roo.Resizable.superclass.constructor.call(this);
31027 Roo.extend(Roo.Resizable, Roo.util.Observable, {
31028 resizeChild : false,
31029 adjustments : [0, 0],
31039 multiDirectional : false,
31040 disableTrackOver : false,
31041 easing : 'easeOutStrong',
31042 widthIncrement : 0,
31043 heightIncrement : 0,
31047 preserveRatio : false,
31048 transparent: false,
31054 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
31056 constrainTo: undefined,
31058 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31060 resizeRegion: undefined,
31064 * Perform a manual resize
31065 * @param {Number} width
31066 * @param {Number} height
31068 resizeTo : function(width, height){
31069 this.el.setSize(width, height);
31070 this.updateChildSize();
31071 this.fireEvent("resize", this, width, height, null);
31075 startSizing : function(e, handle){
31076 this.fireEvent("beforeresize", this, e);
31077 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31080 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31081 this.overlay.unselectable();
31082 this.overlay.enableDisplayMode("block");
31083 this.overlay.on("mousemove", this.onMouseMove, this);
31084 this.overlay.on("mouseup", this.onMouseUp, this);
31086 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31088 this.resizing = true;
31089 this.startBox = this.el.getBox();
31090 this.startPoint = e.getXY();
31091 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31092 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31094 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31095 this.overlay.show();
31097 if(this.constrainTo) {
31098 var ct = Roo.get(this.constrainTo);
31099 this.resizeRegion = ct.getRegion().adjust(
31100 ct.getFrameWidth('t'),
31101 ct.getFrameWidth('l'),
31102 -ct.getFrameWidth('b'),
31103 -ct.getFrameWidth('r')
31107 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31109 this.proxy.setBox(this.startBox);
31111 this.proxy.setStyle('visibility', 'visible');
31117 onMouseDown : function(handle, e){
31120 this.activeHandle = handle;
31121 this.startSizing(e, handle);
31126 onMouseUp : function(e){
31127 var size = this.resizeElement();
31128 this.resizing = false;
31130 this.overlay.hide();
31132 this.fireEvent("resize", this, size.width, size.height, e);
31136 updateChildSize : function(){
31138 if(this.resizeChild){
31140 var child = this.resizeChild;
31141 var adj = this.adjustments;
31142 if(el.dom.offsetWidth){
31143 var b = el.getSize(true);
31144 child.setSize(b.width+adj[0], b.height+adj[1]);
31146 // Second call here for IE
31147 // The first call enables instant resizing and
31148 // the second call corrects scroll bars if they
31151 setTimeout(function(){
31152 if(el.dom.offsetWidth){
31153 var b = el.getSize(true);
31154 child.setSize(b.width+adj[0], b.height+adj[1]);
31162 snap : function(value, inc, min){
31163 if(!inc || !value) {
31166 var newValue = value;
31167 var m = value % inc;
31170 newValue = value + (inc-m);
31172 newValue = value - m;
31175 return Math.max(min, newValue);
31179 resizeElement : function(){
31180 var box = this.proxy.getBox();
31181 if(this.updateBox){
31182 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31184 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31186 this.updateChildSize();
31194 constrain : function(v, diff, m, mx){
31197 }else if(v - diff > mx){
31204 onMouseMove : function(e){
31207 try{// try catch so if something goes wrong the user doesn't get hung
31209 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31213 //var curXY = this.startPoint;
31214 var curSize = this.curSize || this.startBox;
31215 var x = this.startBox.x, y = this.startBox.y;
31216 var ox = x, oy = y;
31217 var w = curSize.width, h = curSize.height;
31218 var ow = w, oh = h;
31219 var mw = this.minWidth, mh = this.minHeight;
31220 var mxw = this.maxWidth, mxh = this.maxHeight;
31221 var wi = this.widthIncrement;
31222 var hi = this.heightIncrement;
31224 var eventXY = e.getXY();
31225 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31226 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31228 var pos = this.activeHandle.position;
31233 w = Math.min(Math.max(mw, w), mxw);
31238 h = Math.min(Math.max(mh, h), mxh);
31243 w = Math.min(Math.max(mw, w), mxw);
31244 h = Math.min(Math.max(mh, h), mxh);
31247 diffY = this.constrain(h, diffY, mh, mxh);
31254 var adiffX = Math.abs(diffX);
31255 var sub = (adiffX % wi); // how much
31256 if (sub > (wi/2)) { // far enough to snap
31257 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31259 // remove difference..
31260 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31264 x = Math.max(this.minX, x);
31267 diffX = this.constrain(w, diffX, mw, mxw);
31273 w = Math.min(Math.max(mw, w), mxw);
31274 diffY = this.constrain(h, diffY, mh, mxh);
31279 diffX = this.constrain(w, diffX, mw, mxw);
31280 diffY = this.constrain(h, diffY, mh, mxh);
31287 diffX = this.constrain(w, diffX, mw, mxw);
31289 h = Math.min(Math.max(mh, h), mxh);
31295 var sw = this.snap(w, wi, mw);
31296 var sh = this.snap(h, hi, mh);
31297 if(sw != w || sh != h){
31320 if(this.preserveRatio){
31325 h = Math.min(Math.max(mh, h), mxh);
31330 w = Math.min(Math.max(mw, w), mxw);
31335 w = Math.min(Math.max(mw, w), mxw);
31341 w = Math.min(Math.max(mw, w), mxw);
31347 h = Math.min(Math.max(mh, h), mxh);
31355 h = Math.min(Math.max(mh, h), mxh);
31365 h = Math.min(Math.max(mh, h), mxh);
31373 if (pos == 'hdrag') {
31376 this.proxy.setBounds(x, y, w, h);
31378 this.resizeElement();
31382 this.fireEvent("resizing", this, x, y, w, h, e);
31386 handleOver : function(){
31388 this.el.addClass("x-resizable-over");
31393 handleOut : function(){
31394 if(!this.resizing){
31395 this.el.removeClass("x-resizable-over");
31400 * Returns the element this component is bound to.
31401 * @return {Roo.Element}
31403 getEl : function(){
31408 * Returns the resizeChild element (or null).
31409 * @return {Roo.Element}
31411 getResizeChild : function(){
31412 return this.resizeChild;
31414 groupHandler : function()
31419 * Destroys this resizable. If the element was wrapped and
31420 * removeEl is not true then the element remains.
31421 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31423 destroy : function(removeEl){
31424 this.proxy.remove();
31426 this.overlay.removeAllListeners();
31427 this.overlay.remove();
31429 var ps = Roo.Resizable.positions;
31431 if(typeof ps[k] != "function" && this[ps[k]]){
31432 var h = this[ps[k]];
31433 h.el.removeAllListeners();
31438 this.el.update("");
31445 // hash to map config positions to true positions
31446 Roo.Resizable.positions = {
31447 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31452 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31454 // only initialize the template if resizable is used
31455 var tpl = Roo.DomHelper.createTemplate(
31456 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31459 Roo.Resizable.Handle.prototype.tpl = tpl;
31461 this.position = pos;
31463 // show north drag fro topdra
31464 var handlepos = pos == 'hdrag' ? 'north' : pos;
31466 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31467 if (pos == 'hdrag') {
31468 this.el.setStyle('cursor', 'pointer');
31470 this.el.unselectable();
31472 this.el.setOpacity(0);
31474 this.el.on("mousedown", this.onMouseDown, this);
31475 if(!disableTrackOver){
31476 this.el.on("mouseover", this.onMouseOver, this);
31477 this.el.on("mouseout", this.onMouseOut, this);
31482 Roo.Resizable.Handle.prototype = {
31483 afterResize : function(rz){
31488 onMouseDown : function(e){
31489 this.rz.onMouseDown(this, e);
31492 onMouseOver : function(e){
31493 this.rz.handleOver(this, e);
31496 onMouseOut : function(e){
31497 this.rz.handleOut(this, e);
31501 * Ext JS Library 1.1.1
31502 * Copyright(c) 2006-2007, Ext JS, LLC.
31504 * Originally Released Under LGPL - original licence link has changed is not relivant.
31507 * <script type="text/javascript">
31511 * @class Roo.Editor
31512 * @extends Roo.Component
31513 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31515 * Create a new Editor
31516 * @param {Roo.form.Field} field The Field object (or descendant)
31517 * @param {Object} config The config object
31519 Roo.Editor = function(field, config){
31520 Roo.Editor.superclass.constructor.call(this, config);
31521 this.field = field;
31524 * @event beforestartedit
31525 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31526 * false from the handler of this event.
31527 * @param {Editor} this
31528 * @param {Roo.Element} boundEl The underlying element bound to this editor
31529 * @param {Mixed} value The field value being set
31531 "beforestartedit" : true,
31534 * Fires when this editor is displayed
31535 * @param {Roo.Element} boundEl The underlying element bound to this editor
31536 * @param {Mixed} value The starting field value
31538 "startedit" : true,
31540 * @event beforecomplete
31541 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31542 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31543 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31544 * event will not fire since no edit actually occurred.
31545 * @param {Editor} this
31546 * @param {Mixed} value The current field value
31547 * @param {Mixed} startValue The original field value
31549 "beforecomplete" : true,
31552 * Fires after editing is complete and any changed value has been written to the underlying field.
31553 * @param {Editor} this
31554 * @param {Mixed} value The current field value
31555 * @param {Mixed} startValue The original field value
31559 * @event specialkey
31560 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31561 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31562 * @param {Roo.form.Field} this
31563 * @param {Roo.EventObject} e The event object
31565 "specialkey" : true
31569 Roo.extend(Roo.Editor, Roo.Component, {
31571 * @cfg {Boolean/String} autosize
31572 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31573 * or "height" to adopt the height only (defaults to false)
31576 * @cfg {Boolean} revertInvalid
31577 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31578 * validation fails (defaults to true)
31581 * @cfg {Boolean} ignoreNoChange
31582 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31583 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31584 * will never be ignored.
31587 * @cfg {Boolean} hideEl
31588 * False to keep the bound element visible while the editor is displayed (defaults to true)
31591 * @cfg {Mixed} value
31592 * The data value of the underlying field (defaults to "")
31596 * @cfg {String} alignment
31597 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31601 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31602 * for bottom-right shadow (defaults to "frame")
31606 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31610 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31612 completeOnEnter : false,
31614 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31616 cancelOnEsc : false,
31618 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31623 onRender : function(ct, position){
31624 this.el = new Roo.Layer({
31625 shadow: this.shadow,
31631 constrain: this.constrain
31633 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31634 if(this.field.msgTarget != 'title'){
31635 this.field.msgTarget = 'qtip';
31637 this.field.render(this.el);
31639 this.field.el.dom.setAttribute('autocomplete', 'off');
31641 this.field.on("specialkey", this.onSpecialKey, this);
31642 if(this.swallowKeys){
31643 this.field.el.swallowEvent(['keydown','keypress']);
31646 this.field.on("blur", this.onBlur, this);
31647 if(this.field.grow){
31648 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31652 onSpecialKey : function(field, e)
31654 //Roo.log('editor onSpecialKey');
31655 if(this.completeOnEnter && e.getKey() == e.ENTER){
31657 this.completeEdit();
31660 // do not fire special key otherwise it might hide close the editor...
31661 if(e.getKey() == e.ENTER){
31664 if(this.cancelOnEsc && e.getKey() == e.ESC){
31668 this.fireEvent('specialkey', field, e);
31673 * Starts the editing process and shows the editor.
31674 * @param {String/HTMLElement/Element} el The element to edit
31675 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31676 * to the innerHTML of el.
31678 startEdit : function(el, value){
31680 this.completeEdit();
31682 this.boundEl = Roo.get(el);
31683 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31684 if(!this.rendered){
31685 this.render(this.parentEl || document.body);
31687 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31690 this.startValue = v;
31691 this.field.setValue(v);
31693 var sz = this.boundEl.getSize();
31694 switch(this.autoSize){
31696 this.setSize(sz.width, "");
31699 this.setSize("", sz.height);
31702 this.setSize(sz.width, sz.height);
31705 this.el.alignTo(this.boundEl, this.alignment);
31706 this.editing = true;
31708 Roo.QuickTips.disable();
31714 * Sets the height and width of this editor.
31715 * @param {Number} width The new width
31716 * @param {Number} height The new height
31718 setSize : function(w, h){
31719 this.field.setSize(w, h);
31726 * Realigns the editor to the bound field based on the current alignment config value.
31728 realign : function(){
31729 this.el.alignTo(this.boundEl, this.alignment);
31733 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31734 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31736 completeEdit : function(remainVisible){
31740 var v = this.getValue();
31741 if(this.revertInvalid !== false && !this.field.isValid()){
31742 v = this.startValue;
31743 this.cancelEdit(true);
31745 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31746 this.editing = false;
31750 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31751 this.editing = false;
31752 if(this.updateEl && this.boundEl){
31753 this.boundEl.update(v);
31755 if(remainVisible !== true){
31758 this.fireEvent("complete", this, v, this.startValue);
31763 onShow : function(){
31765 if(this.hideEl !== false){
31766 this.boundEl.hide();
31769 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31770 this.fixIEFocus = true;
31771 this.deferredFocus.defer(50, this);
31773 this.field.focus();
31775 this.fireEvent("startedit", this.boundEl, this.startValue);
31778 deferredFocus : function(){
31780 this.field.focus();
31785 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31786 * reverted to the original starting value.
31787 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31788 * cancel (defaults to false)
31790 cancelEdit : function(remainVisible){
31792 this.setValue(this.startValue);
31793 if(remainVisible !== true){
31800 onBlur : function(){
31801 if(this.allowBlur !== true && this.editing){
31802 this.completeEdit();
31807 onHide : function(){
31809 this.completeEdit();
31813 if(this.field.collapse){
31814 this.field.collapse();
31817 if(this.hideEl !== false){
31818 this.boundEl.show();
31821 Roo.QuickTips.enable();
31826 * Sets the data value of the editor
31827 * @param {Mixed} value Any valid value supported by the underlying field
31829 setValue : function(v){
31830 this.field.setValue(v);
31834 * Gets the data value of the editor
31835 * @return {Mixed} The data value
31837 getValue : function(){
31838 return this.field.getValue();
31842 * Ext JS Library 1.1.1
31843 * Copyright(c) 2006-2007, Ext JS, LLC.
31845 * Originally Released Under LGPL - original licence link has changed is not relivant.
31848 * <script type="text/javascript">
31852 * @class Roo.BasicDialog
31853 * @extends Roo.util.Observable
31854 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31856 var dlg = new Roo.BasicDialog("my-dlg", {
31865 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31866 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31867 dlg.addButton('Cancel', dlg.hide, dlg);
31870 <b>A Dialog should always be a direct child of the body element.</b>
31871 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31872 * @cfg {String} title Default text to display in the title bar (defaults to null)
31873 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31874 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31875 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31876 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31877 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31878 * (defaults to null with no animation)
31879 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31880 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31881 * property for valid values (defaults to 'all')
31882 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31883 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31884 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31885 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31886 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31887 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31888 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31889 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31890 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31891 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31892 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31893 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31894 * draggable = true (defaults to false)
31895 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31896 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31897 * shadow (defaults to false)
31898 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31899 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31900 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31901 * @cfg {Array} buttons Array of buttons
31902 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31904 * Create a new BasicDialog.
31905 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31906 * @param {Object} config Configuration options
31908 Roo.BasicDialog = function(el, config){
31909 this.el = Roo.get(el);
31910 var dh = Roo.DomHelper;
31911 if(!this.el && config && config.autoCreate){
31912 if(typeof config.autoCreate == "object"){
31913 if(!config.autoCreate.id){
31914 config.autoCreate.id = el;
31916 this.el = dh.append(document.body,
31917 config.autoCreate, true);
31919 this.el = dh.append(document.body,
31920 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31924 el.setDisplayed(true);
31925 el.hide = this.hideAction;
31927 el.addClass("x-dlg");
31929 Roo.apply(this, config);
31931 this.proxy = el.createProxy("x-dlg-proxy");
31932 this.proxy.hide = this.hideAction;
31933 this.proxy.setOpacity(.5);
31937 el.setWidth(config.width);
31940 el.setHeight(config.height);
31942 this.size = el.getSize();
31943 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31944 this.xy = [config.x,config.y];
31946 this.xy = el.getCenterXY(true);
31948 /** The header element @type Roo.Element */
31949 this.header = el.child("> .x-dlg-hd");
31950 /** The body element @type Roo.Element */
31951 this.body = el.child("> .x-dlg-bd");
31952 /** The footer element @type Roo.Element */
31953 this.footer = el.child("> .x-dlg-ft");
31956 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31959 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31962 this.header.unselectable();
31964 this.header.update(this.title);
31966 // this element allows the dialog to be focused for keyboard event
31967 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31968 this.focusEl.swallowEvent("click", true);
31970 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31972 // wrap the body and footer for special rendering
31973 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31975 this.bwrap.dom.appendChild(this.footer.dom);
31978 this.bg = this.el.createChild({
31979 tag: "div", cls:"x-dlg-bg",
31980 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31982 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31985 if(this.autoScroll !== false && !this.autoTabs){
31986 this.body.setStyle("overflow", "auto");
31989 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31991 if(this.closable !== false){
31992 this.el.addClass("x-dlg-closable");
31993 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31994 this.close.on("click", this.closeClick, this);
31995 this.close.addClassOnOver("x-dlg-close-over");
31997 if(this.collapsible !== false){
31998 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31999 this.collapseBtn.on("click", this.collapseClick, this);
32000 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
32001 this.header.on("dblclick", this.collapseClick, this);
32003 if(this.resizable !== false){
32004 this.el.addClass("x-dlg-resizable");
32005 this.resizer = new Roo.Resizable(el, {
32006 minWidth: this.minWidth || 80,
32007 minHeight:this.minHeight || 80,
32008 handles: this.resizeHandles || "all",
32011 this.resizer.on("beforeresize", this.beforeResize, this);
32012 this.resizer.on("resize", this.onResize, this);
32014 if(this.draggable !== false){
32015 el.addClass("x-dlg-draggable");
32016 if (!this.proxyDrag) {
32017 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
32020 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
32022 dd.setHandleElId(this.header.id);
32023 dd.endDrag = this.endMove.createDelegate(this);
32024 dd.startDrag = this.startMove.createDelegate(this);
32025 dd.onDrag = this.onDrag.createDelegate(this);
32030 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
32031 this.mask.enableDisplayMode("block");
32033 this.el.addClass("x-dlg-modal");
32036 this.shadow = new Roo.Shadow({
32037 mode : typeof this.shadow == "string" ? this.shadow : "sides",
32038 offset : this.shadowOffset
32041 this.shadowOffset = 0;
32043 if(Roo.useShims && this.shim !== false){
32044 this.shim = this.el.createShim();
32045 this.shim.hide = this.hideAction;
32053 if (this.buttons) {
32054 var bts= this.buttons;
32056 Roo.each(bts, function(b) {
32065 * Fires when a key is pressed
32066 * @param {Roo.BasicDialog} this
32067 * @param {Roo.EventObject} e
32072 * Fires when this dialog is moved by the user.
32073 * @param {Roo.BasicDialog} this
32074 * @param {Number} x The new page X
32075 * @param {Number} y The new page Y
32080 * Fires when this dialog is resized by the user.
32081 * @param {Roo.BasicDialog} this
32082 * @param {Number} width The new width
32083 * @param {Number} height The new height
32087 * @event beforehide
32088 * Fires before this dialog is hidden.
32089 * @param {Roo.BasicDialog} this
32091 "beforehide" : true,
32094 * Fires when this dialog is hidden.
32095 * @param {Roo.BasicDialog} this
32099 * @event beforeshow
32100 * Fires before this dialog is shown.
32101 * @param {Roo.BasicDialog} this
32103 "beforeshow" : true,
32106 * Fires when this dialog is shown.
32107 * @param {Roo.BasicDialog} this
32111 el.on("keydown", this.onKeyDown, this);
32112 el.on("mousedown", this.toFront, this);
32113 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32115 Roo.DialogManager.register(this);
32116 Roo.BasicDialog.superclass.constructor.call(this);
32119 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32120 shadowOffset: Roo.isIE ? 6 : 5,
32123 minButtonWidth: 75,
32124 defaultButton: null,
32125 buttonAlign: "right",
32130 * Sets the dialog title text
32131 * @param {String} text The title text to display
32132 * @return {Roo.BasicDialog} this
32134 setTitle : function(text){
32135 this.header.update(text);
32140 closeClick : function(){
32145 collapseClick : function(){
32146 this[this.collapsed ? "expand" : "collapse"]();
32150 * Collapses the dialog to its minimized state (only the title bar is visible).
32151 * Equivalent to the user clicking the collapse dialog button.
32153 collapse : function(){
32154 if(!this.collapsed){
32155 this.collapsed = true;
32156 this.el.addClass("x-dlg-collapsed");
32157 this.restoreHeight = this.el.getHeight();
32158 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32163 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32164 * clicking the expand dialog button.
32166 expand : function(){
32167 if(this.collapsed){
32168 this.collapsed = false;
32169 this.el.removeClass("x-dlg-collapsed");
32170 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32175 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32176 * @return {Roo.TabPanel} The tabs component
32178 initTabs : function(){
32179 var tabs = this.getTabs();
32180 while(tabs.getTab(0)){
32183 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32185 tabs.addTab(Roo.id(dom), dom.title);
32193 beforeResize : function(){
32194 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32198 onResize : function(){
32199 this.refreshSize();
32200 this.syncBodyHeight();
32201 this.adjustAssets();
32203 this.fireEvent("resize", this, this.size.width, this.size.height);
32207 onKeyDown : function(e){
32208 if(this.isVisible()){
32209 this.fireEvent("keydown", this, e);
32214 * Resizes the dialog.
32215 * @param {Number} width
32216 * @param {Number} height
32217 * @return {Roo.BasicDialog} this
32219 resizeTo : function(width, height){
32220 this.el.setSize(width, height);
32221 this.size = {width: width, height: height};
32222 this.syncBodyHeight();
32223 if(this.fixedcenter){
32226 if(this.isVisible()){
32227 this.constrainXY();
32228 this.adjustAssets();
32230 this.fireEvent("resize", this, width, height);
32236 * Resizes the dialog to fit the specified content size.
32237 * @param {Number} width
32238 * @param {Number} height
32239 * @return {Roo.BasicDialog} this
32241 setContentSize : function(w, h){
32242 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32243 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32244 //if(!this.el.isBorderBox()){
32245 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32246 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32249 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32250 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32252 this.resizeTo(w, h);
32257 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32258 * executed in response to a particular key being pressed while the dialog is active.
32259 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32260 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32261 * @param {Function} fn The function to call
32262 * @param {Object} scope (optional) The scope of the function
32263 * @return {Roo.BasicDialog} this
32265 addKeyListener : function(key, fn, scope){
32266 var keyCode, shift, ctrl, alt;
32267 if(typeof key == "object" && !(key instanceof Array)){
32268 keyCode = key["key"];
32269 shift = key["shift"];
32270 ctrl = key["ctrl"];
32275 var handler = function(dlg, e){
32276 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32277 var k = e.getKey();
32278 if(keyCode instanceof Array){
32279 for(var i = 0, len = keyCode.length; i < len; i++){
32280 if(keyCode[i] == k){
32281 fn.call(scope || window, dlg, k, e);
32287 fn.call(scope || window, dlg, k, e);
32292 this.on("keydown", handler);
32297 * Returns the TabPanel component (creates it if it doesn't exist).
32298 * Note: If you wish to simply check for the existence of tabs without creating them,
32299 * check for a null 'tabs' property.
32300 * @return {Roo.TabPanel} The tabs component
32302 getTabs : function(){
32304 this.el.addClass("x-dlg-auto-tabs");
32305 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32306 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32312 * Adds a button to the footer section of the dialog.
32313 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32314 * object or a valid Roo.DomHelper element config
32315 * @param {Function} handler The function called when the button is clicked
32316 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32317 * @return {Roo.Button} The new button
32319 addButton : function(config, handler, scope){
32320 var dh = Roo.DomHelper;
32322 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32324 if(!this.btnContainer){
32325 var tb = this.footer.createChild({
32327 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32328 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32330 this.btnContainer = tb.firstChild.firstChild.firstChild;
32335 minWidth: this.minButtonWidth,
32338 if(typeof config == "string"){
32339 bconfig.text = config;
32342 bconfig.dhconfig = config;
32344 Roo.apply(bconfig, config);
32348 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32349 bconfig.position = Math.max(0, bconfig.position);
32350 fc = this.btnContainer.childNodes[bconfig.position];
32353 var btn = new Roo.Button(
32355 this.btnContainer.insertBefore(document.createElement("td"),fc)
32356 : this.btnContainer.appendChild(document.createElement("td")),
32357 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32360 this.syncBodyHeight();
32363 * Array of all the buttons that have been added to this dialog via addButton
32368 this.buttons.push(btn);
32373 * Sets the default button to be focused when the dialog is displayed.
32374 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32375 * @return {Roo.BasicDialog} this
32377 setDefaultButton : function(btn){
32378 this.defaultButton = btn;
32383 getHeaderFooterHeight : function(safe){
32386 height += this.header.getHeight();
32389 var fm = this.footer.getMargins();
32390 height += (this.footer.getHeight()+fm.top+fm.bottom);
32392 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32393 height += this.centerBg.getPadding("tb");
32398 syncBodyHeight : function()
32400 var bd = this.body, // the text
32401 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32403 var height = this.size.height - this.getHeaderFooterHeight(false);
32404 bd.setHeight(height-bd.getMargins("tb"));
32405 var hh = this.header.getHeight();
32406 var h = this.size.height-hh;
32409 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32410 bw.setHeight(h-cb.getPadding("tb"));
32412 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32413 bd.setWidth(bw.getWidth(true));
32415 this.tabs.syncHeight();
32417 this.tabs.el.repaint();
32423 * Restores the previous state of the dialog if Roo.state is configured.
32424 * @return {Roo.BasicDialog} this
32426 restoreState : function(){
32427 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32428 if(box && box.width){
32429 this.xy = [box.x, box.y];
32430 this.resizeTo(box.width, box.height);
32436 beforeShow : function(){
32438 if(this.fixedcenter){
32439 this.xy = this.el.getCenterXY(true);
32442 Roo.get(document.body).addClass("x-body-masked");
32443 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32446 this.constrainXY();
32450 animShow : function(){
32451 var b = Roo.get(this.animateTarget).getBox();
32452 this.proxy.setSize(b.width, b.height);
32453 this.proxy.setLocation(b.x, b.y);
32455 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32456 true, .35, this.showEl.createDelegate(this));
32460 * Shows the dialog.
32461 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32462 * @return {Roo.BasicDialog} this
32464 show : function(animateTarget){
32465 if (this.fireEvent("beforeshow", this) === false){
32468 if(this.syncHeightBeforeShow){
32469 this.syncBodyHeight();
32470 }else if(this.firstShow){
32471 this.firstShow = false;
32472 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32474 this.animateTarget = animateTarget || this.animateTarget;
32475 if(!this.el.isVisible()){
32477 if(this.animateTarget && Roo.get(this.animateTarget)){
32487 showEl : function(){
32489 this.el.setXY(this.xy);
32491 this.adjustAssets(true);
32494 // IE peekaboo bug - fix found by Dave Fenwick
32498 this.fireEvent("show", this);
32502 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32503 * dialog itself will receive focus.
32505 focus : function(){
32506 if(this.defaultButton){
32507 this.defaultButton.focus();
32509 this.focusEl.focus();
32514 constrainXY : function(){
32515 if(this.constraintoviewport !== false){
32516 if(!this.viewSize){
32517 if(this.container){
32518 var s = this.container.getSize();
32519 this.viewSize = [s.width, s.height];
32521 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32524 var s = Roo.get(this.container||document).getScroll();
32526 var x = this.xy[0], y = this.xy[1];
32527 var w = this.size.width, h = this.size.height;
32528 var vw = this.viewSize[0], vh = this.viewSize[1];
32529 // only move it if it needs it
32531 // first validate right/bottom
32532 if(x + w > vw+s.left){
32536 if(y + h > vh+s.top){
32540 // then make sure top/left isn't negative
32552 if(this.isVisible()){
32553 this.el.setLocation(x, y);
32554 this.adjustAssets();
32561 onDrag : function(){
32562 if(!this.proxyDrag){
32563 this.xy = this.el.getXY();
32564 this.adjustAssets();
32569 adjustAssets : function(doShow){
32570 var x = this.xy[0], y = this.xy[1];
32571 var w = this.size.width, h = this.size.height;
32572 if(doShow === true){
32574 this.shadow.show(this.el);
32580 if(this.shadow && this.shadow.isVisible()){
32581 this.shadow.show(this.el);
32583 if(this.shim && this.shim.isVisible()){
32584 this.shim.setBounds(x, y, w, h);
32589 adjustViewport : function(w, h){
32591 w = Roo.lib.Dom.getViewWidth();
32592 h = Roo.lib.Dom.getViewHeight();
32595 this.viewSize = [w, h];
32596 if(this.modal && this.mask.isVisible()){
32597 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32598 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32600 if(this.isVisible()){
32601 this.constrainXY();
32606 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32607 * shadow, proxy, mask, etc.) Also removes all event listeners.
32608 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32610 destroy : function(removeEl){
32611 if(this.isVisible()){
32612 this.animateTarget = null;
32615 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32617 this.tabs.destroy(removeEl);
32630 for(var i = 0, len = this.buttons.length; i < len; i++){
32631 this.buttons[i].destroy();
32634 this.el.removeAllListeners();
32635 if(removeEl === true){
32636 this.el.update("");
32639 Roo.DialogManager.unregister(this);
32643 startMove : function(){
32644 if(this.proxyDrag){
32647 if(this.constraintoviewport !== false){
32648 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32653 endMove : function(){
32654 if(!this.proxyDrag){
32655 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32657 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32660 this.refreshSize();
32661 this.adjustAssets();
32663 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32667 * Brings this dialog to the front of any other visible dialogs
32668 * @return {Roo.BasicDialog} this
32670 toFront : function(){
32671 Roo.DialogManager.bringToFront(this);
32676 * Sends this dialog to the back (under) of any other visible dialogs
32677 * @return {Roo.BasicDialog} this
32679 toBack : function(){
32680 Roo.DialogManager.sendToBack(this);
32685 * Centers this dialog in the viewport
32686 * @return {Roo.BasicDialog} this
32688 center : function(){
32689 var xy = this.el.getCenterXY(true);
32690 this.moveTo(xy[0], xy[1]);
32695 * Moves the dialog's top-left corner to the specified point
32696 * @param {Number} x
32697 * @param {Number} y
32698 * @return {Roo.BasicDialog} this
32700 moveTo : function(x, y){
32702 if(this.isVisible()){
32703 this.el.setXY(this.xy);
32704 this.adjustAssets();
32710 * Aligns the dialog to the specified element
32711 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32712 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32713 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32714 * @return {Roo.BasicDialog} this
32716 alignTo : function(element, position, offsets){
32717 this.xy = this.el.getAlignToXY(element, position, offsets);
32718 if(this.isVisible()){
32719 this.el.setXY(this.xy);
32720 this.adjustAssets();
32726 * Anchors an element to another element and realigns it when the window is resized.
32727 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32728 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32729 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32730 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32731 * is a number, it is used as the buffer delay (defaults to 50ms).
32732 * @return {Roo.BasicDialog} this
32734 anchorTo : function(el, alignment, offsets, monitorScroll){
32735 var action = function(){
32736 this.alignTo(el, alignment, offsets);
32738 Roo.EventManager.onWindowResize(action, this);
32739 var tm = typeof monitorScroll;
32740 if(tm != 'undefined'){
32741 Roo.EventManager.on(window, 'scroll', action, this,
32742 {buffer: tm == 'number' ? monitorScroll : 50});
32749 * Returns true if the dialog is visible
32750 * @return {Boolean}
32752 isVisible : function(){
32753 return this.el.isVisible();
32757 animHide : function(callback){
32758 var b = Roo.get(this.animateTarget).getBox();
32760 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32762 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32763 this.hideEl.createDelegate(this, [callback]));
32767 * Hides the dialog.
32768 * @param {Function} callback (optional) Function to call when the dialog is hidden
32769 * @return {Roo.BasicDialog} this
32771 hide : function(callback){
32772 if (this.fireEvent("beforehide", this) === false){
32776 this.shadow.hide();
32781 // sometimes animateTarget seems to get set.. causing problems...
32782 // this just double checks..
32783 if(this.animateTarget && Roo.get(this.animateTarget)) {
32784 this.animHide(callback);
32787 this.hideEl(callback);
32793 hideEl : function(callback){
32797 Roo.get(document.body).removeClass("x-body-masked");
32799 this.fireEvent("hide", this);
32800 if(typeof callback == "function"){
32806 hideAction : function(){
32807 this.setLeft("-10000px");
32808 this.setTop("-10000px");
32809 this.setStyle("visibility", "hidden");
32813 refreshSize : function(){
32814 this.size = this.el.getSize();
32815 this.xy = this.el.getXY();
32816 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32820 // z-index is managed by the DialogManager and may be overwritten at any time
32821 setZIndex : function(index){
32823 this.mask.setStyle("z-index", index);
32826 this.shim.setStyle("z-index", ++index);
32829 this.shadow.setZIndex(++index);
32831 this.el.setStyle("z-index", ++index);
32833 this.proxy.setStyle("z-index", ++index);
32836 this.resizer.proxy.setStyle("z-index", ++index);
32839 this.lastZIndex = index;
32843 * Returns the element for this dialog
32844 * @return {Roo.Element} The underlying dialog Element
32846 getEl : function(){
32852 * @class Roo.DialogManager
32853 * Provides global access to BasicDialogs that have been created and
32854 * support for z-indexing (layering) multiple open dialogs.
32856 Roo.DialogManager = function(){
32858 var accessList = [];
32862 var sortDialogs = function(d1, d2){
32863 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32867 var orderDialogs = function(){
32868 accessList.sort(sortDialogs);
32869 var seed = Roo.DialogManager.zseed;
32870 for(var i = 0, len = accessList.length; i < len; i++){
32871 var dlg = accessList[i];
32873 dlg.setZIndex(seed + (i*10));
32880 * The starting z-index for BasicDialogs (defaults to 9000)
32881 * @type Number The z-index value
32886 register : function(dlg){
32887 list[dlg.id] = dlg;
32888 accessList.push(dlg);
32892 unregister : function(dlg){
32893 delete list[dlg.id];
32896 if(!accessList.indexOf){
32897 for( i = 0, len = accessList.length; i < len; i++){
32898 if(accessList[i] == dlg){
32899 accessList.splice(i, 1);
32904 i = accessList.indexOf(dlg);
32906 accessList.splice(i, 1);
32912 * Gets a registered dialog by id
32913 * @param {String/Object} id The id of the dialog or a dialog
32914 * @return {Roo.BasicDialog} this
32916 get : function(id){
32917 return typeof id == "object" ? id : list[id];
32921 * Brings the specified dialog to the front
32922 * @param {String/Object} dlg The id of the dialog or a dialog
32923 * @return {Roo.BasicDialog} this
32925 bringToFront : function(dlg){
32926 dlg = this.get(dlg);
32929 dlg._lastAccess = new Date().getTime();
32936 * Sends the specified dialog to the back
32937 * @param {String/Object} dlg The id of the dialog or a dialog
32938 * @return {Roo.BasicDialog} this
32940 sendToBack : function(dlg){
32941 dlg = this.get(dlg);
32942 dlg._lastAccess = -(new Date().getTime());
32948 * Hides all dialogs
32950 hideAll : function(){
32951 for(var id in list){
32952 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32961 * @class Roo.LayoutDialog
32962 * @extends Roo.BasicDialog
32963 * Dialog which provides adjustments for working with a layout in a Dialog.
32964 * Add your necessary layout config options to the dialog's config.<br>
32965 * Example usage (including a nested layout):
32968 dialog = new Roo.LayoutDialog("download-dlg", {
32977 // layout config merges with the dialog config
32979 tabPosition: "top",
32980 alwaysShowTabs: true
32983 dialog.addKeyListener(27, dialog.hide, dialog);
32984 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32985 dialog.addButton("Build It!", this.getDownload, this);
32987 // we can even add nested layouts
32988 var innerLayout = new Roo.BorderLayout("dl-inner", {
32998 innerLayout.beginUpdate();
32999 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
33000 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
33001 innerLayout.endUpdate(true);
33003 var layout = dialog.getLayout();
33004 layout.beginUpdate();
33005 layout.add("center", new Roo.ContentPanel("standard-panel",
33006 {title: "Download the Source", fitToFrame:true}));
33007 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
33008 {title: "Build your own roo.js"}));
33009 layout.getRegion("center").showPanel(sp);
33010 layout.endUpdate();
33014 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
33015 * @param {Object} config configuration options
33017 Roo.LayoutDialog = function(el, cfg){
33020 if (typeof(cfg) == 'undefined') {
33021 config = Roo.apply({}, el);
33022 // not sure why we use documentElement here.. - it should always be body.
33023 // IE7 borks horribly if we use documentElement.
33024 // webkit also does not like documentElement - it creates a body element...
33025 el = Roo.get( document.body || document.documentElement ).createChild();
33026 //config.autoCreate = true;
33030 config.autoTabs = false;
33031 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
33032 this.body.setStyle({overflow:"hidden", position:"relative"});
33033 this.layout = new Roo.BorderLayout(this.body.dom, config);
33034 this.layout.monitorWindowResize = false;
33035 this.el.addClass("x-dlg-auto-layout");
33036 // fix case when center region overwrites center function
33037 this.center = Roo.BasicDialog.prototype.center;
33038 this.on("show", this.layout.layout, this.layout, true);
33039 if (config.items) {
33040 var xitems = config.items;
33041 delete config.items;
33042 Roo.each(xitems, this.addxtype, this);
33047 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
33049 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
33052 endUpdate : function(){
33053 this.layout.endUpdate();
33057 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33060 beginUpdate : function(){
33061 this.layout.beginUpdate();
33065 * Get the BorderLayout for this dialog
33066 * @return {Roo.BorderLayout}
33068 getLayout : function(){
33069 return this.layout;
33072 showEl : function(){
33073 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33075 this.layout.layout();
33080 // Use the syncHeightBeforeShow config option to control this automatically
33081 syncBodyHeight : function(){
33082 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33083 if(this.layout){this.layout.layout();}
33087 * Add an xtype element (actually adds to the layout.)
33088 * @return {Object} xdata xtype object data.
33091 addxtype : function(c) {
33092 return this.layout.addxtype(c);
33096 * Ext JS Library 1.1.1
33097 * Copyright(c) 2006-2007, Ext JS, LLC.
33099 * Originally Released Under LGPL - original licence link has changed is not relivant.
33102 * <script type="text/javascript">
33106 * @class Roo.MessageBox
33107 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33111 Roo.Msg.alert('Status', 'Changes saved successfully.');
33113 // Prompt for user data:
33114 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33116 // process text value...
33120 // Show a dialog using config options:
33122 title:'Save Changes?',
33123 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33124 buttons: Roo.Msg.YESNOCANCEL,
33131 Roo.MessageBox = function(){
33132 var dlg, opt, mask, waitTimer;
33133 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33134 var buttons, activeTextEl, bwidth;
33137 var handleButton = function(button){
33139 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33143 var handleHide = function(){
33144 if(opt && opt.cls){
33145 dlg.el.removeClass(opt.cls);
33148 Roo.TaskMgr.stop(waitTimer);
33154 var updateButtons = function(b){
33157 buttons["ok"].hide();
33158 buttons["cancel"].hide();
33159 buttons["yes"].hide();
33160 buttons["no"].hide();
33161 dlg.footer.dom.style.display = 'none';
33164 dlg.footer.dom.style.display = '';
33165 for(var k in buttons){
33166 if(typeof buttons[k] != "function"){
33169 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33170 width += buttons[k].el.getWidth()+15;
33180 var handleEsc = function(d, k, e){
33181 if(opt && opt.closable !== false){
33191 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33192 * @return {Roo.BasicDialog} The BasicDialog element
33194 getDialog : function(){
33196 dlg = new Roo.BasicDialog("x-msg-box", {
33201 constraintoviewport:false,
33203 collapsible : false,
33206 width:400, height:100,
33207 buttonAlign:"center",
33208 closeClick : function(){
33209 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33210 handleButton("no");
33212 handleButton("cancel");
33216 dlg.on("hide", handleHide);
33218 dlg.addKeyListener(27, handleEsc);
33220 var bt = this.buttonText;
33221 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33222 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33223 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33224 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33225 bodyEl = dlg.body.createChild({
33227 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>'
33229 msgEl = bodyEl.dom.firstChild;
33230 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33231 textboxEl.enableDisplayMode();
33232 textboxEl.addKeyListener([10,13], function(){
33233 if(dlg.isVisible() && opt && opt.buttons){
33234 if(opt.buttons.ok){
33235 handleButton("ok");
33236 }else if(opt.buttons.yes){
33237 handleButton("yes");
33241 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33242 textareaEl.enableDisplayMode();
33243 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33244 progressEl.enableDisplayMode();
33245 var pf = progressEl.dom.firstChild;
33247 pp = Roo.get(pf.firstChild);
33248 pp.setHeight(pf.offsetHeight);
33256 * Updates the message box body text
33257 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33258 * the XHTML-compliant non-breaking space character '&#160;')
33259 * @return {Roo.MessageBox} This message box
33261 updateText : function(text){
33262 if(!dlg.isVisible() && !opt.width){
33263 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33265 msgEl.innerHTML = text || ' ';
33267 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33268 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33270 Math.min(opt.width || cw , this.maxWidth),
33271 Math.max(opt.minWidth || this.minWidth, bwidth)
33274 activeTextEl.setWidth(w);
33276 if(dlg.isVisible()){
33277 dlg.fixedcenter = false;
33279 // to big, make it scroll. = But as usual stupid IE does not support
33282 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33283 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33284 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33286 bodyEl.dom.style.height = '';
33287 bodyEl.dom.style.overflowY = '';
33290 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33292 bodyEl.dom.style.overflowX = '';
33295 dlg.setContentSize(w, bodyEl.getHeight());
33296 if(dlg.isVisible()){
33297 dlg.fixedcenter = true;
33303 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33304 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33305 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33306 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33307 * @return {Roo.MessageBox} This message box
33309 updateProgress : function(value, text){
33311 this.updateText(text);
33313 if (pp) { // weird bug on my firefox - for some reason this is not defined
33314 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33320 * Returns true if the message box is currently displayed
33321 * @return {Boolean} True if the message box is visible, else false
33323 isVisible : function(){
33324 return dlg && dlg.isVisible();
33328 * Hides the message box if it is displayed
33331 if(this.isVisible()){
33337 * Displays a new message box, or reinitializes an existing message box, based on the config options
33338 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33339 * The following config object properties are supported:
33341 Property Type Description
33342 ---------- --------------- ------------------------------------------------------------------------------------
33343 animEl String/Element An id or Element from which the message box should animate as it opens and
33344 closes (defaults to undefined)
33345 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33346 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33347 closable Boolean False to hide the top-right close button (defaults to true). Note that
33348 progress and wait dialogs will ignore this property and always hide the
33349 close button as they can only be closed programmatically.
33350 cls String A custom CSS class to apply to the message box element
33351 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33352 displayed (defaults to 75)
33353 fn Function A callback function to execute after closing the dialog. The arguments to the
33354 function will be btn (the name of the button that was clicked, if applicable,
33355 e.g. "ok"), and text (the value of the active text field, if applicable).
33356 Progress and wait dialogs will ignore this option since they do not respond to
33357 user actions and can only be closed programmatically, so any required function
33358 should be called by the same code after it closes the dialog.
33359 icon String A CSS class that provides a background image to be used as an icon for
33360 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33361 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33362 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33363 modal Boolean False to allow user interaction with the page while the message box is
33364 displayed (defaults to true)
33365 msg String A string that will replace the existing message box body text (defaults
33366 to the XHTML-compliant non-breaking space character ' ')
33367 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33368 progress Boolean True to display a progress bar (defaults to false)
33369 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33370 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33371 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33372 title String The title text
33373 value String The string value to set into the active textbox element if displayed
33374 wait Boolean True to display a progress bar (defaults to false)
33375 width Number The width of the dialog in pixels
33382 msg: 'Please enter your address:',
33384 buttons: Roo.MessageBox.OKCANCEL,
33387 animEl: 'addAddressBtn'
33390 * @param {Object} config Configuration options
33391 * @return {Roo.MessageBox} This message box
33393 show : function(options)
33396 // this causes nightmares if you show one dialog after another
33397 // especially on callbacks..
33399 if(this.isVisible()){
33402 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33403 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33404 Roo.log("New Dialog Message:" + options.msg )
33405 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33406 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33409 var d = this.getDialog();
33411 d.setTitle(opt.title || " ");
33412 d.close.setDisplayed(opt.closable !== false);
33413 activeTextEl = textboxEl;
33414 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33419 textareaEl.setHeight(typeof opt.multiline == "number" ?
33420 opt.multiline : this.defaultTextHeight);
33421 activeTextEl = textareaEl;
33430 progressEl.setDisplayed(opt.progress === true);
33431 this.updateProgress(0);
33432 activeTextEl.dom.value = opt.value || "";
33434 dlg.setDefaultButton(activeTextEl);
33436 var bs = opt.buttons;
33439 db = buttons["ok"];
33440 }else if(bs && bs.yes){
33441 db = buttons["yes"];
33443 dlg.setDefaultButton(db);
33445 bwidth = updateButtons(opt.buttons);
33446 this.updateText(opt.msg);
33448 d.el.addClass(opt.cls);
33450 d.proxyDrag = opt.proxyDrag === true;
33451 d.modal = opt.modal !== false;
33452 d.mask = opt.modal !== false ? mask : false;
33453 if(!d.isVisible()){
33454 // force it to the end of the z-index stack so it gets a cursor in FF
33455 document.body.appendChild(dlg.el.dom);
33456 d.animateTarget = null;
33457 d.show(options.animEl);
33463 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33464 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33465 * and closing the message box when the process is complete.
33466 * @param {String} title The title bar text
33467 * @param {String} msg The message box body text
33468 * @return {Roo.MessageBox} This message box
33470 progress : function(title, msg){
33477 minWidth: this.minProgressWidth,
33484 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33485 * If a callback function is passed it will be called after the user clicks the button, and the
33486 * id of the button that was clicked will be passed as the only parameter to the callback
33487 * (could also be the top-right close button).
33488 * @param {String} title The title bar text
33489 * @param {String} msg The message box body text
33490 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33491 * @param {Object} scope (optional) The scope of the callback function
33492 * @return {Roo.MessageBox} This message box
33494 alert : function(title, msg, fn, scope){
33507 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33508 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33509 * You are responsible for closing the message box when the process is complete.
33510 * @param {String} msg The message box body text
33511 * @param {String} title (optional) The title bar text
33512 * @return {Roo.MessageBox} This message box
33514 wait : function(msg, title){
33525 waitTimer = Roo.TaskMgr.start({
33527 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33535 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33536 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33537 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33538 * @param {String} title The title bar text
33539 * @param {String} msg The message box body text
33540 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33541 * @param {Object} scope (optional) The scope of the callback function
33542 * @return {Roo.MessageBox} This message box
33544 confirm : function(title, msg, fn, scope){
33548 buttons: this.YESNO,
33557 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33558 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33559 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33560 * (could also be the top-right close button) and the text that was entered will be passed as the two
33561 * parameters to the callback.
33562 * @param {String} title The title bar text
33563 * @param {String} msg The message box body text
33564 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33565 * @param {Object} scope (optional) The scope of the callback function
33566 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33567 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33568 * @return {Roo.MessageBox} This message box
33570 prompt : function(title, msg, fn, scope, multiline){
33574 buttons: this.OKCANCEL,
33579 multiline: multiline,
33586 * Button config that displays a single OK button
33591 * Button config that displays Yes and No buttons
33594 YESNO : {yes:true, no:true},
33596 * Button config that displays OK and Cancel buttons
33599 OKCANCEL : {ok:true, cancel:true},
33601 * Button config that displays Yes, No and Cancel buttons
33604 YESNOCANCEL : {yes:true, no:true, cancel:true},
33607 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33610 defaultTextHeight : 75,
33612 * The maximum width in pixels of the message box (defaults to 600)
33617 * The minimum width in pixels of the message box (defaults to 100)
33622 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33623 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33626 minProgressWidth : 250,
33628 * An object containing the default button text strings that can be overriden for localized language support.
33629 * Supported properties are: ok, cancel, yes and no.
33630 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33643 * Shorthand for {@link Roo.MessageBox}
33645 Roo.Msg = Roo.MessageBox;/*
33647 * Ext JS Library 1.1.1
33648 * Copyright(c) 2006-2007, Ext JS, LLC.
33650 * Originally Released Under LGPL - original licence link has changed is not relivant.
33653 * <script type="text/javascript">
33656 * @class Roo.QuickTips
33657 * Provides attractive and customizable tooltips for any element.
33660 Roo.QuickTips = function(){
33661 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33662 var ce, bd, xy, dd;
33663 var visible = false, disabled = true, inited = false;
33664 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33666 var onOver = function(e){
33670 var t = e.getTarget();
33671 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33674 if(ce && t == ce.el){
33675 clearTimeout(hideProc);
33678 if(t && tagEls[t.id]){
33679 tagEls[t.id].el = t;
33680 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33683 var ttp, et = Roo.fly(t);
33684 var ns = cfg.namespace;
33685 if(tm.interceptTitles && t.title){
33688 t.removeAttribute("title");
33689 e.preventDefault();
33691 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33694 showProc = show.defer(tm.showDelay, tm, [{
33696 text: ttp.replace(/\\n/g,'<br/>'),
33697 width: et.getAttributeNS(ns, cfg.width),
33698 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33699 title: et.getAttributeNS(ns, cfg.title),
33700 cls: et.getAttributeNS(ns, cfg.cls)
33705 var onOut = function(e){
33706 clearTimeout(showProc);
33707 var t = e.getTarget();
33708 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33709 hideProc = setTimeout(hide, tm.hideDelay);
33713 var onMove = function(e){
33719 if(tm.trackMouse && ce){
33724 var onDown = function(e){
33725 clearTimeout(showProc);
33726 clearTimeout(hideProc);
33728 if(tm.hideOnClick){
33731 tm.enable.defer(100, tm);
33736 var getPad = function(){
33737 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33740 var show = function(o){
33744 clearTimeout(dismissProc);
33746 if(removeCls){ // in case manually hidden
33747 el.removeClass(removeCls);
33751 el.addClass(ce.cls);
33752 removeCls = ce.cls;
33755 tipTitle.update(ce.title);
33758 tipTitle.update('');
33761 el.dom.style.width = tm.maxWidth+'px';
33762 //tipBody.dom.style.width = '';
33763 tipBodyText.update(o.text);
33764 var p = getPad(), w = ce.width;
33766 var td = tipBodyText.dom;
33767 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33768 if(aw > tm.maxWidth){
33770 }else if(aw < tm.minWidth){
33776 //tipBody.setWidth(w);
33777 el.setWidth(parseInt(w, 10) + p);
33778 if(ce.autoHide === false){
33779 close.setDisplayed(true);
33784 close.setDisplayed(false);
33790 el.avoidY = xy[1]-18;
33795 el.setStyle("visibility", "visible");
33796 el.fadeIn({callback: afterShow});
33802 var afterShow = function(){
33806 if(tm.autoDismiss && ce.autoHide !== false){
33807 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33812 var hide = function(noanim){
33813 clearTimeout(dismissProc);
33814 clearTimeout(hideProc);
33816 if(el.isVisible()){
33818 if(noanim !== true && tm.animate){
33819 el.fadeOut({callback: afterHide});
33826 var afterHide = function(){
33829 el.removeClass(removeCls);
33836 * @cfg {Number} minWidth
33837 * The minimum width of the quick tip (defaults to 40)
33841 * @cfg {Number} maxWidth
33842 * The maximum width of the quick tip (defaults to 300)
33846 * @cfg {Boolean} interceptTitles
33847 * True to automatically use the element's DOM title value if available (defaults to false)
33849 interceptTitles : false,
33851 * @cfg {Boolean} trackMouse
33852 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33854 trackMouse : false,
33856 * @cfg {Boolean} hideOnClick
33857 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33859 hideOnClick : true,
33861 * @cfg {Number} showDelay
33862 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33866 * @cfg {Number} hideDelay
33867 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33871 * @cfg {Boolean} autoHide
33872 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33873 * Used in conjunction with hideDelay.
33878 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33879 * (defaults to true). Used in conjunction with autoDismissDelay.
33881 autoDismiss : true,
33884 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33886 autoDismissDelay : 5000,
33888 * @cfg {Boolean} animate
33889 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33894 * @cfg {String} title
33895 * Title text to display (defaults to ''). This can be any valid HTML markup.
33899 * @cfg {String} text
33900 * Body text to display (defaults to ''). This can be any valid HTML markup.
33904 * @cfg {String} cls
33905 * A CSS class to apply to the base quick tip element (defaults to '').
33909 * @cfg {Number} width
33910 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33911 * minWidth or maxWidth.
33916 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33917 * or display QuickTips in a page.
33920 tm = Roo.QuickTips;
33921 cfg = tm.tagConfig;
33923 if(!Roo.isReady){ // allow calling of init() before onReady
33924 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33927 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33928 el.fxDefaults = {stopFx: true};
33929 // maximum custom styling
33930 //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>');
33931 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>');
33932 tipTitle = el.child('h3');
33933 tipTitle.enableDisplayMode("block");
33934 tipBody = el.child('div.x-tip-bd');
33935 tipBodyText = el.child('div.x-tip-bd-inner');
33936 //bdLeft = el.child('div.x-tip-bd-left');
33937 //bdRight = el.child('div.x-tip-bd-right');
33938 close = el.child('div.x-tip-close');
33939 close.enableDisplayMode("block");
33940 close.on("click", hide);
33941 var d = Roo.get(document);
33942 d.on("mousedown", onDown);
33943 d.on("mouseover", onOver);
33944 d.on("mouseout", onOut);
33945 d.on("mousemove", onMove);
33946 esc = d.addKeyListener(27, hide);
33949 dd = el.initDD("default", null, {
33950 onDrag : function(){
33954 dd.setHandleElId(tipTitle.id);
33963 * Configures a new quick tip instance and assigns it to a target element. The following config options
33966 Property Type Description
33967 ---------- --------------------- ------------------------------------------------------------------------
33968 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33970 * @param {Object} config The config object
33972 register : function(config){
33973 var cs = config instanceof Array ? config : arguments;
33974 for(var i = 0, len = cs.length; i < len; i++) {
33976 var target = c.target;
33978 if(target instanceof Array){
33979 for(var j = 0, jlen = target.length; j < jlen; j++){
33980 tagEls[target[j]] = c;
33983 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33990 * Removes this quick tip from its element and destroys it.
33991 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33993 unregister : function(el){
33994 delete tagEls[Roo.id(el)];
33998 * Enable this quick tip.
34000 enable : function(){
34001 if(inited && disabled){
34003 if(locks.length < 1){
34010 * Disable this quick tip.
34012 disable : function(){
34014 clearTimeout(showProc);
34015 clearTimeout(hideProc);
34016 clearTimeout(dismissProc);
34024 * Returns true if the quick tip is enabled, else false.
34026 isEnabled : function(){
34032 namespace : "roo", // was ext?? this may break..
34033 alt_namespace : "ext",
34034 attribute : "qtip",
34044 // backwards compat
34045 Roo.QuickTips.tips = Roo.QuickTips.register;/*
34047 * Ext JS Library 1.1.1
34048 * Copyright(c) 2006-2007, Ext JS, LLC.
34050 * Originally Released Under LGPL - original licence link has changed is not relivant.
34053 * <script type="text/javascript">
34058 * @class Roo.tree.TreePanel
34059 * @extends Roo.data.Tree
34061 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34062 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34063 * @cfg {Boolean} enableDD true to enable drag and drop
34064 * @cfg {Boolean} enableDrag true to enable just drag
34065 * @cfg {Boolean} enableDrop true to enable just drop
34066 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34067 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34068 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34069 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34070 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34071 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34072 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34073 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34074 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34075 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34076 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34077 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
34078 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
34079 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34080 * @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>
34081 * @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>
34084 * @param {String/HTMLElement/Element} el The container element
34085 * @param {Object} config
34087 Roo.tree.TreePanel = function(el, config){
34089 var loader = false;
34091 root = config.root;
34092 delete config.root;
34094 if (config.loader) {
34095 loader = config.loader;
34096 delete config.loader;
34099 Roo.apply(this, config);
34100 Roo.tree.TreePanel.superclass.constructor.call(this);
34101 this.el = Roo.get(el);
34102 this.el.addClass('x-tree');
34103 //console.log(root);
34105 this.setRootNode( Roo.factory(root, Roo.tree));
34108 this.loader = Roo.factory(loader, Roo.tree);
34111 * Read-only. The id of the container element becomes this TreePanel's id.
34113 this.id = this.el.id;
34116 * @event beforeload
34117 * Fires before a node is loaded, return false to cancel
34118 * @param {Node} node The node being loaded
34120 "beforeload" : true,
34123 * Fires when a node is loaded
34124 * @param {Node} node The node that was loaded
34128 * @event textchange
34129 * Fires when the text for a node is changed
34130 * @param {Node} node The node
34131 * @param {String} text The new text
34132 * @param {String} oldText The old text
34134 "textchange" : true,
34136 * @event beforeexpand
34137 * Fires before a node is expanded, return false to cancel.
34138 * @param {Node} node The node
34139 * @param {Boolean} deep
34140 * @param {Boolean} anim
34142 "beforeexpand" : true,
34144 * @event beforecollapse
34145 * Fires before a node is collapsed, return false to cancel.
34146 * @param {Node} node The node
34147 * @param {Boolean} deep
34148 * @param {Boolean} anim
34150 "beforecollapse" : true,
34153 * Fires when a node is expanded
34154 * @param {Node} node The node
34158 * @event disabledchange
34159 * Fires when the disabled status of a node changes
34160 * @param {Node} node The node
34161 * @param {Boolean} disabled
34163 "disabledchange" : true,
34166 * Fires when a node is collapsed
34167 * @param {Node} node The node
34171 * @event beforeclick
34172 * Fires before click processing on a node. Return false to cancel the default action.
34173 * @param {Node} node The node
34174 * @param {Roo.EventObject} e The event object
34176 "beforeclick":true,
34178 * @event checkchange
34179 * Fires when a node with a checkbox's checked property changes
34180 * @param {Node} this This node
34181 * @param {Boolean} checked
34183 "checkchange":true,
34186 * Fires when a node is clicked
34187 * @param {Node} node The node
34188 * @param {Roo.EventObject} e The event object
34193 * Fires when a node is double clicked
34194 * @param {Node} node The node
34195 * @param {Roo.EventObject} e The event object
34199 * @event contextmenu
34200 * Fires when a node is right clicked
34201 * @param {Node} node The node
34202 * @param {Roo.EventObject} e The event object
34204 "contextmenu":true,
34206 * @event beforechildrenrendered
34207 * Fires right before the child nodes for a node are rendered
34208 * @param {Node} node The node
34210 "beforechildrenrendered":true,
34213 * Fires when a node starts being dragged
34214 * @param {Roo.tree.TreePanel} this
34215 * @param {Roo.tree.TreeNode} node
34216 * @param {event} e The raw browser event
34218 "startdrag" : true,
34221 * Fires when a drag operation is complete
34222 * @param {Roo.tree.TreePanel} this
34223 * @param {Roo.tree.TreeNode} node
34224 * @param {event} e The raw browser event
34229 * Fires when a dragged node is dropped on a valid DD target
34230 * @param {Roo.tree.TreePanel} this
34231 * @param {Roo.tree.TreeNode} node
34232 * @param {DD} dd The dd it was dropped on
34233 * @param {event} e The raw browser event
34237 * @event beforenodedrop
34238 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34239 * passed to handlers has the following properties:<br />
34240 * <ul style="padding:5px;padding-left:16px;">
34241 * <li>tree - The TreePanel</li>
34242 * <li>target - The node being targeted for the drop</li>
34243 * <li>data - The drag data from the drag source</li>
34244 * <li>point - The point of the drop - append, above or below</li>
34245 * <li>source - The drag source</li>
34246 * <li>rawEvent - Raw mouse event</li>
34247 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34248 * to be inserted by setting them on this object.</li>
34249 * <li>cancel - Set this to true to cancel the drop.</li>
34251 * @param {Object} dropEvent
34253 "beforenodedrop" : true,
34256 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34257 * passed to handlers has the following properties:<br />
34258 * <ul style="padding:5px;padding-left:16px;">
34259 * <li>tree - The TreePanel</li>
34260 * <li>target - The node being targeted for the drop</li>
34261 * <li>data - The drag data from the drag source</li>
34262 * <li>point - The point of the drop - append, above or below</li>
34263 * <li>source - The drag source</li>
34264 * <li>rawEvent - Raw mouse event</li>
34265 * <li>dropNode - Dropped node(s).</li>
34267 * @param {Object} dropEvent
34271 * @event nodedragover
34272 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34273 * passed to handlers has the following properties:<br />
34274 * <ul style="padding:5px;padding-left:16px;">
34275 * <li>tree - The TreePanel</li>
34276 * <li>target - The node being targeted for the drop</li>
34277 * <li>data - The drag data from the drag source</li>
34278 * <li>point - The point of the drop - append, above or below</li>
34279 * <li>source - The drag source</li>
34280 * <li>rawEvent - Raw mouse event</li>
34281 * <li>dropNode - Drop node(s) provided by the source.</li>
34282 * <li>cancel - Set this to true to signal drop not allowed.</li>
34284 * @param {Object} dragOverEvent
34286 "nodedragover" : true,
34288 * @event appendnode
34289 * Fires when append node to the tree
34290 * @param {Roo.tree.TreePanel} this
34291 * @param {Roo.tree.TreeNode} node
34292 * @param {Number} index The index of the newly appended node
34294 "appendnode" : true
34297 if(this.singleExpand){
34298 this.on("beforeexpand", this.restrictExpand, this);
34301 this.editor.tree = this;
34302 this.editor = Roo.factory(this.editor, Roo.tree);
34305 if (this.selModel) {
34306 this.selModel = Roo.factory(this.selModel, Roo.tree);
34310 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34311 rootVisible : true,
34312 animate: Roo.enableFx,
34315 hlDrop : Roo.enableFx,
34319 rendererTip: false,
34321 restrictExpand : function(node){
34322 var p = node.parentNode;
34324 if(p.expandedChild && p.expandedChild.parentNode == p){
34325 p.expandedChild.collapse();
34327 p.expandedChild = node;
34331 // private override
34332 setRootNode : function(node){
34333 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34334 if(!this.rootVisible){
34335 node.ui = new Roo.tree.RootTreeNodeUI(node);
34341 * Returns the container element for this TreePanel
34343 getEl : function(){
34348 * Returns the default TreeLoader for this TreePanel
34350 getLoader : function(){
34351 return this.loader;
34357 expandAll : function(){
34358 this.root.expand(true);
34362 * Collapse all nodes
34364 collapseAll : function(){
34365 this.root.collapse(true);
34369 * Returns the selection model used by this TreePanel
34371 getSelectionModel : function(){
34372 if(!this.selModel){
34373 this.selModel = new Roo.tree.DefaultSelectionModel();
34375 return this.selModel;
34379 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34380 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34381 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34384 getChecked : function(a, startNode){
34385 startNode = startNode || this.root;
34387 var f = function(){
34388 if(this.attributes.checked){
34389 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34392 startNode.cascade(f);
34397 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34398 * @param {String} path
34399 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34400 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34401 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34403 expandPath : function(path, attr, callback){
34404 attr = attr || "id";
34405 var keys = path.split(this.pathSeparator);
34406 var curNode = this.root;
34407 if(curNode.attributes[attr] != keys[1]){ // invalid root
34409 callback(false, null);
34414 var f = function(){
34415 if(++index == keys.length){
34417 callback(true, curNode);
34421 var c = curNode.findChild(attr, keys[index]);
34424 callback(false, curNode);
34429 c.expand(false, false, f);
34431 curNode.expand(false, false, f);
34435 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34436 * @param {String} path
34437 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34438 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34439 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34441 selectPath : function(path, attr, callback){
34442 attr = attr || "id";
34443 var keys = path.split(this.pathSeparator);
34444 var v = keys.pop();
34445 if(keys.length > 0){
34446 var f = function(success, node){
34447 if(success && node){
34448 var n = node.findChild(attr, v);
34454 }else if(callback){
34455 callback(false, n);
34459 callback(false, n);
34463 this.expandPath(keys.join(this.pathSeparator), attr, f);
34465 this.root.select();
34467 callback(true, this.root);
34472 getTreeEl : function(){
34477 * Trigger rendering of this TreePanel
34479 render : function(){
34480 if (this.innerCt) {
34481 return this; // stop it rendering more than once!!
34484 this.innerCt = this.el.createChild({tag:"ul",
34485 cls:"x-tree-root-ct " +
34486 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34488 if(this.containerScroll){
34489 Roo.dd.ScrollManager.register(this.el);
34491 if((this.enableDD || this.enableDrop) && !this.dropZone){
34493 * The dropZone used by this tree if drop is enabled
34494 * @type Roo.tree.TreeDropZone
34496 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34497 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34500 if((this.enableDD || this.enableDrag) && !this.dragZone){
34502 * The dragZone used by this tree if drag is enabled
34503 * @type Roo.tree.TreeDragZone
34505 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34506 ddGroup: this.ddGroup || "TreeDD",
34507 scroll: this.ddScroll
34510 this.getSelectionModel().init(this);
34512 Roo.log("ROOT not set in tree");
34515 this.root.render();
34516 if(!this.rootVisible){
34517 this.root.renderChildren();
34523 * Ext JS Library 1.1.1
34524 * Copyright(c) 2006-2007, Ext JS, LLC.
34526 * Originally Released Under LGPL - original licence link has changed is not relivant.
34529 * <script type="text/javascript">
34534 * @class Roo.tree.DefaultSelectionModel
34535 * @extends Roo.util.Observable
34536 * The default single selection for a TreePanel.
34537 * @param {Object} cfg Configuration
34539 Roo.tree.DefaultSelectionModel = function(cfg){
34540 this.selNode = null;
34546 * @event selectionchange
34547 * Fires when the selected node changes
34548 * @param {DefaultSelectionModel} this
34549 * @param {TreeNode} node the new selection
34551 "selectionchange" : true,
34554 * @event beforeselect
34555 * Fires before the selected node changes, return false to cancel the change
34556 * @param {DefaultSelectionModel} this
34557 * @param {TreeNode} node the new selection
34558 * @param {TreeNode} node the old selection
34560 "beforeselect" : true
34563 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34566 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34567 init : function(tree){
34569 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34570 tree.on("click", this.onNodeClick, this);
34573 onNodeClick : function(node, e){
34574 if (e.ctrlKey && this.selNode == node) {
34575 this.unselect(node);
34583 * @param {TreeNode} node The node to select
34584 * @return {TreeNode} The selected node
34586 select : function(node){
34587 var last = this.selNode;
34588 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34590 last.ui.onSelectedChange(false);
34592 this.selNode = node;
34593 node.ui.onSelectedChange(true);
34594 this.fireEvent("selectionchange", this, node, last);
34601 * @param {TreeNode} node The node to unselect
34603 unselect : function(node){
34604 if(this.selNode == node){
34605 this.clearSelections();
34610 * Clear all selections
34612 clearSelections : function(){
34613 var n = this.selNode;
34615 n.ui.onSelectedChange(false);
34616 this.selNode = null;
34617 this.fireEvent("selectionchange", this, null);
34623 * Get the selected node
34624 * @return {TreeNode} The selected node
34626 getSelectedNode : function(){
34627 return this.selNode;
34631 * Returns true if the node is selected
34632 * @param {TreeNode} node The node to check
34633 * @return {Boolean}
34635 isSelected : function(node){
34636 return this.selNode == node;
34640 * Selects the node above the selected node in the tree, intelligently walking the nodes
34641 * @return TreeNode The new selection
34643 selectPrevious : function(){
34644 var s = this.selNode || this.lastSelNode;
34648 var ps = s.previousSibling;
34650 if(!ps.isExpanded() || ps.childNodes.length < 1){
34651 return this.select(ps);
34653 var lc = ps.lastChild;
34654 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34657 return this.select(lc);
34659 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34660 return this.select(s.parentNode);
34666 * Selects the node above the selected node in the tree, intelligently walking the nodes
34667 * @return TreeNode The new selection
34669 selectNext : function(){
34670 var s = this.selNode || this.lastSelNode;
34674 if(s.firstChild && s.isExpanded()){
34675 return this.select(s.firstChild);
34676 }else if(s.nextSibling){
34677 return this.select(s.nextSibling);
34678 }else if(s.parentNode){
34680 s.parentNode.bubble(function(){
34681 if(this.nextSibling){
34682 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34691 onKeyDown : function(e){
34692 var s = this.selNode || this.lastSelNode;
34693 // undesirable, but required
34698 var k = e.getKey();
34706 this.selectPrevious();
34709 e.preventDefault();
34710 if(s.hasChildNodes()){
34711 if(!s.isExpanded()){
34713 }else if(s.firstChild){
34714 this.select(s.firstChild, e);
34719 e.preventDefault();
34720 if(s.hasChildNodes() && s.isExpanded()){
34722 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34723 this.select(s.parentNode, e);
34731 * @class Roo.tree.MultiSelectionModel
34732 * @extends Roo.util.Observable
34733 * Multi selection for a TreePanel.
34734 * @param {Object} cfg Configuration
34736 Roo.tree.MultiSelectionModel = function(){
34737 this.selNodes = [];
34741 * @event selectionchange
34742 * Fires when the selected nodes change
34743 * @param {MultiSelectionModel} this
34744 * @param {Array} nodes Array of the selected nodes
34746 "selectionchange" : true
34748 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34752 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34753 init : function(tree){
34755 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34756 tree.on("click", this.onNodeClick, this);
34759 onNodeClick : function(node, e){
34760 this.select(node, e, e.ctrlKey);
34765 * @param {TreeNode} node The node to select
34766 * @param {EventObject} e (optional) An event associated with the selection
34767 * @param {Boolean} keepExisting True to retain existing selections
34768 * @return {TreeNode} The selected node
34770 select : function(node, e, keepExisting){
34771 if(keepExisting !== true){
34772 this.clearSelections(true);
34774 if(this.isSelected(node)){
34775 this.lastSelNode = node;
34778 this.selNodes.push(node);
34779 this.selMap[node.id] = node;
34780 this.lastSelNode = node;
34781 node.ui.onSelectedChange(true);
34782 this.fireEvent("selectionchange", this, this.selNodes);
34788 * @param {TreeNode} node The node to unselect
34790 unselect : function(node){
34791 if(this.selMap[node.id]){
34792 node.ui.onSelectedChange(false);
34793 var sn = this.selNodes;
34796 index = sn.indexOf(node);
34798 for(var i = 0, len = sn.length; i < len; i++){
34806 this.selNodes.splice(index, 1);
34808 delete this.selMap[node.id];
34809 this.fireEvent("selectionchange", this, this.selNodes);
34814 * Clear all selections
34816 clearSelections : function(suppressEvent){
34817 var sn = this.selNodes;
34819 for(var i = 0, len = sn.length; i < len; i++){
34820 sn[i].ui.onSelectedChange(false);
34822 this.selNodes = [];
34824 if(suppressEvent !== true){
34825 this.fireEvent("selectionchange", this, this.selNodes);
34831 * Returns true if the node is selected
34832 * @param {TreeNode} node The node to check
34833 * @return {Boolean}
34835 isSelected : function(node){
34836 return this.selMap[node.id] ? true : false;
34840 * Returns an array of the selected nodes
34843 getSelectedNodes : function(){
34844 return this.selNodes;
34847 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34849 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34851 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34854 * Ext JS Library 1.1.1
34855 * Copyright(c) 2006-2007, Ext JS, LLC.
34857 * Originally Released Under LGPL - original licence link has changed is not relivant.
34860 * <script type="text/javascript">
34864 * @class Roo.tree.TreeNode
34865 * @extends Roo.data.Node
34866 * @cfg {String} text The text for this node
34867 * @cfg {Boolean} expanded true to start the node expanded
34868 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34869 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34870 * @cfg {Boolean} disabled true to start the node disabled
34871 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34872 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34873 * @cfg {String} cls A css class to be added to the node
34874 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34875 * @cfg {String} href URL of the link used for the node (defaults to #)
34876 * @cfg {String} hrefTarget target frame for the link
34877 * @cfg {String} qtip An Ext QuickTip for the node
34878 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34879 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34880 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34881 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34882 * (defaults to undefined with no checkbox rendered)
34884 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34886 Roo.tree.TreeNode = function(attributes){
34887 attributes = attributes || {};
34888 if(typeof attributes == "string"){
34889 attributes = {text: attributes};
34891 this.childrenRendered = false;
34892 this.rendered = false;
34893 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34894 this.expanded = attributes.expanded === true;
34895 this.isTarget = attributes.isTarget !== false;
34896 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34897 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34900 * Read-only. The text for this node. To change it use setText().
34903 this.text = attributes.text;
34905 * True if this node is disabled.
34908 this.disabled = attributes.disabled === true;
34912 * @event textchange
34913 * Fires when the text for this node is changed
34914 * @param {Node} this This node
34915 * @param {String} text The new text
34916 * @param {String} oldText The old text
34918 "textchange" : true,
34920 * @event beforeexpand
34921 * Fires before this node is expanded, return false to cancel.
34922 * @param {Node} this This node
34923 * @param {Boolean} deep
34924 * @param {Boolean} anim
34926 "beforeexpand" : true,
34928 * @event beforecollapse
34929 * Fires before this node is collapsed, return false to cancel.
34930 * @param {Node} this This node
34931 * @param {Boolean} deep
34932 * @param {Boolean} anim
34934 "beforecollapse" : true,
34937 * Fires when this node is expanded
34938 * @param {Node} this This node
34942 * @event disabledchange
34943 * Fires when the disabled status of this node changes
34944 * @param {Node} this This node
34945 * @param {Boolean} disabled
34947 "disabledchange" : true,
34950 * Fires when this node is collapsed
34951 * @param {Node} this This node
34955 * @event beforeclick
34956 * Fires before click processing. Return false to cancel the default action.
34957 * @param {Node} this This node
34958 * @param {Roo.EventObject} e The event object
34960 "beforeclick":true,
34962 * @event checkchange
34963 * Fires when a node with a checkbox's checked property changes
34964 * @param {Node} this This node
34965 * @param {Boolean} checked
34967 "checkchange":true,
34970 * Fires when this node is clicked
34971 * @param {Node} this This node
34972 * @param {Roo.EventObject} e The event object
34977 * Fires when this node is double clicked
34978 * @param {Node} this This node
34979 * @param {Roo.EventObject} e The event object
34983 * @event contextmenu
34984 * Fires when this node is right clicked
34985 * @param {Node} this This node
34986 * @param {Roo.EventObject} e The event object
34988 "contextmenu":true,
34990 * @event beforechildrenrendered
34991 * Fires right before the child nodes for this node are rendered
34992 * @param {Node} this This node
34994 "beforechildrenrendered":true
34997 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
35000 * Read-only. The UI for this node
35003 this.ui = new uiClass(this);
35005 // finally support items[]
35006 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
35011 Roo.each(this.attributes.items, function(c) {
35012 this.appendChild(Roo.factory(c,Roo.Tree));
35014 delete this.attributes.items;
35019 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
35020 preventHScroll: true,
35022 * Returns true if this node is expanded
35023 * @return {Boolean}
35025 isExpanded : function(){
35026 return this.expanded;
35030 * Returns the UI object for this node
35031 * @return {TreeNodeUI}
35033 getUI : function(){
35037 // private override
35038 setFirstChild : function(node){
35039 var of = this.firstChild;
35040 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
35041 if(this.childrenRendered && of && node != of){
35042 of.renderIndent(true, true);
35045 this.renderIndent(true, true);
35049 // private override
35050 setLastChild : function(node){
35051 var ol = this.lastChild;
35052 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
35053 if(this.childrenRendered && ol && node != ol){
35054 ol.renderIndent(true, true);
35057 this.renderIndent(true, true);
35061 // these methods are overridden to provide lazy rendering support
35062 // private override
35063 appendChild : function()
35065 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35066 if(node && this.childrenRendered){
35069 this.ui.updateExpandIcon();
35073 // private override
35074 removeChild : function(node){
35075 this.ownerTree.getSelectionModel().unselect(node);
35076 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35077 // if it's been rendered remove dom node
35078 if(this.childrenRendered){
35081 if(this.childNodes.length < 1){
35082 this.collapse(false, false);
35084 this.ui.updateExpandIcon();
35086 if(!this.firstChild) {
35087 this.childrenRendered = false;
35092 // private override
35093 insertBefore : function(node, refNode){
35094 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35095 if(newNode && refNode && this.childrenRendered){
35098 this.ui.updateExpandIcon();
35103 * Sets the text for this node
35104 * @param {String} text
35106 setText : function(text){
35107 var oldText = this.text;
35109 this.attributes.text = text;
35110 if(this.rendered){ // event without subscribing
35111 this.ui.onTextChange(this, text, oldText);
35113 this.fireEvent("textchange", this, text, oldText);
35117 * Triggers selection of this node
35119 select : function(){
35120 this.getOwnerTree().getSelectionModel().select(this);
35124 * Triggers deselection of this node
35126 unselect : function(){
35127 this.getOwnerTree().getSelectionModel().unselect(this);
35131 * Returns true if this node is selected
35132 * @return {Boolean}
35134 isSelected : function(){
35135 return this.getOwnerTree().getSelectionModel().isSelected(this);
35139 * Expand this node.
35140 * @param {Boolean} deep (optional) True to expand all children as well
35141 * @param {Boolean} anim (optional) false to cancel the default animation
35142 * @param {Function} callback (optional) A callback to be called when
35143 * expanding this node completes (does not wait for deep expand to complete).
35144 * Called with 1 parameter, this node.
35146 expand : function(deep, anim, callback){
35147 if(!this.expanded){
35148 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35151 if(!this.childrenRendered){
35152 this.renderChildren();
35154 this.expanded = true;
35156 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
35157 this.ui.animExpand(function(){
35158 this.fireEvent("expand", this);
35159 if(typeof callback == "function"){
35163 this.expandChildNodes(true);
35165 }.createDelegate(this));
35169 this.fireEvent("expand", this);
35170 if(typeof callback == "function"){
35175 if(typeof callback == "function"){
35180 this.expandChildNodes(true);
35184 isHiddenRoot : function(){
35185 return this.isRoot && !this.getOwnerTree().rootVisible;
35189 * Collapse this node.
35190 * @param {Boolean} deep (optional) True to collapse all children as well
35191 * @param {Boolean} anim (optional) false to cancel the default animation
35193 collapse : function(deep, anim){
35194 if(this.expanded && !this.isHiddenRoot()){
35195 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35198 this.expanded = false;
35199 if((this.getOwnerTree().animate && anim !== false) || anim){
35200 this.ui.animCollapse(function(){
35201 this.fireEvent("collapse", this);
35203 this.collapseChildNodes(true);
35205 }.createDelegate(this));
35208 this.ui.collapse();
35209 this.fireEvent("collapse", this);
35213 var cs = this.childNodes;
35214 for(var i = 0, len = cs.length; i < len; i++) {
35215 cs[i].collapse(true, false);
35221 delayedExpand : function(delay){
35222 if(!this.expandProcId){
35223 this.expandProcId = this.expand.defer(delay, this);
35228 cancelExpand : function(){
35229 if(this.expandProcId){
35230 clearTimeout(this.expandProcId);
35232 this.expandProcId = false;
35236 * Toggles expanded/collapsed state of the node
35238 toggle : function(){
35247 * Ensures all parent nodes are expanded
35249 ensureVisible : function(callback){
35250 var tree = this.getOwnerTree();
35251 tree.expandPath(this.parentNode.getPath(), false, function(){
35252 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35253 Roo.callback(callback);
35254 }.createDelegate(this));
35258 * Expand all child nodes
35259 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35261 expandChildNodes : function(deep){
35262 var cs = this.childNodes;
35263 for(var i = 0, len = cs.length; i < len; i++) {
35264 cs[i].expand(deep);
35269 * Collapse all child nodes
35270 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35272 collapseChildNodes : function(deep){
35273 var cs = this.childNodes;
35274 for(var i = 0, len = cs.length; i < len; i++) {
35275 cs[i].collapse(deep);
35280 * Disables this node
35282 disable : function(){
35283 this.disabled = true;
35285 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35286 this.ui.onDisableChange(this, true);
35288 this.fireEvent("disabledchange", this, true);
35292 * Enables this node
35294 enable : function(){
35295 this.disabled = false;
35296 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35297 this.ui.onDisableChange(this, false);
35299 this.fireEvent("disabledchange", this, false);
35303 renderChildren : function(suppressEvent){
35304 if(suppressEvent !== false){
35305 this.fireEvent("beforechildrenrendered", this);
35307 var cs = this.childNodes;
35308 for(var i = 0, len = cs.length; i < len; i++){
35309 cs[i].render(true);
35311 this.childrenRendered = true;
35315 sort : function(fn, scope){
35316 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35317 if(this.childrenRendered){
35318 var cs = this.childNodes;
35319 for(var i = 0, len = cs.length; i < len; i++){
35320 cs[i].render(true);
35326 render : function(bulkRender){
35327 this.ui.render(bulkRender);
35328 if(!this.rendered){
35329 this.rendered = true;
35331 this.expanded = false;
35332 this.expand(false, false);
35338 renderIndent : function(deep, refresh){
35340 this.ui.childIndent = null;
35342 this.ui.renderIndent();
35343 if(deep === true && this.childrenRendered){
35344 var cs = this.childNodes;
35345 for(var i = 0, len = cs.length; i < len; i++){
35346 cs[i].renderIndent(true, refresh);
35352 * Ext JS Library 1.1.1
35353 * Copyright(c) 2006-2007, Ext JS, LLC.
35355 * Originally Released Under LGPL - original licence link has changed is not relivant.
35358 * <script type="text/javascript">
35362 * @class Roo.tree.AsyncTreeNode
35363 * @extends Roo.tree.TreeNode
35364 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35366 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35368 Roo.tree.AsyncTreeNode = function(config){
35369 this.loaded = false;
35370 this.loading = false;
35371 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35373 * @event beforeload
35374 * Fires before this node is loaded, return false to cancel
35375 * @param {Node} this This node
35377 this.addEvents({'beforeload':true, 'load': true});
35380 * Fires when this node is loaded
35381 * @param {Node} this This node
35384 * The loader used by this node (defaults to using the tree's defined loader)
35389 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35390 expand : function(deep, anim, callback){
35391 if(this.loading){ // if an async load is already running, waiting til it's done
35393 var f = function(){
35394 if(!this.loading){ // done loading
35395 clearInterval(timer);
35396 this.expand(deep, anim, callback);
35398 }.createDelegate(this);
35399 timer = setInterval(f, 200);
35403 if(this.fireEvent("beforeload", this) === false){
35406 this.loading = true;
35407 this.ui.beforeLoad(this);
35408 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35410 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35414 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35418 * Returns true if this node is currently loading
35419 * @return {Boolean}
35421 isLoading : function(){
35422 return this.loading;
35425 loadComplete : function(deep, anim, callback){
35426 this.loading = false;
35427 this.loaded = true;
35428 this.ui.afterLoad(this);
35429 this.fireEvent("load", this);
35430 this.expand(deep, anim, callback);
35434 * Returns true if this node has been loaded
35435 * @return {Boolean}
35437 isLoaded : function(){
35438 return this.loaded;
35441 hasChildNodes : function(){
35442 if(!this.isLeaf() && !this.loaded){
35445 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35450 * Trigger a reload for this node
35451 * @param {Function} callback
35453 reload : function(callback){
35454 this.collapse(false, false);
35455 while(this.firstChild){
35456 this.removeChild(this.firstChild);
35458 this.childrenRendered = false;
35459 this.loaded = false;
35460 if(this.isHiddenRoot()){
35461 this.expanded = false;
35463 this.expand(false, false, callback);
35467 * Ext JS Library 1.1.1
35468 * Copyright(c) 2006-2007, Ext JS, LLC.
35470 * Originally Released Under LGPL - original licence link has changed is not relivant.
35473 * <script type="text/javascript">
35477 * @class Roo.tree.TreeNodeUI
35479 * @param {Object} node The node to render
35480 * The TreeNode UI implementation is separate from the
35481 * tree implementation. Unless you are customizing the tree UI,
35482 * you should never have to use this directly.
35484 Roo.tree.TreeNodeUI = function(node){
35486 this.rendered = false;
35487 this.animating = false;
35488 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35491 Roo.tree.TreeNodeUI.prototype = {
35492 removeChild : function(node){
35494 this.ctNode.removeChild(node.ui.getEl());
35498 beforeLoad : function(){
35499 this.addClass("x-tree-node-loading");
35502 afterLoad : function(){
35503 this.removeClass("x-tree-node-loading");
35506 onTextChange : function(node, text, oldText){
35508 this.textNode.innerHTML = text;
35512 onDisableChange : function(node, state){
35513 this.disabled = state;
35515 this.addClass("x-tree-node-disabled");
35517 this.removeClass("x-tree-node-disabled");
35521 onSelectedChange : function(state){
35524 this.addClass("x-tree-selected");
35527 this.removeClass("x-tree-selected");
35531 onMove : function(tree, node, oldParent, newParent, index, refNode){
35532 this.childIndent = null;
35534 var targetNode = newParent.ui.getContainer();
35535 if(!targetNode){//target not rendered
35536 this.holder = document.createElement("div");
35537 this.holder.appendChild(this.wrap);
35540 var insertBefore = refNode ? refNode.ui.getEl() : null;
35542 targetNode.insertBefore(this.wrap, insertBefore);
35544 targetNode.appendChild(this.wrap);
35546 this.node.renderIndent(true);
35550 addClass : function(cls){
35552 Roo.fly(this.elNode).addClass(cls);
35556 removeClass : function(cls){
35558 Roo.fly(this.elNode).removeClass(cls);
35562 remove : function(){
35564 this.holder = document.createElement("div");
35565 this.holder.appendChild(this.wrap);
35569 fireEvent : function(){
35570 return this.node.fireEvent.apply(this.node, arguments);
35573 initEvents : function(){
35574 this.node.on("move", this.onMove, this);
35575 var E = Roo.EventManager;
35576 var a = this.anchor;
35578 var el = Roo.fly(a, '_treeui');
35580 if(Roo.isOpera){ // opera render bug ignores the CSS
35581 el.setStyle("text-decoration", "none");
35584 el.on("click", this.onClick, this);
35585 el.on("dblclick", this.onDblClick, this);
35588 Roo.EventManager.on(this.checkbox,
35589 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35592 el.on("contextmenu", this.onContextMenu, this);
35594 var icon = Roo.fly(this.iconNode);
35595 icon.on("click", this.onClick, this);
35596 icon.on("dblclick", this.onDblClick, this);
35597 icon.on("contextmenu", this.onContextMenu, this);
35598 E.on(this.ecNode, "click", this.ecClick, this, true);
35600 if(this.node.disabled){
35601 this.addClass("x-tree-node-disabled");
35603 if(this.node.hidden){
35604 this.addClass("x-tree-node-disabled");
35606 var ot = this.node.getOwnerTree();
35607 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
35608 if(dd && (!this.node.isRoot || ot.rootVisible)){
35609 Roo.dd.Registry.register(this.elNode, {
35611 handles: this.getDDHandles(),
35617 getDDHandles : function(){
35618 return [this.iconNode, this.textNode];
35623 this.wrap.style.display = "none";
35629 this.wrap.style.display = "";
35633 onContextMenu : function(e){
35634 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35635 e.preventDefault();
35637 this.fireEvent("contextmenu", this.node, e);
35641 onClick : function(e){
35646 if(this.fireEvent("beforeclick", this.node, e) !== false){
35647 if(!this.disabled && this.node.attributes.href){
35648 this.fireEvent("click", this.node, e);
35651 e.preventDefault();
35656 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35657 this.node.toggle();
35660 this.fireEvent("click", this.node, e);
35666 onDblClick : function(e){
35667 e.preventDefault();
35672 this.toggleCheck();
35674 if(!this.animating && this.node.hasChildNodes()){
35675 this.node.toggle();
35677 this.fireEvent("dblclick", this.node, e);
35680 onCheckChange : function(){
35681 var checked = this.checkbox.checked;
35682 this.node.attributes.checked = checked;
35683 this.fireEvent('checkchange', this.node, checked);
35686 ecClick : function(e){
35687 if(!this.animating && this.node.hasChildNodes()){
35688 this.node.toggle();
35692 startDrop : function(){
35693 this.dropping = true;
35696 // delayed drop so the click event doesn't get fired on a drop
35697 endDrop : function(){
35698 setTimeout(function(){
35699 this.dropping = false;
35700 }.createDelegate(this), 50);
35703 expand : function(){
35704 this.updateExpandIcon();
35705 this.ctNode.style.display = "";
35708 focus : function(){
35709 if(!this.node.preventHScroll){
35710 try{this.anchor.focus();
35712 }else if(!Roo.isIE){
35714 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35715 var l = noscroll.scrollLeft;
35716 this.anchor.focus();
35717 noscroll.scrollLeft = l;
35722 toggleCheck : function(value){
35723 var cb = this.checkbox;
35725 cb.checked = (value === undefined ? !cb.checked : value);
35731 this.anchor.blur();
35735 animExpand : function(callback){
35736 var ct = Roo.get(this.ctNode);
35738 if(!this.node.hasChildNodes()){
35739 this.updateExpandIcon();
35740 this.ctNode.style.display = "";
35741 Roo.callback(callback);
35744 this.animating = true;
35745 this.updateExpandIcon();
35748 callback : function(){
35749 this.animating = false;
35750 Roo.callback(callback);
35753 duration: this.node.ownerTree.duration || .25
35757 highlight : function(){
35758 var tree = this.node.getOwnerTree();
35759 Roo.fly(this.wrap).highlight(
35760 tree.hlColor || "C3DAF9",
35761 {endColor: tree.hlBaseColor}
35765 collapse : function(){
35766 this.updateExpandIcon();
35767 this.ctNode.style.display = "none";
35770 animCollapse : function(callback){
35771 var ct = Roo.get(this.ctNode);
35772 ct.enableDisplayMode('block');
35775 this.animating = true;
35776 this.updateExpandIcon();
35779 callback : function(){
35780 this.animating = false;
35781 Roo.callback(callback);
35784 duration: this.node.ownerTree.duration || .25
35788 getContainer : function(){
35789 return this.ctNode;
35792 getEl : function(){
35796 appendDDGhost : function(ghostNode){
35797 ghostNode.appendChild(this.elNode.cloneNode(true));
35800 getDDRepairXY : function(){
35801 return Roo.lib.Dom.getXY(this.iconNode);
35804 onRender : function(){
35808 render : function(bulkRender){
35809 var n = this.node, a = n.attributes;
35810 var targetNode = n.parentNode ?
35811 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35813 if(!this.rendered){
35814 this.rendered = true;
35816 this.renderElements(n, a, targetNode, bulkRender);
35819 if(this.textNode.setAttributeNS){
35820 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35822 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35825 this.textNode.setAttribute("ext:qtip", a.qtip);
35827 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35830 }else if(a.qtipCfg){
35831 a.qtipCfg.target = Roo.id(this.textNode);
35832 Roo.QuickTips.register(a.qtipCfg);
35835 if(!this.node.expanded){
35836 this.updateExpandIcon();
35839 if(bulkRender === true) {
35840 targetNode.appendChild(this.wrap);
35845 renderElements : function(n, a, targetNode, bulkRender)
35847 // add some indent caching, this helps performance when rendering a large tree
35848 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35849 var t = n.getOwnerTree();
35850 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35851 if (typeof(n.attributes.html) != 'undefined') {
35852 txt = n.attributes.html;
35854 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
35855 var cb = typeof a.checked == 'boolean';
35856 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35857 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35858 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35859 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35860 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35861 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35862 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35863 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35864 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35865 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35868 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35869 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35870 n.nextSibling.ui.getEl(), buf.join(""));
35872 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35875 this.elNode = this.wrap.childNodes[0];
35876 this.ctNode = this.wrap.childNodes[1];
35877 var cs = this.elNode.childNodes;
35878 this.indentNode = cs[0];
35879 this.ecNode = cs[1];
35880 this.iconNode = cs[2];
35883 this.checkbox = cs[3];
35886 this.anchor = cs[index];
35887 this.textNode = cs[index].firstChild;
35890 getAnchor : function(){
35891 return this.anchor;
35894 getTextEl : function(){
35895 return this.textNode;
35898 getIconEl : function(){
35899 return this.iconNode;
35902 isChecked : function(){
35903 return this.checkbox ? this.checkbox.checked : false;
35906 updateExpandIcon : function(){
35908 var n = this.node, c1, c2;
35909 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35910 var hasChild = n.hasChildNodes();
35914 c1 = "x-tree-node-collapsed";
35915 c2 = "x-tree-node-expanded";
35918 c1 = "x-tree-node-expanded";
35919 c2 = "x-tree-node-collapsed";
35922 this.removeClass("x-tree-node-leaf");
35923 this.wasLeaf = false;
35925 if(this.c1 != c1 || this.c2 != c2){
35926 Roo.fly(this.elNode).replaceClass(c1, c2);
35927 this.c1 = c1; this.c2 = c2;
35930 // this changes non-leafs into leafs if they have no children.
35931 // it's not very rational behaviour..
35933 if(!this.wasLeaf && this.node.leaf){
35934 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35937 this.wasLeaf = true;
35940 var ecc = "x-tree-ec-icon "+cls;
35941 if(this.ecc != ecc){
35942 this.ecNode.className = ecc;
35948 getChildIndent : function(){
35949 if(!this.childIndent){
35953 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35955 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35957 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35962 this.childIndent = buf.join("");
35964 return this.childIndent;
35967 renderIndent : function(){
35970 var p = this.node.parentNode;
35972 indent = p.ui.getChildIndent();
35974 if(this.indentMarkup != indent){ // don't rerender if not required
35975 this.indentNode.innerHTML = indent;
35976 this.indentMarkup = indent;
35978 this.updateExpandIcon();
35983 Roo.tree.RootTreeNodeUI = function(){
35984 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35986 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35987 render : function(){
35988 if(!this.rendered){
35989 var targetNode = this.node.ownerTree.innerCt.dom;
35990 this.node.expanded = true;
35991 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35992 this.wrap = this.ctNode = targetNode.firstChild;
35995 collapse : function(){
35997 expand : function(){
36001 * Ext JS Library 1.1.1
36002 * Copyright(c) 2006-2007, Ext JS, LLC.
36004 * Originally Released Under LGPL - original licence link has changed is not relivant.
36007 * <script type="text/javascript">
36010 * @class Roo.tree.TreeLoader
36011 * @extends Roo.util.Observable
36012 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
36013 * nodes from a specified URL. The response must be a javascript Array definition
36014 * who's elements are node definition objects. eg:
36019 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
36020 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
36027 * The old style respose with just an array is still supported, but not recommended.
36030 * A server request is sent, and child nodes are loaded only when a node is expanded.
36031 * The loading node's id is passed to the server under the parameter name "node" to
36032 * enable the server to produce the correct child nodes.
36034 * To pass extra parameters, an event handler may be attached to the "beforeload"
36035 * event, and the parameters specified in the TreeLoader's baseParams property:
36037 myTreeLoader.on("beforeload", function(treeLoader, node) {
36038 this.baseParams.category = node.attributes.category;
36043 * This would pass an HTTP parameter called "category" to the server containing
36044 * the value of the Node's "category" attribute.
36046 * Creates a new Treeloader.
36047 * @param {Object} config A config object containing config properties.
36049 Roo.tree.TreeLoader = function(config){
36050 this.baseParams = {};
36051 this.requestMethod = "POST";
36052 Roo.apply(this, config);
36057 * @event beforeload
36058 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
36059 * @param {Object} This TreeLoader object.
36060 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36061 * @param {Object} callback The callback function specified in the {@link #load} call.
36066 * Fires when the node has been successfuly loaded.
36067 * @param {Object} This TreeLoader object.
36068 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36069 * @param {Object} response The response object containing the data from the server.
36073 * @event loadexception
36074 * Fires if the network request failed.
36075 * @param {Object} This TreeLoader object.
36076 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36077 * @param {Object} response The response object containing the data from the server.
36079 loadexception : true,
36082 * Fires before a node is created, enabling you to return custom Node types
36083 * @param {Object} This TreeLoader object.
36084 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36089 Roo.tree.TreeLoader.superclass.constructor.call(this);
36092 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36094 * @cfg {String} dataUrl The URL from which to request a Json string which
36095 * specifies an array of node definition object representing the child nodes
36099 * @cfg {String} requestMethod either GET or POST
36100 * defaults to POST (due to BC)
36104 * @cfg {Object} baseParams (optional) An object containing properties which
36105 * specify HTTP parameters to be passed to each request for child nodes.
36108 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36109 * created by this loader. If the attributes sent by the server have an attribute in this object,
36110 * they take priority.
36113 * @cfg {Object} uiProviders (optional) An object containing properties which
36115 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36116 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36117 * <i>uiProvider</i> attribute of a returned child node is a string rather
36118 * than a reference to a TreeNodeUI implementation, this that string value
36119 * is used as a property name in the uiProviders object. You can define the provider named
36120 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36125 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36126 * child nodes before loading.
36128 clearOnLoad : true,
36131 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36132 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36133 * Grid query { data : [ .....] }
36138 * @cfg {String} queryParam (optional)
36139 * Name of the query as it will be passed on the querystring (defaults to 'node')
36140 * eg. the request will be ?node=[id]
36147 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36148 * This is called automatically when a node is expanded, but may be used to reload
36149 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36150 * @param {Roo.tree.TreeNode} node
36151 * @param {Function} callback
36153 load : function(node, callback){
36154 if(this.clearOnLoad){
36155 while(node.firstChild){
36156 node.removeChild(node.firstChild);
36159 if(node.attributes.children){ // preloaded json children
36160 var cs = node.attributes.children;
36161 for(var i = 0, len = cs.length; i < len; i++){
36162 node.appendChild(this.createNode(cs[i]));
36164 if(typeof callback == "function"){
36167 }else if(this.dataUrl){
36168 this.requestData(node, callback);
36172 getParams: function(node){
36173 var buf = [], bp = this.baseParams;
36174 for(var key in bp){
36175 if(typeof bp[key] != "function"){
36176 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36179 var n = this.queryParam === false ? 'node' : this.queryParam;
36180 buf.push(n + "=", encodeURIComponent(node.id));
36181 return buf.join("");
36184 requestData : function(node, callback){
36185 if(this.fireEvent("beforeload", this, node, callback) !== false){
36186 this.transId = Roo.Ajax.request({
36187 method:this.requestMethod,
36188 url: this.dataUrl||this.url,
36189 success: this.handleResponse,
36190 failure: this.handleFailure,
36192 argument: {callback: callback, node: node},
36193 params: this.getParams(node)
36196 // if the load is cancelled, make sure we notify
36197 // the node that we are done
36198 if(typeof callback == "function"){
36204 isLoading : function(){
36205 return this.transId ? true : false;
36208 abort : function(){
36209 if(this.isLoading()){
36210 Roo.Ajax.abort(this.transId);
36215 createNode : function(attr)
36217 // apply baseAttrs, nice idea Corey!
36218 if(this.baseAttrs){
36219 Roo.applyIf(attr, this.baseAttrs);
36221 if(this.applyLoader !== false){
36222 attr.loader = this;
36224 // uiProvider = depreciated..
36226 if(typeof(attr.uiProvider) == 'string'){
36227 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36228 /** eval:var:attr */ eval(attr.uiProvider);
36230 if(typeof(this.uiProviders['default']) != 'undefined') {
36231 attr.uiProvider = this.uiProviders['default'];
36234 this.fireEvent('create', this, attr);
36236 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36238 new Roo.tree.TreeNode(attr) :
36239 new Roo.tree.AsyncTreeNode(attr));
36242 processResponse : function(response, node, callback)
36244 var json = response.responseText;
36247 var o = Roo.decode(json);
36249 if (this.root === false && typeof(o.success) != undefined) {
36250 this.root = 'data'; // the default behaviour for list like data..
36253 if (this.root !== false && !o.success) {
36254 // it's a failure condition.
36255 var a = response.argument;
36256 this.fireEvent("loadexception", this, a.node, response);
36257 Roo.log("Load failed - should have a handler really");
36263 if (this.root !== false) {
36267 for(var i = 0, len = o.length; i < len; i++){
36268 var n = this.createNode(o[i]);
36270 node.appendChild(n);
36273 if(typeof callback == "function"){
36274 callback(this, node);
36277 this.handleFailure(response);
36281 handleResponse : function(response){
36282 this.transId = false;
36283 var a = response.argument;
36284 this.processResponse(response, a.node, a.callback);
36285 this.fireEvent("load", this, a.node, response);
36288 handleFailure : function(response)
36290 // should handle failure better..
36291 this.transId = false;
36292 var a = response.argument;
36293 this.fireEvent("loadexception", this, a.node, response);
36294 if(typeof a.callback == "function"){
36295 a.callback(this, a.node);
36300 * Ext JS Library 1.1.1
36301 * Copyright(c) 2006-2007, Ext JS, LLC.
36303 * Originally Released Under LGPL - original licence link has changed is not relivant.
36306 * <script type="text/javascript">
36310 * @class Roo.tree.TreeFilter
36311 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36312 * @param {TreePanel} tree
36313 * @param {Object} config (optional)
36315 Roo.tree.TreeFilter = function(tree, config){
36317 this.filtered = {};
36318 Roo.apply(this, config);
36321 Roo.tree.TreeFilter.prototype = {
36328 * Filter the data by a specific attribute.
36329 * @param {String/RegExp} value Either string that the attribute value
36330 * should start with or a RegExp to test against the attribute
36331 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36332 * @param {TreeNode} startNode (optional) The node to start the filter at.
36334 filter : function(value, attr, startNode){
36335 attr = attr || "text";
36337 if(typeof value == "string"){
36338 var vlen = value.length;
36339 // auto clear empty filter
36340 if(vlen == 0 && this.clearBlank){
36344 value = value.toLowerCase();
36346 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36348 }else if(value.exec){ // regex?
36350 return value.test(n.attributes[attr]);
36353 throw 'Illegal filter type, must be string or regex';
36355 this.filterBy(f, null, startNode);
36359 * Filter by a function. The passed function will be called with each
36360 * node in the tree (or from the startNode). If the function returns true, the node is kept
36361 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36362 * @param {Function} fn The filter function
36363 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36365 filterBy : function(fn, scope, startNode){
36366 startNode = startNode || this.tree.root;
36367 if(this.autoClear){
36370 var af = this.filtered, rv = this.reverse;
36371 var f = function(n){
36372 if(n == startNode){
36378 var m = fn.call(scope || n, n);
36386 startNode.cascade(f);
36389 if(typeof id != "function"){
36391 if(n && n.parentNode){
36392 n.parentNode.removeChild(n);
36400 * Clears the current filter. Note: with the "remove" option
36401 * set a filter cannot be cleared.
36403 clear : function(){
36405 var af = this.filtered;
36407 if(typeof id != "function"){
36414 this.filtered = {};
36419 * Ext JS Library 1.1.1
36420 * Copyright(c) 2006-2007, Ext JS, LLC.
36422 * Originally Released Under LGPL - original licence link has changed is not relivant.
36425 * <script type="text/javascript">
36430 * @class Roo.tree.TreeSorter
36431 * Provides sorting of nodes in a TreePanel
36433 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36434 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36435 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36436 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36437 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36438 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36440 * @param {TreePanel} tree
36441 * @param {Object} config
36443 Roo.tree.TreeSorter = function(tree, config){
36444 Roo.apply(this, config);
36445 tree.on("beforechildrenrendered", this.doSort, this);
36446 tree.on("append", this.updateSort, this);
36447 tree.on("insert", this.updateSort, this);
36449 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36450 var p = this.property || "text";
36451 var sortType = this.sortType;
36452 var fs = this.folderSort;
36453 var cs = this.caseSensitive === true;
36454 var leafAttr = this.leafAttr || 'leaf';
36456 this.sortFn = function(n1, n2){
36458 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36461 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36465 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36466 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36468 return dsc ? +1 : -1;
36470 return dsc ? -1 : +1;
36477 Roo.tree.TreeSorter.prototype = {
36478 doSort : function(node){
36479 node.sort(this.sortFn);
36482 compareNodes : function(n1, n2){
36483 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36486 updateSort : function(tree, node){
36487 if(node.childrenRendered){
36488 this.doSort.defer(1, this, [node]);
36493 * Ext JS Library 1.1.1
36494 * Copyright(c) 2006-2007, Ext JS, LLC.
36496 * Originally Released Under LGPL - original licence link has changed is not relivant.
36499 * <script type="text/javascript">
36502 if(Roo.dd.DropZone){
36504 Roo.tree.TreeDropZone = function(tree, config){
36505 this.allowParentInsert = false;
36506 this.allowContainerDrop = false;
36507 this.appendOnly = false;
36508 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36510 this.lastInsertClass = "x-tree-no-status";
36511 this.dragOverData = {};
36514 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36515 ddGroup : "TreeDD",
36518 expandDelay : 1000,
36520 expandNode : function(node){
36521 if(node.hasChildNodes() && !node.isExpanded()){
36522 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36526 queueExpand : function(node){
36527 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36530 cancelExpand : function(){
36531 if(this.expandProcId){
36532 clearTimeout(this.expandProcId);
36533 this.expandProcId = false;
36537 isValidDropPoint : function(n, pt, dd, e, data){
36538 if(!n || !data){ return false; }
36539 var targetNode = n.node;
36540 var dropNode = data.node;
36541 // default drop rules
36542 if(!(targetNode && targetNode.isTarget && pt)){
36545 if(pt == "append" && targetNode.allowChildren === false){
36548 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36551 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36554 // reuse the object
36555 var overEvent = this.dragOverData;
36556 overEvent.tree = this.tree;
36557 overEvent.target = targetNode;
36558 overEvent.data = data;
36559 overEvent.point = pt;
36560 overEvent.source = dd;
36561 overEvent.rawEvent = e;
36562 overEvent.dropNode = dropNode;
36563 overEvent.cancel = false;
36564 var result = this.tree.fireEvent("nodedragover", overEvent);
36565 return overEvent.cancel === false && result !== false;
36568 getDropPoint : function(e, n, dd)
36572 return tn.allowChildren !== false ? "append" : false; // always append for root
36574 var dragEl = n.ddel;
36575 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36576 var y = Roo.lib.Event.getPageY(e);
36577 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36579 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36580 var noAppend = tn.allowChildren === false;
36581 if(this.appendOnly || tn.parentNode.allowChildren === false){
36582 return noAppend ? false : "append";
36584 var noBelow = false;
36585 if(!this.allowParentInsert){
36586 noBelow = tn.hasChildNodes() && tn.isExpanded();
36588 var q = (b - t) / (noAppend ? 2 : 3);
36589 if(y >= t && y < (t + q)){
36591 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36598 onNodeEnter : function(n, dd, e, data)
36600 this.cancelExpand();
36603 onNodeOver : function(n, dd, e, data)
36606 var pt = this.getDropPoint(e, n, dd);
36609 // auto node expand check
36610 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36611 this.queueExpand(node);
36612 }else if(pt != "append"){
36613 this.cancelExpand();
36616 // set the insert point style on the target node
36617 var returnCls = this.dropNotAllowed;
36618 if(this.isValidDropPoint(n, pt, dd, e, data)){
36623 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36624 cls = "x-tree-drag-insert-above";
36625 }else if(pt == "below"){
36626 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36627 cls = "x-tree-drag-insert-below";
36629 returnCls = "x-tree-drop-ok-append";
36630 cls = "x-tree-drag-append";
36632 if(this.lastInsertClass != cls){
36633 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36634 this.lastInsertClass = cls;
36641 onNodeOut : function(n, dd, e, data){
36643 this.cancelExpand();
36644 this.removeDropIndicators(n);
36647 onNodeDrop : function(n, dd, e, data){
36648 var point = this.getDropPoint(e, n, dd);
36649 var targetNode = n.node;
36650 targetNode.ui.startDrop();
36651 if(!this.isValidDropPoint(n, point, dd, e, data)){
36652 targetNode.ui.endDrop();
36655 // first try to find the drop node
36656 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36659 target: targetNode,
36664 dropNode: dropNode,
36667 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36668 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36669 targetNode.ui.endDrop();
36672 // allow target changing
36673 targetNode = dropEvent.target;
36674 if(point == "append" && !targetNode.isExpanded()){
36675 targetNode.expand(false, null, function(){
36676 this.completeDrop(dropEvent);
36677 }.createDelegate(this));
36679 this.completeDrop(dropEvent);
36684 completeDrop : function(de){
36685 var ns = de.dropNode, p = de.point, t = de.target;
36686 if(!(ns instanceof Array)){
36690 for(var i = 0, len = ns.length; i < len; i++){
36693 t.parentNode.insertBefore(n, t);
36694 }else if(p == "below"){
36695 t.parentNode.insertBefore(n, t.nextSibling);
36701 if(this.tree.hlDrop){
36705 this.tree.fireEvent("nodedrop", de);
36708 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36709 if(this.tree.hlDrop){
36710 dropNode.ui.focus();
36711 dropNode.ui.highlight();
36713 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36716 getTree : function(){
36720 removeDropIndicators : function(n){
36723 Roo.fly(el).removeClass([
36724 "x-tree-drag-insert-above",
36725 "x-tree-drag-insert-below",
36726 "x-tree-drag-append"]);
36727 this.lastInsertClass = "_noclass";
36731 beforeDragDrop : function(target, e, id){
36732 this.cancelExpand();
36736 afterRepair : function(data){
36737 if(data && Roo.enableFx){
36738 data.node.ui.highlight();
36748 * Ext JS Library 1.1.1
36749 * Copyright(c) 2006-2007, Ext JS, LLC.
36751 * Originally Released Under LGPL - original licence link has changed is not relivant.
36754 * <script type="text/javascript">
36758 if(Roo.dd.DragZone){
36759 Roo.tree.TreeDragZone = function(tree, config){
36760 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36764 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36765 ddGroup : "TreeDD",
36767 onBeforeDrag : function(data, e){
36769 return n && n.draggable && !n.disabled;
36773 onInitDrag : function(e){
36774 var data = this.dragData;
36775 this.tree.getSelectionModel().select(data.node);
36776 this.proxy.update("");
36777 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36778 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36781 getRepairXY : function(e, data){
36782 return data.node.ui.getDDRepairXY();
36785 onEndDrag : function(data, e){
36786 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36791 onValidDrop : function(dd, e, id){
36792 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36796 beforeInvalidDrop : function(e, id){
36797 // this scrolls the original position back into view
36798 var sm = this.tree.getSelectionModel();
36799 sm.clearSelections();
36800 sm.select(this.dragData.node);
36805 * Ext JS Library 1.1.1
36806 * Copyright(c) 2006-2007, Ext JS, LLC.
36808 * Originally Released Under LGPL - original licence link has changed is not relivant.
36811 * <script type="text/javascript">
36814 * @class Roo.tree.TreeEditor
36815 * @extends Roo.Editor
36816 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36817 * as the editor field.
36819 * @param {Object} config (used to be the tree panel.)
36820 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36822 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36823 * @cfg {Roo.form.TextField|Object} field The field configuration
36827 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36830 if (oldconfig) { // old style..
36831 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36834 tree = config.tree;
36835 config.field = config.field || {};
36836 config.field.xtype = 'TextField';
36837 field = Roo.factory(config.field, Roo.form);
36839 config = config || {};
36844 * @event beforenodeedit
36845 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36846 * false from the handler of this event.
36847 * @param {Editor} this
36848 * @param {Roo.tree.Node} node
36850 "beforenodeedit" : true
36854 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36858 tree.on('beforeclick', this.beforeNodeClick, this);
36859 tree.getTreeEl().on('mousedown', this.hide, this);
36860 this.on('complete', this.updateNode, this);
36861 this.on('beforestartedit', this.fitToTree, this);
36862 this.on('startedit', this.bindScroll, this, {delay:10});
36863 this.on('specialkey', this.onSpecialKey, this);
36866 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36868 * @cfg {String} alignment
36869 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36875 * @cfg {Boolean} hideEl
36876 * True to hide the bound element while the editor is displayed (defaults to false)
36880 * @cfg {String} cls
36881 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36883 cls: "x-small-editor x-tree-editor",
36885 * @cfg {Boolean} shim
36886 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36892 * @cfg {Number} maxWidth
36893 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36894 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36895 * scroll and client offsets into account prior to each edit.
36902 fitToTree : function(ed, el){
36903 var td = this.tree.getTreeEl().dom, nd = el.dom;
36904 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36905 td.scrollLeft = nd.offsetLeft;
36909 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36910 this.setSize(w, '');
36912 return this.fireEvent('beforenodeedit', this, this.editNode);
36917 triggerEdit : function(node){
36918 this.completeEdit();
36919 this.editNode = node;
36920 this.startEdit(node.ui.textNode, node.text);
36924 bindScroll : function(){
36925 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36929 beforeNodeClick : function(node, e){
36930 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36931 this.lastClick = new Date();
36932 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36934 this.triggerEdit(node);
36941 updateNode : function(ed, value){
36942 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36943 this.editNode.setText(value);
36947 onHide : function(){
36948 Roo.tree.TreeEditor.superclass.onHide.call(this);
36950 this.editNode.ui.focus();
36955 onSpecialKey : function(field, e){
36956 var k = e.getKey();
36960 }else if(k == e.ENTER && !e.hasModifier()){
36962 this.completeEdit();
36965 });//<Script type="text/javascript">
36968 * Ext JS Library 1.1.1
36969 * Copyright(c) 2006-2007, Ext JS, LLC.
36971 * Originally Released Under LGPL - original licence link has changed is not relivant.
36974 * <script type="text/javascript">
36978 * Not documented??? - probably should be...
36981 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36982 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36984 renderElements : function(n, a, targetNode, bulkRender){
36985 //consel.log("renderElements?");
36986 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36988 var t = n.getOwnerTree();
36989 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36991 var cols = t.columns;
36992 var bw = t.borderWidth;
36994 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36995 var cb = typeof a.checked == "boolean";
36996 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36997 var colcls = 'x-t-' + tid + '-c0';
36999 '<li class="x-tree-node">',
37002 '<div class="x-tree-node-el ', a.cls,'">',
37004 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
37007 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
37008 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
37009 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
37010 (a.icon ? ' x-tree-node-inline-icon' : ''),
37011 (a.iconCls ? ' '+a.iconCls : ''),
37012 '" unselectable="on" />',
37013 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
37014 (a.checked ? 'checked="checked" />' : ' />')) : ''),
37016 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37017 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
37018 '<span unselectable="on" qtip="' + tx + '">',
37022 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37023 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
37025 for(var i = 1, len = cols.length; i < len; i++){
37027 colcls = 'x-t-' + tid + '-c' +i;
37028 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37029 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
37030 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
37036 '<div class="x-clear"></div></div>',
37037 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37040 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37041 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37042 n.nextSibling.ui.getEl(), buf.join(""));
37044 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37046 var el = this.wrap.firstChild;
37048 this.elNode = el.firstChild;
37049 this.ranchor = el.childNodes[1];
37050 this.ctNode = this.wrap.childNodes[1];
37051 var cs = el.firstChild.childNodes;
37052 this.indentNode = cs[0];
37053 this.ecNode = cs[1];
37054 this.iconNode = cs[2];
37057 this.checkbox = cs[3];
37060 this.anchor = cs[index];
37062 this.textNode = cs[index].firstChild;
37064 //el.on("click", this.onClick, this);
37065 //el.on("dblclick", this.onDblClick, this);
37068 // console.log(this);
37070 initEvents : function(){
37071 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37074 var a = this.ranchor;
37076 var el = Roo.get(a);
37078 if(Roo.isOpera){ // opera render bug ignores the CSS
37079 el.setStyle("text-decoration", "none");
37082 el.on("click", this.onClick, this);
37083 el.on("dblclick", this.onDblClick, this);
37084 el.on("contextmenu", this.onContextMenu, this);
37088 /*onSelectedChange : function(state){
37091 this.addClass("x-tree-selected");
37094 this.removeClass("x-tree-selected");
37097 addClass : function(cls){
37099 Roo.fly(this.elRow).addClass(cls);
37105 removeClass : function(cls){
37107 Roo.fly(this.elRow).removeClass(cls);
37113 });//<Script type="text/javascript">
37117 * Ext JS Library 1.1.1
37118 * Copyright(c) 2006-2007, Ext JS, LLC.
37120 * Originally Released Under LGPL - original licence link has changed is not relivant.
37123 * <script type="text/javascript">
37128 * @class Roo.tree.ColumnTree
37129 * @extends Roo.data.TreePanel
37130 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37131 * @cfg {int} borderWidth compined right/left border allowance
37133 * @param {String/HTMLElement/Element} el The container element
37134 * @param {Object} config
37136 Roo.tree.ColumnTree = function(el, config)
37138 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37142 * Fire this event on a container when it resizes
37143 * @param {int} w Width
37144 * @param {int} h Height
37148 this.on('resize', this.onResize, this);
37151 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37155 borderWidth: Roo.isBorderBox ? 0 : 2,
37158 render : function(){
37159 // add the header.....
37161 Roo.tree.ColumnTree.superclass.render.apply(this);
37163 this.el.addClass('x-column-tree');
37165 this.headers = this.el.createChild(
37166 {cls:'x-tree-headers'},this.innerCt.dom);
37168 var cols = this.columns, c;
37169 var totalWidth = 0;
37171 var len = cols.length;
37172 for(var i = 0; i < len; i++){
37174 totalWidth += c.width;
37175 this.headEls.push(this.headers.createChild({
37176 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37178 cls:'x-tree-hd-text',
37181 style:'width:'+(c.width-this.borderWidth)+'px;'
37184 this.headers.createChild({cls:'x-clear'});
37185 // prevent floats from wrapping when clipped
37186 this.headers.setWidth(totalWidth);
37187 //this.innerCt.setWidth(totalWidth);
37188 this.innerCt.setStyle({ overflow: 'auto' });
37189 this.onResize(this.width, this.height);
37193 onResize : function(w,h)
37198 this.innerCt.setWidth(this.width);
37199 this.innerCt.setHeight(this.height-20);
37202 var cols = this.columns, c;
37203 var totalWidth = 0;
37205 var len = cols.length;
37206 for(var i = 0; i < len; i++){
37208 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37209 // it's the expander..
37210 expEl = this.headEls[i];
37213 totalWidth += c.width;
37217 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37219 this.headers.setWidth(w-20);
37228 * Ext JS Library 1.1.1
37229 * Copyright(c) 2006-2007, Ext JS, LLC.
37231 * Originally Released Under LGPL - original licence link has changed is not relivant.
37234 * <script type="text/javascript">
37238 * @class Roo.menu.Menu
37239 * @extends Roo.util.Observable
37240 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37241 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37243 * Creates a new Menu
37244 * @param {Object} config Configuration options
37246 Roo.menu.Menu = function(config){
37248 Roo.menu.Menu.superclass.constructor.call(this, config);
37250 this.id = this.id || Roo.id();
37253 * @event beforeshow
37254 * Fires before this menu is displayed
37255 * @param {Roo.menu.Menu} this
37259 * @event beforehide
37260 * Fires before this menu is hidden
37261 * @param {Roo.menu.Menu} this
37266 * Fires after this menu is displayed
37267 * @param {Roo.menu.Menu} this
37272 * Fires after this menu is hidden
37273 * @param {Roo.menu.Menu} this
37278 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37279 * @param {Roo.menu.Menu} this
37280 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37281 * @param {Roo.EventObject} e
37286 * Fires when the mouse is hovering over this menu
37287 * @param {Roo.menu.Menu} this
37288 * @param {Roo.EventObject} e
37289 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37294 * Fires when the mouse exits this menu
37295 * @param {Roo.menu.Menu} this
37296 * @param {Roo.EventObject} e
37297 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37302 * Fires when a menu item contained in this menu is clicked
37303 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37304 * @param {Roo.EventObject} e
37308 if (this.registerMenu) {
37309 Roo.menu.MenuMgr.register(this);
37312 var mis = this.items;
37313 this.items = new Roo.util.MixedCollection();
37315 this.add.apply(this, mis);
37319 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37321 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37325 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37326 * for bottom-right shadow (defaults to "sides")
37330 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37331 * this menu (defaults to "tl-tr?")
37333 subMenuAlign : "tl-tr?",
37335 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37336 * relative to its element of origin (defaults to "tl-bl?")
37338 defaultAlign : "tl-bl?",
37340 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37342 allowOtherMenus : false,
37344 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37346 registerMenu : true,
37351 render : function(){
37355 var el = this.el = new Roo.Layer({
37357 shadow:this.shadow,
37359 parentEl: this.parentEl || document.body,
37363 this.keyNav = new Roo.menu.MenuNav(this);
37366 el.addClass("x-menu-plain");
37369 el.addClass(this.cls);
37371 // generic focus element
37372 this.focusEl = el.createChild({
37373 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37375 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37376 //disabling touch- as it's causing issues ..
37377 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37378 ul.on('click' , this.onClick, this);
37381 ul.on("mouseover", this.onMouseOver, this);
37382 ul.on("mouseout", this.onMouseOut, this);
37383 this.items.each(function(item){
37388 var li = document.createElement("li");
37389 li.className = "x-menu-list-item";
37390 ul.dom.appendChild(li);
37391 item.render(li, this);
37398 autoWidth : function(){
37399 var el = this.el, ul = this.ul;
37403 var w = this.width;
37406 }else if(Roo.isIE){
37407 el.setWidth(this.minWidth);
37408 var t = el.dom.offsetWidth; // force recalc
37409 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37414 delayAutoWidth : function(){
37417 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37419 this.awTask.delay(20);
37424 findTargetItem : function(e){
37425 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37426 if(t && t.menuItemId){
37427 return this.items.get(t.menuItemId);
37432 onClick : function(e){
37433 Roo.log("menu.onClick");
37434 var t = this.findTargetItem(e);
37439 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37440 if(t == this.activeItem && t.shouldDeactivate(e)){
37441 this.activeItem.deactivate();
37442 delete this.activeItem;
37446 this.setActiveItem(t, true);
37454 this.fireEvent("click", this, t, e);
37458 setActiveItem : function(item, autoExpand){
37459 if(item != this.activeItem){
37460 if(this.activeItem){
37461 this.activeItem.deactivate();
37463 this.activeItem = item;
37464 item.activate(autoExpand);
37465 }else if(autoExpand){
37471 tryActivate : function(start, step){
37472 var items = this.items;
37473 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37474 var item = items.get(i);
37475 if(!item.disabled && item.canActivate){
37476 this.setActiveItem(item, false);
37484 onMouseOver : function(e){
37486 if(t = this.findTargetItem(e)){
37487 if(t.canActivate && !t.disabled){
37488 this.setActiveItem(t, true);
37491 this.fireEvent("mouseover", this, e, t);
37495 onMouseOut : function(e){
37497 if(t = this.findTargetItem(e)){
37498 if(t == this.activeItem && t.shouldDeactivate(e)){
37499 this.activeItem.deactivate();
37500 delete this.activeItem;
37503 this.fireEvent("mouseout", this, e, t);
37507 * Read-only. Returns true if the menu is currently displayed, else false.
37510 isVisible : function(){
37511 return this.el && !this.hidden;
37515 * Displays this menu relative to another element
37516 * @param {String/HTMLElement/Roo.Element} element The element to align to
37517 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37518 * the element (defaults to this.defaultAlign)
37519 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37521 show : function(el, pos, parentMenu){
37522 this.parentMenu = parentMenu;
37526 this.fireEvent("beforeshow", this);
37527 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37531 * Displays this menu at a specific xy position
37532 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37533 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37535 showAt : function(xy, parentMenu, /* private: */_e){
37536 this.parentMenu = parentMenu;
37541 this.fireEvent("beforeshow", this);
37542 xy = this.el.adjustForConstraints(xy);
37546 this.hidden = false;
37548 this.fireEvent("show", this);
37551 focus : function(){
37553 this.doFocus.defer(50, this);
37557 doFocus : function(){
37559 this.focusEl.focus();
37564 * Hides this menu and optionally all parent menus
37565 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37567 hide : function(deep){
37568 if(this.el && this.isVisible()){
37569 this.fireEvent("beforehide", this);
37570 if(this.activeItem){
37571 this.activeItem.deactivate();
37572 this.activeItem = null;
37575 this.hidden = true;
37576 this.fireEvent("hide", this);
37578 if(deep === true && this.parentMenu){
37579 this.parentMenu.hide(true);
37584 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37585 * Any of the following are valid:
37587 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37588 * <li>An HTMLElement object which will be converted to a menu item</li>
37589 * <li>A menu item config object that will be created as a new menu item</li>
37590 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37591 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37596 var menu = new Roo.menu.Menu();
37598 // Create a menu item to add by reference
37599 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37601 // Add a bunch of items at once using different methods.
37602 // Only the last item added will be returned.
37603 var item = menu.add(
37604 menuItem, // add existing item by ref
37605 'Dynamic Item', // new TextItem
37606 '-', // new separator
37607 { text: 'Config Item' } // new item by config
37610 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37611 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37614 var a = arguments, l = a.length, item;
37615 for(var i = 0; i < l; i++){
37617 if ((typeof(el) == "object") && el.xtype && el.xns) {
37618 el = Roo.factory(el, Roo.menu);
37621 if(el.render){ // some kind of Item
37622 item = this.addItem(el);
37623 }else if(typeof el == "string"){ // string
37624 if(el == "separator" || el == "-"){
37625 item = this.addSeparator();
37627 item = this.addText(el);
37629 }else if(el.tagName || el.el){ // element
37630 item = this.addElement(el);
37631 }else if(typeof el == "object"){ // must be menu item config?
37632 item = this.addMenuItem(el);
37639 * Returns this menu's underlying {@link Roo.Element} object
37640 * @return {Roo.Element} The element
37642 getEl : function(){
37650 * Adds a separator bar to the menu
37651 * @return {Roo.menu.Item} The menu item that was added
37653 addSeparator : function(){
37654 return this.addItem(new Roo.menu.Separator());
37658 * Adds an {@link Roo.Element} object to the menu
37659 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37660 * @return {Roo.menu.Item} The menu item that was added
37662 addElement : function(el){
37663 return this.addItem(new Roo.menu.BaseItem(el));
37667 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37668 * @param {Roo.menu.Item} item The menu item to add
37669 * @return {Roo.menu.Item} The menu item that was added
37671 addItem : function(item){
37672 this.items.add(item);
37674 var li = document.createElement("li");
37675 li.className = "x-menu-list-item";
37676 this.ul.dom.appendChild(li);
37677 item.render(li, this);
37678 this.delayAutoWidth();
37684 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37685 * @param {Object} config A MenuItem config object
37686 * @return {Roo.menu.Item} The menu item that was added
37688 addMenuItem : function(config){
37689 if(!(config instanceof Roo.menu.Item)){
37690 if(typeof config.checked == "boolean"){ // must be check menu item config?
37691 config = new Roo.menu.CheckItem(config);
37693 config = new Roo.menu.Item(config);
37696 return this.addItem(config);
37700 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37701 * @param {String} text The text to display in the menu item
37702 * @return {Roo.menu.Item} The menu item that was added
37704 addText : function(text){
37705 return this.addItem(new Roo.menu.TextItem({ text : text }));
37709 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37710 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37711 * @param {Roo.menu.Item} item The menu item to add
37712 * @return {Roo.menu.Item} The menu item that was added
37714 insert : function(index, item){
37715 this.items.insert(index, item);
37717 var li = document.createElement("li");
37718 li.className = "x-menu-list-item";
37719 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37720 item.render(li, this);
37721 this.delayAutoWidth();
37727 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37728 * @param {Roo.menu.Item} item The menu item to remove
37730 remove : function(item){
37731 this.items.removeKey(item.id);
37736 * Removes and destroys all items in the menu
37738 removeAll : function(){
37740 while(f = this.items.first()){
37746 // MenuNav is a private utility class used internally by the Menu
37747 Roo.menu.MenuNav = function(menu){
37748 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37749 this.scope = this.menu = menu;
37752 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37753 doRelay : function(e, h){
37754 var k = e.getKey();
37755 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37756 this.menu.tryActivate(0, 1);
37759 return h.call(this.scope || this, e, this.menu);
37762 up : function(e, m){
37763 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37764 m.tryActivate(m.items.length-1, -1);
37768 down : function(e, m){
37769 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37770 m.tryActivate(0, 1);
37774 right : function(e, m){
37776 m.activeItem.expandMenu(true);
37780 left : function(e, m){
37782 if(m.parentMenu && m.parentMenu.activeItem){
37783 m.parentMenu.activeItem.activate();
37787 enter : function(e, m){
37789 e.stopPropagation();
37790 m.activeItem.onClick(e);
37791 m.fireEvent("click", this, m.activeItem);
37797 * Ext JS Library 1.1.1
37798 * Copyright(c) 2006-2007, Ext JS, LLC.
37800 * Originally Released Under LGPL - original licence link has changed is not relivant.
37803 * <script type="text/javascript">
37807 * @class Roo.menu.MenuMgr
37808 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37811 Roo.menu.MenuMgr = function(){
37812 var menus, active, groups = {}, attached = false, lastShow = new Date();
37814 // private - called when first menu is created
37817 active = new Roo.util.MixedCollection();
37818 Roo.get(document).addKeyListener(27, function(){
37819 if(active.length > 0){
37826 function hideAll(){
37827 if(active && active.length > 0){
37828 var c = active.clone();
37829 c.each(function(m){
37836 function onHide(m){
37838 if(active.length < 1){
37839 Roo.get(document).un("mousedown", onMouseDown);
37845 function onShow(m){
37846 var last = active.last();
37847 lastShow = new Date();
37850 Roo.get(document).on("mousedown", onMouseDown);
37854 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37855 m.parentMenu.activeChild = m;
37856 }else if(last && last.isVisible()){
37857 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37862 function onBeforeHide(m){
37864 m.activeChild.hide();
37866 if(m.autoHideTimer){
37867 clearTimeout(m.autoHideTimer);
37868 delete m.autoHideTimer;
37873 function onBeforeShow(m){
37874 var pm = m.parentMenu;
37875 if(!pm && !m.allowOtherMenus){
37877 }else if(pm && pm.activeChild && active != m){
37878 pm.activeChild.hide();
37883 function onMouseDown(e){
37884 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37890 function onBeforeCheck(mi, state){
37892 var g = groups[mi.group];
37893 for(var i = 0, l = g.length; i < l; i++){
37895 g[i].setChecked(false);
37904 * Hides all menus that are currently visible
37906 hideAll : function(){
37911 register : function(menu){
37915 menus[menu.id] = menu;
37916 menu.on("beforehide", onBeforeHide);
37917 menu.on("hide", onHide);
37918 menu.on("beforeshow", onBeforeShow);
37919 menu.on("show", onShow);
37920 var g = menu.group;
37921 if(g && menu.events["checkchange"]){
37925 groups[g].push(menu);
37926 menu.on("checkchange", onCheck);
37931 * Returns a {@link Roo.menu.Menu} object
37932 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37933 * be used to generate and return a new Menu instance.
37935 get : function(menu){
37936 if(typeof menu == "string"){ // menu id
37937 return menus[menu];
37938 }else if(menu.events){ // menu instance
37940 }else if(typeof menu.length == 'number'){ // array of menu items?
37941 return new Roo.menu.Menu({items:menu});
37942 }else{ // otherwise, must be a config
37943 return new Roo.menu.Menu(menu);
37948 unregister : function(menu){
37949 delete menus[menu.id];
37950 menu.un("beforehide", onBeforeHide);
37951 menu.un("hide", onHide);
37952 menu.un("beforeshow", onBeforeShow);
37953 menu.un("show", onShow);
37954 var g = menu.group;
37955 if(g && menu.events["checkchange"]){
37956 groups[g].remove(menu);
37957 menu.un("checkchange", onCheck);
37962 registerCheckable : function(menuItem){
37963 var g = menuItem.group;
37968 groups[g].push(menuItem);
37969 menuItem.on("beforecheckchange", onBeforeCheck);
37974 unregisterCheckable : function(menuItem){
37975 var g = menuItem.group;
37977 groups[g].remove(menuItem);
37978 menuItem.un("beforecheckchange", onBeforeCheck);
37984 * Ext JS Library 1.1.1
37985 * Copyright(c) 2006-2007, Ext JS, LLC.
37987 * Originally Released Under LGPL - original licence link has changed is not relivant.
37990 * <script type="text/javascript">
37995 * @class Roo.menu.BaseItem
37996 * @extends Roo.Component
37997 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37998 * management and base configuration options shared by all menu components.
38000 * Creates a new BaseItem
38001 * @param {Object} config Configuration options
38003 Roo.menu.BaseItem = function(config){
38004 Roo.menu.BaseItem.superclass.constructor.call(this, config);
38009 * Fires when this item is clicked
38010 * @param {Roo.menu.BaseItem} this
38011 * @param {Roo.EventObject} e
38016 * Fires when this item is activated
38017 * @param {Roo.menu.BaseItem} this
38021 * @event deactivate
38022 * Fires when this item is deactivated
38023 * @param {Roo.menu.BaseItem} this
38029 this.on("click", this.handler, this.scope, true);
38033 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
38035 * @cfg {Function} handler
38036 * A function that will handle the click event of this menu item (defaults to undefined)
38039 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
38041 canActivate : false,
38044 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
38049 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
38051 activeClass : "x-menu-item-active",
38053 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
38055 hideOnClick : true,
38057 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
38062 ctype: "Roo.menu.BaseItem",
38065 actionMode : "container",
38068 render : function(container, parentMenu){
38069 this.parentMenu = parentMenu;
38070 Roo.menu.BaseItem.superclass.render.call(this, container);
38071 this.container.menuItemId = this.id;
38075 onRender : function(container, position){
38076 this.el = Roo.get(this.el);
38077 container.dom.appendChild(this.el.dom);
38081 onClick : function(e){
38082 if(!this.disabled && this.fireEvent("click", this, e) !== false
38083 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38084 this.handleClick(e);
38091 activate : function(){
38095 var li = this.container;
38096 li.addClass(this.activeClass);
38097 this.region = li.getRegion().adjust(2, 2, -2, -2);
38098 this.fireEvent("activate", this);
38103 deactivate : function(){
38104 this.container.removeClass(this.activeClass);
38105 this.fireEvent("deactivate", this);
38109 shouldDeactivate : function(e){
38110 return !this.region || !this.region.contains(e.getPoint());
38114 handleClick : function(e){
38115 if(this.hideOnClick){
38116 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38121 expandMenu : function(autoActivate){
38126 hideMenu : function(){
38131 * Ext JS Library 1.1.1
38132 * Copyright(c) 2006-2007, Ext JS, LLC.
38134 * Originally Released Under LGPL - original licence link has changed is not relivant.
38137 * <script type="text/javascript">
38141 * @class Roo.menu.Adapter
38142 * @extends Roo.menu.BaseItem
38143 * 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.
38144 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38146 * Creates a new Adapter
38147 * @param {Object} config Configuration options
38149 Roo.menu.Adapter = function(component, config){
38150 Roo.menu.Adapter.superclass.constructor.call(this, config);
38151 this.component = component;
38153 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38155 canActivate : true,
38158 onRender : function(container, position){
38159 this.component.render(container);
38160 this.el = this.component.getEl();
38164 activate : function(){
38168 this.component.focus();
38169 this.fireEvent("activate", this);
38174 deactivate : function(){
38175 this.fireEvent("deactivate", this);
38179 disable : function(){
38180 this.component.disable();
38181 Roo.menu.Adapter.superclass.disable.call(this);
38185 enable : function(){
38186 this.component.enable();
38187 Roo.menu.Adapter.superclass.enable.call(this);
38191 * Ext JS Library 1.1.1
38192 * Copyright(c) 2006-2007, Ext JS, LLC.
38194 * Originally Released Under LGPL - original licence link has changed is not relivant.
38197 * <script type="text/javascript">
38201 * @class Roo.menu.TextItem
38202 * @extends Roo.menu.BaseItem
38203 * Adds a static text string to a menu, usually used as either a heading or group separator.
38204 * Note: old style constructor with text is still supported.
38207 * Creates a new TextItem
38208 * @param {Object} cfg Configuration
38210 Roo.menu.TextItem = function(cfg){
38211 if (typeof(cfg) == 'string') {
38214 Roo.apply(this,cfg);
38217 Roo.menu.TextItem.superclass.constructor.call(this);
38220 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38222 * @cfg {Boolean} text Text to show on item.
38227 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38229 hideOnClick : false,
38231 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38233 itemCls : "x-menu-text",
38236 onRender : function(){
38237 var s = document.createElement("span");
38238 s.className = this.itemCls;
38239 s.innerHTML = this.text;
38241 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38245 * Ext JS Library 1.1.1
38246 * Copyright(c) 2006-2007, Ext JS, LLC.
38248 * Originally Released Under LGPL - original licence link has changed is not relivant.
38251 * <script type="text/javascript">
38255 * @class Roo.menu.Separator
38256 * @extends Roo.menu.BaseItem
38257 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38258 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38260 * @param {Object} config Configuration options
38262 Roo.menu.Separator = function(config){
38263 Roo.menu.Separator.superclass.constructor.call(this, config);
38266 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38268 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38270 itemCls : "x-menu-sep",
38272 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38274 hideOnClick : false,
38277 onRender : function(li){
38278 var s = document.createElement("span");
38279 s.className = this.itemCls;
38280 s.innerHTML = " ";
38282 li.addClass("x-menu-sep-li");
38283 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38287 * Ext JS Library 1.1.1
38288 * Copyright(c) 2006-2007, Ext JS, LLC.
38290 * Originally Released Under LGPL - original licence link has changed is not relivant.
38293 * <script type="text/javascript">
38296 * @class Roo.menu.Item
38297 * @extends Roo.menu.BaseItem
38298 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38299 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38300 * activation and click handling.
38302 * Creates a new Item
38303 * @param {Object} config Configuration options
38305 Roo.menu.Item = function(config){
38306 Roo.menu.Item.superclass.constructor.call(this, config);
38308 this.menu = Roo.menu.MenuMgr.get(this.menu);
38311 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38314 * @cfg {String} text
38315 * The text to show on the menu item.
38319 * @cfg {String} HTML to render in menu
38320 * The text to show on the menu item (HTML version).
38324 * @cfg {String} icon
38325 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38329 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38331 itemCls : "x-menu-item",
38333 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38335 canActivate : true,
38337 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38340 // doc'd in BaseItem
38344 ctype: "Roo.menu.Item",
38347 onRender : function(container, position){
38348 var el = document.createElement("a");
38349 el.hideFocus = true;
38350 el.unselectable = "on";
38351 el.href = this.href || "#";
38352 if(this.hrefTarget){
38353 el.target = this.hrefTarget;
38355 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38357 var html = this.html.length ? this.html : String.format('{0}',this.text);
38359 el.innerHTML = String.format(
38360 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38361 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38363 Roo.menu.Item.superclass.onRender.call(this, container, position);
38367 * Sets the text to display in this menu item
38368 * @param {String} text The text to display
38369 * @param {Boolean} isHTML true to indicate text is pure html.
38371 setText : function(text, isHTML){
38379 var html = this.html.length ? this.html : String.format('{0}',this.text);
38381 this.el.update(String.format(
38382 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38383 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38384 this.parentMenu.autoWidth();
38389 handleClick : function(e){
38390 if(!this.href){ // if no link defined, stop the event automatically
38393 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38397 activate : function(autoExpand){
38398 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38408 shouldDeactivate : function(e){
38409 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38410 if(this.menu && this.menu.isVisible()){
38411 return !this.menu.getEl().getRegion().contains(e.getPoint());
38419 deactivate : function(){
38420 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38425 expandMenu : function(autoActivate){
38426 if(!this.disabled && this.menu){
38427 clearTimeout(this.hideTimer);
38428 delete this.hideTimer;
38429 if(!this.menu.isVisible() && !this.showTimer){
38430 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38431 }else if (this.menu.isVisible() && autoActivate){
38432 this.menu.tryActivate(0, 1);
38438 deferExpand : function(autoActivate){
38439 delete this.showTimer;
38440 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38442 this.menu.tryActivate(0, 1);
38447 hideMenu : function(){
38448 clearTimeout(this.showTimer);
38449 delete this.showTimer;
38450 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38451 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38456 deferHide : function(){
38457 delete this.hideTimer;
38462 * Ext JS Library 1.1.1
38463 * Copyright(c) 2006-2007, Ext JS, LLC.
38465 * Originally Released Under LGPL - original licence link has changed is not relivant.
38468 * <script type="text/javascript">
38472 * @class Roo.menu.CheckItem
38473 * @extends Roo.menu.Item
38474 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38476 * Creates a new CheckItem
38477 * @param {Object} config Configuration options
38479 Roo.menu.CheckItem = function(config){
38480 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38483 * @event beforecheckchange
38484 * Fires before the checked value is set, providing an opportunity to cancel if needed
38485 * @param {Roo.menu.CheckItem} this
38486 * @param {Boolean} checked The new checked value that will be set
38488 "beforecheckchange" : true,
38490 * @event checkchange
38491 * Fires after the checked value has been set
38492 * @param {Roo.menu.CheckItem} this
38493 * @param {Boolean} checked The checked value that was set
38495 "checkchange" : true
38497 if(this.checkHandler){
38498 this.on('checkchange', this.checkHandler, this.scope);
38501 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38503 * @cfg {String} group
38504 * All check items with the same group name will automatically be grouped into a single-select
38505 * radio button group (defaults to '')
38508 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38510 itemCls : "x-menu-item x-menu-check-item",
38512 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38514 groupClass : "x-menu-group-item",
38517 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38518 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38519 * initialized with checked = true will be rendered as checked.
38524 ctype: "Roo.menu.CheckItem",
38527 onRender : function(c){
38528 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38530 this.el.addClass(this.groupClass);
38532 Roo.menu.MenuMgr.registerCheckable(this);
38534 this.checked = false;
38535 this.setChecked(true, true);
38540 destroy : function(){
38542 Roo.menu.MenuMgr.unregisterCheckable(this);
38544 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38548 * Set the checked state of this item
38549 * @param {Boolean} checked The new checked value
38550 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38552 setChecked : function(state, suppressEvent){
38553 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38554 if(this.container){
38555 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38557 this.checked = state;
38558 if(suppressEvent !== true){
38559 this.fireEvent("checkchange", this, state);
38565 handleClick : function(e){
38566 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38567 this.setChecked(!this.checked);
38569 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38573 * Ext JS Library 1.1.1
38574 * Copyright(c) 2006-2007, Ext JS, LLC.
38576 * Originally Released Under LGPL - original licence link has changed is not relivant.
38579 * <script type="text/javascript">
38583 * @class Roo.menu.DateItem
38584 * @extends Roo.menu.Adapter
38585 * A menu item that wraps the {@link Roo.DatPicker} component.
38587 * Creates a new DateItem
38588 * @param {Object} config Configuration options
38590 Roo.menu.DateItem = function(config){
38591 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38592 /** The Roo.DatePicker object @type Roo.DatePicker */
38593 this.picker = this.component;
38594 this.addEvents({select: true});
38596 this.picker.on("render", function(picker){
38597 picker.getEl().swallowEvent("click");
38598 picker.container.addClass("x-menu-date-item");
38601 this.picker.on("select", this.onSelect, this);
38604 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38606 onSelect : function(picker, date){
38607 this.fireEvent("select", this, date, picker);
38608 Roo.menu.DateItem.superclass.handleClick.call(this);
38612 * Ext JS Library 1.1.1
38613 * Copyright(c) 2006-2007, Ext JS, LLC.
38615 * Originally Released Under LGPL - original licence link has changed is not relivant.
38618 * <script type="text/javascript">
38622 * @class Roo.menu.ColorItem
38623 * @extends Roo.menu.Adapter
38624 * A menu item that wraps the {@link Roo.ColorPalette} component.
38626 * Creates a new ColorItem
38627 * @param {Object} config Configuration options
38629 Roo.menu.ColorItem = function(config){
38630 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38631 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38632 this.palette = this.component;
38633 this.relayEvents(this.palette, ["select"]);
38634 if(this.selectHandler){
38635 this.on('select', this.selectHandler, this.scope);
38638 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38640 * Ext JS Library 1.1.1
38641 * Copyright(c) 2006-2007, Ext JS, LLC.
38643 * Originally Released Under LGPL - original licence link has changed is not relivant.
38646 * <script type="text/javascript">
38651 * @class Roo.menu.DateMenu
38652 * @extends Roo.menu.Menu
38653 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38655 * Creates a new DateMenu
38656 * @param {Object} config Configuration options
38658 Roo.menu.DateMenu = function(config){
38659 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38661 var di = new Roo.menu.DateItem(config);
38664 * The {@link Roo.DatePicker} instance for this DateMenu
38667 this.picker = di.picker;
38670 * @param {DatePicker} picker
38671 * @param {Date} date
38673 this.relayEvents(di, ["select"]);
38674 this.on('beforeshow', function(){
38676 this.picker.hideMonthPicker(false);
38680 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38684 * Ext JS Library 1.1.1
38685 * Copyright(c) 2006-2007, Ext JS, LLC.
38687 * Originally Released Under LGPL - original licence link has changed is not relivant.
38690 * <script type="text/javascript">
38695 * @class Roo.menu.ColorMenu
38696 * @extends Roo.menu.Menu
38697 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38699 * Creates a new ColorMenu
38700 * @param {Object} config Configuration options
38702 Roo.menu.ColorMenu = function(config){
38703 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38705 var ci = new Roo.menu.ColorItem(config);
38708 * The {@link Roo.ColorPalette} instance for this ColorMenu
38709 * @type ColorPalette
38711 this.palette = ci.palette;
38714 * @param {ColorPalette} palette
38715 * @param {String} color
38717 this.relayEvents(ci, ["select"]);
38719 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38721 * Ext JS Library 1.1.1
38722 * Copyright(c) 2006-2007, Ext JS, LLC.
38724 * Originally Released Under LGPL - original licence link has changed is not relivant.
38727 * <script type="text/javascript">
38731 * @class Roo.form.TextItem
38732 * @extends Roo.BoxComponent
38733 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38735 * Creates a new TextItem
38736 * @param {Object} config Configuration options
38738 Roo.form.TextItem = function(config){
38739 Roo.form.TextItem.superclass.constructor.call(this, config);
38742 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
38745 * @cfg {String} tag the tag for this item (default div)
38749 * @cfg {String} html the content for this item
38753 getAutoCreate : function()
38766 onRender : function(ct, position)
38768 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
38771 var cfg = this.getAutoCreate();
38773 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38775 if (!cfg.name.length) {
38778 this.el = ct.createChild(cfg, position);
38784 * Ext JS Library 1.1.1
38785 * Copyright(c) 2006-2007, Ext JS, LLC.
38787 * Originally Released Under LGPL - original licence link has changed is not relivant.
38790 * <script type="text/javascript">
38794 * @class Roo.form.Field
38795 * @extends Roo.BoxComponent
38796 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38798 * Creates a new Field
38799 * @param {Object} config Configuration options
38801 Roo.form.Field = function(config){
38802 Roo.form.Field.superclass.constructor.call(this, config);
38805 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38807 * @cfg {String} fieldLabel Label to use when rendering a form.
38810 * @cfg {String} qtip Mouse over tip
38814 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38816 invalidClass : "x-form-invalid",
38818 * @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")
38820 invalidText : "The value in this field is invalid",
38822 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38824 focusClass : "x-form-focus",
38826 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38827 automatic validation (defaults to "keyup").
38829 validationEvent : "keyup",
38831 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38833 validateOnBlur : true,
38835 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38837 validationDelay : 250,
38839 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38840 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38842 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38844 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38846 fieldClass : "x-form-field",
38848 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38851 ----------- ----------------------------------------------------------------------
38852 qtip Display a quick tip when the user hovers over the field
38853 title Display a default browser title attribute popup
38854 under Add a block div beneath the field containing the error text
38855 side Add an error icon to the right of the field with a popup on hover
38856 [element id] Add the error text directly to the innerHTML of the specified element
38859 msgTarget : 'qtip',
38861 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38866 * @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.
38871 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38876 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38878 inputType : undefined,
38881 * @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).
38883 tabIndex : undefined,
38886 isFormField : true,
38891 * @property {Roo.Element} fieldEl
38892 * Element Containing the rendered Field (with label etc.)
38895 * @cfg {Mixed} value A value to initialize this field with.
38900 * @cfg {String} name The field's HTML name attribute.
38903 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38906 loadedValue : false,
38910 initComponent : function(){
38911 Roo.form.Field.superclass.initComponent.call(this);
38915 * Fires when this field receives input focus.
38916 * @param {Roo.form.Field} this
38921 * Fires when this field loses input focus.
38922 * @param {Roo.form.Field} this
38926 * @event specialkey
38927 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38928 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38929 * @param {Roo.form.Field} this
38930 * @param {Roo.EventObject} e The event object
38935 * Fires just before the field blurs if the field value has changed.
38936 * @param {Roo.form.Field} this
38937 * @param {Mixed} newValue The new value
38938 * @param {Mixed} oldValue The original value
38943 * Fires after the field has been marked as invalid.
38944 * @param {Roo.form.Field} this
38945 * @param {String} msg The validation message
38950 * Fires after the field has been validated with no errors.
38951 * @param {Roo.form.Field} this
38956 * Fires after the key up
38957 * @param {Roo.form.Field} this
38958 * @param {Roo.EventObject} e The event Object
38965 * Returns the name attribute of the field if available
38966 * @return {String} name The field name
38968 getName: function(){
38969 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38973 onRender : function(ct, position){
38974 Roo.form.Field.superclass.onRender.call(this, ct, position);
38976 var cfg = this.getAutoCreate();
38978 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38980 if (!cfg.name.length) {
38983 if(this.inputType){
38984 cfg.type = this.inputType;
38986 this.el = ct.createChild(cfg, position);
38988 var type = this.el.dom.type;
38990 if(type == 'password'){
38993 this.el.addClass('x-form-'+type);
38996 this.el.dom.readOnly = true;
38998 if(this.tabIndex !== undefined){
38999 this.el.dom.setAttribute('tabIndex', this.tabIndex);
39002 this.el.addClass([this.fieldClass, this.cls]);
39007 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
39008 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
39009 * @return {Roo.form.Field} this
39011 applyTo : function(target){
39012 this.allowDomMove = false;
39013 this.el = Roo.get(target);
39014 this.render(this.el.dom.parentNode);
39019 initValue : function(){
39020 if(this.value !== undefined){
39021 this.setValue(this.value);
39022 }else if(this.el.dom.value.length > 0){
39023 this.setValue(this.el.dom.value);
39028 * Returns true if this field has been changed since it was originally loaded and is not disabled.
39029 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
39031 isDirty : function() {
39032 if(this.disabled) {
39035 return String(this.getValue()) !== String(this.originalValue);
39039 * stores the current value in loadedValue
39041 resetHasChanged : function()
39043 this.loadedValue = String(this.getValue());
39046 * checks the current value against the 'loaded' value.
39047 * Note - will return false if 'resetHasChanged' has not been called first.
39049 hasChanged : function()
39051 if(this.disabled || this.readOnly) {
39054 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
39060 afterRender : function(){
39061 Roo.form.Field.superclass.afterRender.call(this);
39066 fireKey : function(e){
39067 //Roo.log('field ' + e.getKey());
39068 if(e.isNavKeyPress()){
39069 this.fireEvent("specialkey", this, e);
39074 * Resets the current field value to the originally loaded value and clears any validation messages
39076 reset : function(){
39077 this.setValue(this.resetValue);
39078 this.originalValue = this.getValue();
39079 this.clearInvalid();
39083 initEvents : function(){
39084 // safari killled keypress - so keydown is now used..
39085 this.el.on("keydown" , this.fireKey, this);
39086 this.el.on("focus", this.onFocus, this);
39087 this.el.on("blur", this.onBlur, this);
39088 this.el.relayEvent('keyup', this);
39090 // reference to original value for reset
39091 this.originalValue = this.getValue();
39092 this.resetValue = this.getValue();
39096 onFocus : function(){
39097 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39098 this.el.addClass(this.focusClass);
39100 if(!this.hasFocus){
39101 this.hasFocus = true;
39102 this.startValue = this.getValue();
39103 this.fireEvent("focus", this);
39107 beforeBlur : Roo.emptyFn,
39110 onBlur : function(){
39112 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39113 this.el.removeClass(this.focusClass);
39115 this.hasFocus = false;
39116 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
39119 var v = this.getValue();
39120 if(String(v) !== String(this.startValue)){
39121 this.fireEvent('change', this, v, this.startValue);
39123 this.fireEvent("blur", this);
39127 * Returns whether or not the field value is currently valid
39128 * @param {Boolean} preventMark True to disable marking the field invalid
39129 * @return {Boolean} True if the value is valid, else false
39131 isValid : function(preventMark){
39135 var restore = this.preventMark;
39136 this.preventMark = preventMark === true;
39137 var v = this.validateValue(this.processValue(this.getRawValue()));
39138 this.preventMark = restore;
39143 * Validates the field value
39144 * @return {Boolean} True if the value is valid, else false
39146 validate : function(){
39147 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39148 this.clearInvalid();
39154 processValue : function(value){
39159 // Subclasses should provide the validation implementation by overriding this
39160 validateValue : function(value){
39165 * Mark this field as invalid
39166 * @param {String} msg The validation message
39168 markInvalid : function(msg){
39169 if(!this.rendered || this.preventMark){ // not rendered
39173 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39175 obj.el.addClass(this.invalidClass);
39176 msg = msg || this.invalidText;
39177 switch(this.msgTarget){
39179 obj.el.dom.qtip = msg;
39180 obj.el.dom.qclass = 'x-form-invalid-tip';
39181 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39182 Roo.QuickTips.enable();
39186 this.el.dom.title = msg;
39190 var elp = this.el.findParent('.x-form-element', 5, true);
39191 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39192 this.errorEl.setWidth(elp.getWidth(true)-20);
39194 this.errorEl.update(msg);
39195 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39198 if(!this.errorIcon){
39199 var elp = this.el.findParent('.x-form-element', 5, true);
39200 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39202 this.alignErrorIcon();
39203 this.errorIcon.dom.qtip = msg;
39204 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39205 this.errorIcon.show();
39206 this.on('resize', this.alignErrorIcon, this);
39209 var t = Roo.getDom(this.msgTarget);
39211 t.style.display = this.msgDisplay;
39214 this.fireEvent('invalid', this, msg);
39218 alignErrorIcon : function(){
39219 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39223 * Clear any invalid styles/messages for this field
39225 clearInvalid : function(){
39226 if(!this.rendered || this.preventMark){ // not rendered
39229 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39231 obj.el.removeClass(this.invalidClass);
39232 switch(this.msgTarget){
39234 obj.el.dom.qtip = '';
39237 this.el.dom.title = '';
39241 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39245 if(this.errorIcon){
39246 this.errorIcon.dom.qtip = '';
39247 this.errorIcon.hide();
39248 this.un('resize', this.alignErrorIcon, this);
39252 var t = Roo.getDom(this.msgTarget);
39254 t.style.display = 'none';
39257 this.fireEvent('valid', this);
39261 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39262 * @return {Mixed} value The field value
39264 getRawValue : function(){
39265 var v = this.el.getValue();
39271 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39272 * @return {Mixed} value The field value
39274 getValue : function(){
39275 var v = this.el.getValue();
39281 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39282 * @param {Mixed} value The value to set
39284 setRawValue : function(v){
39285 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39289 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39290 * @param {Mixed} value The value to set
39292 setValue : function(v){
39295 this.el.dom.value = (v === null || v === undefined ? '' : v);
39300 adjustSize : function(w, h){
39301 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39302 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39306 adjustWidth : function(tag, w){
39307 tag = tag.toLowerCase();
39308 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39309 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39310 if(tag == 'input'){
39313 if(tag == 'textarea'){
39316 }else if(Roo.isOpera){
39317 if(tag == 'input'){
39320 if(tag == 'textarea'){
39330 // anything other than normal should be considered experimental
39331 Roo.form.Field.msgFx = {
39333 show: function(msgEl, f){
39334 msgEl.setDisplayed('block');
39337 hide : function(msgEl, f){
39338 msgEl.setDisplayed(false).update('');
39343 show: function(msgEl, f){
39344 msgEl.slideIn('t', {stopFx:true});
39347 hide : function(msgEl, f){
39348 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39353 show: function(msgEl, f){
39354 msgEl.fixDisplay();
39355 msgEl.alignTo(f.el, 'tl-tr');
39356 msgEl.slideIn('l', {stopFx:true});
39359 hide : function(msgEl, f){
39360 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39365 * Ext JS Library 1.1.1
39366 * Copyright(c) 2006-2007, Ext JS, LLC.
39368 * Originally Released Under LGPL - original licence link has changed is not relivant.
39371 * <script type="text/javascript">
39376 * @class Roo.form.TextField
39377 * @extends Roo.form.Field
39378 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39379 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39381 * Creates a new TextField
39382 * @param {Object} config Configuration options
39384 Roo.form.TextField = function(config){
39385 Roo.form.TextField.superclass.constructor.call(this, config);
39389 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39390 * according to the default logic, but this event provides a hook for the developer to apply additional
39391 * logic at runtime to resize the field if needed.
39392 * @param {Roo.form.Field} this This text field
39393 * @param {Number} width The new field width
39399 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39401 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39405 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39409 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39413 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39417 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39421 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39423 disableKeyFilter : false,
39425 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39429 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39433 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39435 maxLength : Number.MAX_VALUE,
39437 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39439 minLengthText : "The minimum length for this field is {0}",
39441 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39443 maxLengthText : "The maximum length for this field is {0}",
39445 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39447 selectOnFocus : false,
39449 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
39451 allowLeadingSpace : false,
39453 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39455 blankText : "This field is required",
39457 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39458 * If available, this function will be called only after the basic validators all return true, and will be passed the
39459 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39463 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39464 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39465 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39469 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39473 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39479 initEvents : function()
39481 if (this.emptyText) {
39482 this.el.attr('placeholder', this.emptyText);
39485 Roo.form.TextField.superclass.initEvents.call(this);
39486 if(this.validationEvent == 'keyup'){
39487 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39488 this.el.on('keyup', this.filterValidation, this);
39490 else if(this.validationEvent !== false){
39491 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39494 if(this.selectOnFocus){
39495 this.on("focus", this.preFocus, this);
39497 if (!this.allowLeadingSpace) {
39498 this.on('blur', this.cleanLeadingSpace, this);
39501 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39502 this.el.on("keypress", this.filterKeys, this);
39505 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39506 this.el.on("click", this.autoSize, this);
39508 if(this.el.is('input[type=password]') && Roo.isSafari){
39509 this.el.on('keydown', this.SafariOnKeyDown, this);
39513 processValue : function(value){
39514 if(this.stripCharsRe){
39515 var newValue = value.replace(this.stripCharsRe, '');
39516 if(newValue !== value){
39517 this.setRawValue(newValue);
39524 filterValidation : function(e){
39525 if(!e.isNavKeyPress()){
39526 this.validationTask.delay(this.validationDelay);
39531 onKeyUp : function(e){
39532 if(!e.isNavKeyPress()){
39536 // private - clean the leading white space
39537 cleanLeadingSpace : function(e)
39539 if ( this.inputType == 'file') {
39543 this.setValue((this.getValue() + '').replace(/^\s+/,''));
39546 * Resets the current field value to the originally-loaded value and clears any validation messages.
39549 reset : function(){
39550 Roo.form.TextField.superclass.reset.call(this);
39554 preFocus : function(){
39556 if(this.selectOnFocus){
39557 this.el.dom.select();
39563 filterKeys : function(e){
39564 var k = e.getKey();
39565 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39568 var c = e.getCharCode(), cc = String.fromCharCode(c);
39569 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39572 if(!this.maskRe.test(cc)){
39577 setValue : function(v){
39579 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39585 * Validates a value according to the field's validation rules and marks the field as invalid
39586 * if the validation fails
39587 * @param {Mixed} value The value to validate
39588 * @return {Boolean} True if the value is valid, else false
39590 validateValue : function(value){
39591 if(value.length < 1) { // if it's blank
39592 if(this.allowBlank){
39593 this.clearInvalid();
39596 this.markInvalid(this.blankText);
39600 if(value.length < this.minLength){
39601 this.markInvalid(String.format(this.minLengthText, this.minLength));
39604 if(value.length > this.maxLength){
39605 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39609 var vt = Roo.form.VTypes;
39610 if(!vt[this.vtype](value, this)){
39611 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39615 if(typeof this.validator == "function"){
39616 var msg = this.validator(value);
39618 this.markInvalid(msg);
39622 if(this.regex && !this.regex.test(value)){
39623 this.markInvalid(this.regexText);
39630 * Selects text in this field
39631 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39632 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39634 selectText : function(start, end){
39635 var v = this.getRawValue();
39637 start = start === undefined ? 0 : start;
39638 end = end === undefined ? v.length : end;
39639 var d = this.el.dom;
39640 if(d.setSelectionRange){
39641 d.setSelectionRange(start, end);
39642 }else if(d.createTextRange){
39643 var range = d.createTextRange();
39644 range.moveStart("character", start);
39645 range.moveEnd("character", v.length-end);
39652 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39653 * This only takes effect if grow = true, and fires the autosize event.
39655 autoSize : function(){
39656 if(!this.grow || !this.rendered){
39660 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39663 var v = el.dom.value;
39664 var d = document.createElement('div');
39665 d.appendChild(document.createTextNode(v));
39669 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39670 this.el.setWidth(w);
39671 this.fireEvent("autosize", this, w);
39675 SafariOnKeyDown : function(event)
39677 // this is a workaround for a password hang bug on chrome/ webkit.
39679 var isSelectAll = false;
39681 if(this.el.dom.selectionEnd > 0){
39682 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39684 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39685 event.preventDefault();
39690 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39692 event.preventDefault();
39693 // this is very hacky as keydown always get's upper case.
39695 var cc = String.fromCharCode(event.getCharCode());
39698 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39706 * Ext JS Library 1.1.1
39707 * Copyright(c) 2006-2007, Ext JS, LLC.
39709 * Originally Released Under LGPL - original licence link has changed is not relivant.
39712 * <script type="text/javascript">
39716 * @class Roo.form.Hidden
39717 * @extends Roo.form.TextField
39718 * Simple Hidden element used on forms
39720 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39723 * Creates a new Hidden form element.
39724 * @param {Object} config Configuration options
39729 // easy hidden field...
39730 Roo.form.Hidden = function(config){
39731 Roo.form.Hidden.superclass.constructor.call(this, config);
39734 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39736 inputType: 'hidden',
39739 labelSeparator: '',
39741 itemCls : 'x-form-item-display-none'
39749 * Ext JS Library 1.1.1
39750 * Copyright(c) 2006-2007, Ext JS, LLC.
39752 * Originally Released Under LGPL - original licence link has changed is not relivant.
39755 * <script type="text/javascript">
39759 * @class Roo.form.TriggerField
39760 * @extends Roo.form.TextField
39761 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39762 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39763 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39764 * for which you can provide a custom implementation. For example:
39766 var trigger = new Roo.form.TriggerField();
39767 trigger.onTriggerClick = myTriggerFn;
39768 trigger.applyTo('my-field');
39771 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39772 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39773 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39774 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39776 * Create a new TriggerField.
39777 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39778 * to the base TextField)
39780 Roo.form.TriggerField = function(config){
39781 this.mimicing = false;
39782 Roo.form.TriggerField.superclass.constructor.call(this, config);
39785 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39787 * @cfg {String} triggerClass A CSS class to apply to the trigger
39790 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39791 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39793 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39795 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39799 /** @cfg {Boolean} grow @hide */
39800 /** @cfg {Number} growMin @hide */
39801 /** @cfg {Number} growMax @hide */
39807 autoSize: Roo.emptyFn,
39811 deferHeight : true,
39814 actionMode : 'wrap',
39816 onResize : function(w, h){
39817 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39818 if(typeof w == 'number'){
39819 var x = w - this.trigger.getWidth();
39820 this.el.setWidth(this.adjustWidth('input', x));
39821 this.trigger.setStyle('left', x+'px');
39826 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39829 getResizeEl : function(){
39834 getPositionEl : function(){
39839 alignErrorIcon : function(){
39840 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39844 onRender : function(ct, position){
39845 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39846 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39847 this.trigger = this.wrap.createChild(this.triggerConfig ||
39848 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39849 if(this.hideTrigger){
39850 this.trigger.setDisplayed(false);
39852 this.initTrigger();
39854 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39859 initTrigger : function(){
39860 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39861 this.trigger.addClassOnOver('x-form-trigger-over');
39862 this.trigger.addClassOnClick('x-form-trigger-click');
39866 onDestroy : function(){
39868 this.trigger.removeAllListeners();
39869 this.trigger.remove();
39872 this.wrap.remove();
39874 Roo.form.TriggerField.superclass.onDestroy.call(this);
39878 onFocus : function(){
39879 Roo.form.TriggerField.superclass.onFocus.call(this);
39880 if(!this.mimicing){
39881 this.wrap.addClass('x-trigger-wrap-focus');
39882 this.mimicing = true;
39883 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39884 if(this.monitorTab){
39885 this.el.on("keydown", this.checkTab, this);
39891 checkTab : function(e){
39892 if(e.getKey() == e.TAB){
39893 this.triggerBlur();
39898 onBlur : function(){
39903 mimicBlur : function(e, t){
39904 if(!this.wrap.contains(t) && this.validateBlur()){
39905 this.triggerBlur();
39910 triggerBlur : function(){
39911 this.mimicing = false;
39912 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39913 if(this.monitorTab){
39914 this.el.un("keydown", this.checkTab, this);
39916 this.wrap.removeClass('x-trigger-wrap-focus');
39917 Roo.form.TriggerField.superclass.onBlur.call(this);
39921 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39922 validateBlur : function(e, t){
39927 onDisable : function(){
39928 Roo.form.TriggerField.superclass.onDisable.call(this);
39930 this.wrap.addClass('x-item-disabled');
39935 onEnable : function(){
39936 Roo.form.TriggerField.superclass.onEnable.call(this);
39938 this.wrap.removeClass('x-item-disabled');
39943 onShow : function(){
39944 var ae = this.getActionEl();
39947 ae.dom.style.display = '';
39948 ae.dom.style.visibility = 'visible';
39954 onHide : function(){
39955 var ae = this.getActionEl();
39956 ae.dom.style.display = 'none';
39960 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39961 * by an implementing function.
39963 * @param {EventObject} e
39965 onTriggerClick : Roo.emptyFn
39968 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39969 // to be extended by an implementing class. For an example of implementing this class, see the custom
39970 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39971 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39972 initComponent : function(){
39973 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39975 this.triggerConfig = {
39976 tag:'span', cls:'x-form-twin-triggers', cn:[
39977 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39978 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39982 getTrigger : function(index){
39983 return this.triggers[index];
39986 initTrigger : function(){
39987 var ts = this.trigger.select('.x-form-trigger', true);
39988 this.wrap.setStyle('overflow', 'hidden');
39989 var triggerField = this;
39990 ts.each(function(t, all, index){
39991 t.hide = function(){
39992 var w = triggerField.wrap.getWidth();
39993 this.dom.style.display = 'none';
39994 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39996 t.show = function(){
39997 var w = triggerField.wrap.getWidth();
39998 this.dom.style.display = '';
39999 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40001 var triggerIndex = 'Trigger'+(index+1);
40003 if(this['hide'+triggerIndex]){
40004 t.dom.style.display = 'none';
40006 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
40007 t.addClassOnOver('x-form-trigger-over');
40008 t.addClassOnClick('x-form-trigger-click');
40010 this.triggers = ts.elements;
40013 onTrigger1Click : Roo.emptyFn,
40014 onTrigger2Click : Roo.emptyFn
40017 * Ext JS Library 1.1.1
40018 * Copyright(c) 2006-2007, Ext JS, LLC.
40020 * Originally Released Under LGPL - original licence link has changed is not relivant.
40023 * <script type="text/javascript">
40027 * @class Roo.form.TextArea
40028 * @extends Roo.form.TextField
40029 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
40030 * support for auto-sizing.
40032 * Creates a new TextArea
40033 * @param {Object} config Configuration options
40035 Roo.form.TextArea = function(config){
40036 Roo.form.TextArea.superclass.constructor.call(this, config);
40037 // these are provided exchanges for backwards compat
40038 // minHeight/maxHeight were replaced by growMin/growMax to be
40039 // compatible with TextField growing config values
40040 if(this.minHeight !== undefined){
40041 this.growMin = this.minHeight;
40043 if(this.maxHeight !== undefined){
40044 this.growMax = this.maxHeight;
40048 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
40050 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
40054 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
40058 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
40059 * in the field (equivalent to setting overflow: hidden, defaults to false)
40061 preventScrollbars: false,
40063 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40064 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
40068 onRender : function(ct, position){
40070 this.defaultAutoCreate = {
40072 style:"width:300px;height:60px;",
40073 autocomplete: "new-password"
40076 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
40078 this.textSizeEl = Roo.DomHelper.append(document.body, {
40079 tag: "pre", cls: "x-form-grow-sizer"
40081 if(this.preventScrollbars){
40082 this.el.setStyle("overflow", "hidden");
40084 this.el.setHeight(this.growMin);
40088 onDestroy : function(){
40089 if(this.textSizeEl){
40090 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
40092 Roo.form.TextArea.superclass.onDestroy.call(this);
40096 onKeyUp : function(e){
40097 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
40103 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
40104 * This only takes effect if grow = true, and fires the autosize event if the height changes.
40106 autoSize : function(){
40107 if(!this.grow || !this.textSizeEl){
40111 var v = el.dom.value;
40112 var ts = this.textSizeEl;
40115 ts.appendChild(document.createTextNode(v));
40118 Roo.fly(ts).setWidth(this.el.getWidth());
40120 v = "  ";
40123 v = v.replace(/\n/g, '<p> </p>');
40125 v += " \n ";
40128 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
40129 if(h != this.lastHeight){
40130 this.lastHeight = h;
40131 this.el.setHeight(h);
40132 this.fireEvent("autosize", this, h);
40137 * Ext JS Library 1.1.1
40138 * Copyright(c) 2006-2007, Ext JS, LLC.
40140 * Originally Released Under LGPL - original licence link has changed is not relivant.
40143 * <script type="text/javascript">
40148 * @class Roo.form.NumberField
40149 * @extends Roo.form.TextField
40150 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40152 * Creates a new NumberField
40153 * @param {Object} config Configuration options
40155 Roo.form.NumberField = function(config){
40156 Roo.form.NumberField.superclass.constructor.call(this, config);
40159 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40161 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40163 fieldClass: "x-form-field x-form-num-field",
40165 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40167 allowDecimals : true,
40169 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40171 decimalSeparator : ".",
40173 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40175 decimalPrecision : 2,
40177 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40179 allowNegative : true,
40181 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40183 minValue : Number.NEGATIVE_INFINITY,
40185 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40187 maxValue : Number.MAX_VALUE,
40189 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40191 minText : "The minimum value for this field is {0}",
40193 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40195 maxText : "The maximum value for this field is {0}",
40197 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40198 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40200 nanText : "{0} is not a valid number",
40203 initEvents : function(){
40204 Roo.form.NumberField.superclass.initEvents.call(this);
40205 var allowed = "0123456789";
40206 if(this.allowDecimals){
40207 allowed += this.decimalSeparator;
40209 if(this.allowNegative){
40212 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40213 var keyPress = function(e){
40214 var k = e.getKey();
40215 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40218 var c = e.getCharCode();
40219 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40223 this.el.on("keypress", keyPress, this);
40227 validateValue : function(value){
40228 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40231 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40234 var num = this.parseValue(value);
40236 this.markInvalid(String.format(this.nanText, value));
40239 if(num < this.minValue){
40240 this.markInvalid(String.format(this.minText, this.minValue));
40243 if(num > this.maxValue){
40244 this.markInvalid(String.format(this.maxText, this.maxValue));
40250 getValue : function(){
40251 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40255 parseValue : function(value){
40256 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40257 return isNaN(value) ? '' : value;
40261 fixPrecision : function(value){
40262 var nan = isNaN(value);
40263 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40264 return nan ? '' : value;
40266 return parseFloat(value).toFixed(this.decimalPrecision);
40269 setValue : function(v){
40270 v = this.fixPrecision(v);
40271 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40275 decimalPrecisionFcn : function(v){
40276 return Math.floor(v);
40279 beforeBlur : function(){
40280 var v = this.parseValue(this.getRawValue());
40287 * Ext JS Library 1.1.1
40288 * Copyright(c) 2006-2007, Ext JS, LLC.
40290 * Originally Released Under LGPL - original licence link has changed is not relivant.
40293 * <script type="text/javascript">
40297 * @class Roo.form.DateField
40298 * @extends Roo.form.TriggerField
40299 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40301 * Create a new DateField
40302 * @param {Object} config
40304 Roo.form.DateField = function(config)
40306 Roo.form.DateField.superclass.constructor.call(this, config);
40312 * Fires when a date is selected
40313 * @param {Roo.form.DateField} combo This combo box
40314 * @param {Date} date The date selected
40321 if(typeof this.minValue == "string") {
40322 this.minValue = this.parseDate(this.minValue);
40324 if(typeof this.maxValue == "string") {
40325 this.maxValue = this.parseDate(this.maxValue);
40327 this.ddMatch = null;
40328 if(this.disabledDates){
40329 var dd = this.disabledDates;
40331 for(var i = 0; i < dd.length; i++){
40333 if(i != dd.length-1) {
40337 this.ddMatch = new RegExp(re + ")");
40341 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40343 * @cfg {String} format
40344 * The default date format string which can be overriden for localization support. The format must be
40345 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40349 * @cfg {String} altFormats
40350 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40351 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40353 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40355 * @cfg {Array} disabledDays
40356 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40358 disabledDays : null,
40360 * @cfg {String} disabledDaysText
40361 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40363 disabledDaysText : "Disabled",
40365 * @cfg {Array} disabledDates
40366 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40367 * expression so they are very powerful. Some examples:
40369 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40370 * <li>["03/08", "09/16"] would disable those days for every year</li>
40371 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40372 * <li>["03/../2006"] would disable every day in March 2006</li>
40373 * <li>["^03"] would disable every day in every March</li>
40375 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40376 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40378 disabledDates : null,
40380 * @cfg {String} disabledDatesText
40381 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40383 disabledDatesText : "Disabled",
40385 * @cfg {Date/String} minValue
40386 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40387 * valid format (defaults to null).
40391 * @cfg {Date/String} maxValue
40392 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40393 * valid format (defaults to null).
40397 * @cfg {String} minText
40398 * The error text to display when the date in the cell is before minValue (defaults to
40399 * 'The date in this field must be after {minValue}').
40401 minText : "The date in this field must be equal to or after {0}",
40403 * @cfg {String} maxText
40404 * The error text to display when the date in the cell is after maxValue (defaults to
40405 * 'The date in this field must be before {maxValue}').
40407 maxText : "The date in this field must be equal to or before {0}",
40409 * @cfg {String} invalidText
40410 * The error text to display when the date in the field is invalid (defaults to
40411 * '{value} is not a valid date - it must be in the format {format}').
40413 invalidText : "{0} is not a valid date - it must be in the format {1}",
40415 * @cfg {String} triggerClass
40416 * An additional CSS class used to style the trigger button. The trigger will always get the
40417 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40418 * which displays a calendar icon).
40420 triggerClass : 'x-form-date-trigger',
40424 * @cfg {Boolean} useIso
40425 * if enabled, then the date field will use a hidden field to store the
40426 * real value as iso formated date. default (false)
40430 * @cfg {String/Object} autoCreate
40431 * A DomHelper element spec, or true for a default element spec (defaults to
40432 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40435 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40438 hiddenField: false,
40440 onRender : function(ct, position)
40442 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40444 //this.el.dom.removeAttribute('name');
40445 Roo.log("Changing name?");
40446 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40447 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40449 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40450 // prevent input submission
40451 this.hiddenName = this.name;
40458 validateValue : function(value)
40460 value = this.formatDate(value);
40461 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40462 Roo.log('super failed');
40465 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40468 var svalue = value;
40469 value = this.parseDate(value);
40471 Roo.log('parse date failed' + svalue);
40472 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40475 var time = value.getTime();
40476 if(this.minValue && time < this.minValue.getTime()){
40477 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40480 if(this.maxValue && time > this.maxValue.getTime()){
40481 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40484 if(this.disabledDays){
40485 var day = value.getDay();
40486 for(var i = 0; i < this.disabledDays.length; i++) {
40487 if(day === this.disabledDays[i]){
40488 this.markInvalid(this.disabledDaysText);
40493 var fvalue = this.formatDate(value);
40494 if(this.ddMatch && this.ddMatch.test(fvalue)){
40495 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40502 // Provides logic to override the default TriggerField.validateBlur which just returns true
40503 validateBlur : function(){
40504 return !this.menu || !this.menu.isVisible();
40507 getName: function()
40509 // returns hidden if it's set..
40510 if (!this.rendered) {return ''};
40511 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40516 * Returns the current date value of the date field.
40517 * @return {Date} The date value
40519 getValue : function(){
40521 return this.hiddenField ?
40522 this.hiddenField.value :
40523 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40527 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40528 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40529 * (the default format used is "m/d/y").
40532 //All of these calls set the same date value (May 4, 2006)
40534 //Pass a date object:
40535 var dt = new Date('5/4/06');
40536 dateField.setValue(dt);
40538 //Pass a date string (default format):
40539 dateField.setValue('5/4/06');
40541 //Pass a date string (custom format):
40542 dateField.format = 'Y-m-d';
40543 dateField.setValue('2006-5-4');
40545 * @param {String/Date} date The date or valid date string
40547 setValue : function(date){
40548 if (this.hiddenField) {
40549 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40551 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40552 // make sure the value field is always stored as a date..
40553 this.value = this.parseDate(date);
40559 parseDate : function(value){
40560 if(!value || value instanceof Date){
40563 var v = Date.parseDate(value, this.format);
40564 if (!v && this.useIso) {
40565 v = Date.parseDate(value, 'Y-m-d');
40567 if(!v && this.altFormats){
40568 if(!this.altFormatsArray){
40569 this.altFormatsArray = this.altFormats.split("|");
40571 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40572 v = Date.parseDate(value, this.altFormatsArray[i]);
40579 formatDate : function(date, fmt){
40580 return (!date || !(date instanceof Date)) ?
40581 date : date.dateFormat(fmt || this.format);
40586 select: function(m, d){
40589 this.fireEvent('select', this, d);
40591 show : function(){ // retain focus styling
40595 this.focus.defer(10, this);
40596 var ml = this.menuListeners;
40597 this.menu.un("select", ml.select, this);
40598 this.menu.un("show", ml.show, this);
40599 this.menu.un("hide", ml.hide, this);
40604 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40605 onTriggerClick : function(){
40609 if(this.menu == null){
40610 this.menu = new Roo.menu.DateMenu();
40612 Roo.apply(this.menu.picker, {
40613 showClear: this.allowBlank,
40614 minDate : this.minValue,
40615 maxDate : this.maxValue,
40616 disabledDatesRE : this.ddMatch,
40617 disabledDatesText : this.disabledDatesText,
40618 disabledDays : this.disabledDays,
40619 disabledDaysText : this.disabledDaysText,
40620 format : this.useIso ? 'Y-m-d' : this.format,
40621 minText : String.format(this.minText, this.formatDate(this.minValue)),
40622 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40624 this.menu.on(Roo.apply({}, this.menuListeners, {
40627 this.menu.picker.setValue(this.getValue() || new Date());
40628 this.menu.show(this.el, "tl-bl?");
40631 beforeBlur : function(){
40632 var v = this.parseDate(this.getRawValue());
40642 isDirty : function() {
40643 if(this.disabled) {
40647 if(typeof(this.startValue) === 'undefined'){
40651 return String(this.getValue()) !== String(this.startValue);
40655 cleanLeadingSpace : function(e)
40662 * Ext JS Library 1.1.1
40663 * Copyright(c) 2006-2007, Ext JS, LLC.
40665 * Originally Released Under LGPL - original licence link has changed is not relivant.
40668 * <script type="text/javascript">
40672 * @class Roo.form.MonthField
40673 * @extends Roo.form.TriggerField
40674 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40676 * Create a new MonthField
40677 * @param {Object} config
40679 Roo.form.MonthField = function(config){
40681 Roo.form.MonthField.superclass.constructor.call(this, config);
40687 * Fires when a date is selected
40688 * @param {Roo.form.MonthFieeld} combo This combo box
40689 * @param {Date} date The date selected
40696 if(typeof this.minValue == "string") {
40697 this.minValue = this.parseDate(this.minValue);
40699 if(typeof this.maxValue == "string") {
40700 this.maxValue = this.parseDate(this.maxValue);
40702 this.ddMatch = null;
40703 if(this.disabledDates){
40704 var dd = this.disabledDates;
40706 for(var i = 0; i < dd.length; i++){
40708 if(i != dd.length-1) {
40712 this.ddMatch = new RegExp(re + ")");
40716 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40718 * @cfg {String} format
40719 * The default date format string which can be overriden for localization support. The format must be
40720 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40724 * @cfg {String} altFormats
40725 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40726 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40728 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40730 * @cfg {Array} disabledDays
40731 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40733 disabledDays : [0,1,2,3,4,5,6],
40735 * @cfg {String} disabledDaysText
40736 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40738 disabledDaysText : "Disabled",
40740 * @cfg {Array} disabledDates
40741 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40742 * expression so they are very powerful. Some examples:
40744 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40745 * <li>["03/08", "09/16"] would disable those days for every year</li>
40746 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40747 * <li>["03/../2006"] would disable every day in March 2006</li>
40748 * <li>["^03"] would disable every day in every March</li>
40750 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40751 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40753 disabledDates : null,
40755 * @cfg {String} disabledDatesText
40756 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40758 disabledDatesText : "Disabled",
40760 * @cfg {Date/String} minValue
40761 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40762 * valid format (defaults to null).
40766 * @cfg {Date/String} maxValue
40767 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40768 * valid format (defaults to null).
40772 * @cfg {String} minText
40773 * The error text to display when the date in the cell is before minValue (defaults to
40774 * 'The date in this field must be after {minValue}').
40776 minText : "The date in this field must be equal to or after {0}",
40778 * @cfg {String} maxTextf
40779 * The error text to display when the date in the cell is after maxValue (defaults to
40780 * 'The date in this field must be before {maxValue}').
40782 maxText : "The date in this field must be equal to or before {0}",
40784 * @cfg {String} invalidText
40785 * The error text to display when the date in the field is invalid (defaults to
40786 * '{value} is not a valid date - it must be in the format {format}').
40788 invalidText : "{0} is not a valid date - it must be in the format {1}",
40790 * @cfg {String} triggerClass
40791 * An additional CSS class used to style the trigger button. The trigger will always get the
40792 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40793 * which displays a calendar icon).
40795 triggerClass : 'x-form-date-trigger',
40799 * @cfg {Boolean} useIso
40800 * if enabled, then the date field will use a hidden field to store the
40801 * real value as iso formated date. default (true)
40805 * @cfg {String/Object} autoCreate
40806 * A DomHelper element spec, or true for a default element spec (defaults to
40807 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40810 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40813 hiddenField: false,
40815 hideMonthPicker : false,
40817 onRender : function(ct, position)
40819 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40821 this.el.dom.removeAttribute('name');
40822 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40824 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40825 // prevent input submission
40826 this.hiddenName = this.name;
40833 validateValue : function(value)
40835 value = this.formatDate(value);
40836 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40839 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40842 var svalue = value;
40843 value = this.parseDate(value);
40845 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40848 var time = value.getTime();
40849 if(this.minValue && time < this.minValue.getTime()){
40850 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40853 if(this.maxValue && time > this.maxValue.getTime()){
40854 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40857 /*if(this.disabledDays){
40858 var day = value.getDay();
40859 for(var i = 0; i < this.disabledDays.length; i++) {
40860 if(day === this.disabledDays[i]){
40861 this.markInvalid(this.disabledDaysText);
40867 var fvalue = this.formatDate(value);
40868 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40869 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40877 // Provides logic to override the default TriggerField.validateBlur which just returns true
40878 validateBlur : function(){
40879 return !this.menu || !this.menu.isVisible();
40883 * Returns the current date value of the date field.
40884 * @return {Date} The date value
40886 getValue : function(){
40890 return this.hiddenField ?
40891 this.hiddenField.value :
40892 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40896 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40897 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40898 * (the default format used is "m/d/y").
40901 //All of these calls set the same date value (May 4, 2006)
40903 //Pass a date object:
40904 var dt = new Date('5/4/06');
40905 monthField.setValue(dt);
40907 //Pass a date string (default format):
40908 monthField.setValue('5/4/06');
40910 //Pass a date string (custom format):
40911 monthField.format = 'Y-m-d';
40912 monthField.setValue('2006-5-4');
40914 * @param {String/Date} date The date or valid date string
40916 setValue : function(date){
40917 Roo.log('month setValue' + date);
40918 // can only be first of month..
40920 var val = this.parseDate(date);
40922 if (this.hiddenField) {
40923 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40925 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40926 this.value = this.parseDate(date);
40930 parseDate : function(value){
40931 if(!value || value instanceof Date){
40932 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40935 var v = Date.parseDate(value, this.format);
40936 if (!v && this.useIso) {
40937 v = Date.parseDate(value, 'Y-m-d');
40941 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40945 if(!v && this.altFormats){
40946 if(!this.altFormatsArray){
40947 this.altFormatsArray = this.altFormats.split("|");
40949 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40950 v = Date.parseDate(value, this.altFormatsArray[i]);
40957 formatDate : function(date, fmt){
40958 return (!date || !(date instanceof Date)) ?
40959 date : date.dateFormat(fmt || this.format);
40964 select: function(m, d){
40966 this.fireEvent('select', this, d);
40968 show : function(){ // retain focus styling
40972 this.focus.defer(10, this);
40973 var ml = this.menuListeners;
40974 this.menu.un("select", ml.select, this);
40975 this.menu.un("show", ml.show, this);
40976 this.menu.un("hide", ml.hide, this);
40980 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40981 onTriggerClick : function(){
40985 if(this.menu == null){
40986 this.menu = new Roo.menu.DateMenu();
40990 Roo.apply(this.menu.picker, {
40992 showClear: this.allowBlank,
40993 minDate : this.minValue,
40994 maxDate : this.maxValue,
40995 disabledDatesRE : this.ddMatch,
40996 disabledDatesText : this.disabledDatesText,
40998 format : this.useIso ? 'Y-m-d' : this.format,
40999 minText : String.format(this.minText, this.formatDate(this.minValue)),
41000 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
41003 this.menu.on(Roo.apply({}, this.menuListeners, {
41011 // hide month picker get's called when we called by 'before hide';
41013 var ignorehide = true;
41014 p.hideMonthPicker = function(disableAnim){
41018 if(this.monthPicker){
41019 Roo.log("hideMonthPicker called");
41020 if(disableAnim === true){
41021 this.monthPicker.hide();
41023 this.monthPicker.slideOut('t', {duration:.2});
41024 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
41025 p.fireEvent("select", this, this.value);
41031 Roo.log('picker set value');
41032 Roo.log(this.getValue());
41033 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
41034 m.show(this.el, 'tl-bl?');
41035 ignorehide = false;
41036 // this will trigger hideMonthPicker..
41039 // hidden the day picker
41040 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
41046 p.showMonthPicker.defer(100, p);
41052 beforeBlur : function(){
41053 var v = this.parseDate(this.getRawValue());
41059 /** @cfg {Boolean} grow @hide */
41060 /** @cfg {Number} growMin @hide */
41061 /** @cfg {Number} growMax @hide */
41068 * Ext JS Library 1.1.1
41069 * Copyright(c) 2006-2007, Ext JS, LLC.
41071 * Originally Released Under LGPL - original licence link has changed is not relivant.
41074 * <script type="text/javascript">
41079 * @class Roo.form.ComboBox
41080 * @extends Roo.form.TriggerField
41081 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
41083 * Create a new ComboBox.
41084 * @param {Object} config Configuration options
41086 Roo.form.ComboBox = function(config){
41087 Roo.form.ComboBox.superclass.constructor.call(this, config);
41091 * Fires when the dropdown list is expanded
41092 * @param {Roo.form.ComboBox} combo This combo box
41097 * Fires when the dropdown list is collapsed
41098 * @param {Roo.form.ComboBox} combo This combo box
41102 * @event beforeselect
41103 * Fires before a list item is selected. Return false to cancel the selection.
41104 * @param {Roo.form.ComboBox} combo This combo box
41105 * @param {Roo.data.Record} record The data record returned from the underlying store
41106 * @param {Number} index The index of the selected item in the dropdown list
41108 'beforeselect' : true,
41111 * Fires when a list item is selected
41112 * @param {Roo.form.ComboBox} combo This combo box
41113 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
41114 * @param {Number} index The index of the selected item in the dropdown list
41118 * @event beforequery
41119 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
41120 * The event object passed has these properties:
41121 * @param {Roo.form.ComboBox} combo This combo box
41122 * @param {String} query The query
41123 * @param {Boolean} forceAll true to force "all" query
41124 * @param {Boolean} cancel true to cancel the query
41125 * @param {Object} e The query event object
41127 'beforequery': true,
41130 * Fires when the 'add' icon is pressed (add a listener to enable add button)
41131 * @param {Roo.form.ComboBox} combo This combo box
41136 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
41137 * @param {Roo.form.ComboBox} combo This combo box
41138 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
41144 if(this.transform){
41145 this.allowDomMove = false;
41146 var s = Roo.getDom(this.transform);
41147 if(!this.hiddenName){
41148 this.hiddenName = s.name;
41151 this.mode = 'local';
41152 var d = [], opts = s.options;
41153 for(var i = 0, len = opts.length;i < len; i++){
41155 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41157 this.value = value;
41159 d.push([value, o.text]);
41161 this.store = new Roo.data.SimpleStore({
41163 fields: ['value', 'text'],
41166 this.valueField = 'value';
41167 this.displayField = 'text';
41169 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41170 if(!this.lazyRender){
41171 this.target = true;
41172 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41173 s.parentNode.removeChild(s); // remove it
41174 this.render(this.el.parentNode);
41176 s.parentNode.removeChild(s); // remove it
41181 this.store = Roo.factory(this.store, Roo.data);
41184 this.selectedIndex = -1;
41185 if(this.mode == 'local'){
41186 if(config.queryDelay === undefined){
41187 this.queryDelay = 10;
41189 if(config.minChars === undefined){
41195 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41197 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41200 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41201 * rendering into an Roo.Editor, defaults to false)
41204 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41205 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41208 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41211 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41212 * the dropdown list (defaults to undefined, with no header element)
41216 * @cfg {String/Roo.Template} tpl The template to use to render the output
41220 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41222 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41224 listWidth: undefined,
41226 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41227 * mode = 'remote' or 'text' if mode = 'local')
41229 displayField: undefined,
41231 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41232 * mode = 'remote' or 'value' if mode = 'local').
41233 * Note: use of a valueField requires the user make a selection
41234 * in order for a value to be mapped.
41236 valueField: undefined,
41240 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41241 * field's data value (defaults to the underlying DOM element's name)
41243 hiddenName: undefined,
41245 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41249 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41251 selectedClass: 'x-combo-selected',
41253 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41254 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41255 * which displays a downward arrow icon).
41257 triggerClass : 'x-form-arrow-trigger',
41259 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41263 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41264 * anchor positions (defaults to 'tl-bl')
41266 listAlign: 'tl-bl?',
41268 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41272 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41273 * query specified by the allQuery config option (defaults to 'query')
41275 triggerAction: 'query',
41277 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41278 * (defaults to 4, does not apply if editable = false)
41282 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41283 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41287 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41288 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41292 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41293 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41297 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41298 * when editable = true (defaults to false)
41300 selectOnFocus:false,
41302 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41304 queryParam: 'query',
41306 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41307 * when mode = 'remote' (defaults to 'Loading...')
41309 loadingText: 'Loading...',
41311 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41315 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41319 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41320 * traditional select (defaults to true)
41324 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41328 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41332 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41333 * listWidth has a higher value)
41337 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41338 * allow the user to set arbitrary text into the field (defaults to false)
41340 forceSelection:false,
41342 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41343 * if typeAhead = true (defaults to 250)
41345 typeAheadDelay : 250,
41347 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41348 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41350 valueNotFoundText : undefined,
41352 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41354 blockFocus : false,
41357 * @cfg {Boolean} disableClear Disable showing of clear button.
41359 disableClear : false,
41361 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41363 alwaysQuery : false,
41369 // element that contains real text value.. (when hidden is used..)
41372 onRender : function(ct, position)
41374 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41376 if(this.hiddenName){
41377 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41379 this.hiddenField.value =
41380 this.hiddenValue !== undefined ? this.hiddenValue :
41381 this.value !== undefined ? this.value : '';
41383 // prevent input submission
41384 this.el.dom.removeAttribute('name');
41390 this.el.dom.setAttribute('autocomplete', 'off');
41393 var cls = 'x-combo-list';
41395 this.list = new Roo.Layer({
41396 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41399 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41400 this.list.setWidth(lw);
41401 this.list.swallowEvent('mousewheel');
41402 this.assetHeight = 0;
41405 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41406 this.assetHeight += this.header.getHeight();
41409 this.innerList = this.list.createChild({cls:cls+'-inner'});
41410 this.innerList.on('mouseover', this.onViewOver, this);
41411 this.innerList.on('mousemove', this.onViewMove, this);
41412 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41414 if(this.allowBlank && !this.pageSize && !this.disableClear){
41415 this.footer = this.list.createChild({cls:cls+'-ft'});
41416 this.pageTb = new Roo.Toolbar(this.footer);
41420 this.footer = this.list.createChild({cls:cls+'-ft'});
41421 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41422 {pageSize: this.pageSize});
41426 if (this.pageTb && this.allowBlank && !this.disableClear) {
41428 this.pageTb.add(new Roo.Toolbar.Fill(), {
41429 cls: 'x-btn-icon x-btn-clear',
41431 handler: function()
41434 _this.clearValue();
41435 _this.onSelect(false, -1);
41440 this.assetHeight += this.footer.getHeight();
41445 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41448 this.view = new Roo.View(this.innerList, this.tpl, {
41451 selectedClass: this.selectedClass
41454 this.view.on('click', this.onViewClick, this);
41456 this.store.on('beforeload', this.onBeforeLoad, this);
41457 this.store.on('load', this.onLoad, this);
41458 this.store.on('loadexception', this.onLoadException, this);
41460 if(this.resizable){
41461 this.resizer = new Roo.Resizable(this.list, {
41462 pinned:true, handles:'se'
41464 this.resizer.on('resize', function(r, w, h){
41465 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41466 this.listWidth = w;
41467 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41468 this.restrictHeight();
41470 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41472 if(!this.editable){
41473 this.editable = true;
41474 this.setEditable(false);
41478 if (typeof(this.events.add.listeners) != 'undefined') {
41480 this.addicon = this.wrap.createChild(
41481 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41483 this.addicon.on('click', function(e) {
41484 this.fireEvent('add', this);
41487 if (typeof(this.events.edit.listeners) != 'undefined') {
41489 this.editicon = this.wrap.createChild(
41490 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41491 if (this.addicon) {
41492 this.editicon.setStyle('margin-left', '40px');
41494 this.editicon.on('click', function(e) {
41496 // we fire even if inothing is selected..
41497 this.fireEvent('edit', this, this.lastData );
41507 initEvents : function(){
41508 Roo.form.ComboBox.superclass.initEvents.call(this);
41510 this.keyNav = new Roo.KeyNav(this.el, {
41511 "up" : function(e){
41512 this.inKeyMode = true;
41516 "down" : function(e){
41517 if(!this.isExpanded()){
41518 this.onTriggerClick();
41520 this.inKeyMode = true;
41525 "enter" : function(e){
41526 this.onViewClick();
41530 "esc" : function(e){
41534 "tab" : function(e){
41535 this.onViewClick(false);
41536 this.fireEvent("specialkey", this, e);
41542 doRelay : function(foo, bar, hname){
41543 if(hname == 'down' || this.scope.isExpanded()){
41544 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41551 this.queryDelay = Math.max(this.queryDelay || 10,
41552 this.mode == 'local' ? 10 : 250);
41553 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41554 if(this.typeAhead){
41555 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41557 if(this.editable !== false){
41558 this.el.on("keyup", this.onKeyUp, this);
41560 if(this.forceSelection){
41561 this.on('blur', this.doForce, this);
41565 onDestroy : function(){
41567 this.view.setStore(null);
41568 this.view.el.removeAllListeners();
41569 this.view.el.remove();
41570 this.view.purgeListeners();
41573 this.list.destroy();
41576 this.store.un('beforeload', this.onBeforeLoad, this);
41577 this.store.un('load', this.onLoad, this);
41578 this.store.un('loadexception', this.onLoadException, this);
41580 Roo.form.ComboBox.superclass.onDestroy.call(this);
41584 fireKey : function(e){
41585 if(e.isNavKeyPress() && !this.list.isVisible()){
41586 this.fireEvent("specialkey", this, e);
41591 onResize: function(w, h){
41592 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41594 if(typeof w != 'number'){
41595 // we do not handle it!?!?
41598 var tw = this.trigger.getWidth();
41599 tw += this.addicon ? this.addicon.getWidth() : 0;
41600 tw += this.editicon ? this.editicon.getWidth() : 0;
41602 this.el.setWidth( this.adjustWidth('input', x));
41604 this.trigger.setStyle('left', x+'px');
41606 if(this.list && this.listWidth === undefined){
41607 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41608 this.list.setWidth(lw);
41609 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41617 * Allow or prevent the user from directly editing the field text. If false is passed,
41618 * the user will only be able to select from the items defined in the dropdown list. This method
41619 * is the runtime equivalent of setting the 'editable' config option at config time.
41620 * @param {Boolean} value True to allow the user to directly edit the field text
41622 setEditable : function(value){
41623 if(value == this.editable){
41626 this.editable = value;
41628 this.el.dom.setAttribute('readOnly', true);
41629 this.el.on('mousedown', this.onTriggerClick, this);
41630 this.el.addClass('x-combo-noedit');
41632 this.el.dom.setAttribute('readOnly', false);
41633 this.el.un('mousedown', this.onTriggerClick, this);
41634 this.el.removeClass('x-combo-noedit');
41639 onBeforeLoad : function(){
41640 if(!this.hasFocus){
41643 this.innerList.update(this.loadingText ?
41644 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41645 this.restrictHeight();
41646 this.selectedIndex = -1;
41650 onLoad : function(){
41651 if(!this.hasFocus){
41654 if(this.store.getCount() > 0){
41656 this.restrictHeight();
41657 if(this.lastQuery == this.allQuery){
41659 this.el.dom.select();
41661 if(!this.selectByValue(this.value, true)){
41662 this.select(0, true);
41666 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41667 this.taTask.delay(this.typeAheadDelay);
41671 this.onEmptyResults();
41676 onLoadException : function()
41679 Roo.log(this.store.reader.jsonData);
41680 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41681 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41687 onTypeAhead : function(){
41688 if(this.store.getCount() > 0){
41689 var r = this.store.getAt(0);
41690 var newValue = r.data[this.displayField];
41691 var len = newValue.length;
41692 var selStart = this.getRawValue().length;
41693 if(selStart != len){
41694 this.setRawValue(newValue);
41695 this.selectText(selStart, newValue.length);
41701 onSelect : function(record, index){
41702 if(this.fireEvent('beforeselect', this, record, index) !== false){
41703 this.setFromData(index > -1 ? record.data : false);
41705 this.fireEvent('select', this, record, index);
41710 * Returns the currently selected field value or empty string if no value is set.
41711 * @return {String} value The selected value
41713 getValue : function(){
41714 if(this.valueField){
41715 return typeof this.value != 'undefined' ? this.value : '';
41717 return Roo.form.ComboBox.superclass.getValue.call(this);
41721 * Clears any text/value currently set in the field
41723 clearValue : function(){
41724 if(this.hiddenField){
41725 this.hiddenField.value = '';
41728 this.setRawValue('');
41729 this.lastSelectionText = '';
41734 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41735 * will be displayed in the field. If the value does not match the data value of an existing item,
41736 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41737 * Otherwise the field will be blank (although the value will still be set).
41738 * @param {String} value The value to match
41740 setValue : function(v){
41742 if(this.valueField){
41743 var r = this.findRecord(this.valueField, v);
41745 text = r.data[this.displayField];
41746 }else if(this.valueNotFoundText !== undefined){
41747 text = this.valueNotFoundText;
41750 this.lastSelectionText = text;
41751 if(this.hiddenField){
41752 this.hiddenField.value = v;
41754 Roo.form.ComboBox.superclass.setValue.call(this, text);
41758 * @property {Object} the last set data for the element
41763 * Sets the value of the field based on a object which is related to the record format for the store.
41764 * @param {Object} value the value to set as. or false on reset?
41766 setFromData : function(o){
41767 var dv = ''; // display value
41768 var vv = ''; // value value..
41770 if (this.displayField) {
41771 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41773 // this is an error condition!!!
41774 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41777 if(this.valueField){
41778 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41780 if(this.hiddenField){
41781 this.hiddenField.value = vv;
41783 this.lastSelectionText = dv;
41784 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41788 // no hidden field.. - we store the value in 'value', but still display
41789 // display field!!!!
41790 this.lastSelectionText = dv;
41791 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41797 reset : function(){
41798 // overridden so that last data is reset..
41799 this.setValue(this.resetValue);
41800 this.originalValue = this.getValue();
41801 this.clearInvalid();
41802 this.lastData = false;
41804 this.view.clearSelections();
41808 findRecord : function(prop, value){
41810 if(this.store.getCount() > 0){
41811 this.store.each(function(r){
41812 if(r.data[prop] == value){
41822 getName: function()
41824 // returns hidden if it's set..
41825 if (!this.rendered) {return ''};
41826 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41830 onViewMove : function(e, t){
41831 this.inKeyMode = false;
41835 onViewOver : function(e, t){
41836 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41839 var item = this.view.findItemFromChild(t);
41841 var index = this.view.indexOf(item);
41842 this.select(index, false);
41847 onViewClick : function(doFocus)
41849 var index = this.view.getSelectedIndexes()[0];
41850 var r = this.store.getAt(index);
41852 this.onSelect(r, index);
41854 if(doFocus !== false && !this.blockFocus){
41860 restrictHeight : function(){
41861 this.innerList.dom.style.height = '';
41862 var inner = this.innerList.dom;
41863 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41864 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41865 this.list.beginUpdate();
41866 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41867 this.list.alignTo(this.el, this.listAlign);
41868 this.list.endUpdate();
41872 onEmptyResults : function(){
41877 * Returns true if the dropdown list is expanded, else false.
41879 isExpanded : function(){
41880 return this.list.isVisible();
41884 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41885 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41886 * @param {String} value The data value of the item to select
41887 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41888 * selected item if it is not currently in view (defaults to true)
41889 * @return {Boolean} True if the value matched an item in the list, else false
41891 selectByValue : function(v, scrollIntoView){
41892 if(v !== undefined && v !== null){
41893 var r = this.findRecord(this.valueField || this.displayField, v);
41895 this.select(this.store.indexOf(r), scrollIntoView);
41903 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41904 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41905 * @param {Number} index The zero-based index of the list item to select
41906 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41907 * selected item if it is not currently in view (defaults to true)
41909 select : function(index, scrollIntoView){
41910 this.selectedIndex = index;
41911 this.view.select(index);
41912 if(scrollIntoView !== false){
41913 var el = this.view.getNode(index);
41915 this.innerList.scrollChildIntoView(el, false);
41921 selectNext : function(){
41922 var ct = this.store.getCount();
41924 if(this.selectedIndex == -1){
41926 }else if(this.selectedIndex < ct-1){
41927 this.select(this.selectedIndex+1);
41933 selectPrev : function(){
41934 var ct = this.store.getCount();
41936 if(this.selectedIndex == -1){
41938 }else if(this.selectedIndex != 0){
41939 this.select(this.selectedIndex-1);
41945 onKeyUp : function(e){
41946 if(this.editable !== false && !e.isSpecialKey()){
41947 this.lastKey = e.getKey();
41948 this.dqTask.delay(this.queryDelay);
41953 validateBlur : function(){
41954 return !this.list || !this.list.isVisible();
41958 initQuery : function(){
41959 this.doQuery(this.getRawValue());
41963 doForce : function(){
41964 if(this.el.dom.value.length > 0){
41965 this.el.dom.value =
41966 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41972 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41973 * query allowing the query action to be canceled if needed.
41974 * @param {String} query The SQL query to execute
41975 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41976 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41977 * saved in the current store (defaults to false)
41979 doQuery : function(q, forceAll){
41980 if(q === undefined || q === null){
41985 forceAll: forceAll,
41989 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41993 forceAll = qe.forceAll;
41994 if(forceAll === true || (q.length >= this.minChars)){
41995 if(this.lastQuery != q || this.alwaysQuery){
41996 this.lastQuery = q;
41997 if(this.mode == 'local'){
41998 this.selectedIndex = -1;
42000 this.store.clearFilter();
42002 this.store.filter(this.displayField, q);
42006 this.store.baseParams[this.queryParam] = q;
42008 params: this.getParams(q)
42013 this.selectedIndex = -1;
42020 getParams : function(q){
42022 //p[this.queryParam] = q;
42025 p.limit = this.pageSize;
42031 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
42033 collapse : function(){
42034 if(!this.isExpanded()){
42038 Roo.get(document).un('mousedown', this.collapseIf, this);
42039 Roo.get(document).un('mousewheel', this.collapseIf, this);
42040 if (!this.editable) {
42041 Roo.get(document).un('keydown', this.listKeyPress, this);
42043 this.fireEvent('collapse', this);
42047 collapseIf : function(e){
42048 if(!e.within(this.wrap) && !e.within(this.list)){
42054 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
42056 expand : function(){
42057 if(this.isExpanded() || !this.hasFocus){
42060 this.list.alignTo(this.el, this.listAlign);
42062 Roo.get(document).on('mousedown', this.collapseIf, this);
42063 Roo.get(document).on('mousewheel', this.collapseIf, this);
42064 if (!this.editable) {
42065 Roo.get(document).on('keydown', this.listKeyPress, this);
42068 this.fireEvent('expand', this);
42072 // Implements the default empty TriggerField.onTriggerClick function
42073 onTriggerClick : function(){
42077 if(this.isExpanded()){
42079 if (!this.blockFocus) {
42084 this.hasFocus = true;
42085 if(this.triggerAction == 'all') {
42086 this.doQuery(this.allQuery, true);
42088 this.doQuery(this.getRawValue());
42090 if (!this.blockFocus) {
42095 listKeyPress : function(e)
42097 //Roo.log('listkeypress');
42098 // scroll to first matching element based on key pres..
42099 if (e.isSpecialKey()) {
42102 var k = String.fromCharCode(e.getKey()).toUpperCase();
42105 var csel = this.view.getSelectedNodes();
42106 var cselitem = false;
42108 var ix = this.view.indexOf(csel[0]);
42109 cselitem = this.store.getAt(ix);
42110 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
42116 this.store.each(function(v) {
42118 // start at existing selection.
42119 if (cselitem.id == v.id) {
42125 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
42126 match = this.store.indexOf(v);
42131 if (match === false) {
42132 return true; // no more action?
42135 this.view.select(match);
42136 var sn = Roo.get(this.view.getSelectedNodes()[0]);
42137 sn.scrollIntoView(sn.dom.parentNode, false);
42141 * @cfg {Boolean} grow
42145 * @cfg {Number} growMin
42149 * @cfg {Number} growMax
42157 * Copyright(c) 2010-2012, Roo J Solutions Limited
42164 * @class Roo.form.ComboBoxArray
42165 * @extends Roo.form.TextField
42166 * A facebook style adder... for lists of email / people / countries etc...
42167 * pick multiple items from a combo box, and shows each one.
42169 * Fred [x] Brian [x] [Pick another |v]
42172 * For this to work: it needs various extra information
42173 * - normal combo problay has
42175 * + displayField, valueField
42177 * For our purpose...
42180 * If we change from 'extends' to wrapping...
42187 * Create a new ComboBoxArray.
42188 * @param {Object} config Configuration options
42192 Roo.form.ComboBoxArray = function(config)
42196 * @event beforeremove
42197 * Fires before remove the value from the list
42198 * @param {Roo.form.ComboBoxArray} _self This combo box array
42199 * @param {Roo.form.ComboBoxArray.Item} item removed item
42201 'beforeremove' : true,
42204 * Fires when remove the value from the list
42205 * @param {Roo.form.ComboBoxArray} _self This combo box array
42206 * @param {Roo.form.ComboBoxArray.Item} item removed item
42213 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42215 this.items = new Roo.util.MixedCollection(false);
42217 // construct the child combo...
42227 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42230 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42235 // behavies liek a hiddne field
42236 inputType: 'hidden',
42238 * @cfg {Number} width The width of the box that displays the selected element
42245 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42249 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42251 hiddenName : false,
42254 // private the array of items that are displayed..
42256 // private - the hidden field el.
42258 // private - the filed el..
42261 //validateValue : function() { return true; }, // all values are ok!
42262 //onAddClick: function() { },
42264 onRender : function(ct, position)
42267 // create the standard hidden element
42268 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42271 // give fake names to child combo;
42272 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42273 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
42275 this.combo = Roo.factory(this.combo, Roo.form);
42276 this.combo.onRender(ct, position);
42277 if (typeof(this.combo.width) != 'undefined') {
42278 this.combo.onResize(this.combo.width,0);
42281 this.combo.initEvents();
42283 // assigned so form know we need to do this..
42284 this.store = this.combo.store;
42285 this.valueField = this.combo.valueField;
42286 this.displayField = this.combo.displayField ;
42289 this.combo.wrap.addClass('x-cbarray-grp');
42291 var cbwrap = this.combo.wrap.createChild(
42292 {tag: 'div', cls: 'x-cbarray-cb'},
42297 this.hiddenEl = this.combo.wrap.createChild({
42298 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42300 this.el = this.combo.wrap.createChild({
42301 tag: 'input', type:'hidden' , name: this.name, value : ''
42303 // this.el.dom.removeAttribute("name");
42306 this.outerWrap = this.combo.wrap;
42307 this.wrap = cbwrap;
42309 this.outerWrap.setWidth(this.width);
42310 this.outerWrap.dom.removeChild(this.el.dom);
42312 this.wrap.dom.appendChild(this.el.dom);
42313 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42314 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42316 this.combo.trigger.setStyle('position','relative');
42317 this.combo.trigger.setStyle('left', '0px');
42318 this.combo.trigger.setStyle('top', '2px');
42320 this.combo.el.setStyle('vertical-align', 'text-bottom');
42322 //this.trigger.setStyle('vertical-align', 'top');
42324 // this should use the code from combo really... on('add' ....)
42328 this.adder = this.outerWrap.createChild(
42329 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42331 this.adder.on('click', function(e) {
42332 _t.fireEvent('adderclick', this, e);
42336 //this.adder.on('click', this.onAddClick, _t);
42339 this.combo.on('select', function(cb, rec, ix) {
42340 this.addItem(rec.data);
42343 cb.el.dom.value = '';
42344 //cb.lastData = rec.data;
42353 getName: function()
42355 // returns hidden if it's set..
42356 if (!this.rendered) {return ''};
42357 return this.hiddenName ? this.hiddenName : this.name;
42362 onResize: function(w, h){
42365 // not sure if this is needed..
42366 //this.combo.onResize(w,h);
42368 if(typeof w != 'number'){
42369 // we do not handle it!?!?
42372 var tw = this.combo.trigger.getWidth();
42373 tw += this.addicon ? this.addicon.getWidth() : 0;
42374 tw += this.editicon ? this.editicon.getWidth() : 0;
42376 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42378 this.combo.trigger.setStyle('left', '0px');
42380 if(this.list && this.listWidth === undefined){
42381 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42382 this.list.setWidth(lw);
42383 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42390 addItem: function(rec)
42392 var valueField = this.combo.valueField;
42393 var displayField = this.combo.displayField;
42395 if (this.items.indexOfKey(rec[valueField]) > -1) {
42396 //console.log("GOT " + rec.data.id);
42400 var x = new Roo.form.ComboBoxArray.Item({
42401 //id : rec[this.idField],
42403 displayField : displayField ,
42404 tipField : displayField ,
42408 this.items.add(rec[valueField],x);
42409 // add it before the element..
42410 this.updateHiddenEl();
42411 x.render(this.outerWrap, this.wrap.dom);
42412 // add the image handler..
42415 updateHiddenEl : function()
42418 if (!this.hiddenEl) {
42422 var idField = this.combo.valueField;
42424 this.items.each(function(f) {
42425 ar.push(f.data[idField]);
42427 this.hiddenEl.dom.value = ar.join(',');
42433 this.items.clear();
42435 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42439 this.el.dom.value = '';
42440 if (this.hiddenEl) {
42441 this.hiddenEl.dom.value = '';
42445 getValue: function()
42447 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42449 setValue: function(v) // not a valid action - must use addItems..
42454 if (this.store.isLocal && (typeof(v) == 'string')) {
42455 // then we can use the store to find the values..
42456 // comma seperated at present.. this needs to allow JSON based encoding..
42457 this.hiddenEl.value = v;
42459 Roo.each(v.split(','), function(k) {
42460 Roo.log("CHECK " + this.valueField + ',' + k);
42461 var li = this.store.query(this.valueField, k);
42466 add[this.valueField] = k;
42467 add[this.displayField] = li.item(0).data[this.displayField];
42473 if (typeof(v) == 'object' ) {
42474 // then let's assume it's an array of objects..
42475 Roo.each(v, function(l) {
42483 setFromData: function(v)
42485 // this recieves an object, if setValues is called.
42487 this.el.dom.value = v[this.displayField];
42488 this.hiddenEl.dom.value = v[this.valueField];
42489 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42492 var kv = v[this.valueField];
42493 var dv = v[this.displayField];
42494 kv = typeof(kv) != 'string' ? '' : kv;
42495 dv = typeof(dv) != 'string' ? '' : dv;
42498 var keys = kv.split(',');
42499 var display = dv.split(',');
42500 for (var i = 0 ; i < keys.length; i++) {
42503 add[this.valueField] = keys[i];
42504 add[this.displayField] = display[i];
42512 * Validates the combox array value
42513 * @return {Boolean} True if the value is valid, else false
42515 validate : function(){
42516 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42517 this.clearInvalid();
42523 validateValue : function(value){
42524 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42532 isDirty : function() {
42533 if(this.disabled) {
42538 var d = Roo.decode(String(this.originalValue));
42540 return String(this.getValue()) !== String(this.originalValue);
42543 var originalValue = [];
42545 for (var i = 0; i < d.length; i++){
42546 originalValue.push(d[i][this.valueField]);
42549 return String(this.getValue()) !== String(originalValue.join(','));
42558 * @class Roo.form.ComboBoxArray.Item
42559 * @extends Roo.BoxComponent
42560 * A selected item in the list
42561 * Fred [x] Brian [x] [Pick another |v]
42564 * Create a new item.
42565 * @param {Object} config Configuration options
42568 Roo.form.ComboBoxArray.Item = function(config) {
42569 config.id = Roo.id();
42570 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42573 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42576 displayField : false,
42580 defaultAutoCreate : {
42582 cls: 'x-cbarray-item',
42589 src : Roo.BLANK_IMAGE_URL ,
42597 onRender : function(ct, position)
42599 Roo.form.Field.superclass.onRender.call(this, ct, position);
42602 var cfg = this.getAutoCreate();
42603 this.el = ct.createChild(cfg, position);
42606 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42608 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42609 this.cb.renderer(this.data) :
42610 String.format('{0}',this.data[this.displayField]);
42613 this.el.child('div').dom.setAttribute('qtip',
42614 String.format('{0}',this.data[this.tipField])
42617 this.el.child('img').on('click', this.remove, this);
42621 remove : function()
42623 if(this.cb.disabled){
42627 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42628 this.cb.items.remove(this);
42629 this.el.child('img').un('click', this.remove, this);
42631 this.cb.updateHiddenEl();
42633 this.cb.fireEvent('remove', this.cb, this);
42639 * Ext JS Library 1.1.1
42640 * Copyright(c) 2006-2007, Ext JS, LLC.
42642 * Originally Released Under LGPL - original licence link has changed is not relivant.
42645 * <script type="text/javascript">
42648 * @class Roo.form.Checkbox
42649 * @extends Roo.form.Field
42650 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42652 * Creates a new Checkbox
42653 * @param {Object} config Configuration options
42655 Roo.form.Checkbox = function(config){
42656 Roo.form.Checkbox.superclass.constructor.call(this, config);
42660 * Fires when the checkbox is checked or unchecked.
42661 * @param {Roo.form.Checkbox} this This checkbox
42662 * @param {Boolean} checked The new checked value
42668 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42670 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42672 focusClass : undefined,
42674 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42676 fieldClass: "x-form-field",
42678 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42682 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42683 * {tag: "input", type: "checkbox", autocomplete: "off"})
42685 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42687 * @cfg {String} boxLabel The text that appears beside the checkbox
42691 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42695 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42697 valueOff: '0', // value when not checked..
42699 actionMode : 'viewEl',
42702 itemCls : 'x-menu-check-item x-form-item',
42703 groupClass : 'x-menu-group-item',
42704 inputType : 'hidden',
42707 inSetChecked: false, // check that we are not calling self...
42709 inputElement: false, // real input element?
42710 basedOn: false, // ????
42712 isFormField: true, // not sure where this is needed!!!!
42714 onResize : function(){
42715 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42716 if(!this.boxLabel){
42717 this.el.alignTo(this.wrap, 'c-c');
42721 initEvents : function(){
42722 Roo.form.Checkbox.superclass.initEvents.call(this);
42723 this.el.on("click", this.onClick, this);
42724 this.el.on("change", this.onClick, this);
42728 getResizeEl : function(){
42732 getPositionEl : function(){
42737 onRender : function(ct, position){
42738 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42740 if(this.inputValue !== undefined){
42741 this.el.dom.value = this.inputValue;
42744 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42745 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42746 var viewEl = this.wrap.createChild({
42747 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42748 this.viewEl = viewEl;
42749 this.wrap.on('click', this.onClick, this);
42751 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42752 this.el.on('propertychange', this.setFromHidden, this); //ie
42757 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42758 // viewEl.on('click', this.onClick, this);
42760 //if(this.checked){
42761 this.setChecked(this.checked);
42763 //this.checked = this.el.dom;
42769 initValue : Roo.emptyFn,
42772 * Returns the checked state of the checkbox.
42773 * @return {Boolean} True if checked, else false
42775 getValue : function(){
42777 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42779 return this.valueOff;
42784 onClick : function(){
42785 if (this.disabled) {
42788 this.setChecked(!this.checked);
42790 //if(this.el.dom.checked != this.checked){
42791 // this.setValue(this.el.dom.checked);
42796 * Sets the checked state of the checkbox.
42797 * On is always based on a string comparison between inputValue and the param.
42798 * @param {Boolean/String} value - the value to set
42799 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42801 setValue : function(v,suppressEvent){
42804 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42805 //if(this.el && this.el.dom){
42806 // this.el.dom.checked = this.checked;
42807 // this.el.dom.defaultChecked = this.checked;
42809 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42810 //this.fireEvent("check", this, this.checked);
42813 setChecked : function(state,suppressEvent)
42815 if (this.inSetChecked) {
42816 this.checked = state;
42822 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42824 this.checked = state;
42825 if(suppressEvent !== true){
42826 this.fireEvent('check', this, state);
42828 this.inSetChecked = true;
42829 this.el.dom.value = state ? this.inputValue : this.valueOff;
42830 this.inSetChecked = false;
42833 // handle setting of hidden value by some other method!!?!?
42834 setFromHidden: function()
42839 //console.log("SET FROM HIDDEN");
42840 //alert('setFrom hidden');
42841 this.setValue(this.el.dom.value);
42844 onDestroy : function()
42847 Roo.get(this.viewEl).remove();
42850 Roo.form.Checkbox.superclass.onDestroy.call(this);
42853 setBoxLabel : function(str)
42855 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42860 * Ext JS Library 1.1.1
42861 * Copyright(c) 2006-2007, Ext JS, LLC.
42863 * Originally Released Under LGPL - original licence link has changed is not relivant.
42866 * <script type="text/javascript">
42870 * @class Roo.form.Radio
42871 * @extends Roo.form.Checkbox
42872 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42873 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42875 * Creates a new Radio
42876 * @param {Object} config Configuration options
42878 Roo.form.Radio = function(){
42879 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42881 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42882 inputType: 'radio',
42885 * If this radio is part of a group, it will return the selected value
42888 getGroupValue : function(){
42889 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42893 onRender : function(ct, position){
42894 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42896 if(this.inputValue !== undefined){
42897 this.el.dom.value = this.inputValue;
42900 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42901 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42902 //var viewEl = this.wrap.createChild({
42903 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42904 //this.viewEl = viewEl;
42905 //this.wrap.on('click', this.onClick, this);
42907 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42908 //this.el.on('propertychange', this.setFromHidden, this); //ie
42913 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42914 // viewEl.on('click', this.onClick, this);
42917 this.el.dom.checked = 'checked' ;
42923 });//<script type="text/javascript">
42926 * Based Ext JS Library 1.1.1
42927 * Copyright(c) 2006-2007, Ext JS, LLC.
42933 * @class Roo.HtmlEditorCore
42934 * @extends Roo.Component
42935 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42937 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42940 Roo.HtmlEditorCore = function(config){
42943 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42948 * @event initialize
42949 * Fires when the editor is fully initialized (including the iframe)
42950 * @param {Roo.HtmlEditorCore} this
42955 * Fires when the editor is first receives the focus. Any insertion must wait
42956 * until after this event.
42957 * @param {Roo.HtmlEditorCore} this
42961 * @event beforesync
42962 * Fires before the textarea is updated with content from the editor iframe. Return false
42963 * to cancel the sync.
42964 * @param {Roo.HtmlEditorCore} this
42965 * @param {String} html
42969 * @event beforepush
42970 * Fires before the iframe editor is updated with content from the textarea. Return false
42971 * to cancel the push.
42972 * @param {Roo.HtmlEditorCore} this
42973 * @param {String} html
42978 * Fires when the textarea is updated with content from the editor iframe.
42979 * @param {Roo.HtmlEditorCore} this
42980 * @param {String} html
42985 * Fires when the iframe editor is updated with content from the textarea.
42986 * @param {Roo.HtmlEditorCore} this
42987 * @param {String} html
42992 * @event editorevent
42993 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42994 * @param {Roo.HtmlEditorCore} this
43000 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
43002 // defaults : white / black...
43003 this.applyBlacklists();
43010 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
43014 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
43020 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
43025 * @cfg {Number} height (in pixels)
43029 * @cfg {Number} width (in pixels)
43034 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
43037 stylesheets: false,
43042 // private properties
43043 validationEvent : false,
43045 initialized : false,
43047 sourceEditMode : false,
43048 onFocus : Roo.emptyFn,
43050 hideMode:'offsets',
43054 // blacklist + whitelisted elements..
43061 * Protected method that will not generally be called directly. It
43062 * is called when the editor initializes the iframe with HTML contents. Override this method if you
43063 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
43065 getDocMarkup : function(){
43069 // inherit styels from page...??
43070 if (this.stylesheets === false) {
43072 Roo.get(document.head).select('style').each(function(node) {
43073 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43076 Roo.get(document.head).select('link').each(function(node) {
43077 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43080 } else if (!this.stylesheets.length) {
43082 st = '<style type="text/css">' +
43083 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43086 st = '<style type="text/css">' +
43091 st += '<style type="text/css">' +
43092 'IMG { cursor: pointer } ' +
43095 var cls = 'roo-htmleditor-body';
43097 if(this.bodyCls.length){
43098 cls += ' ' + this.bodyCls;
43101 return '<html><head>' + st +
43102 //<style type="text/css">' +
43103 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43105 ' </head><body class="' + cls + '"></body></html>';
43109 onRender : function(ct, position)
43112 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
43113 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
43116 this.el.dom.style.border = '0 none';
43117 this.el.dom.setAttribute('tabIndex', -1);
43118 this.el.addClass('x-hidden hide');
43122 if(Roo.isIE){ // fix IE 1px bogus margin
43123 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
43127 this.frameId = Roo.id();
43131 var iframe = this.owner.wrap.createChild({
43133 cls: 'form-control', // bootstrap..
43135 name: this.frameId,
43136 frameBorder : 'no',
43137 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
43142 this.iframe = iframe.dom;
43144 this.assignDocWin();
43146 this.doc.designMode = 'on';
43149 this.doc.write(this.getDocMarkup());
43153 var task = { // must defer to wait for browser to be ready
43155 //console.log("run task?" + this.doc.readyState);
43156 this.assignDocWin();
43157 if(this.doc.body || this.doc.readyState == 'complete'){
43159 this.doc.designMode="on";
43163 Roo.TaskMgr.stop(task);
43164 this.initEditor.defer(10, this);
43171 Roo.TaskMgr.start(task);
43176 onResize : function(w, h)
43178 Roo.log('resize: ' +w + ',' + h );
43179 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43183 if(typeof w == 'number'){
43185 this.iframe.style.width = w + 'px';
43187 if(typeof h == 'number'){
43189 this.iframe.style.height = h + 'px';
43191 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43198 * Toggles the editor between standard and source edit mode.
43199 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43201 toggleSourceEdit : function(sourceEditMode){
43203 this.sourceEditMode = sourceEditMode === true;
43205 if(this.sourceEditMode){
43207 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43210 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43211 //this.iframe.className = '';
43214 //this.setSize(this.owner.wrap.getSize());
43215 //this.fireEvent('editmodechange', this, this.sourceEditMode);
43222 * Protected method that will not generally be called directly. If you need/want
43223 * custom HTML cleanup, this is the method you should override.
43224 * @param {String} html The HTML to be cleaned
43225 * return {String} The cleaned HTML
43227 cleanHtml : function(html){
43228 html = String(html);
43229 if(html.length > 5){
43230 if(Roo.isSafari){ // strip safari nonsense
43231 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
43234 if(html == ' '){
43241 * HTML Editor -> Textarea
43242 * Protected method that will not generally be called directly. Syncs the contents
43243 * of the editor iframe with the textarea.
43245 syncValue : function(){
43246 if(this.initialized){
43247 var bd = (this.doc.body || this.doc.documentElement);
43248 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43249 var html = bd.innerHTML;
43251 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43252 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43254 html = '<div style="'+m[0]+'">' + html + '</div>';
43257 html = this.cleanHtml(html);
43258 // fix up the special chars.. normaly like back quotes in word...
43259 // however we do not want to do this with chinese..
43260 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
43262 var cc = match.charCodeAt();
43264 // Get the character value, handling surrogate pairs
43265 if (match.length == 2) {
43266 // It's a surrogate pair, calculate the Unicode code point
43267 var high = match.charCodeAt(0) - 0xD800;
43268 var low = match.charCodeAt(1) - 0xDC00;
43269 cc = (high * 0x400) + low + 0x10000;
43271 (cc >= 0x4E00 && cc < 0xA000 ) ||
43272 (cc >= 0x3400 && cc < 0x4E00 ) ||
43273 (cc >= 0xf900 && cc < 0xfb00 )
43278 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
43279 return "&#" + cc + ";";
43286 if(this.owner.fireEvent('beforesync', this, html) !== false){
43287 this.el.dom.value = html;
43288 this.owner.fireEvent('sync', this, html);
43294 * Protected method that will not generally be called directly. Pushes the value of the textarea
43295 * into the iframe editor.
43297 pushValue : function(){
43298 if(this.initialized){
43299 var v = this.el.dom.value.trim();
43301 // if(v.length < 1){
43305 if(this.owner.fireEvent('beforepush', this, v) !== false){
43306 var d = (this.doc.body || this.doc.documentElement);
43308 this.cleanUpPaste();
43309 this.el.dom.value = d.innerHTML;
43310 this.owner.fireEvent('push', this, v);
43316 deferFocus : function(){
43317 this.focus.defer(10, this);
43321 focus : function(){
43322 if(this.win && !this.sourceEditMode){
43329 assignDocWin: function()
43331 var iframe = this.iframe;
43334 this.doc = iframe.contentWindow.document;
43335 this.win = iframe.contentWindow;
43337 // if (!Roo.get(this.frameId)) {
43340 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43341 // this.win = Roo.get(this.frameId).dom.contentWindow;
43343 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43347 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43348 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43353 initEditor : function(){
43354 //console.log("INIT EDITOR");
43355 this.assignDocWin();
43359 this.doc.designMode="on";
43361 this.doc.write(this.getDocMarkup());
43364 var dbody = (this.doc.body || this.doc.documentElement);
43365 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43366 // this copies styles from the containing element into thsi one..
43367 // not sure why we need all of this..
43368 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43370 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43371 //ss['background-attachment'] = 'fixed'; // w3c
43372 dbody.bgProperties = 'fixed'; // ie
43373 //Roo.DomHelper.applyStyles(dbody, ss);
43374 Roo.EventManager.on(this.doc, {
43375 //'mousedown': this.onEditorEvent,
43376 'mouseup': this.onEditorEvent,
43377 'dblclick': this.onEditorEvent,
43378 'click': this.onEditorEvent,
43379 'keyup': this.onEditorEvent,
43384 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43386 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43387 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43389 this.initialized = true;
43391 this.owner.fireEvent('initialize', this);
43396 onDestroy : function(){
43402 //for (var i =0; i < this.toolbars.length;i++) {
43403 // // fixme - ask toolbars for heights?
43404 // this.toolbars[i].onDestroy();
43407 //this.wrap.dom.innerHTML = '';
43408 //this.wrap.remove();
43413 onFirstFocus : function(){
43415 this.assignDocWin();
43418 this.activated = true;
43421 if(Roo.isGecko){ // prevent silly gecko errors
43423 var s = this.win.getSelection();
43424 if(!s.focusNode || s.focusNode.nodeType != 3){
43425 var r = s.getRangeAt(0);
43426 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43431 this.execCmd('useCSS', true);
43432 this.execCmd('styleWithCSS', false);
43435 this.owner.fireEvent('activate', this);
43439 adjustFont: function(btn){
43440 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43441 //if(Roo.isSafari){ // safari
43444 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43445 if(Roo.isSafari){ // safari
43446 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43447 v = (v < 10) ? 10 : v;
43448 v = (v > 48) ? 48 : v;
43449 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43454 v = Math.max(1, v+adjust);
43456 this.execCmd('FontSize', v );
43459 onEditorEvent : function(e)
43461 this.owner.fireEvent('editorevent', this, e);
43462 // this.updateToolbar();
43463 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43466 insertTag : function(tg)
43468 // could be a bit smarter... -> wrap the current selected tRoo..
43469 if (tg.toLowerCase() == 'span' ||
43470 tg.toLowerCase() == 'code' ||
43471 tg.toLowerCase() == 'sup' ||
43472 tg.toLowerCase() == 'sub'
43475 range = this.createRange(this.getSelection());
43476 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43477 wrappingNode.appendChild(range.extractContents());
43478 range.insertNode(wrappingNode);
43485 this.execCmd("formatblock", tg);
43489 insertText : function(txt)
43493 var range = this.createRange();
43494 range.deleteContents();
43495 //alert(Sender.getAttribute('label'));
43497 range.insertNode(this.doc.createTextNode(txt));
43503 * Executes a Midas editor command on the editor document and performs necessary focus and
43504 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43505 * @param {String} cmd The Midas command
43506 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43508 relayCmd : function(cmd, value){
43510 this.execCmd(cmd, value);
43511 this.owner.fireEvent('editorevent', this);
43512 //this.updateToolbar();
43513 this.owner.deferFocus();
43517 * Executes a Midas editor command directly on the editor document.
43518 * For visual commands, you should use {@link #relayCmd} instead.
43519 * <b>This should only be called after the editor is initialized.</b>
43520 * @param {String} cmd The Midas command
43521 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43523 execCmd : function(cmd, value){
43524 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43531 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43533 * @param {String} text | dom node..
43535 insertAtCursor : function(text)
43538 if(!this.activated){
43544 var r = this.doc.selection.createRange();
43555 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43559 // from jquery ui (MIT licenced)
43561 var win = this.win;
43563 if (win.getSelection && win.getSelection().getRangeAt) {
43564 range = win.getSelection().getRangeAt(0);
43565 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43566 range.insertNode(node);
43567 } else if (win.document.selection && win.document.selection.createRange) {
43568 // no firefox support
43569 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43570 win.document.selection.createRange().pasteHTML(txt);
43572 // no firefox support
43573 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43574 this.execCmd('InsertHTML', txt);
43583 mozKeyPress : function(e){
43585 var c = e.getCharCode(), cmd;
43588 c = String.fromCharCode(c).toLowerCase();
43602 this.cleanUpPaste.defer(100, this);
43610 e.preventDefault();
43618 fixKeys : function(){ // load time branching for fastest keydown performance
43620 return function(e){
43621 var k = e.getKey(), r;
43624 r = this.doc.selection.createRange();
43627 r.pasteHTML('    ');
43634 r = this.doc.selection.createRange();
43636 var target = r.parentElement();
43637 if(!target || target.tagName.toLowerCase() != 'li'){
43639 r.pasteHTML('<br />');
43645 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43646 this.cleanUpPaste.defer(100, this);
43652 }else if(Roo.isOpera){
43653 return function(e){
43654 var k = e.getKey();
43658 this.execCmd('InsertHTML','    ');
43661 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43662 this.cleanUpPaste.defer(100, this);
43667 }else if(Roo.isSafari){
43668 return function(e){
43669 var k = e.getKey();
43673 this.execCmd('InsertText','\t');
43677 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43678 this.cleanUpPaste.defer(100, this);
43686 getAllAncestors: function()
43688 var p = this.getSelectedNode();
43691 a.push(p); // push blank onto stack..
43692 p = this.getParentElement();
43696 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43700 a.push(this.doc.body);
43704 lastSelNode : false,
43707 getSelection : function()
43709 this.assignDocWin();
43710 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43713 getSelectedNode: function()
43715 // this may only work on Gecko!!!
43717 // should we cache this!!!!
43722 var range = this.createRange(this.getSelection()).cloneRange();
43725 var parent = range.parentElement();
43727 var testRange = range.duplicate();
43728 testRange.moveToElementText(parent);
43729 if (testRange.inRange(range)) {
43732 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43735 parent = parent.parentElement;
43740 // is ancestor a text element.
43741 var ac = range.commonAncestorContainer;
43742 if (ac.nodeType == 3) {
43743 ac = ac.parentNode;
43746 var ar = ac.childNodes;
43749 var other_nodes = [];
43750 var has_other_nodes = false;
43751 for (var i=0;i<ar.length;i++) {
43752 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43755 // fullly contained node.
43757 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43762 // probably selected..
43763 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43764 other_nodes.push(ar[i]);
43768 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43773 has_other_nodes = true;
43775 if (!nodes.length && other_nodes.length) {
43776 nodes= other_nodes;
43778 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43784 createRange: function(sel)
43786 // this has strange effects when using with
43787 // top toolbar - not sure if it's a great idea.
43788 //this.editor.contentWindow.focus();
43789 if (typeof sel != "undefined") {
43791 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43793 return this.doc.createRange();
43796 return this.doc.createRange();
43799 getParentElement: function()
43802 this.assignDocWin();
43803 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43805 var range = this.createRange(sel);
43808 var p = range.commonAncestorContainer;
43809 while (p.nodeType == 3) { // text node
43820 * Range intersection.. the hard stuff...
43824 * [ -- selected range --- ]
43828 * if end is before start or hits it. fail.
43829 * if start is after end or hits it fail.
43831 * if either hits (but other is outside. - then it's not
43837 // @see http://www.thismuchiknow.co.uk/?p=64.
43838 rangeIntersectsNode : function(range, node)
43840 var nodeRange = node.ownerDocument.createRange();
43842 nodeRange.selectNode(node);
43844 nodeRange.selectNodeContents(node);
43847 var rangeStartRange = range.cloneRange();
43848 rangeStartRange.collapse(true);
43850 var rangeEndRange = range.cloneRange();
43851 rangeEndRange.collapse(false);
43853 var nodeStartRange = nodeRange.cloneRange();
43854 nodeStartRange.collapse(true);
43856 var nodeEndRange = nodeRange.cloneRange();
43857 nodeEndRange.collapse(false);
43859 return rangeStartRange.compareBoundaryPoints(
43860 Range.START_TO_START, nodeEndRange) == -1 &&
43861 rangeEndRange.compareBoundaryPoints(
43862 Range.START_TO_START, nodeStartRange) == 1;
43866 rangeCompareNode : function(range, node)
43868 var nodeRange = node.ownerDocument.createRange();
43870 nodeRange.selectNode(node);
43872 nodeRange.selectNodeContents(node);
43876 range.collapse(true);
43878 nodeRange.collapse(true);
43880 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43881 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43883 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43885 var nodeIsBefore = ss == 1;
43886 var nodeIsAfter = ee == -1;
43888 if (nodeIsBefore && nodeIsAfter) {
43891 if (!nodeIsBefore && nodeIsAfter) {
43892 return 1; //right trailed.
43895 if (nodeIsBefore && !nodeIsAfter) {
43896 return 2; // left trailed.
43902 // private? - in a new class?
43903 cleanUpPaste : function()
43905 // cleans up the whole document..
43906 Roo.log('cleanuppaste');
43908 this.cleanUpChildren(this.doc.body);
43909 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43910 if (clean != this.doc.body.innerHTML) {
43911 this.doc.body.innerHTML = clean;
43916 cleanWordChars : function(input) {// change the chars to hex code
43917 var he = Roo.HtmlEditorCore;
43919 var output = input;
43920 Roo.each(he.swapCodes, function(sw) {
43921 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43923 output = output.replace(swapper, sw[1]);
43930 cleanUpChildren : function (n)
43932 if (!n.childNodes.length) {
43935 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43936 this.cleanUpChild(n.childNodes[i]);
43943 cleanUpChild : function (node)
43946 //console.log(node);
43947 if (node.nodeName == "#text") {
43948 // clean up silly Windows -- stuff?
43951 if (node.nodeName == "#comment") {
43952 node.parentNode.removeChild(node);
43953 // clean up silly Windows -- stuff?
43956 var lcname = node.tagName.toLowerCase();
43957 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43958 // whitelist of tags..
43960 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43962 node.parentNode.removeChild(node);
43967 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43969 // spans with no attributes - just remove them..
43970 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
43971 remove_keep_children = true;
43974 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43975 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43977 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43978 // remove_keep_children = true;
43981 if (remove_keep_children) {
43982 this.cleanUpChildren(node);
43983 // inserts everything just before this node...
43984 while (node.childNodes.length) {
43985 var cn = node.childNodes[0];
43986 node.removeChild(cn);
43987 node.parentNode.insertBefore(cn, node);
43989 node.parentNode.removeChild(node);
43993 if (!node.attributes || !node.attributes.length) {
43998 this.cleanUpChildren(node);
44002 function cleanAttr(n,v)
44005 if (v.match(/^\./) || v.match(/^\//)) {
44008 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
44011 if (v.match(/^#/)) {
44014 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
44015 node.removeAttribute(n);
44019 var cwhite = this.cwhite;
44020 var cblack = this.cblack;
44022 function cleanStyle(n,v)
44024 if (v.match(/expression/)) { //XSS?? should we even bother..
44025 node.removeAttribute(n);
44029 var parts = v.split(/;/);
44032 Roo.each(parts, function(p) {
44033 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
44037 var l = p.split(':').shift().replace(/\s+/g,'');
44038 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
44040 if ( cwhite.length && cblack.indexOf(l) > -1) {
44041 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44042 //node.removeAttribute(n);
44046 // only allow 'c whitelisted system attributes'
44047 if ( cwhite.length && cwhite.indexOf(l) < 0) {
44048 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44049 //node.removeAttribute(n);
44059 if (clean.length) {
44060 node.setAttribute(n, clean.join(';'));
44062 node.removeAttribute(n);
44068 for (var i = node.attributes.length-1; i > -1 ; i--) {
44069 var a = node.attributes[i];
44072 if (a.name.toLowerCase().substr(0,2)=='on') {
44073 node.removeAttribute(a.name);
44076 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
44077 node.removeAttribute(a.name);
44080 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
44081 cleanAttr(a.name,a.value); // fixme..
44084 if (a.name == 'style') {
44085 cleanStyle(a.name,a.value);
44088 /// clean up MS crap..
44089 // tecnically this should be a list of valid class'es..
44092 if (a.name == 'class') {
44093 if (a.value.match(/^Mso/)) {
44094 node.removeAttribute('class');
44097 if (a.value.match(/^body$/)) {
44098 node.removeAttribute('class');
44109 this.cleanUpChildren(node);
44115 * Clean up MS wordisms...
44117 cleanWord : function(node)
44120 this.cleanWord(this.doc.body);
44125 node.nodeName == 'SPAN' &&
44126 !node.hasAttributes() &&
44127 node.childNodes.length == 1 &&
44128 node.firstChild.nodeName == "#text"
44130 var textNode = node.firstChild;
44131 node.removeChild(textNode);
44132 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44133 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44135 node.parentNode.insertBefore(textNode, node);
44136 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44137 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
44139 node.parentNode.removeChild(node);
44142 if (node.nodeName == "#text") {
44143 // clean up silly Windows -- stuff?
44146 if (node.nodeName == "#comment") {
44147 node.parentNode.removeChild(node);
44148 // clean up silly Windows -- stuff?
44152 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
44153 node.parentNode.removeChild(node);
44156 //Roo.log(node.tagName);
44157 // remove - but keep children..
44158 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
44159 //Roo.log('-- removed');
44160 while (node.childNodes.length) {
44161 var cn = node.childNodes[0];
44162 node.removeChild(cn);
44163 node.parentNode.insertBefore(cn, node);
44164 // move node to parent - and clean it..
44165 this.cleanWord(cn);
44167 node.parentNode.removeChild(node);
44168 /// no need to iterate chidlren = it's got none..
44169 //this.iterateChildren(node, this.cleanWord);
44173 if (node.className.length) {
44175 var cn = node.className.split(/\W+/);
44177 Roo.each(cn, function(cls) {
44178 if (cls.match(/Mso[a-zA-Z]+/)) {
44183 node.className = cna.length ? cna.join(' ') : '';
44185 node.removeAttribute("class");
44189 if (node.hasAttribute("lang")) {
44190 node.removeAttribute("lang");
44193 if (node.hasAttribute("style")) {
44195 var styles = node.getAttribute("style").split(";");
44197 Roo.each(styles, function(s) {
44198 if (!s.match(/:/)) {
44201 var kv = s.split(":");
44202 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44205 // what ever is left... we allow.
44208 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44209 if (!nstyle.length) {
44210 node.removeAttribute('style');
44213 this.iterateChildren(node, this.cleanWord);
44219 * iterateChildren of a Node, calling fn each time, using this as the scole..
44220 * @param {DomNode} node node to iterate children of.
44221 * @param {Function} fn method of this class to call on each item.
44223 iterateChildren : function(node, fn)
44225 if (!node.childNodes.length) {
44228 for (var i = node.childNodes.length-1; i > -1 ; i--) {
44229 fn.call(this, node.childNodes[i])
44235 * cleanTableWidths.
44237 * Quite often pasting from word etc.. results in tables with column and widths.
44238 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
44241 cleanTableWidths : function(node)
44246 this.cleanTableWidths(this.doc.body);
44251 if (node.nodeName == "#text" || node.nodeName == "#comment") {
44254 Roo.log(node.tagName);
44255 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
44256 this.iterateChildren(node, this.cleanTableWidths);
44259 if (node.hasAttribute('width')) {
44260 node.removeAttribute('width');
44264 if (node.hasAttribute("style")) {
44267 var styles = node.getAttribute("style").split(";");
44269 Roo.each(styles, function(s) {
44270 if (!s.match(/:/)) {
44273 var kv = s.split(":");
44274 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
44277 // what ever is left... we allow.
44280 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44281 if (!nstyle.length) {
44282 node.removeAttribute('style');
44286 this.iterateChildren(node, this.cleanTableWidths);
44294 domToHTML : function(currentElement, depth, nopadtext) {
44296 depth = depth || 0;
44297 nopadtext = nopadtext || false;
44299 if (!currentElement) {
44300 return this.domToHTML(this.doc.body);
44303 //Roo.log(currentElement);
44305 var allText = false;
44306 var nodeName = currentElement.nodeName;
44307 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44309 if (nodeName == '#text') {
44311 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44316 if (nodeName != 'BODY') {
44319 // Prints the node tagName, such as <A>, <IMG>, etc
44322 for(i = 0; i < currentElement.attributes.length;i++) {
44324 var aname = currentElement.attributes.item(i).name;
44325 if (!currentElement.attributes.item(i).value.length) {
44328 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44331 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44340 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44343 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44348 // Traverse the tree
44350 var currentElementChild = currentElement.childNodes.item(i);
44351 var allText = true;
44352 var innerHTML = '';
44354 while (currentElementChild) {
44355 // Formatting code (indent the tree so it looks nice on the screen)
44356 var nopad = nopadtext;
44357 if (lastnode == 'SPAN') {
44361 if (currentElementChild.nodeName == '#text') {
44362 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44363 toadd = nopadtext ? toadd : toadd.trim();
44364 if (!nopad && toadd.length > 80) {
44365 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44367 innerHTML += toadd;
44370 currentElementChild = currentElement.childNodes.item(i);
44376 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44378 // Recursively traverse the tree structure of the child node
44379 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44380 lastnode = currentElementChild.nodeName;
44382 currentElementChild=currentElement.childNodes.item(i);
44388 // The remaining code is mostly for formatting the tree
44389 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44394 ret+= "</"+tagName+">";
44400 applyBlacklists : function()
44402 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44403 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44407 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44408 if (b.indexOf(tag) > -1) {
44411 this.white.push(tag);
44415 Roo.each(w, function(tag) {
44416 if (b.indexOf(tag) > -1) {
44419 if (this.white.indexOf(tag) > -1) {
44422 this.white.push(tag);
44427 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44428 if (w.indexOf(tag) > -1) {
44431 this.black.push(tag);
44435 Roo.each(b, function(tag) {
44436 if (w.indexOf(tag) > -1) {
44439 if (this.black.indexOf(tag) > -1) {
44442 this.black.push(tag);
44447 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44448 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44452 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44453 if (b.indexOf(tag) > -1) {
44456 this.cwhite.push(tag);
44460 Roo.each(w, function(tag) {
44461 if (b.indexOf(tag) > -1) {
44464 if (this.cwhite.indexOf(tag) > -1) {
44467 this.cwhite.push(tag);
44472 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44473 if (w.indexOf(tag) > -1) {
44476 this.cblack.push(tag);
44480 Roo.each(b, function(tag) {
44481 if (w.indexOf(tag) > -1) {
44484 if (this.cblack.indexOf(tag) > -1) {
44487 this.cblack.push(tag);
44492 setStylesheets : function(stylesheets)
44494 if(typeof(stylesheets) == 'string'){
44495 Roo.get(this.iframe.contentDocument.head).createChild({
44497 rel : 'stylesheet',
44506 Roo.each(stylesheets, function(s) {
44511 Roo.get(_this.iframe.contentDocument.head).createChild({
44513 rel : 'stylesheet',
44522 removeStylesheets : function()
44526 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44531 setStyle : function(style)
44533 Roo.get(this.iframe.contentDocument.head).createChild({
44542 // hide stuff that is not compatible
44556 * @event specialkey
44560 * @cfg {String} fieldClass @hide
44563 * @cfg {String} focusClass @hide
44566 * @cfg {String} autoCreate @hide
44569 * @cfg {String} inputType @hide
44572 * @cfg {String} invalidClass @hide
44575 * @cfg {String} invalidText @hide
44578 * @cfg {String} msgFx @hide
44581 * @cfg {String} validateOnBlur @hide
44585 Roo.HtmlEditorCore.white = [
44586 'area', 'br', 'img', 'input', 'hr', 'wbr',
44588 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44589 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44590 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44591 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44592 'table', 'ul', 'xmp',
44594 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44597 'dir', 'menu', 'ol', 'ul', 'dl',
44603 Roo.HtmlEditorCore.black = [
44604 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44606 'base', 'basefont', 'bgsound', 'blink', 'body',
44607 'frame', 'frameset', 'head', 'html', 'ilayer',
44608 'iframe', 'layer', 'link', 'meta', 'object',
44609 'script', 'style' ,'title', 'xml' // clean later..
44611 Roo.HtmlEditorCore.clean = [
44612 'script', 'style', 'title', 'xml'
44614 Roo.HtmlEditorCore.remove = [
44619 Roo.HtmlEditorCore.ablack = [
44623 Roo.HtmlEditorCore.aclean = [
44624 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44628 Roo.HtmlEditorCore.pwhite= [
44629 'http', 'https', 'mailto'
44632 // white listed style attributes.
44633 Roo.HtmlEditorCore.cwhite= [
44634 // 'text-align', /// default is to allow most things..
44640 // black listed style attributes.
44641 Roo.HtmlEditorCore.cblack= [
44642 // 'font-size' -- this can be set by the project
44646 Roo.HtmlEditorCore.swapCodes =[
44657 //<script type="text/javascript">
44660 * Ext JS Library 1.1.1
44661 * Copyright(c) 2006-2007, Ext JS, LLC.
44667 Roo.form.HtmlEditor = function(config){
44671 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44673 if (!this.toolbars) {
44674 this.toolbars = [];
44676 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44682 * @class Roo.form.HtmlEditor
44683 * @extends Roo.form.Field
44684 * Provides a lightweight HTML Editor component.
44686 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44688 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44689 * supported by this editor.</b><br/><br/>
44690 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44691 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44693 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44695 * @cfg {Boolean} clearUp
44699 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44704 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44709 * @cfg {Number} height (in pixels)
44713 * @cfg {Number} width (in pixels)
44718 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44721 stylesheets: false,
44725 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44730 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44736 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44741 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44749 // private properties
44750 validationEvent : false,
44752 initialized : false,
44755 onFocus : Roo.emptyFn,
44757 hideMode:'offsets',
44759 actionMode : 'container', // defaults to hiding it...
44761 defaultAutoCreate : { // modified by initCompnoent..
44763 style:"width:500px;height:300px;",
44764 autocomplete: "new-password"
44768 initComponent : function(){
44771 * @event initialize
44772 * Fires when the editor is fully initialized (including the iframe)
44773 * @param {HtmlEditor} this
44778 * Fires when the editor is first receives the focus. Any insertion must wait
44779 * until after this event.
44780 * @param {HtmlEditor} this
44784 * @event beforesync
44785 * Fires before the textarea is updated with content from the editor iframe. Return false
44786 * to cancel the sync.
44787 * @param {HtmlEditor} this
44788 * @param {String} html
44792 * @event beforepush
44793 * Fires before the iframe editor is updated with content from the textarea. Return false
44794 * to cancel the push.
44795 * @param {HtmlEditor} this
44796 * @param {String} html
44801 * Fires when the textarea is updated with content from the editor iframe.
44802 * @param {HtmlEditor} this
44803 * @param {String} html
44808 * Fires when the iframe editor is updated with content from the textarea.
44809 * @param {HtmlEditor} this
44810 * @param {String} html
44814 * @event editmodechange
44815 * Fires when the editor switches edit modes
44816 * @param {HtmlEditor} this
44817 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44819 editmodechange: true,
44821 * @event editorevent
44822 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44823 * @param {HtmlEditor} this
44827 * @event firstfocus
44828 * Fires when on first focus - needed by toolbars..
44829 * @param {HtmlEditor} this
44834 * Auto save the htmlEditor value as a file into Events
44835 * @param {HtmlEditor} this
44839 * @event savedpreview
44840 * preview the saved version of htmlEditor
44841 * @param {HtmlEditor} this
44843 savedpreview: true,
44846 * @event stylesheetsclick
44847 * Fires when press the Sytlesheets button
44848 * @param {Roo.HtmlEditorCore} this
44850 stylesheetsclick: true
44852 this.defaultAutoCreate = {
44854 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44855 autocomplete: "new-password"
44860 * Protected method that will not generally be called directly. It
44861 * is called when the editor creates its toolbar. Override this method if you need to
44862 * add custom toolbar buttons.
44863 * @param {HtmlEditor} editor
44865 createToolbar : function(editor){
44866 Roo.log("create toolbars");
44867 if (!editor.toolbars || !editor.toolbars.length) {
44868 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44871 for (var i =0 ; i < editor.toolbars.length;i++) {
44872 editor.toolbars[i] = Roo.factory(
44873 typeof(editor.toolbars[i]) == 'string' ?
44874 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44875 Roo.form.HtmlEditor);
44876 editor.toolbars[i].init(editor);
44884 onRender : function(ct, position)
44887 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44889 this.wrap = this.el.wrap({
44890 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44893 this.editorcore.onRender(ct, position);
44895 if (this.resizable) {
44896 this.resizeEl = new Roo.Resizable(this.wrap, {
44900 minHeight : this.height,
44901 height: this.height,
44902 handles : this.resizable,
44905 resize : function(r, w, h) {
44906 _t.onResize(w,h); // -something
44912 this.createToolbar(this);
44916 this.setSize(this.wrap.getSize());
44918 if (this.resizeEl) {
44919 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44920 // should trigger onReize..
44923 this.keyNav = new Roo.KeyNav(this.el, {
44925 "tab" : function(e){
44926 e.preventDefault();
44928 var value = this.getValue();
44930 var start = this.el.dom.selectionStart;
44931 var end = this.el.dom.selectionEnd;
44935 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44936 this.el.dom.setSelectionRange(end + 1, end + 1);
44940 var f = value.substring(0, start).split("\t");
44942 if(f.pop().length != 0){
44946 this.setValue(f.join("\t") + value.substring(end));
44947 this.el.dom.setSelectionRange(start - 1, start - 1);
44951 "home" : function(e){
44952 e.preventDefault();
44954 var curr = this.el.dom.selectionStart;
44955 var lines = this.getValue().split("\n");
44962 this.el.dom.setSelectionRange(0, 0);
44968 for (var i = 0; i < lines.length;i++) {
44969 pos += lines[i].length;
44979 pos -= lines[i].length;
44985 this.el.dom.setSelectionRange(pos, pos);
44989 this.el.dom.selectionStart = pos;
44990 this.el.dom.selectionEnd = curr;
44993 "end" : function(e){
44994 e.preventDefault();
44996 var curr = this.el.dom.selectionStart;
44997 var lines = this.getValue().split("\n");
45004 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
45010 for (var i = 0; i < lines.length;i++) {
45012 pos += lines[i].length;
45026 this.el.dom.setSelectionRange(pos, pos);
45030 this.el.dom.selectionStart = curr;
45031 this.el.dom.selectionEnd = pos;
45036 doRelay : function(foo, bar, hname){
45037 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
45043 // if(this.autosave && this.w){
45044 // this.autoSaveFn = setInterval(this.autosave, 1000);
45049 onResize : function(w, h)
45051 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
45056 if(typeof w == 'number'){
45057 var aw = w - this.wrap.getFrameWidth('lr');
45058 this.el.setWidth(this.adjustWidth('textarea', aw));
45061 if(typeof h == 'number'){
45063 for (var i =0; i < this.toolbars.length;i++) {
45064 // fixme - ask toolbars for heights?
45065 tbh += this.toolbars[i].tb.el.getHeight();
45066 if (this.toolbars[i].footer) {
45067 tbh += this.toolbars[i].footer.el.getHeight();
45074 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
45075 ah -= 5; // knock a few pixes off for look..
45077 this.el.setHeight(this.adjustWidth('textarea', ah));
45081 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
45082 this.editorcore.onResize(ew,eh);
45087 * Toggles the editor between standard and source edit mode.
45088 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45090 toggleSourceEdit : function(sourceEditMode)
45092 this.editorcore.toggleSourceEdit(sourceEditMode);
45094 if(this.editorcore.sourceEditMode){
45095 Roo.log('editor - showing textarea');
45098 // Roo.log(this.syncValue());
45099 this.editorcore.syncValue();
45100 this.el.removeClass('x-hidden');
45101 this.el.dom.removeAttribute('tabIndex');
45104 for (var i = 0; i < this.toolbars.length; i++) {
45105 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45106 this.toolbars[i].tb.hide();
45107 this.toolbars[i].footer.hide();
45112 Roo.log('editor - hiding textarea');
45114 // Roo.log(this.pushValue());
45115 this.editorcore.pushValue();
45117 this.el.addClass('x-hidden');
45118 this.el.dom.setAttribute('tabIndex', -1);
45120 for (var i = 0; i < this.toolbars.length; i++) {
45121 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45122 this.toolbars[i].tb.show();
45123 this.toolbars[i].footer.show();
45127 //this.deferFocus();
45130 this.setSize(this.wrap.getSize());
45131 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
45133 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
45136 // private (for BoxComponent)
45137 adjustSize : Roo.BoxComponent.prototype.adjustSize,
45139 // private (for BoxComponent)
45140 getResizeEl : function(){
45144 // private (for BoxComponent)
45145 getPositionEl : function(){
45150 initEvents : function(){
45151 this.originalValue = this.getValue();
45155 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45158 markInvalid : Roo.emptyFn,
45160 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45163 clearInvalid : Roo.emptyFn,
45165 setValue : function(v){
45166 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
45167 this.editorcore.pushValue();
45172 deferFocus : function(){
45173 this.focus.defer(10, this);
45177 focus : function(){
45178 this.editorcore.focus();
45184 onDestroy : function(){
45190 for (var i =0; i < this.toolbars.length;i++) {
45191 // fixme - ask toolbars for heights?
45192 this.toolbars[i].onDestroy();
45195 this.wrap.dom.innerHTML = '';
45196 this.wrap.remove();
45201 onFirstFocus : function(){
45202 //Roo.log("onFirstFocus");
45203 this.editorcore.onFirstFocus();
45204 for (var i =0; i < this.toolbars.length;i++) {
45205 this.toolbars[i].onFirstFocus();
45211 syncValue : function()
45213 this.editorcore.syncValue();
45216 pushValue : function()
45218 this.editorcore.pushValue();
45221 setStylesheets : function(stylesheets)
45223 this.editorcore.setStylesheets(stylesheets);
45226 removeStylesheets : function()
45228 this.editorcore.removeStylesheets();
45232 // hide stuff that is not compatible
45246 * @event specialkey
45250 * @cfg {String} fieldClass @hide
45253 * @cfg {String} focusClass @hide
45256 * @cfg {String} autoCreate @hide
45259 * @cfg {String} inputType @hide
45262 * @cfg {String} invalidClass @hide
45265 * @cfg {String} invalidText @hide
45268 * @cfg {String} msgFx @hide
45271 * @cfg {String} validateOnBlur @hide
45275 // <script type="text/javascript">
45278 * Ext JS Library 1.1.1
45279 * Copyright(c) 2006-2007, Ext JS, LLC.
45285 * @class Roo.form.HtmlEditorToolbar1
45290 new Roo.form.HtmlEditor({
45293 new Roo.form.HtmlEditorToolbar1({
45294 disable : { fonts: 1 , format: 1, ..., ... , ...],
45300 * @cfg {Object} disable List of elements to disable..
45301 * @cfg {Array} btns List of additional buttons.
45305 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45308 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45311 Roo.apply(this, config);
45313 // default disabled, based on 'good practice'..
45314 this.disable = this.disable || {};
45315 Roo.applyIf(this.disable, {
45318 specialElements : true
45322 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45323 // dont call parent... till later.
45326 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45333 editorcore : false,
45335 * @cfg {Object} disable List of toolbar elements to disable
45342 * @cfg {String} createLinkText The default text for the create link prompt
45344 createLinkText : 'Please enter the URL for the link:',
45346 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45348 defaultLinkValue : 'http:/'+'/',
45352 * @cfg {Array} fontFamilies An array of available font families
45370 // "á" , ?? a acute?
45375 "°" // , // degrees
45377 // "é" , // e ecute
45378 // "ú" , // u ecute?
45381 specialElements : [
45383 text: "Insert Table",
45386 ihtml : '<table><tr><td>Cell</td></tr></table>'
45390 text: "Insert Image",
45393 ihtml : '<img src="about:blank"/>'
45402 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45403 "input:submit", "input:button", "select", "textarea", "label" ],
45406 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45408 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45417 * @cfg {String} defaultFont default font to use.
45419 defaultFont: 'tahoma',
45421 fontSelect : false,
45424 formatCombo : false,
45426 init : function(editor)
45428 this.editor = editor;
45429 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45430 var editorcore = this.editorcore;
45434 var fid = editorcore.frameId;
45436 function btn(id, toggle, handler){
45437 var xid = fid + '-'+ id ;
45441 cls : 'x-btn-icon x-edit-'+id,
45442 enableToggle:toggle !== false,
45443 scope: _t, // was editor...
45444 handler:handler||_t.relayBtnCmd,
45445 clickEvent:'mousedown',
45446 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45453 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45455 // stop form submits
45456 tb.el.on('click', function(e){
45457 e.preventDefault(); // what does this do?
45460 if(!this.disable.font) { // && !Roo.isSafari){
45461 /* why no safari for fonts
45462 editor.fontSelect = tb.el.createChild({
45465 cls:'x-font-select',
45466 html: this.createFontOptions()
45469 editor.fontSelect.on('change', function(){
45470 var font = editor.fontSelect.dom.value;
45471 editor.relayCmd('fontname', font);
45472 editor.deferFocus();
45476 editor.fontSelect.dom,
45482 if(!this.disable.formats){
45483 this.formatCombo = new Roo.form.ComboBox({
45484 store: new Roo.data.SimpleStore({
45487 data : this.formats // from states.js
45491 //autoCreate : {tag: "div", size: "20"},
45492 displayField:'tag',
45496 triggerAction: 'all',
45497 emptyText:'Add tag',
45498 selectOnFocus:true,
45501 'select': function(c, r, i) {
45502 editorcore.insertTag(r.get('tag'));
45508 tb.addField(this.formatCombo);
45512 if(!this.disable.format){
45517 btn('strikethrough')
45520 if(!this.disable.fontSize){
45525 btn('increasefontsize', false, editorcore.adjustFont),
45526 btn('decreasefontsize', false, editorcore.adjustFont)
45531 if(!this.disable.colors){
45534 id:editorcore.frameId +'-forecolor',
45535 cls:'x-btn-icon x-edit-forecolor',
45536 clickEvent:'mousedown',
45537 tooltip: this.buttonTips['forecolor'] || undefined,
45539 menu : new Roo.menu.ColorMenu({
45540 allowReselect: true,
45541 focus: Roo.emptyFn,
45544 selectHandler: function(cp, color){
45545 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45546 editor.deferFocus();
45549 clickEvent:'mousedown'
45552 id:editorcore.frameId +'backcolor',
45553 cls:'x-btn-icon x-edit-backcolor',
45554 clickEvent:'mousedown',
45555 tooltip: this.buttonTips['backcolor'] || undefined,
45557 menu : new Roo.menu.ColorMenu({
45558 focus: Roo.emptyFn,
45561 allowReselect: true,
45562 selectHandler: function(cp, color){
45564 editorcore.execCmd('useCSS', false);
45565 editorcore.execCmd('hilitecolor', color);
45566 editorcore.execCmd('useCSS', true);
45567 editor.deferFocus();
45569 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45570 Roo.isSafari || Roo.isIE ? '#'+color : color);
45571 editor.deferFocus();
45575 clickEvent:'mousedown'
45580 // now add all the items...
45583 if(!this.disable.alignments){
45586 btn('justifyleft'),
45587 btn('justifycenter'),
45588 btn('justifyright')
45592 //if(!Roo.isSafari){
45593 if(!this.disable.links){
45596 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45600 if(!this.disable.lists){
45603 btn('insertorderedlist'),
45604 btn('insertunorderedlist')
45607 if(!this.disable.sourceEdit){
45610 btn('sourceedit', true, function(btn){
45611 this.toggleSourceEdit(btn.pressed);
45618 // special menu.. - needs to be tidied up..
45619 if (!this.disable.special) {
45622 cls: 'x-edit-none',
45628 for (var i =0; i < this.specialChars.length; i++) {
45629 smenu.menu.items.push({
45631 html: this.specialChars[i],
45632 handler: function(a,b) {
45633 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45634 //editor.insertAtCursor(a.html);
45648 if (!this.disable.cleanStyles) {
45650 cls: 'x-btn-icon x-btn-clear',
45656 for (var i =0; i < this.cleanStyles.length; i++) {
45657 cmenu.menu.items.push({
45658 actiontype : this.cleanStyles[i],
45659 html: 'Remove ' + this.cleanStyles[i],
45660 handler: function(a,b) {
45663 var c = Roo.get(editorcore.doc.body);
45664 c.select('[style]').each(function(s) {
45665 s.dom.style.removeProperty(a.actiontype);
45667 editorcore.syncValue();
45672 cmenu.menu.items.push({
45673 actiontype : 'tablewidths',
45674 html: 'Remove Table Widths',
45675 handler: function(a,b) {
45676 editorcore.cleanTableWidths();
45677 editorcore.syncValue();
45681 cmenu.menu.items.push({
45682 actiontype : 'word',
45683 html: 'Remove MS Word Formating',
45684 handler: function(a,b) {
45685 editorcore.cleanWord();
45686 editorcore.syncValue();
45691 cmenu.menu.items.push({
45692 actiontype : 'all',
45693 html: 'Remove All Styles',
45694 handler: function(a,b) {
45696 var c = Roo.get(editorcore.doc.body);
45697 c.select('[style]').each(function(s) {
45698 s.dom.removeAttribute('style');
45700 editorcore.syncValue();
45705 cmenu.menu.items.push({
45706 actiontype : 'all',
45707 html: 'Remove All CSS Classes',
45708 handler: function(a,b) {
45710 var c = Roo.get(editorcore.doc.body);
45711 c.select('[class]').each(function(s) {
45712 s.dom.removeAttribute('class');
45714 editorcore.cleanWord();
45715 editorcore.syncValue();
45720 cmenu.menu.items.push({
45721 actiontype : 'tidy',
45722 html: 'Tidy HTML Source',
45723 handler: function(a,b) {
45724 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45725 editorcore.syncValue();
45734 if (!this.disable.specialElements) {
45737 cls: 'x-edit-none',
45742 for (var i =0; i < this.specialElements.length; i++) {
45743 semenu.menu.items.push(
45745 handler: function(a,b) {
45746 editor.insertAtCursor(this.ihtml);
45748 }, this.specialElements[i])
45760 for(var i =0; i< this.btns.length;i++) {
45761 var b = Roo.factory(this.btns[i],Roo.form);
45762 b.cls = 'x-edit-none';
45764 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45765 b.cls += ' x-init-enable';
45768 b.scope = editorcore;
45776 // disable everything...
45778 this.tb.items.each(function(item){
45781 item.id != editorcore.frameId+ '-sourceedit' &&
45782 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45788 this.rendered = true;
45790 // the all the btns;
45791 editor.on('editorevent', this.updateToolbar, this);
45792 // other toolbars need to implement this..
45793 //editor.on('editmodechange', this.updateToolbar, this);
45797 relayBtnCmd : function(btn) {
45798 this.editorcore.relayCmd(btn.cmd);
45800 // private used internally
45801 createLink : function(){
45802 Roo.log("create link?");
45803 var url = prompt(this.createLinkText, this.defaultLinkValue);
45804 if(url && url != 'http:/'+'/'){
45805 this.editorcore.relayCmd('createlink', url);
45811 * Protected method that will not generally be called directly. It triggers
45812 * a toolbar update by reading the markup state of the current selection in the editor.
45814 updateToolbar: function(){
45816 if(!this.editorcore.activated){
45817 this.editor.onFirstFocus();
45821 var btns = this.tb.items.map,
45822 doc = this.editorcore.doc,
45823 frameId = this.editorcore.frameId;
45825 if(!this.disable.font && !Roo.isSafari){
45827 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45828 if(name != this.fontSelect.dom.value){
45829 this.fontSelect.dom.value = name;
45833 if(!this.disable.format){
45834 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45835 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45836 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45837 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45839 if(!this.disable.alignments){
45840 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45841 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45842 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45844 if(!Roo.isSafari && !this.disable.lists){
45845 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45846 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45849 var ans = this.editorcore.getAllAncestors();
45850 if (this.formatCombo) {
45853 var store = this.formatCombo.store;
45854 this.formatCombo.setValue("");
45855 for (var i =0; i < ans.length;i++) {
45856 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45858 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45866 // hides menus... - so this cant be on a menu...
45867 Roo.menu.MenuMgr.hideAll();
45869 //this.editorsyncValue();
45873 createFontOptions : function(){
45874 var buf = [], fs = this.fontFamilies, ff, lc;
45878 for(var i = 0, len = fs.length; i< len; i++){
45880 lc = ff.toLowerCase();
45882 '<option value="',lc,'" style="font-family:',ff,';"',
45883 (this.defaultFont == lc ? ' selected="true">' : '>'),
45888 return buf.join('');
45891 toggleSourceEdit : function(sourceEditMode){
45893 Roo.log("toolbar toogle");
45894 if(sourceEditMode === undefined){
45895 sourceEditMode = !this.sourceEditMode;
45897 this.sourceEditMode = sourceEditMode === true;
45898 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45899 // just toggle the button?
45900 if(btn.pressed !== this.sourceEditMode){
45901 btn.toggle(this.sourceEditMode);
45905 if(sourceEditMode){
45906 Roo.log("disabling buttons");
45907 this.tb.items.each(function(item){
45908 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45914 Roo.log("enabling buttons");
45915 if(this.editorcore.initialized){
45916 this.tb.items.each(function(item){
45922 Roo.log("calling toggole on editor");
45923 // tell the editor that it's been pressed..
45924 this.editor.toggleSourceEdit(sourceEditMode);
45928 * Object collection of toolbar tooltips for the buttons in the editor. The key
45929 * is the command id associated with that button and the value is a valid QuickTips object.
45934 title: 'Bold (Ctrl+B)',
45935 text: 'Make the selected text bold.',
45936 cls: 'x-html-editor-tip'
45939 title: 'Italic (Ctrl+I)',
45940 text: 'Make the selected text italic.',
45941 cls: 'x-html-editor-tip'
45949 title: 'Bold (Ctrl+B)',
45950 text: 'Make the selected text bold.',
45951 cls: 'x-html-editor-tip'
45954 title: 'Italic (Ctrl+I)',
45955 text: 'Make the selected text italic.',
45956 cls: 'x-html-editor-tip'
45959 title: 'Underline (Ctrl+U)',
45960 text: 'Underline the selected text.',
45961 cls: 'x-html-editor-tip'
45964 title: 'Strikethrough',
45965 text: 'Strikethrough the selected text.',
45966 cls: 'x-html-editor-tip'
45968 increasefontsize : {
45969 title: 'Grow Text',
45970 text: 'Increase the font size.',
45971 cls: 'x-html-editor-tip'
45973 decreasefontsize : {
45974 title: 'Shrink Text',
45975 text: 'Decrease the font size.',
45976 cls: 'x-html-editor-tip'
45979 title: 'Text Highlight Color',
45980 text: 'Change the background color of the selected text.',
45981 cls: 'x-html-editor-tip'
45984 title: 'Font Color',
45985 text: 'Change the color of the selected text.',
45986 cls: 'x-html-editor-tip'
45989 title: 'Align Text Left',
45990 text: 'Align text to the left.',
45991 cls: 'x-html-editor-tip'
45994 title: 'Center Text',
45995 text: 'Center text in the editor.',
45996 cls: 'x-html-editor-tip'
45999 title: 'Align Text Right',
46000 text: 'Align text to the right.',
46001 cls: 'x-html-editor-tip'
46003 insertunorderedlist : {
46004 title: 'Bullet List',
46005 text: 'Start a bulleted list.',
46006 cls: 'x-html-editor-tip'
46008 insertorderedlist : {
46009 title: 'Numbered List',
46010 text: 'Start a numbered list.',
46011 cls: 'x-html-editor-tip'
46014 title: 'Hyperlink',
46015 text: 'Make the selected text a hyperlink.',
46016 cls: 'x-html-editor-tip'
46019 title: 'Source Edit',
46020 text: 'Switch to source editing mode.',
46021 cls: 'x-html-editor-tip'
46025 onDestroy : function(){
46028 this.tb.items.each(function(item){
46030 item.menu.removeAll();
46032 item.menu.el.destroy();
46040 onFirstFocus: function() {
46041 this.tb.items.each(function(item){
46050 // <script type="text/javascript">
46053 * Ext JS Library 1.1.1
46054 * Copyright(c) 2006-2007, Ext JS, LLC.
46061 * @class Roo.form.HtmlEditor.ToolbarContext
46066 new Roo.form.HtmlEditor({
46069 { xtype: 'ToolbarStandard', styles : {} }
46070 { xtype: 'ToolbarContext', disable : {} }
46076 * @config : {Object} disable List of elements to disable.. (not done yet.)
46077 * @config : {Object} styles Map of styles available.
46081 Roo.form.HtmlEditor.ToolbarContext = function(config)
46084 Roo.apply(this, config);
46085 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46086 // dont call parent... till later.
46087 this.styles = this.styles || {};
46092 Roo.form.HtmlEditor.ToolbarContext.types = {
46104 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
46170 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
46175 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
46185 style : 'fontFamily',
46186 displayField: 'display',
46187 optname : 'font-family',
46236 // should we really allow this??
46237 // should this just be
46248 style : 'fontFamily',
46249 displayField: 'display',
46250 optname : 'font-family',
46257 style : 'fontFamily',
46258 displayField: 'display',
46259 optname : 'font-family',
46266 style : 'fontFamily',
46267 displayField: 'display',
46268 optname : 'font-family',
46279 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
46280 Roo.form.HtmlEditor.ToolbarContext.stores = false;
46282 Roo.form.HtmlEditor.ToolbarContext.options = {
46284 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
46285 [ 'Courier New', 'Courier New'],
46286 [ 'Tahoma', 'Tahoma'],
46287 [ 'Times New Roman,serif', 'Times'],
46288 [ 'Verdana','Verdana' ]
46292 // fixme - these need to be configurable..
46295 //Roo.form.HtmlEditor.ToolbarContext.types
46298 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46305 editorcore : false,
46307 * @cfg {Object} disable List of toolbar elements to disable
46312 * @cfg {Object} styles List of styles
46313 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46315 * These must be defined in the page, so they get rendered correctly..
46326 init : function(editor)
46328 this.editor = editor;
46329 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46330 var editorcore = this.editorcore;
46332 var fid = editorcore.frameId;
46334 function btn(id, toggle, handler){
46335 var xid = fid + '-'+ id ;
46339 cls : 'x-btn-icon x-edit-'+id,
46340 enableToggle:toggle !== false,
46341 scope: editorcore, // was editor...
46342 handler:handler||editorcore.relayBtnCmd,
46343 clickEvent:'mousedown',
46344 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46348 // create a new element.
46349 var wdiv = editor.wrap.createChild({
46351 }, editor.wrap.dom.firstChild.nextSibling, true);
46353 // can we do this more than once??
46355 // stop form submits
46358 // disable everything...
46359 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46360 this.toolbars = {};
46362 for (var i in ty) {
46364 this.toolbars[i] = this.buildToolbar(ty[i],i);
46366 this.tb = this.toolbars.BODY;
46368 this.buildFooter();
46369 this.footer.show();
46370 editor.on('hide', function( ) { this.footer.hide() }, this);
46371 editor.on('show', function( ) { this.footer.show() }, this);
46374 this.rendered = true;
46376 // the all the btns;
46377 editor.on('editorevent', this.updateToolbar, this);
46378 // other toolbars need to implement this..
46379 //editor.on('editmodechange', this.updateToolbar, this);
46385 * Protected method that will not generally be called directly. It triggers
46386 * a toolbar update by reading the markup state of the current selection in the editor.
46388 * Note you can force an update by calling on('editorevent', scope, false)
46390 updateToolbar: function(editor,ev,sel){
46393 // capture mouse up - this is handy for selecting images..
46394 // perhaps should go somewhere else...
46395 if(!this.editorcore.activated){
46396 this.editor.onFirstFocus();
46402 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46403 // selectNode - might want to handle IE?
46405 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46406 ev.target && ev.target.tagName == 'IMG') {
46407 // they have click on an image...
46408 // let's see if we can change the selection...
46411 var nodeRange = sel.ownerDocument.createRange();
46413 nodeRange.selectNode(sel);
46415 nodeRange.selectNodeContents(sel);
46417 //nodeRange.collapse(true);
46418 var s = this.editorcore.win.getSelection();
46419 s.removeAllRanges();
46420 s.addRange(nodeRange);
46424 var updateFooter = sel ? false : true;
46427 var ans = this.editorcore.getAllAncestors();
46430 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46433 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46434 sel = sel ? sel : this.editorcore.doc.body;
46435 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46438 // pick a menu that exists..
46439 var tn = sel.tagName.toUpperCase();
46440 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46442 tn = sel.tagName.toUpperCase();
46444 var lastSel = this.tb.selectedNode;
46446 this.tb.selectedNode = sel;
46448 // if current menu does not match..
46450 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46453 ///console.log("show: " + tn);
46454 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46457 this.tb.items.first().el.innerHTML = tn + ': ';
46460 // update attributes
46461 if (this.tb.fields) {
46462 this.tb.fields.each(function(e) {
46464 e.setValue(sel.style[e.stylename]);
46467 e.setValue(sel.getAttribute(e.attrname));
46471 var hasStyles = false;
46472 for(var i in this.styles) {
46479 var st = this.tb.fields.item(0);
46481 st.store.removeAll();
46484 var cn = sel.className.split(/\s+/);
46487 if (this.styles['*']) {
46489 Roo.each(this.styles['*'], function(v) {
46490 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46493 if (this.styles[tn]) {
46494 Roo.each(this.styles[tn], function(v) {
46495 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46499 st.store.loadData(avs);
46503 // flag our selected Node.
46504 this.tb.selectedNode = sel;
46507 Roo.menu.MenuMgr.hideAll();
46511 if (!updateFooter) {
46512 //this.footDisp.dom.innerHTML = '';
46515 // update the footer
46519 this.footerEls = ans.reverse();
46520 Roo.each(this.footerEls, function(a,i) {
46521 if (!a) { return; }
46522 html += html.length ? ' > ' : '';
46524 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46529 var sz = this.footDisp.up('td').getSize();
46530 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46531 this.footDisp.dom.style.marginLeft = '5px';
46533 this.footDisp.dom.style.overflow = 'hidden';
46535 this.footDisp.dom.innerHTML = html;
46537 //this.editorsyncValue();
46544 onDestroy : function(){
46547 this.tb.items.each(function(item){
46549 item.menu.removeAll();
46551 item.menu.el.destroy();
46559 onFirstFocus: function() {
46560 // need to do this for all the toolbars..
46561 this.tb.items.each(function(item){
46565 buildToolbar: function(tlist, nm)
46567 var editor = this.editor;
46568 var editorcore = this.editorcore;
46569 // create a new element.
46570 var wdiv = editor.wrap.createChild({
46572 }, editor.wrap.dom.firstChild.nextSibling, true);
46575 var tb = new Roo.Toolbar(wdiv);
46578 tb.add(nm+ ": ");
46581 for(var i in this.styles) {
46586 if (styles && styles.length) {
46588 // this needs a multi-select checkbox...
46589 tb.addField( new Roo.form.ComboBox({
46590 store: new Roo.data.SimpleStore({
46592 fields: ['val', 'selected'],
46595 name : '-roo-edit-className',
46596 attrname : 'className',
46597 displayField: 'val',
46601 triggerAction: 'all',
46602 emptyText:'Select Style',
46603 selectOnFocus:true,
46606 'select': function(c, r, i) {
46607 // initial support only for on class per el..
46608 tb.selectedNode.className = r ? r.get('val') : '';
46609 editorcore.syncValue();
46616 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46617 var tbops = tbc.options;
46619 for (var i in tlist) {
46621 var item = tlist[i];
46622 tb.add(item.title + ": ");
46625 //optname == used so you can configure the options available..
46626 var opts = item.opts ? item.opts : false;
46627 if (item.optname) {
46628 opts = tbops[item.optname];
46633 // opts == pulldown..
46634 tb.addField( new Roo.form.ComboBox({
46635 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46637 fields: ['val', 'display'],
46640 name : '-roo-edit-' + i,
46642 stylename : item.style ? item.style : false,
46643 displayField: item.displayField ? item.displayField : 'val',
46644 valueField : 'val',
46646 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46648 triggerAction: 'all',
46649 emptyText:'Select',
46650 selectOnFocus:true,
46651 width: item.width ? item.width : 130,
46653 'select': function(c, r, i) {
46655 tb.selectedNode.style[c.stylename] = r.get('val');
46658 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46667 tb.addField( new Roo.form.TextField({
46670 //allowBlank:false,
46675 tb.addField( new Roo.form.TextField({
46676 name: '-roo-edit-' + i,
46683 'change' : function(f, nv, ov) {
46684 tb.selectedNode.setAttribute(f.attrname, nv);
46685 editorcore.syncValue();
46698 text: 'Stylesheets',
46701 click : function ()
46703 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46711 text: 'Remove Tag',
46714 click : function ()
46717 // undo does not work.
46719 var sn = tb.selectedNode;
46721 var pn = sn.parentNode;
46723 var stn = sn.childNodes[0];
46724 var en = sn.childNodes[sn.childNodes.length - 1 ];
46725 while (sn.childNodes.length) {
46726 var node = sn.childNodes[0];
46727 sn.removeChild(node);
46729 pn.insertBefore(node, sn);
46732 pn.removeChild(sn);
46733 var range = editorcore.createRange();
46735 range.setStart(stn,0);
46736 range.setEnd(en,0); //????
46737 //range.selectNode(sel);
46740 var selection = editorcore.getSelection();
46741 selection.removeAllRanges();
46742 selection.addRange(range);
46746 //_this.updateToolbar(null, null, pn);
46747 _this.updateToolbar(null, null, null);
46748 _this.footDisp.dom.innerHTML = '';
46758 tb.el.on('click', function(e){
46759 e.preventDefault(); // what does this do?
46761 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46764 // dont need to disable them... as they will get hidden
46769 buildFooter : function()
46772 var fel = this.editor.wrap.createChild();
46773 this.footer = new Roo.Toolbar(fel);
46774 // toolbar has scrolly on left / right?
46775 var footDisp= new Roo.Toolbar.Fill();
46781 handler : function() {
46782 _t.footDisp.scrollTo('left',0,true)
46786 this.footer.add( footDisp );
46791 handler : function() {
46793 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46797 var fel = Roo.get(footDisp.el);
46798 fel.addClass('x-editor-context');
46799 this.footDispWrap = fel;
46800 this.footDispWrap.overflow = 'hidden';
46802 this.footDisp = fel.createChild();
46803 this.footDispWrap.on('click', this.onContextClick, this)
46807 onContextClick : function (ev,dom)
46809 ev.preventDefault();
46810 var cn = dom.className;
46812 if (!cn.match(/x-ed-loc-/)) {
46815 var n = cn.split('-').pop();
46816 var ans = this.footerEls;
46820 var range = this.editorcore.createRange();
46822 range.selectNodeContents(sel);
46823 //range.selectNode(sel);
46826 var selection = this.editorcore.getSelection();
46827 selection.removeAllRanges();
46828 selection.addRange(range);
46832 this.updateToolbar(null, null, sel);
46849 * Ext JS Library 1.1.1
46850 * Copyright(c) 2006-2007, Ext JS, LLC.
46852 * Originally Released Under LGPL - original licence link has changed is not relivant.
46855 * <script type="text/javascript">
46859 * @class Roo.form.BasicForm
46860 * @extends Roo.util.Observable
46861 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46863 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46864 * @param {Object} config Configuration options
46866 Roo.form.BasicForm = function(el, config){
46867 this.allItems = [];
46868 this.childForms = [];
46869 Roo.apply(this, config);
46871 * The Roo.form.Field items in this form.
46872 * @type MixedCollection
46876 this.items = new Roo.util.MixedCollection(false, function(o){
46877 return o.id || (o.id = Roo.id());
46881 * @event beforeaction
46882 * Fires before any action is performed. Return false to cancel the action.
46883 * @param {Form} this
46884 * @param {Action} action The action to be performed
46886 beforeaction: true,
46888 * @event actionfailed
46889 * Fires when an action fails.
46890 * @param {Form} this
46891 * @param {Action} action The action that failed
46893 actionfailed : true,
46895 * @event actioncomplete
46896 * Fires when an action is completed.
46897 * @param {Form} this
46898 * @param {Action} action The action that completed
46900 actioncomplete : true
46905 Roo.form.BasicForm.superclass.constructor.call(this);
46907 Roo.form.BasicForm.popover.apply();
46910 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46912 * @cfg {String} method
46913 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46916 * @cfg {DataReader} reader
46917 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46918 * This is optional as there is built-in support for processing JSON.
46921 * @cfg {DataReader} errorReader
46922 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46923 * This is completely optional as there is built-in support for processing JSON.
46926 * @cfg {String} url
46927 * The URL to use for form actions if one isn't supplied in the action options.
46930 * @cfg {Boolean} fileUpload
46931 * Set to true if this form is a file upload.
46935 * @cfg {Object} baseParams
46936 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46941 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46946 activeAction : null,
46949 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46950 * or setValues() data instead of when the form was first created.
46952 trackResetOnLoad : false,
46956 * childForms - used for multi-tab forms
46959 childForms : false,
46962 * allItems - full list of fields.
46968 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46969 * element by passing it or its id or mask the form itself by passing in true.
46972 waitMsgTarget : false,
46977 disableMask : false,
46980 * @cfg {Boolean} errorMask (true|false) default false
46985 * @cfg {Number} maskOffset Default 100
46990 initEl : function(el){
46991 this.el = Roo.get(el);
46992 this.id = this.el.id || Roo.id();
46993 this.el.on('submit', this.onSubmit, this);
46994 this.el.addClass('x-form');
46998 onSubmit : function(e){
47003 * Returns true if client-side validation on the form is successful.
47006 isValid : function(){
47008 var target = false;
47009 this.items.each(function(f){
47016 if(!target && f.el.isVisible(true)){
47021 if(this.errorMask && !valid){
47022 Roo.form.BasicForm.popover.mask(this, target);
47029 * DEPRICATED Returns true if any fields in this form have changed since their original load.
47032 isDirty : function(){
47034 this.items.each(function(f){
47044 * Returns true if any fields in this form have changed since their original load. (New version)
47048 hasChanged : function()
47051 this.items.each(function(f){
47052 if(f.hasChanged()){
47061 * Resets all hasChanged to 'false' -
47062 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
47063 * So hasChanged storage is only to be used for this purpose
47066 resetHasChanged : function()
47068 this.items.each(function(f){
47069 f.resetHasChanged();
47076 * Performs a predefined action (submit or load) or custom actions you define on this form.
47077 * @param {String} actionName The name of the action type
47078 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
47079 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
47080 * accept other config options):
47082 Property Type Description
47083 ---------------- --------------- ----------------------------------------------------------------------------------
47084 url String The url for the action (defaults to the form's url)
47085 method String The form method to use (defaults to the form's method, or POST if not defined)
47086 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
47087 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
47088 validate the form on the client (defaults to false)
47090 * @return {BasicForm} this
47092 doAction : function(action, options){
47093 if(typeof action == 'string'){
47094 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
47096 if(this.fireEvent('beforeaction', this, action) !== false){
47097 this.beforeAction(action);
47098 action.run.defer(100, action);
47104 * Shortcut to do a submit action.
47105 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47106 * @return {BasicForm} this
47108 submit : function(options){
47109 this.doAction('submit', options);
47114 * Shortcut to do a load action.
47115 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47116 * @return {BasicForm} this
47118 load : function(options){
47119 this.doAction('load', options);
47124 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
47125 * @param {Record} record The record to edit
47126 * @return {BasicForm} this
47128 updateRecord : function(record){
47129 record.beginEdit();
47130 var fs = record.fields;
47131 fs.each(function(f){
47132 var field = this.findField(f.name);
47134 record.set(f.name, field.getValue());
47142 * Loads an Roo.data.Record into this form.
47143 * @param {Record} record The record to load
47144 * @return {BasicForm} this
47146 loadRecord : function(record){
47147 this.setValues(record.data);
47152 beforeAction : function(action){
47153 var o = action.options;
47155 if(!this.disableMask) {
47156 if(this.waitMsgTarget === true){
47157 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
47158 }else if(this.waitMsgTarget){
47159 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
47160 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
47162 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
47170 afterAction : function(action, success){
47171 this.activeAction = null;
47172 var o = action.options;
47174 if(!this.disableMask) {
47175 if(this.waitMsgTarget === true){
47177 }else if(this.waitMsgTarget){
47178 this.waitMsgTarget.unmask();
47180 Roo.MessageBox.updateProgress(1);
47181 Roo.MessageBox.hide();
47189 Roo.callback(o.success, o.scope, [this, action]);
47190 this.fireEvent('actioncomplete', this, action);
47194 // failure condition..
47195 // we have a scenario where updates need confirming.
47196 // eg. if a locking scenario exists..
47197 // we look for { errors : { needs_confirm : true }} in the response.
47199 (typeof(action.result) != 'undefined') &&
47200 (typeof(action.result.errors) != 'undefined') &&
47201 (typeof(action.result.errors.needs_confirm) != 'undefined')
47204 Roo.MessageBox.confirm(
47205 "Change requires confirmation",
47206 action.result.errorMsg,
47211 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
47221 Roo.callback(o.failure, o.scope, [this, action]);
47222 // show an error message if no failed handler is set..
47223 if (!this.hasListener('actionfailed')) {
47224 Roo.MessageBox.alert("Error",
47225 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
47226 action.result.errorMsg :
47227 "Saving Failed, please check your entries or try again"
47231 this.fireEvent('actionfailed', this, action);
47237 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
47238 * @param {String} id The value to search for
47241 findField : function(id){
47242 var field = this.items.get(id);
47244 this.items.each(function(f){
47245 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
47251 return field || null;
47255 * Add a secondary form to this one,
47256 * Used to provide tabbed forms. One form is primary, with hidden values
47257 * which mirror the elements from the other forms.
47259 * @param {Roo.form.Form} form to add.
47262 addForm : function(form)
47265 if (this.childForms.indexOf(form) > -1) {
47269 this.childForms.push(form);
47271 Roo.each(form.allItems, function (fe) {
47273 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
47274 if (this.findField(n)) { // already added..
47277 var add = new Roo.form.Hidden({
47280 add.render(this.el);
47287 * Mark fields in this form invalid in bulk.
47288 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
47289 * @return {BasicForm} this
47291 markInvalid : function(errors){
47292 if(errors instanceof Array){
47293 for(var i = 0, len = errors.length; i < len; i++){
47294 var fieldError = errors[i];
47295 var f = this.findField(fieldError.id);
47297 f.markInvalid(fieldError.msg);
47303 if(typeof errors[id] != 'function' && (field = this.findField(id))){
47304 field.markInvalid(errors[id]);
47308 Roo.each(this.childForms || [], function (f) {
47309 f.markInvalid(errors);
47316 * Set values for fields in this form in bulk.
47317 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
47318 * @return {BasicForm} this
47320 setValues : function(values){
47321 if(values instanceof Array){ // array of objects
47322 for(var i = 0, len = values.length; i < len; i++){
47324 var f = this.findField(v.id);
47326 f.setValue(v.value);
47327 if(this.trackResetOnLoad){
47328 f.originalValue = f.getValue();
47332 }else{ // object hash
47335 if(typeof values[id] != 'function' && (field = this.findField(id))){
47337 if (field.setFromData &&
47338 field.valueField &&
47339 field.displayField &&
47340 // combos' with local stores can
47341 // be queried via setValue()
47342 // to set their value..
47343 (field.store && !field.store.isLocal)
47347 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
47348 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
47349 field.setFromData(sd);
47352 field.setValue(values[id]);
47356 if(this.trackResetOnLoad){
47357 field.originalValue = field.getValue();
47362 this.resetHasChanged();
47365 Roo.each(this.childForms || [], function (f) {
47366 f.setValues(values);
47367 f.resetHasChanged();
47374 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47375 * they are returned as an array.
47376 * @param {Boolean} asString
47379 getValues : function(asString){
47380 if (this.childForms) {
47381 // copy values from the child forms
47382 Roo.each(this.childForms, function (f) {
47383 this.setValues(f.getValues());
47388 if (typeof(FormData) != 'undefined' && asString !== true) {
47389 var fd = (new FormData(this.el.dom)).entries();
47391 var ent = fd.next();
47392 while (!ent.done) {
47393 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
47400 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47401 if(asString === true){
47404 return Roo.urlDecode(fs);
47408 * Returns the fields in this form as an object with key/value pairs.
47409 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47412 getFieldValues : function(with_hidden)
47414 if (this.childForms) {
47415 // copy values from the child forms
47416 // should this call getFieldValues - probably not as we do not currently copy
47417 // hidden fields when we generate..
47418 Roo.each(this.childForms, function (f) {
47419 this.setValues(f.getValues());
47424 this.items.each(function(f){
47425 if (!f.getName()) {
47428 var v = f.getValue();
47429 if (f.inputType =='radio') {
47430 if (typeof(ret[f.getName()]) == 'undefined') {
47431 ret[f.getName()] = ''; // empty..
47434 if (!f.el.dom.checked) {
47438 v = f.el.dom.value;
47442 // not sure if this supported any more..
47443 if ((typeof(v) == 'object') && f.getRawValue) {
47444 v = f.getRawValue() ; // dates..
47446 // combo boxes where name != hiddenName...
47447 if (f.name != f.getName()) {
47448 ret[f.name] = f.getRawValue();
47450 ret[f.getName()] = v;
47457 * Clears all invalid messages in this form.
47458 * @return {BasicForm} this
47460 clearInvalid : function(){
47461 this.items.each(function(f){
47465 Roo.each(this.childForms || [], function (f) {
47474 * Resets this form.
47475 * @return {BasicForm} this
47477 reset : function(){
47478 this.items.each(function(f){
47482 Roo.each(this.childForms || [], function (f) {
47485 this.resetHasChanged();
47491 * Add Roo.form components to this form.
47492 * @param {Field} field1
47493 * @param {Field} field2 (optional)
47494 * @param {Field} etc (optional)
47495 * @return {BasicForm} this
47498 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47504 * Removes a field from the items collection (does NOT remove its markup).
47505 * @param {Field} field
47506 * @return {BasicForm} this
47508 remove : function(field){
47509 this.items.remove(field);
47514 * Looks at the fields in this form, checks them for an id attribute,
47515 * and calls applyTo on the existing dom element with that id.
47516 * @return {BasicForm} this
47518 render : function(){
47519 this.items.each(function(f){
47520 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47528 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47529 * @param {Object} values
47530 * @return {BasicForm} this
47532 applyToFields : function(o){
47533 this.items.each(function(f){
47540 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47541 * @param {Object} values
47542 * @return {BasicForm} this
47544 applyIfToFields : function(o){
47545 this.items.each(function(f){
47553 Roo.BasicForm = Roo.form.BasicForm;
47555 Roo.apply(Roo.form.BasicForm, {
47569 intervalID : false,
47575 if(this.isApplied){
47580 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
47581 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
47582 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
47583 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
47586 this.maskEl.top.enableDisplayMode("block");
47587 this.maskEl.left.enableDisplayMode("block");
47588 this.maskEl.bottom.enableDisplayMode("block");
47589 this.maskEl.right.enableDisplayMode("block");
47591 Roo.get(document.body).on('click', function(){
47595 Roo.get(document.body).on('touchstart', function(){
47599 this.isApplied = true
47602 mask : function(form, target)
47606 this.target = target;
47608 if(!this.form.errorMask || !target.el){
47612 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
47614 var ot = this.target.el.calcOffsetsTo(scrollable);
47616 var scrollTo = ot[1] - this.form.maskOffset;
47618 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
47620 scrollable.scrollTo('top', scrollTo);
47622 var el = this.target.wrap || this.target.el;
47624 var box = el.getBox();
47626 this.maskEl.top.setStyle('position', 'absolute');
47627 this.maskEl.top.setStyle('z-index', 10000);
47628 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
47629 this.maskEl.top.setLeft(0);
47630 this.maskEl.top.setTop(0);
47631 this.maskEl.top.show();
47633 this.maskEl.left.setStyle('position', 'absolute');
47634 this.maskEl.left.setStyle('z-index', 10000);
47635 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
47636 this.maskEl.left.setLeft(0);
47637 this.maskEl.left.setTop(box.y - this.padding);
47638 this.maskEl.left.show();
47640 this.maskEl.bottom.setStyle('position', 'absolute');
47641 this.maskEl.bottom.setStyle('z-index', 10000);
47642 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
47643 this.maskEl.bottom.setLeft(0);
47644 this.maskEl.bottom.setTop(box.bottom + this.padding);
47645 this.maskEl.bottom.show();
47647 this.maskEl.right.setStyle('position', 'absolute');
47648 this.maskEl.right.setStyle('z-index', 10000);
47649 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
47650 this.maskEl.right.setLeft(box.right + this.padding);
47651 this.maskEl.right.setTop(box.y - this.padding);
47652 this.maskEl.right.show();
47654 this.intervalID = window.setInterval(function() {
47655 Roo.form.BasicForm.popover.unmask();
47658 window.onwheel = function(){ return false;};
47660 (function(){ this.isMasked = true; }).defer(500, this);
47664 unmask : function()
47666 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
47670 this.maskEl.top.setStyle('position', 'absolute');
47671 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
47672 this.maskEl.top.hide();
47674 this.maskEl.left.setStyle('position', 'absolute');
47675 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
47676 this.maskEl.left.hide();
47678 this.maskEl.bottom.setStyle('position', 'absolute');
47679 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
47680 this.maskEl.bottom.hide();
47682 this.maskEl.right.setStyle('position', 'absolute');
47683 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
47684 this.maskEl.right.hide();
47686 window.onwheel = function(){ return true;};
47688 if(this.intervalID){
47689 window.clearInterval(this.intervalID);
47690 this.intervalID = false;
47693 this.isMasked = false;
47701 * Ext JS Library 1.1.1
47702 * Copyright(c) 2006-2007, Ext JS, LLC.
47704 * Originally Released Under LGPL - original licence link has changed is not relivant.
47707 * <script type="text/javascript">
47711 * @class Roo.form.Form
47712 * @extends Roo.form.BasicForm
47713 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47715 * @param {Object} config Configuration options
47717 Roo.form.Form = function(config){
47719 if (config.items) {
47720 xitems = config.items;
47721 delete config.items;
47725 Roo.form.Form.superclass.constructor.call(this, null, config);
47726 this.url = this.url || this.action;
47728 this.root = new Roo.form.Layout(Roo.applyIf({
47732 this.active = this.root;
47734 * Array of all the buttons that have been added to this form via {@link addButton}
47738 this.allItems = [];
47741 * @event clientvalidation
47742 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47743 * @param {Form} this
47744 * @param {Boolean} valid true if the form has passed client-side validation
47746 clientvalidation: true,
47749 * Fires when the form is rendered
47750 * @param {Roo.form.Form} form
47755 if (this.progressUrl) {
47756 // push a hidden field onto the list of fields..
47760 name : 'UPLOAD_IDENTIFIER'
47765 Roo.each(xitems, this.addxtype, this);
47769 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47771 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47774 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47777 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47779 buttonAlign:'center',
47782 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47787 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47788 * This property cascades to child containers if not set.
47793 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47794 * fires a looping event with that state. This is required to bind buttons to the valid
47795 * state using the config value formBind:true on the button.
47797 monitorValid : false,
47800 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47805 * @cfg {String} progressUrl - Url to return progress data
47808 progressUrl : false,
47810 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
47811 * sending a formdata with extra parameters - eg uploaded elements.
47817 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47818 * fields are added and the column is closed. If no fields are passed the column remains open
47819 * until end() is called.
47820 * @param {Object} config The config to pass to the column
47821 * @param {Field} field1 (optional)
47822 * @param {Field} field2 (optional)
47823 * @param {Field} etc (optional)
47824 * @return Column The column container object
47826 column : function(c){
47827 var col = new Roo.form.Column(c);
47829 if(arguments.length > 1){ // duplicate code required because of Opera
47830 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47837 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47838 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47839 * until end() is called.
47840 * @param {Object} config The config to pass to the fieldset
47841 * @param {Field} field1 (optional)
47842 * @param {Field} field2 (optional)
47843 * @param {Field} etc (optional)
47844 * @return FieldSet The fieldset container object
47846 fieldset : function(c){
47847 var fs = new Roo.form.FieldSet(c);
47849 if(arguments.length > 1){ // duplicate code required because of Opera
47850 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47857 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47858 * fields are added and the container is closed. If no fields are passed the container remains open
47859 * until end() is called.
47860 * @param {Object} config The config to pass to the Layout
47861 * @param {Field} field1 (optional)
47862 * @param {Field} field2 (optional)
47863 * @param {Field} etc (optional)
47864 * @return Layout The container object
47866 container : function(c){
47867 var l = new Roo.form.Layout(c);
47869 if(arguments.length > 1){ // duplicate code required because of Opera
47870 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47877 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47878 * @param {Object} container A Roo.form.Layout or subclass of Layout
47879 * @return {Form} this
47881 start : function(c){
47882 // cascade label info
47883 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47884 this.active.stack.push(c);
47885 c.ownerCt = this.active;
47891 * Closes the current open container
47892 * @return {Form} this
47895 if(this.active == this.root){
47898 this.active = this.active.ownerCt;
47903 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47904 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47905 * as the label of the field.
47906 * @param {Field} field1
47907 * @param {Field} field2 (optional)
47908 * @param {Field} etc. (optional)
47909 * @return {Form} this
47912 this.active.stack.push.apply(this.active.stack, arguments);
47913 this.allItems.push.apply(this.allItems,arguments);
47915 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47916 if(a[i].isFormField){
47921 Roo.form.Form.superclass.add.apply(this, r);
47931 * Find any element that has been added to a form, using it's ID or name
47932 * This can include framesets, columns etc. along with regular fields..
47933 * @param {String} id - id or name to find.
47935 * @return {Element} e - or false if nothing found.
47937 findbyId : function(id)
47943 Roo.each(this.allItems, function(f){
47944 if (f.id == id || f.name == id ){
47955 * Render this form into the passed container. This should only be called once!
47956 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47957 * @return {Form} this
47959 render : function(ct)
47965 var o = this.autoCreate || {
47967 method : this.method || 'POST',
47968 id : this.id || Roo.id()
47970 this.initEl(ct.createChild(o));
47972 this.root.render(this.el);
47976 this.items.each(function(f){
47977 f.render('x-form-el-'+f.id);
47980 if(this.buttons.length > 0){
47981 // tables are required to maintain order and for correct IE layout
47982 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47983 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47984 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47986 var tr = tb.getElementsByTagName('tr')[0];
47987 for(var i = 0, len = this.buttons.length; i < len; i++) {
47988 var b = this.buttons[i];
47989 var td = document.createElement('td');
47990 td.className = 'x-form-btn-td';
47991 b.render(tr.appendChild(td));
47994 if(this.monitorValid){ // initialize after render
47995 this.startMonitoring();
47997 this.fireEvent('rendered', this);
48002 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
48003 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
48004 * object or a valid Roo.DomHelper element config
48005 * @param {Function} handler The function called when the button is clicked
48006 * @param {Object} scope (optional) The scope of the handler function
48007 * @return {Roo.Button}
48009 addButton : function(config, handler, scope){
48013 minWidth: this.minButtonWidth,
48016 if(typeof config == "string"){
48019 Roo.apply(bc, config);
48021 var btn = new Roo.Button(null, bc);
48022 this.buttons.push(btn);
48027 * Adds a series of form elements (using the xtype property as the factory method.
48028 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
48029 * @param {Object} config
48032 addxtype : function()
48034 var ar = Array.prototype.slice.call(arguments, 0);
48036 for(var i = 0; i < ar.length; i++) {
48038 continue; // skip -- if this happends something invalid got sent, we
48039 // should ignore it, as basically that interface element will not show up
48040 // and that should be pretty obvious!!
48043 if (Roo.form[ar[i].xtype]) {
48045 var fe = Roo.factory(ar[i], Roo.form);
48051 fe.store.form = this;
48056 this.allItems.push(fe);
48057 if (fe.items && fe.addxtype) {
48058 fe.addxtype.apply(fe, fe.items);
48068 // console.log('adding ' + ar[i].xtype);
48070 if (ar[i].xtype == 'Button') {
48071 //console.log('adding button');
48072 //console.log(ar[i]);
48073 this.addButton(ar[i]);
48074 this.allItems.push(fe);
48078 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
48079 alert('end is not supported on xtype any more, use items');
48081 // //console.log('adding end');
48089 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
48090 * option "monitorValid"
48092 startMonitoring : function(){
48095 Roo.TaskMgr.start({
48096 run : this.bindHandler,
48097 interval : this.monitorPoll || 200,
48104 * Stops monitoring of the valid state of this form
48106 stopMonitoring : function(){
48107 this.bound = false;
48111 bindHandler : function(){
48113 return false; // stops binding
48116 this.items.each(function(f){
48117 if(!f.isValid(true)){
48122 for(var i = 0, len = this.buttons.length; i < len; i++){
48123 var btn = this.buttons[i];
48124 if(btn.formBind === true && btn.disabled === valid){
48125 btn.setDisabled(!valid);
48128 this.fireEvent('clientvalidation', this, valid);
48142 Roo.Form = Roo.form.Form;
48145 * Ext JS Library 1.1.1
48146 * Copyright(c) 2006-2007, Ext JS, LLC.
48148 * Originally Released Under LGPL - original licence link has changed is not relivant.
48151 * <script type="text/javascript">
48154 // as we use this in bootstrap.
48155 Roo.namespace('Roo.form');
48157 * @class Roo.form.Action
48158 * Internal Class used to handle form actions
48160 * @param {Roo.form.BasicForm} el The form element or its id
48161 * @param {Object} config Configuration options
48166 // define the action interface
48167 Roo.form.Action = function(form, options){
48169 this.options = options || {};
48172 * Client Validation Failed
48175 Roo.form.Action.CLIENT_INVALID = 'client';
48177 * Server Validation Failed
48180 Roo.form.Action.SERVER_INVALID = 'server';
48182 * Connect to Server Failed
48185 Roo.form.Action.CONNECT_FAILURE = 'connect';
48187 * Reading Data from Server Failed
48190 Roo.form.Action.LOAD_FAILURE = 'load';
48192 Roo.form.Action.prototype = {
48194 failureType : undefined,
48195 response : undefined,
48196 result : undefined,
48198 // interface method
48199 run : function(options){
48203 // interface method
48204 success : function(response){
48208 // interface method
48209 handleResponse : function(response){
48213 // default connection failure
48214 failure : function(response){
48216 this.response = response;
48217 this.failureType = Roo.form.Action.CONNECT_FAILURE;
48218 this.form.afterAction(this, false);
48221 processResponse : function(response){
48222 this.response = response;
48223 if(!response.responseText){
48226 this.result = this.handleResponse(response);
48227 return this.result;
48230 // utility functions used internally
48231 getUrl : function(appendParams){
48232 var url = this.options.url || this.form.url || this.form.el.dom.action;
48234 var p = this.getParams();
48236 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
48242 getMethod : function(){
48243 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
48246 getParams : function(){
48247 var bp = this.form.baseParams;
48248 var p = this.options.params;
48250 if(typeof p == "object"){
48251 p = Roo.urlEncode(Roo.applyIf(p, bp));
48252 }else if(typeof p == 'string' && bp){
48253 p += '&' + Roo.urlEncode(bp);
48256 p = Roo.urlEncode(bp);
48261 createCallback : function(){
48263 success: this.success,
48264 failure: this.failure,
48266 timeout: (this.form.timeout*1000),
48267 upload: this.form.fileUpload ? this.success : undefined
48272 Roo.form.Action.Submit = function(form, options){
48273 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
48276 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
48279 haveProgress : false,
48280 uploadComplete : false,
48282 // uploadProgress indicator.
48283 uploadProgress : function()
48285 if (!this.form.progressUrl) {
48289 if (!this.haveProgress) {
48290 Roo.MessageBox.progress("Uploading", "Uploading");
48292 if (this.uploadComplete) {
48293 Roo.MessageBox.hide();
48297 this.haveProgress = true;
48299 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
48301 var c = new Roo.data.Connection();
48303 url : this.form.progressUrl,
48308 success : function(req){
48309 //console.log(data);
48313 rdata = Roo.decode(req.responseText)
48315 Roo.log("Invalid data from server..");
48319 if (!rdata || !rdata.success) {
48321 Roo.MessageBox.alert(Roo.encode(rdata));
48324 var data = rdata.data;
48326 if (this.uploadComplete) {
48327 Roo.MessageBox.hide();
48332 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
48333 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
48336 this.uploadProgress.defer(2000,this);
48339 failure: function(data) {
48340 Roo.log('progress url failed ');
48351 // run get Values on the form, so it syncs any secondary forms.
48352 this.form.getValues();
48354 var o = this.options;
48355 var method = this.getMethod();
48356 var isPost = method == 'POST';
48357 if(o.clientValidation === false || this.form.isValid()){
48359 if (this.form.progressUrl) {
48360 this.form.findField('UPLOAD_IDENTIFIER').setValue(
48361 (new Date() * 1) + '' + Math.random());
48366 Roo.Ajax.request(Roo.apply(this.createCallback(), {
48367 form:this.form.el.dom,
48368 url:this.getUrl(!isPost),
48370 params:isPost ? this.getParams() : null,
48371 isUpload: this.form.fileUpload,
48372 formData : this.form.formData
48375 this.uploadProgress();
48377 }else if (o.clientValidation !== false){ // client validation failed
48378 this.failureType = Roo.form.Action.CLIENT_INVALID;
48379 this.form.afterAction(this, false);
48383 success : function(response)
48385 this.uploadComplete= true;
48386 if (this.haveProgress) {
48387 Roo.MessageBox.hide();
48391 var result = this.processResponse(response);
48392 if(result === true || result.success){
48393 this.form.afterAction(this, true);
48397 this.form.markInvalid(result.errors);
48398 this.failureType = Roo.form.Action.SERVER_INVALID;
48400 this.form.afterAction(this, false);
48402 failure : function(response)
48404 this.uploadComplete= true;
48405 if (this.haveProgress) {
48406 Roo.MessageBox.hide();
48409 this.response = response;
48410 this.failureType = Roo.form.Action.CONNECT_FAILURE;
48411 this.form.afterAction(this, false);
48414 handleResponse : function(response){
48415 if(this.form.errorReader){
48416 var rs = this.form.errorReader.read(response);
48419 for(var i = 0, len = rs.records.length; i < len; i++) {
48420 var r = rs.records[i];
48421 errors[i] = r.data;
48424 if(errors.length < 1){
48428 success : rs.success,
48434 ret = Roo.decode(response.responseText);
48438 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
48448 Roo.form.Action.Load = function(form, options){
48449 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
48450 this.reader = this.form.reader;
48453 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
48458 Roo.Ajax.request(Roo.apply(
48459 this.createCallback(), {
48460 method:this.getMethod(),
48461 url:this.getUrl(false),
48462 params:this.getParams()
48466 success : function(response){
48468 var result = this.processResponse(response);
48469 if(result === true || !result.success || !result.data){
48470 this.failureType = Roo.form.Action.LOAD_FAILURE;
48471 this.form.afterAction(this, false);
48474 this.form.clearInvalid();
48475 this.form.setValues(result.data);
48476 this.form.afterAction(this, true);
48479 handleResponse : function(response){
48480 if(this.form.reader){
48481 var rs = this.form.reader.read(response);
48482 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
48484 success : rs.success,
48488 return Roo.decode(response.responseText);
48492 Roo.form.Action.ACTION_TYPES = {
48493 'load' : Roo.form.Action.Load,
48494 'submit' : Roo.form.Action.Submit
48497 * Ext JS Library 1.1.1
48498 * Copyright(c) 2006-2007, Ext JS, LLC.
48500 * Originally Released Under LGPL - original licence link has changed is not relivant.
48503 * <script type="text/javascript">
48507 * @class Roo.form.Layout
48508 * @extends Roo.Component
48509 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
48511 * @param {Object} config Configuration options
48513 Roo.form.Layout = function(config){
48515 if (config.items) {
48516 xitems = config.items;
48517 delete config.items;
48519 Roo.form.Layout.superclass.constructor.call(this, config);
48521 Roo.each(xitems, this.addxtype, this);
48525 Roo.extend(Roo.form.Layout, Roo.Component, {
48527 * @cfg {String/Object} autoCreate
48528 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
48531 * @cfg {String/Object/Function} style
48532 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
48533 * a function which returns such a specification.
48536 * @cfg {String} labelAlign
48537 * Valid values are "left," "top" and "right" (defaults to "left")
48540 * @cfg {Number} labelWidth
48541 * Fixed width in pixels of all field labels (defaults to undefined)
48544 * @cfg {Boolean} clear
48545 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
48549 * @cfg {String} labelSeparator
48550 * The separator to use after field labels (defaults to ':')
48552 labelSeparator : ':',
48554 * @cfg {Boolean} hideLabels
48555 * True to suppress the display of field labels in this layout (defaults to false)
48557 hideLabels : false,
48560 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48565 onRender : function(ct, position){
48566 if(this.el){ // from markup
48567 this.el = Roo.get(this.el);
48568 }else { // generate
48569 var cfg = this.getAutoCreate();
48570 this.el = ct.createChild(cfg, position);
48573 this.el.applyStyles(this.style);
48575 if(this.labelAlign){
48576 this.el.addClass('x-form-label-'+this.labelAlign);
48578 if(this.hideLabels){
48579 this.labelStyle = "display:none";
48580 this.elementStyle = "padding-left:0;";
48582 if(typeof this.labelWidth == 'number'){
48583 this.labelStyle = "width:"+this.labelWidth+"px;";
48584 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48586 if(this.labelAlign == 'top'){
48587 this.labelStyle = "width:auto;";
48588 this.elementStyle = "padding-left:0;";
48591 var stack = this.stack;
48592 var slen = stack.length;
48594 if(!this.fieldTpl){
48595 var t = new Roo.Template(
48596 '<div class="x-form-item {5}">',
48597 '<label for="{0}" style="{2}">{1}{4}</label>',
48598 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48600 '</div><div class="x-form-clear-left"></div>'
48602 t.disableFormats = true;
48604 Roo.form.Layout.prototype.fieldTpl = t;
48606 for(var i = 0; i < slen; i++) {
48607 if(stack[i].isFormField){
48608 this.renderField(stack[i]);
48610 this.renderComponent(stack[i]);
48615 this.el.createChild({cls:'x-form-clear'});
48620 renderField : function(f){
48621 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48624 f.labelStyle||this.labelStyle||'', //2
48625 this.elementStyle||'', //3
48626 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48627 f.itemCls||this.itemCls||'' //5
48628 ], true).getPrevSibling());
48632 renderComponent : function(c){
48633 c.render(c.isLayout ? this.el : this.el.createChild());
48636 * Adds a object form elements (using the xtype property as the factory method.)
48637 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48638 * @param {Object} config
48640 addxtype : function(o)
48642 // create the lement.
48643 o.form = this.form;
48644 var fe = Roo.factory(o, Roo.form);
48645 this.form.allItems.push(fe);
48646 this.stack.push(fe);
48648 if (fe.isFormField) {
48649 this.form.items.add(fe);
48657 * @class Roo.form.Column
48658 * @extends Roo.form.Layout
48659 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48661 * @param {Object} config Configuration options
48663 Roo.form.Column = function(config){
48664 Roo.form.Column.superclass.constructor.call(this, config);
48667 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48669 * @cfg {Number/String} width
48670 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48673 * @cfg {String/Object} autoCreate
48674 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48678 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48681 onRender : function(ct, position){
48682 Roo.form.Column.superclass.onRender.call(this, ct, position);
48684 this.el.setWidth(this.width);
48691 * @class Roo.form.Row
48692 * @extends Roo.form.Layout
48693 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48695 * @param {Object} config Configuration options
48699 Roo.form.Row = function(config){
48700 Roo.form.Row.superclass.constructor.call(this, config);
48703 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48705 * @cfg {Number/String} width
48706 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48709 * @cfg {Number/String} height
48710 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48712 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48716 onRender : function(ct, position){
48717 //console.log('row render');
48719 var t = new Roo.Template(
48720 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48721 '<label for="{0}" style="{2}">{1}{4}</label>',
48722 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48726 t.disableFormats = true;
48728 Roo.form.Layout.prototype.rowTpl = t;
48730 this.fieldTpl = this.rowTpl;
48732 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48733 var labelWidth = 100;
48735 if ((this.labelAlign != 'top')) {
48736 if (typeof this.labelWidth == 'number') {
48737 labelWidth = this.labelWidth
48739 this.padWidth = 20 + labelWidth;
48743 Roo.form.Column.superclass.onRender.call(this, ct, position);
48745 this.el.setWidth(this.width);
48748 this.el.setHeight(this.height);
48753 renderField : function(f){
48754 f.fieldEl = this.fieldTpl.append(this.el, [
48755 f.id, f.fieldLabel,
48756 f.labelStyle||this.labelStyle||'',
48757 this.elementStyle||'',
48758 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48759 f.itemCls||this.itemCls||'',
48760 f.width ? f.width + this.padWidth : 160 + this.padWidth
48767 * @class Roo.form.FieldSet
48768 * @extends Roo.form.Layout
48769 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48771 * @param {Object} config Configuration options
48773 Roo.form.FieldSet = function(config){
48774 Roo.form.FieldSet.superclass.constructor.call(this, config);
48777 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48779 * @cfg {String} legend
48780 * The text to display as the legend for the FieldSet (defaults to '')
48783 * @cfg {String/Object} autoCreate
48784 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48788 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48791 onRender : function(ct, position){
48792 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48794 this.setLegend(this.legend);
48799 setLegend : function(text){
48801 this.el.child('legend').update(text);
48806 * Ext JS Library 1.1.1
48807 * Copyright(c) 2006-2007, Ext JS, LLC.
48809 * Originally Released Under LGPL - original licence link has changed is not relivant.
48812 * <script type="text/javascript">
48815 * @class Roo.form.VTypes
48816 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48819 Roo.form.VTypes = function(){
48820 // closure these in so they are only created once.
48821 var alpha = /^[a-zA-Z_]+$/;
48822 var alphanum = /^[a-zA-Z0-9_]+$/;
48823 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48824 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48826 // All these messages and functions are configurable
48829 * The function used to validate email addresses
48830 * @param {String} value The email address
48832 'email' : function(v){
48833 return email.test(v);
48836 * The error text to display when the email validation function returns false
48839 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48841 * The keystroke filter mask to be applied on email input
48844 'emailMask' : /[a-z0-9_\.\-@]/i,
48847 * The function used to validate URLs
48848 * @param {String} value The URL
48850 'url' : function(v){
48851 return url.test(v);
48854 * The error text to display when the url validation function returns false
48857 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48860 * The function used to validate alpha values
48861 * @param {String} value The value
48863 'alpha' : function(v){
48864 return alpha.test(v);
48867 * The error text to display when the alpha validation function returns false
48870 'alphaText' : 'This field should only contain letters and _',
48872 * The keystroke filter mask to be applied on alpha input
48875 'alphaMask' : /[a-z_]/i,
48878 * The function used to validate alphanumeric values
48879 * @param {String} value The value
48881 'alphanum' : function(v){
48882 return alphanum.test(v);
48885 * The error text to display when the alphanumeric validation function returns false
48888 'alphanumText' : 'This field should only contain letters, numbers and _',
48890 * The keystroke filter mask to be applied on alphanumeric input
48893 'alphanumMask' : /[a-z0-9_]/i
48895 }();//<script type="text/javascript">
48898 * @class Roo.form.FCKeditor
48899 * @extends Roo.form.TextArea
48900 * Wrapper around the FCKEditor http://www.fckeditor.net
48902 * Creates a new FCKeditor
48903 * @param {Object} config Configuration options
48905 Roo.form.FCKeditor = function(config){
48906 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48909 * @event editorinit
48910 * Fired when the editor is initialized - you can add extra handlers here..
48911 * @param {FCKeditor} this
48912 * @param {Object} the FCK object.
48919 Roo.form.FCKeditor.editors = { };
48920 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48922 //defaultAutoCreate : {
48923 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48927 * @cfg {Object} fck options - see fck manual for details.
48932 * @cfg {Object} fck toolbar set (Basic or Default)
48934 toolbarSet : 'Basic',
48936 * @cfg {Object} fck BasePath
48938 basePath : '/fckeditor/',
48946 onRender : function(ct, position)
48949 this.defaultAutoCreate = {
48951 style:"width:300px;height:60px;",
48952 autocomplete: "new-password"
48955 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48958 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48959 if(this.preventScrollbars){
48960 this.el.setStyle("overflow", "hidden");
48962 this.el.setHeight(this.growMin);
48965 //console.log('onrender' + this.getId() );
48966 Roo.form.FCKeditor.editors[this.getId()] = this;
48969 this.replaceTextarea() ;
48973 getEditor : function() {
48974 return this.fckEditor;
48977 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48978 * @param {Mixed} value The value to set
48982 setValue : function(value)
48984 //console.log('setValue: ' + value);
48986 if(typeof(value) == 'undefined') { // not sure why this is happending...
48989 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48991 //if(!this.el || !this.getEditor()) {
48992 // this.value = value;
48993 //this.setValue.defer(100,this,[value]);
48997 if(!this.getEditor()) {
49001 this.getEditor().SetData(value);
49008 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
49009 * @return {Mixed} value The field value
49011 getValue : function()
49014 if (this.frame && this.frame.dom.style.display == 'none') {
49015 return Roo.form.FCKeditor.superclass.getValue.call(this);
49018 if(!this.el || !this.getEditor()) {
49020 // this.getValue.defer(100,this);
49025 var value=this.getEditor().GetData();
49026 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49027 return Roo.form.FCKeditor.superclass.getValue.call(this);
49033 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
49034 * @return {Mixed} value The field value
49036 getRawValue : function()
49038 if (this.frame && this.frame.dom.style.display == 'none') {
49039 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49042 if(!this.el || !this.getEditor()) {
49043 //this.getRawValue.defer(100,this);
49050 var value=this.getEditor().GetData();
49051 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
49052 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49056 setSize : function(w,h) {
49060 //if (this.frame && this.frame.dom.style.display == 'none') {
49061 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49064 //if(!this.el || !this.getEditor()) {
49065 // this.setSize.defer(100,this, [w,h]);
49071 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49073 this.frame.dom.setAttribute('width', w);
49074 this.frame.dom.setAttribute('height', h);
49075 this.frame.setSize(w,h);
49079 toggleSourceEdit : function(value) {
49083 this.el.dom.style.display = value ? '' : 'none';
49084 this.frame.dom.style.display = value ? 'none' : '';
49089 focus: function(tag)
49091 if (this.frame.dom.style.display == 'none') {
49092 return Roo.form.FCKeditor.superclass.focus.call(this);
49094 if(!this.el || !this.getEditor()) {
49095 this.focus.defer(100,this, [tag]);
49102 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
49103 this.getEditor().Focus();
49105 if (!this.getEditor().Selection.GetSelection()) {
49106 this.focus.defer(100,this, [tag]);
49111 var r = this.getEditor().EditorDocument.createRange();
49112 r.setStart(tgs[0],0);
49113 r.setEnd(tgs[0],0);
49114 this.getEditor().Selection.GetSelection().removeAllRanges();
49115 this.getEditor().Selection.GetSelection().addRange(r);
49116 this.getEditor().Focus();
49123 replaceTextarea : function()
49125 if ( document.getElementById( this.getId() + '___Frame' ) ) {
49128 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
49130 // We must check the elements firstly using the Id and then the name.
49131 var oTextarea = document.getElementById( this.getId() );
49133 var colElementsByName = document.getElementsByName( this.getId() ) ;
49135 oTextarea.style.display = 'none' ;
49137 if ( oTextarea.tabIndex ) {
49138 this.TabIndex = oTextarea.tabIndex ;
49141 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
49142 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
49143 this.frame = Roo.get(this.getId() + '___Frame')
49146 _getConfigHtml : function()
49150 for ( var o in this.fckconfig ) {
49151 sConfig += sConfig.length > 0 ? '&' : '';
49152 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
49155 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
49159 _getIFrameHtml : function()
49161 var sFile = 'fckeditor.html' ;
49162 /* no idea what this is about..
49165 if ( (/fcksource=true/i).test( window.top.location.search ) )
49166 sFile = 'fckeditor.original.html' ;
49171 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
49172 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
49175 var html = '<iframe id="' + this.getId() +
49176 '___Frame" src="' + sLink +
49177 '" width="' + this.width +
49178 '" height="' + this.height + '"' +
49179 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
49180 ' frameborder="0" scrolling="no"></iframe>' ;
49185 _insertHtmlBefore : function( html, element )
49187 if ( element.insertAdjacentHTML ) {
49189 element.insertAdjacentHTML( 'beforeBegin', html ) ;
49191 var oRange = document.createRange() ;
49192 oRange.setStartBefore( element ) ;
49193 var oFragment = oRange.createContextualFragment( html );
49194 element.parentNode.insertBefore( oFragment, element ) ;
49207 //Roo.reg('fckeditor', Roo.form.FCKeditor);
49209 function FCKeditor_OnComplete(editorInstance){
49210 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
49211 f.fckEditor = editorInstance;
49212 //console.log("loaded");
49213 f.fireEvent('editorinit', f, editorInstance);
49233 //<script type="text/javascript">
49235 * @class Roo.form.GridField
49236 * @extends Roo.form.Field
49237 * Embed a grid (or editable grid into a form)
49240 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
49242 * xgrid.store = Roo.data.Store
49243 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
49244 * xgrid.store.reader = Roo.data.JsonReader
49248 * Creates a new GridField
49249 * @param {Object} config Configuration options
49251 Roo.form.GridField = function(config){
49252 Roo.form.GridField.superclass.constructor.call(this, config);
49256 Roo.extend(Roo.form.GridField, Roo.form.Field, {
49258 * @cfg {Number} width - used to restrict width of grid..
49262 * @cfg {Number} height - used to restrict height of grid..
49266 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
49272 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49273 * {tag: "input", type: "checkbox", autocomplete: "off"})
49275 // defaultAutoCreate : { tag: 'div' },
49276 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
49278 * @cfg {String} addTitle Text to include for adding a title.
49282 onResize : function(){
49283 Roo.form.Field.superclass.onResize.apply(this, arguments);
49286 initEvents : function(){
49287 // Roo.form.Checkbox.superclass.initEvents.call(this);
49288 // has no events...
49293 getResizeEl : function(){
49297 getPositionEl : function(){
49302 onRender : function(ct, position){
49304 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
49305 var style = this.style;
49308 Roo.form.GridField.superclass.onRender.call(this, ct, position);
49309 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
49310 this.viewEl = this.wrap.createChild({ tag: 'div' });
49312 this.viewEl.applyStyles(style);
49315 this.viewEl.setWidth(this.width);
49318 this.viewEl.setHeight(this.height);
49320 //if(this.inputValue !== undefined){
49321 //this.setValue(this.value);
49324 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
49327 this.grid.render();
49328 this.grid.getDataSource().on('remove', this.refreshValue, this);
49329 this.grid.getDataSource().on('update', this.refreshValue, this);
49330 this.grid.on('afteredit', this.refreshValue, this);
49336 * Sets the value of the item.
49337 * @param {String} either an object or a string..
49339 setValue : function(v){
49341 v = v || []; // empty set..
49342 // this does not seem smart - it really only affects memoryproxy grids..
49343 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
49344 var ds = this.grid.getDataSource();
49345 // assumes a json reader..
49347 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
49348 ds.loadData( data);
49350 // clear selection so it does not get stale.
49351 if (this.grid.sm) {
49352 this.grid.sm.clearSelections();
49355 Roo.form.GridField.superclass.setValue.call(this, v);
49356 this.refreshValue();
49357 // should load data in the grid really....
49361 refreshValue: function() {
49363 this.grid.getDataSource().each(function(r) {
49366 this.el.dom.value = Roo.encode(val);
49374 * Ext JS Library 1.1.1
49375 * Copyright(c) 2006-2007, Ext JS, LLC.
49377 * Originally Released Under LGPL - original licence link has changed is not relivant.
49380 * <script type="text/javascript">
49383 * @class Roo.form.DisplayField
49384 * @extends Roo.form.Field
49385 * A generic Field to display non-editable data.
49386 * @cfg {Boolean} closable (true|false) default false
49388 * Creates a new Display Field item.
49389 * @param {Object} config Configuration options
49391 Roo.form.DisplayField = function(config){
49392 Roo.form.DisplayField.superclass.constructor.call(this, config);
49397 * Fires after the click the close btn
49398 * @param {Roo.form.DisplayField} this
49404 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
49405 inputType: 'hidden',
49411 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49413 focusClass : undefined,
49415 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49417 fieldClass: 'x-form-field',
49420 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
49422 valueRenderer: undefined,
49426 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49427 * {tag: "input", type: "checkbox", autocomplete: "off"})
49430 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
49434 onResize : function(){
49435 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
49439 initEvents : function(){
49440 // Roo.form.Checkbox.superclass.initEvents.call(this);
49441 // has no events...
49444 this.closeEl.on('click', this.onClose, this);
49450 getResizeEl : function(){
49454 getPositionEl : function(){
49459 onRender : function(ct, position){
49461 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
49462 //if(this.inputValue !== undefined){
49463 this.wrap = this.el.wrap();
49465 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
49468 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
49471 if (this.bodyStyle) {
49472 this.viewEl.applyStyles(this.bodyStyle);
49474 //this.viewEl.setStyle('padding', '2px');
49476 this.setValue(this.value);
49481 initValue : Roo.emptyFn,
49486 onClick : function(){
49491 * Sets the checked state of the checkbox.
49492 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
49494 setValue : function(v){
49496 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
49497 // this might be called before we have a dom element..
49498 if (!this.viewEl) {
49501 this.viewEl.dom.innerHTML = html;
49502 Roo.form.DisplayField.superclass.setValue.call(this, v);
49506 onClose : function(e)
49508 e.preventDefault();
49510 this.fireEvent('close', this);
49519 * @class Roo.form.DayPicker
49520 * @extends Roo.form.Field
49521 * A Day picker show [M] [T] [W] ....
49523 * Creates a new Day Picker
49524 * @param {Object} config Configuration options
49526 Roo.form.DayPicker= function(config){
49527 Roo.form.DayPicker.superclass.constructor.call(this, config);
49531 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
49533 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49535 focusClass : undefined,
49537 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49539 fieldClass: "x-form-field",
49542 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49543 * {tag: "input", type: "checkbox", autocomplete: "off"})
49545 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
49548 actionMode : 'viewEl',
49552 inputType : 'hidden',
49555 inputElement: false, // real input element?
49556 basedOn: false, // ????
49558 isFormField: true, // not sure where this is needed!!!!
49560 onResize : function(){
49561 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49562 if(!this.boxLabel){
49563 this.el.alignTo(this.wrap, 'c-c');
49567 initEvents : function(){
49568 Roo.form.Checkbox.superclass.initEvents.call(this);
49569 this.el.on("click", this.onClick, this);
49570 this.el.on("change", this.onClick, this);
49574 getResizeEl : function(){
49578 getPositionEl : function(){
49584 onRender : function(ct, position){
49585 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49587 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49589 var r1 = '<table><tr>';
49590 var r2 = '<tr class="x-form-daypick-icons">';
49591 for (var i=0; i < 7; i++) {
49592 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49593 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49596 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49597 viewEl.select('img').on('click', this.onClick, this);
49598 this.viewEl = viewEl;
49601 // this will not work on Chrome!!!
49602 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49603 this.el.on('propertychange', this.setFromHidden, this); //ie
49611 initValue : Roo.emptyFn,
49614 * Returns the checked state of the checkbox.
49615 * @return {Boolean} True if checked, else false
49617 getValue : function(){
49618 return this.el.dom.value;
49623 onClick : function(e){
49624 //this.setChecked(!this.checked);
49625 Roo.get(e.target).toggleClass('x-menu-item-checked');
49626 this.refreshValue();
49627 //if(this.el.dom.checked != this.checked){
49628 // this.setValue(this.el.dom.checked);
49633 refreshValue : function()
49636 this.viewEl.select('img',true).each(function(e,i,n) {
49637 val += e.is(".x-menu-item-checked") ? String(n) : '';
49639 this.setValue(val, true);
49643 * Sets the checked state of the checkbox.
49644 * On is always based on a string comparison between inputValue and the param.
49645 * @param {Boolean/String} value - the value to set
49646 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49648 setValue : function(v,suppressEvent){
49649 if (!this.el.dom) {
49652 var old = this.el.dom.value ;
49653 this.el.dom.value = v;
49654 if (suppressEvent) {
49658 // update display..
49659 this.viewEl.select('img',true).each(function(e,i,n) {
49661 var on = e.is(".x-menu-item-checked");
49662 var newv = v.indexOf(String(n)) > -1;
49664 e.toggleClass('x-menu-item-checked');
49670 this.fireEvent('change', this, v, old);
49675 // handle setting of hidden value by some other method!!?!?
49676 setFromHidden: function()
49681 //console.log("SET FROM HIDDEN");
49682 //alert('setFrom hidden');
49683 this.setValue(this.el.dom.value);
49686 onDestroy : function()
49689 Roo.get(this.viewEl).remove();
49692 Roo.form.DayPicker.superclass.onDestroy.call(this);
49696 * RooJS Library 1.1.1
49697 * Copyright(c) 2008-2011 Alan Knowles
49704 * @class Roo.form.ComboCheck
49705 * @extends Roo.form.ComboBox
49706 * A combobox for multiple select items.
49708 * FIXME - could do with a reset button..
49711 * Create a new ComboCheck
49712 * @param {Object} config Configuration options
49714 Roo.form.ComboCheck = function(config){
49715 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49716 // should verify some data...
49718 // hiddenName = required..
49719 // displayField = required
49720 // valudField == required
49721 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49723 Roo.each(req, function(e) {
49724 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49725 throw "Roo.form.ComboCheck : missing value for: " + e;
49732 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49737 selectedClass: 'x-menu-item-checked',
49740 onRender : function(ct, position){
49746 var cls = 'x-combo-list';
49749 this.tpl = new Roo.Template({
49750 html : '<div class="'+cls+'-item x-menu-check-item">' +
49751 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49752 '<span>{' + this.displayField + '}</span>' +
49759 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49760 this.view.singleSelect = false;
49761 this.view.multiSelect = true;
49762 this.view.toggleSelect = true;
49763 this.pageTb.add(new Roo.Toolbar.Fill(), {
49766 handler: function()
49773 onViewOver : function(e, t){
49779 onViewClick : function(doFocus,index){
49783 select: function () {
49784 //Roo.log("SELECT CALLED");
49787 selectByValue : function(xv, scrollIntoView){
49788 var ar = this.getValueArray();
49791 Roo.each(ar, function(v) {
49792 if(v === undefined || v === null){
49795 var r = this.findRecord(this.valueField, v);
49797 sels.push(this.store.indexOf(r))
49801 this.view.select(sels);
49807 onSelect : function(record, index){
49808 // Roo.log("onselect Called");
49809 // this is only called by the clear button now..
49810 this.view.clearSelections();
49811 this.setValue('[]');
49812 if (this.value != this.valueBefore) {
49813 this.fireEvent('change', this, this.value, this.valueBefore);
49814 this.valueBefore = this.value;
49817 getValueArray : function()
49822 //Roo.log(this.value);
49823 if (typeof(this.value) == 'undefined') {
49826 var ar = Roo.decode(this.value);
49827 return ar instanceof Array ? ar : []; //?? valid?
49830 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49835 expand : function ()
49838 Roo.form.ComboCheck.superclass.expand.call(this);
49839 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49840 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49845 collapse : function(){
49846 Roo.form.ComboCheck.superclass.collapse.call(this);
49847 var sl = this.view.getSelectedIndexes();
49848 var st = this.store;
49852 Roo.each(sl, function(i) {
49854 nv.push(r.get(this.valueField));
49856 this.setValue(Roo.encode(nv));
49857 if (this.value != this.valueBefore) {
49859 this.fireEvent('change', this, this.value, this.valueBefore);
49860 this.valueBefore = this.value;
49865 setValue : function(v){
49869 var vals = this.getValueArray();
49871 Roo.each(vals, function(k) {
49872 var r = this.findRecord(this.valueField, k);
49874 tv.push(r.data[this.displayField]);
49875 }else if(this.valueNotFoundText !== undefined){
49876 tv.push( this.valueNotFoundText );
49881 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49882 this.hiddenField.value = v;
49888 * Ext JS Library 1.1.1
49889 * Copyright(c) 2006-2007, Ext JS, LLC.
49891 * Originally Released Under LGPL - original licence link has changed is not relivant.
49894 * <script type="text/javascript">
49898 * @class Roo.form.Signature
49899 * @extends Roo.form.Field
49903 * @param {Object} config Configuration options
49906 Roo.form.Signature = function(config){
49907 Roo.form.Signature.superclass.constructor.call(this, config);
49909 this.addEvents({// not in used??
49912 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49913 * @param {Roo.form.Signature} combo This combo box
49918 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49919 * @param {Roo.form.ComboBox} combo This combo box
49920 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49926 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49928 * @cfg {Object} labels Label to use when rendering a form.
49932 * confirm : "Confirm"
49937 confirm : "Confirm"
49940 * @cfg {Number} width The signature panel width (defaults to 300)
49944 * @cfg {Number} height The signature panel height (defaults to 100)
49948 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49950 allowBlank : false,
49953 // {Object} signPanel The signature SVG panel element (defaults to {})
49955 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49956 isMouseDown : false,
49957 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49958 isConfirmed : false,
49959 // {String} signatureTmp SVG mapping string (defaults to empty string)
49963 defaultAutoCreate : { // modified by initCompnoent..
49969 onRender : function(ct, position){
49971 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49973 this.wrap = this.el.wrap({
49974 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49977 this.createToolbar(this);
49978 this.signPanel = this.wrap.createChild({
49980 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49984 this.svgID = Roo.id();
49985 this.svgEl = this.signPanel.createChild({
49986 xmlns : 'http://www.w3.org/2000/svg',
49988 id : this.svgID + "-svg",
49990 height: this.height,
49991 viewBox: '0 0 '+this.width+' '+this.height,
49995 id: this.svgID + "-svg-r",
49997 height: this.height,
50002 id: this.svgID + "-svg-l",
50004 y1: (this.height*0.8), // start set the line in 80% of height
50005 x2: this.width, // end
50006 y2: (this.height*0.8), // end set the line in 80% of height
50008 'stroke-width': "1",
50009 'stroke-dasharray': "3",
50010 'shape-rendering': "crispEdges",
50011 'pointer-events': "none"
50015 id: this.svgID + "-svg-p",
50017 'stroke-width': "3",
50019 'pointer-events': 'none'
50024 this.svgBox = this.svgEl.dom.getScreenCTM();
50026 createSVG : function(){
50027 var svg = this.signPanel;
50028 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
50031 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
50032 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
50033 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
50034 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
50035 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
50036 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
50037 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
50040 isTouchEvent : function(e){
50041 return e.type.match(/^touch/);
50043 getCoords : function (e) {
50044 var pt = this.svgEl.dom.createSVGPoint();
50047 if (this.isTouchEvent(e)) {
50048 pt.x = e.targetTouches[0].clientX;
50049 pt.y = e.targetTouches[0].clientY;
50051 var a = this.svgEl.dom.getScreenCTM();
50052 var b = a.inverse();
50053 var mx = pt.matrixTransform(b);
50054 return mx.x + ',' + mx.y;
50056 //mouse event headler
50057 down : function (e) {
50058 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
50059 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
50061 this.isMouseDown = true;
50063 e.preventDefault();
50065 move : function (e) {
50066 if (this.isMouseDown) {
50067 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
50068 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
50071 e.preventDefault();
50073 up : function (e) {
50074 this.isMouseDown = false;
50075 var sp = this.signatureTmp.split(' ');
50078 if(!sp[sp.length-2].match(/^L/)){
50082 this.signatureTmp = sp.join(" ");
50085 if(this.getValue() != this.signatureTmp){
50086 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50087 this.isConfirmed = false;
50089 e.preventDefault();
50093 * Protected method that will not generally be called directly. It
50094 * is called when the editor creates its toolbar. Override this method if you need to
50095 * add custom toolbar buttons.
50096 * @param {HtmlEditor} editor
50098 createToolbar : function(editor){
50099 function btn(id, toggle, handler){
50100 var xid = fid + '-'+ id ;
50104 cls : 'x-btn-icon x-edit-'+id,
50105 enableToggle:toggle !== false,
50106 scope: editor, // was editor...
50107 handler:handler||editor.relayBtnCmd,
50108 clickEvent:'mousedown',
50109 tooltip: etb.buttonTips[id] || undefined, ///tips ???
50115 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
50119 cls : ' x-signature-btn x-signature-'+id,
50120 scope: editor, // was editor...
50121 handler: this.reset,
50122 clickEvent:'mousedown',
50123 text: this.labels.clear
50130 cls : ' x-signature-btn x-signature-'+id,
50131 scope: editor, // was editor...
50132 handler: this.confirmHandler,
50133 clickEvent:'mousedown',
50134 text: this.labels.confirm
50141 * when user is clicked confirm then show this image.....
50143 * @return {String} Image Data URI
50145 getImageDataURI : function(){
50146 var svg = this.svgEl.dom.parentNode.innerHTML;
50147 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
50152 * @return {Boolean} this.isConfirmed
50154 getConfirmed : function(){
50155 return this.isConfirmed;
50159 * @return {Number} this.width
50161 getWidth : function(){
50166 * @return {Number} this.height
50168 getHeight : function(){
50169 return this.height;
50172 getSignature : function(){
50173 return this.signatureTmp;
50176 reset : function(){
50177 this.signatureTmp = '';
50178 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50179 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
50180 this.isConfirmed = false;
50181 Roo.form.Signature.superclass.reset.call(this);
50183 setSignature : function(s){
50184 this.signatureTmp = s;
50185 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50186 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
50188 this.isConfirmed = false;
50189 Roo.form.Signature.superclass.reset.call(this);
50192 // Roo.log(this.signPanel.dom.contentWindow.up())
50195 setConfirmed : function(){
50199 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
50202 confirmHandler : function(){
50203 if(!this.getSignature()){
50207 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
50208 this.setValue(this.getSignature());
50209 this.isConfirmed = true;
50211 this.fireEvent('confirm', this);
50214 // Subclasses should provide the validation implementation by overriding this
50215 validateValue : function(value){
50216 if(this.allowBlank){
50220 if(this.isConfirmed){
50227 * Ext JS Library 1.1.1
50228 * Copyright(c) 2006-2007, Ext JS, LLC.
50230 * Originally Released Under LGPL - original licence link has changed is not relivant.
50233 * <script type="text/javascript">
50238 * @class Roo.form.ComboBox
50239 * @extends Roo.form.TriggerField
50240 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
50242 * Create a new ComboBox.
50243 * @param {Object} config Configuration options
50245 Roo.form.Select = function(config){
50246 Roo.form.Select.superclass.constructor.call(this, config);
50250 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
50252 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
50255 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
50256 * rendering into an Roo.Editor, defaults to false)
50259 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
50260 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
50263 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
50266 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
50267 * the dropdown list (defaults to undefined, with no header element)
50271 * @cfg {String/Roo.Template} tpl The template to use to render the output
50275 defaultAutoCreate : {tag: "select" },
50277 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
50279 listWidth: undefined,
50281 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
50282 * mode = 'remote' or 'text' if mode = 'local')
50284 displayField: undefined,
50286 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
50287 * mode = 'remote' or 'value' if mode = 'local').
50288 * Note: use of a valueField requires the user make a selection
50289 * in order for a value to be mapped.
50291 valueField: undefined,
50295 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
50296 * field's data value (defaults to the underlying DOM element's name)
50298 hiddenName: undefined,
50300 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
50304 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
50306 selectedClass: 'x-combo-selected',
50308 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
50309 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
50310 * which displays a downward arrow icon).
50312 triggerClass : 'x-form-arrow-trigger',
50314 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
50318 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
50319 * anchor positions (defaults to 'tl-bl')
50321 listAlign: 'tl-bl?',
50323 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
50327 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
50328 * query specified by the allQuery config option (defaults to 'query')
50330 triggerAction: 'query',
50332 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
50333 * (defaults to 4, does not apply if editable = false)
50337 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
50338 * delay (typeAheadDelay) if it matches a known value (defaults to false)
50342 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
50343 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
50347 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
50348 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
50352 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
50353 * when editable = true (defaults to false)
50355 selectOnFocus:false,
50357 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
50359 queryParam: 'query',
50361 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
50362 * when mode = 'remote' (defaults to 'Loading...')
50364 loadingText: 'Loading...',
50366 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
50370 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
50374 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
50375 * traditional select (defaults to true)
50379 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
50383 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
50387 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
50388 * listWidth has a higher value)
50392 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
50393 * allow the user to set arbitrary text into the field (defaults to false)
50395 forceSelection:false,
50397 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
50398 * if typeAhead = true (defaults to 250)
50400 typeAheadDelay : 250,
50402 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
50403 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
50405 valueNotFoundText : undefined,
50408 * @cfg {String} defaultValue The value displayed after loading the store.
50413 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
50415 blockFocus : false,
50418 * @cfg {Boolean} disableClear Disable showing of clear button.
50420 disableClear : false,
50422 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
50424 alwaysQuery : false,
50430 // element that contains real text value.. (when hidden is used..)
50433 onRender : function(ct, position){
50434 Roo.form.Field.prototype.onRender.call(this, ct, position);
50437 this.store.on('beforeload', this.onBeforeLoad, this);
50438 this.store.on('load', this.onLoad, this);
50439 this.store.on('loadexception', this.onLoadException, this);
50440 this.store.load({});
50448 initEvents : function(){
50449 //Roo.form.ComboBox.superclass.initEvents.call(this);
50453 onDestroy : function(){
50456 this.store.un('beforeload', this.onBeforeLoad, this);
50457 this.store.un('load', this.onLoad, this);
50458 this.store.un('loadexception', this.onLoadException, this);
50460 //Roo.form.ComboBox.superclass.onDestroy.call(this);
50464 fireKey : function(e){
50465 if(e.isNavKeyPress() && !this.list.isVisible()){
50466 this.fireEvent("specialkey", this, e);
50471 onResize: function(w, h){
50479 * Allow or prevent the user from directly editing the field text. If false is passed,
50480 * the user will only be able to select from the items defined in the dropdown list. This method
50481 * is the runtime equivalent of setting the 'editable' config option at config time.
50482 * @param {Boolean} value True to allow the user to directly edit the field text
50484 setEditable : function(value){
50489 onBeforeLoad : function(){
50491 Roo.log("Select before load");
50494 this.innerList.update(this.loadingText ?
50495 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
50496 //this.restrictHeight();
50497 this.selectedIndex = -1;
50501 onLoad : function(){
50504 var dom = this.el.dom;
50505 dom.innerHTML = '';
50506 var od = dom.ownerDocument;
50508 if (this.emptyText) {
50509 var op = od.createElement('option');
50510 op.setAttribute('value', '');
50511 op.innerHTML = String.format('{0}', this.emptyText);
50512 dom.appendChild(op);
50514 if(this.store.getCount() > 0){
50516 var vf = this.valueField;
50517 var df = this.displayField;
50518 this.store.data.each(function(r) {
50519 // which colmsn to use... testing - cdoe / title..
50520 var op = od.createElement('option');
50521 op.setAttribute('value', r.data[vf]);
50522 op.innerHTML = String.format('{0}', r.data[df]);
50523 dom.appendChild(op);
50525 if (typeof(this.defaultValue != 'undefined')) {
50526 this.setValue(this.defaultValue);
50531 //this.onEmptyResults();
50536 onLoadException : function()
50538 dom.innerHTML = '';
50540 Roo.log("Select on load exception");
50544 Roo.log(this.store.reader.jsonData);
50545 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
50546 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50552 onTypeAhead : function(){
50557 onSelect : function(record, index){
50558 Roo.log('on select?');
50560 if(this.fireEvent('beforeselect', this, record, index) !== false){
50561 this.setFromData(index > -1 ? record.data : false);
50563 this.fireEvent('select', this, record, index);
50568 * Returns the currently selected field value or empty string if no value is set.
50569 * @return {String} value The selected value
50571 getValue : function(){
50572 var dom = this.el.dom;
50573 this.value = dom.options[dom.selectedIndex].value;
50579 * Clears any text/value currently set in the field
50581 clearValue : function(){
50583 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50588 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50589 * will be displayed in the field. If the value does not match the data value of an existing item,
50590 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50591 * Otherwise the field will be blank (although the value will still be set).
50592 * @param {String} value The value to match
50594 setValue : function(v){
50595 var d = this.el.dom;
50596 for (var i =0; i < d.options.length;i++) {
50597 if (v == d.options[i].value) {
50598 d.selectedIndex = i;
50606 * @property {Object} the last set data for the element
50611 * Sets the value of the field based on a object which is related to the record format for the store.
50612 * @param {Object} value the value to set as. or false on reset?
50614 setFromData : function(o){
50615 Roo.log('setfrom data?');
50621 reset : function(){
50625 findRecord : function(prop, value){
50630 if(this.store.getCount() > 0){
50631 this.store.each(function(r){
50632 if(r.data[prop] == value){
50642 getName: function()
50644 // returns hidden if it's set..
50645 if (!this.rendered) {return ''};
50646 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50654 onEmptyResults : function(){
50655 Roo.log('empty results');
50660 * Returns true if the dropdown list is expanded, else false.
50662 isExpanded : function(){
50667 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50668 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50669 * @param {String} value The data value of the item to select
50670 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50671 * selected item if it is not currently in view (defaults to true)
50672 * @return {Boolean} True if the value matched an item in the list, else false
50674 selectByValue : function(v, scrollIntoView){
50675 Roo.log('select By Value');
50678 if(v !== undefined && v !== null){
50679 var r = this.findRecord(this.valueField || this.displayField, v);
50681 this.select(this.store.indexOf(r), scrollIntoView);
50689 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50690 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50691 * @param {Number} index The zero-based index of the list item to select
50692 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50693 * selected item if it is not currently in view (defaults to true)
50695 select : function(index, scrollIntoView){
50696 Roo.log('select ');
50699 this.selectedIndex = index;
50700 this.view.select(index);
50701 if(scrollIntoView !== false){
50702 var el = this.view.getNode(index);
50704 this.innerList.scrollChildIntoView(el, false);
50712 validateBlur : function(){
50719 initQuery : function(){
50720 this.doQuery(this.getRawValue());
50724 doForce : function(){
50725 if(this.el.dom.value.length > 0){
50726 this.el.dom.value =
50727 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50733 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50734 * query allowing the query action to be canceled if needed.
50735 * @param {String} query The SQL query to execute
50736 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50737 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50738 * saved in the current store (defaults to false)
50740 doQuery : function(q, forceAll){
50742 Roo.log('doQuery?');
50743 if(q === undefined || q === null){
50748 forceAll: forceAll,
50752 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50756 forceAll = qe.forceAll;
50757 if(forceAll === true || (q.length >= this.minChars)){
50758 if(this.lastQuery != q || this.alwaysQuery){
50759 this.lastQuery = q;
50760 if(this.mode == 'local'){
50761 this.selectedIndex = -1;
50763 this.store.clearFilter();
50765 this.store.filter(this.displayField, q);
50769 this.store.baseParams[this.queryParam] = q;
50771 params: this.getParams(q)
50776 this.selectedIndex = -1;
50783 getParams : function(q){
50785 //p[this.queryParam] = q;
50788 p.limit = this.pageSize;
50794 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50796 collapse : function(){
50801 collapseIf : function(e){
50806 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50808 expand : function(){
50816 * @cfg {Boolean} grow
50820 * @cfg {Number} growMin
50824 * @cfg {Number} growMax
50832 setWidth : function()
50836 getResizeEl : function(){
50839 });//<script type="text/javasscript">
50843 * @class Roo.DDView
50844 * A DnD enabled version of Roo.View.
50845 * @param {Element/String} container The Element in which to create the View.
50846 * @param {String} tpl The template string used to create the markup for each element of the View
50847 * @param {Object} config The configuration properties. These include all the config options of
50848 * {@link Roo.View} plus some specific to this class.<br>
50850 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50851 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50853 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50854 .x-view-drag-insert-above {
50855 border-top:1px dotted #3366cc;
50857 .x-view-drag-insert-below {
50858 border-bottom:1px dotted #3366cc;
50864 Roo.DDView = function(container, tpl, config) {
50865 Roo.DDView.superclass.constructor.apply(this, arguments);
50866 this.getEl().setStyle("outline", "0px none");
50867 this.getEl().unselectable();
50868 if (this.dragGroup) {
50869 this.setDraggable(this.dragGroup.split(","));
50871 if (this.dropGroup) {
50872 this.setDroppable(this.dropGroup.split(","));
50874 if (this.deletable) {
50875 this.setDeletable();
50877 this.isDirtyFlag = false;
50883 Roo.extend(Roo.DDView, Roo.View, {
50884 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50885 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50886 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50887 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50891 reset: Roo.emptyFn,
50893 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50895 validate: function() {
50899 destroy: function() {
50900 this.purgeListeners();
50901 this.getEl.removeAllListeners();
50902 this.getEl().remove();
50903 if (this.dragZone) {
50904 if (this.dragZone.destroy) {
50905 this.dragZone.destroy();
50908 if (this.dropZone) {
50909 if (this.dropZone.destroy) {
50910 this.dropZone.destroy();
50915 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50916 getName: function() {
50920 /** Loads the View from a JSON string representing the Records to put into the Store. */
50921 setValue: function(v) {
50923 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50926 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50927 this.store.proxy = new Roo.data.MemoryProxy(data);
50931 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50932 getValue: function() {
50934 this.store.each(function(rec) {
50935 result += rec.id + ',';
50937 return result.substr(0, result.length - 1) + ')';
50940 getIds: function() {
50941 var i = 0, result = new Array(this.store.getCount());
50942 this.store.each(function(rec) {
50943 result[i++] = rec.id;
50948 isDirty: function() {
50949 return this.isDirtyFlag;
50953 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50954 * whole Element becomes the target, and this causes the drop gesture to append.
50956 getTargetFromEvent : function(e) {
50957 var target = e.getTarget();
50958 while ((target !== null) && (target.parentNode != this.el.dom)) {
50959 target = target.parentNode;
50962 target = this.el.dom.lastChild || this.el.dom;
50968 * Create the drag data which consists of an object which has the property "ddel" as
50969 * the drag proxy element.
50971 getDragData : function(e) {
50972 var target = this.findItemFromChild(e.getTarget());
50974 this.handleSelection(e);
50975 var selNodes = this.getSelectedNodes();
50978 copy: this.copy || (this.allowCopy && e.ctrlKey),
50982 var selectedIndices = this.getSelectedIndexes();
50983 for (var i = 0; i < selectedIndices.length; i++) {
50984 dragData.records.push(this.store.getAt(selectedIndices[i]));
50986 if (selNodes.length == 1) {
50987 dragData.ddel = target.cloneNode(true); // the div element
50989 var div = document.createElement('div'); // create the multi element drag "ghost"
50990 div.className = 'multi-proxy';
50991 for (var i = 0, len = selNodes.length; i < len; i++) {
50992 div.appendChild(selNodes[i].cloneNode(true));
50994 dragData.ddel = div;
50996 //console.log(dragData)
50997 //console.log(dragData.ddel.innerHTML)
51000 //console.log('nodragData')
51004 /** Specify to which ddGroup items in this DDView may be dragged. */
51005 setDraggable: function(ddGroup) {
51006 if (ddGroup instanceof Array) {
51007 Roo.each(ddGroup, this.setDraggable, this);
51010 if (this.dragZone) {
51011 this.dragZone.addToGroup(ddGroup);
51013 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
51014 containerScroll: true,
51018 // Draggability implies selection. DragZone's mousedown selects the element.
51019 if (!this.multiSelect) { this.singleSelect = true; }
51021 // Wire the DragZone's handlers up to methods in *this*
51022 this.dragZone.getDragData = this.getDragData.createDelegate(this);
51026 /** Specify from which ddGroup this DDView accepts drops. */
51027 setDroppable: function(ddGroup) {
51028 if (ddGroup instanceof Array) {
51029 Roo.each(ddGroup, this.setDroppable, this);
51032 if (this.dropZone) {
51033 this.dropZone.addToGroup(ddGroup);
51035 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
51036 containerScroll: true,
51040 // Wire the DropZone's handlers up to methods in *this*
51041 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
51042 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
51043 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
51044 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
51045 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
51049 /** Decide whether to drop above or below a View node. */
51050 getDropPoint : function(e, n, dd){
51051 if (n == this.el.dom) { return "above"; }
51052 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
51053 var c = t + (b - t) / 2;
51054 var y = Roo.lib.Event.getPageY(e);
51062 onNodeEnter : function(n, dd, e, data){
51066 onNodeOver : function(n, dd, e, data){
51067 var pt = this.getDropPoint(e, n, dd);
51068 // set the insert point style on the target node
51069 var dragElClass = this.dropNotAllowed;
51072 if (pt == "above"){
51073 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
51074 targetElClass = "x-view-drag-insert-above";
51076 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
51077 targetElClass = "x-view-drag-insert-below";
51079 if (this.lastInsertClass != targetElClass){
51080 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
51081 this.lastInsertClass = targetElClass;
51084 return dragElClass;
51087 onNodeOut : function(n, dd, e, data){
51088 this.removeDropIndicators(n);
51091 onNodeDrop : function(n, dd, e, data){
51092 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
51095 var pt = this.getDropPoint(e, n, dd);
51096 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
51097 if (pt == "below") { insertAt++; }
51098 for (var i = 0; i < data.records.length; i++) {
51099 var r = data.records[i];
51100 var dup = this.store.getById(r.id);
51101 if (dup && (dd != this.dragZone)) {
51102 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
51105 this.store.insert(insertAt++, r.copy());
51107 data.source.isDirtyFlag = true;
51109 this.store.insert(insertAt++, r);
51111 this.isDirtyFlag = true;
51114 this.dragZone.cachedTarget = null;
51118 removeDropIndicators : function(n){
51120 Roo.fly(n).removeClass([
51121 "x-view-drag-insert-above",
51122 "x-view-drag-insert-below"]);
51123 this.lastInsertClass = "_noclass";
51128 * Utility method. Add a delete option to the DDView's context menu.
51129 * @param {String} imageUrl The URL of the "delete" icon image.
51131 setDeletable: function(imageUrl) {
51132 if (!this.singleSelect && !this.multiSelect) {
51133 this.singleSelect = true;
51135 var c = this.getContextMenu();
51136 this.contextMenu.on("itemclick", function(item) {
51139 this.remove(this.getSelectedIndexes());
51143 this.contextMenu.add({
51150 /** Return the context menu for this DDView. */
51151 getContextMenu: function() {
51152 if (!this.contextMenu) {
51153 // Create the View's context menu
51154 this.contextMenu = new Roo.menu.Menu({
51155 id: this.id + "-contextmenu"
51157 this.el.on("contextmenu", this.showContextMenu, this);
51159 return this.contextMenu;
51162 disableContextMenu: function() {
51163 if (this.contextMenu) {
51164 this.el.un("contextmenu", this.showContextMenu, this);
51168 showContextMenu: function(e, item) {
51169 item = this.findItemFromChild(e.getTarget());
51172 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
51173 this.contextMenu.showAt(e.getXY());
51178 * Remove {@link Roo.data.Record}s at the specified indices.
51179 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
51181 remove: function(selectedIndices) {
51182 selectedIndices = [].concat(selectedIndices);
51183 for (var i = 0; i < selectedIndices.length; i++) {
51184 var rec = this.store.getAt(selectedIndices[i]);
51185 this.store.remove(rec);
51190 * Double click fires the event, but also, if this is draggable, and there is only one other
51191 * related DropZone, it transfers the selected node.
51193 onDblClick : function(e){
51194 var item = this.findItemFromChild(e.getTarget());
51196 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
51199 if (this.dragGroup) {
51200 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
51201 while (targets.indexOf(this.dropZone) > -1) {
51202 targets.remove(this.dropZone);
51204 if (targets.length == 1) {
51205 this.dragZone.cachedTarget = null;
51206 var el = Roo.get(targets[0].getEl());
51207 var box = el.getBox(true);
51208 targets[0].onNodeDrop(el.dom, {
51210 xy: [box.x, box.y + box.height - 1]
51211 }, null, this.getDragData(e));
51217 handleSelection: function(e) {
51218 this.dragZone.cachedTarget = null;
51219 var item = this.findItemFromChild(e.getTarget());
51221 this.clearSelections(true);
51224 if (item && (this.multiSelect || this.singleSelect)){
51225 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
51226 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
51227 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
51228 this.unselect(item);
51230 this.select(item, this.multiSelect && e.ctrlKey);
51231 this.lastSelection = item;
51236 onItemClick : function(item, index, e){
51237 if(this.fireEvent("beforeclick", this, index, item, e) === false){
51243 unselect : function(nodeInfo, suppressEvent){
51244 var node = this.getNode(nodeInfo);
51245 if(node && this.isSelected(node)){
51246 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
51247 Roo.fly(node).removeClass(this.selectedClass);
51248 this.selections.remove(node);
51249 if(!suppressEvent){
51250 this.fireEvent("selectionchange", this, this.selections);
51258 * Ext JS Library 1.1.1
51259 * Copyright(c) 2006-2007, Ext JS, LLC.
51261 * Originally Released Under LGPL - original licence link has changed is not relivant.
51264 * <script type="text/javascript">
51268 * @class Roo.LayoutManager
51269 * @extends Roo.util.Observable
51270 * Base class for layout managers.
51272 Roo.LayoutManager = function(container, config){
51273 Roo.LayoutManager.superclass.constructor.call(this);
51274 this.el = Roo.get(container);
51275 // ie scrollbar fix
51276 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
51277 document.body.scroll = "no";
51278 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
51279 this.el.position('relative');
51281 this.id = this.el.id;
51282 this.el.addClass("x-layout-container");
51283 /** false to disable window resize monitoring @type Boolean */
51284 this.monitorWindowResize = true;
51289 * Fires when a layout is performed.
51290 * @param {Roo.LayoutManager} this
51294 * @event regionresized
51295 * Fires when the user resizes a region.
51296 * @param {Roo.LayoutRegion} region The resized region
51297 * @param {Number} newSize The new size (width for east/west, height for north/south)
51299 "regionresized" : true,
51301 * @event regioncollapsed
51302 * Fires when a region is collapsed.
51303 * @param {Roo.LayoutRegion} region The collapsed region
51305 "regioncollapsed" : true,
51307 * @event regionexpanded
51308 * Fires when a region is expanded.
51309 * @param {Roo.LayoutRegion} region The expanded region
51311 "regionexpanded" : true
51313 this.updating = false;
51314 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
51317 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
51319 * Returns true if this layout is currently being updated
51320 * @return {Boolean}
51322 isUpdating : function(){
51323 return this.updating;
51327 * Suspend the LayoutManager from doing auto-layouts while
51328 * making multiple add or remove calls
51330 beginUpdate : function(){
51331 this.updating = true;
51335 * Restore auto-layouts and optionally disable the manager from performing a layout
51336 * @param {Boolean} noLayout true to disable a layout update
51338 endUpdate : function(noLayout){
51339 this.updating = false;
51345 layout: function(){
51349 onRegionResized : function(region, newSize){
51350 this.fireEvent("regionresized", region, newSize);
51354 onRegionCollapsed : function(region){
51355 this.fireEvent("regioncollapsed", region);
51358 onRegionExpanded : function(region){
51359 this.fireEvent("regionexpanded", region);
51363 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
51364 * performs box-model adjustments.
51365 * @return {Object} The size as an object {width: (the width), height: (the height)}
51367 getViewSize : function(){
51369 if(this.el.dom != document.body){
51370 size = this.el.getSize();
51372 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
51374 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
51375 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
51380 * Returns the Element this layout is bound to.
51381 * @return {Roo.Element}
51383 getEl : function(){
51388 * Returns the specified region.
51389 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
51390 * @return {Roo.LayoutRegion}
51392 getRegion : function(target){
51393 return this.regions[target.toLowerCase()];
51396 onWindowResize : function(){
51397 if(this.monitorWindowResize){
51403 * Ext JS Library 1.1.1
51404 * Copyright(c) 2006-2007, Ext JS, LLC.
51406 * Originally Released Under LGPL - original licence link has changed is not relivant.
51409 * <script type="text/javascript">
51412 * @class Roo.BorderLayout
51413 * @extends Roo.LayoutManager
51414 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
51415 * please see: <br><br>
51416 * <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>
51417 * <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>
51420 var layout = new Roo.BorderLayout(document.body, {
51454 preferredTabWidth: 150
51459 var CP = Roo.ContentPanel;
51461 layout.beginUpdate();
51462 layout.add("north", new CP("north", "North"));
51463 layout.add("south", new CP("south", {title: "South", closable: true}));
51464 layout.add("west", new CP("west", {title: "West"}));
51465 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
51466 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
51467 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
51468 layout.getRegion("center").showPanel("center1");
51469 layout.endUpdate();
51472 <b>The container the layout is rendered into can be either the body element or any other element.
51473 If it is not the body element, the container needs to either be an absolute positioned element,
51474 or you will need to add "position:relative" to the css of the container. You will also need to specify
51475 the container size if it is not the body element.</b>
51478 * Create a new BorderLayout
51479 * @param {String/HTMLElement/Element} container The container this layout is bound to
51480 * @param {Object} config Configuration options
51482 Roo.BorderLayout = function(container, config){
51483 config = config || {};
51484 Roo.BorderLayout.superclass.constructor.call(this, container, config);
51485 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
51486 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
51487 var target = this.factory.validRegions[i];
51488 if(config[target]){
51489 this.addRegion(target, config[target]);
51494 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
51496 * Creates and adds a new region if it doesn't already exist.
51497 * @param {String} target The target region key (north, south, east, west or center).
51498 * @param {Object} config The regions config object
51499 * @return {BorderLayoutRegion} The new region
51501 addRegion : function(target, config){
51502 if(!this.regions[target]){
51503 var r = this.factory.create(target, this, config);
51504 this.bindRegion(target, r);
51506 return this.regions[target];
51510 bindRegion : function(name, r){
51511 this.regions[name] = r;
51512 r.on("visibilitychange", this.layout, this);
51513 r.on("paneladded", this.layout, this);
51514 r.on("panelremoved", this.layout, this);
51515 r.on("invalidated", this.layout, this);
51516 r.on("resized", this.onRegionResized, this);
51517 r.on("collapsed", this.onRegionCollapsed, this);
51518 r.on("expanded", this.onRegionExpanded, this);
51522 * Performs a layout update.
51524 layout : function(){
51525 if(this.updating) {
51528 var size = this.getViewSize();
51529 var w = size.width;
51530 var h = size.height;
51535 //var x = 0, y = 0;
51537 var rs = this.regions;
51538 var north = rs["north"];
51539 var south = rs["south"];
51540 var west = rs["west"];
51541 var east = rs["east"];
51542 var center = rs["center"];
51543 //if(this.hideOnLayout){ // not supported anymore
51544 //c.el.setStyle("display", "none");
51546 if(north && north.isVisible()){
51547 var b = north.getBox();
51548 var m = north.getMargins();
51549 b.width = w - (m.left+m.right);
51552 centerY = b.height + b.y + m.bottom;
51553 centerH -= centerY;
51554 north.updateBox(this.safeBox(b));
51556 if(south && south.isVisible()){
51557 var b = south.getBox();
51558 var m = south.getMargins();
51559 b.width = w - (m.left+m.right);
51561 var totalHeight = (b.height + m.top + m.bottom);
51562 b.y = h - totalHeight + m.top;
51563 centerH -= totalHeight;
51564 south.updateBox(this.safeBox(b));
51566 if(west && west.isVisible()){
51567 var b = west.getBox();
51568 var m = west.getMargins();
51569 b.height = centerH - (m.top+m.bottom);
51571 b.y = centerY + m.top;
51572 var totalWidth = (b.width + m.left + m.right);
51573 centerX += totalWidth;
51574 centerW -= totalWidth;
51575 west.updateBox(this.safeBox(b));
51577 if(east && east.isVisible()){
51578 var b = east.getBox();
51579 var m = east.getMargins();
51580 b.height = centerH - (m.top+m.bottom);
51581 var totalWidth = (b.width + m.left + m.right);
51582 b.x = w - totalWidth + m.left;
51583 b.y = centerY + m.top;
51584 centerW -= totalWidth;
51585 east.updateBox(this.safeBox(b));
51588 var m = center.getMargins();
51590 x: centerX + m.left,
51591 y: centerY + m.top,
51592 width: centerW - (m.left+m.right),
51593 height: centerH - (m.top+m.bottom)
51595 //if(this.hideOnLayout){
51596 //center.el.setStyle("display", "block");
51598 center.updateBox(this.safeBox(centerBox));
51601 this.fireEvent("layout", this);
51605 safeBox : function(box){
51606 box.width = Math.max(0, box.width);
51607 box.height = Math.max(0, box.height);
51612 * Adds a ContentPanel (or subclass) to this layout.
51613 * @param {String} target The target region key (north, south, east, west or center).
51614 * @param {Roo.ContentPanel} panel The panel to add
51615 * @return {Roo.ContentPanel} The added panel
51617 add : function(target, panel){
51619 target = target.toLowerCase();
51620 return this.regions[target].add(panel);
51624 * Remove a ContentPanel (or subclass) to this layout.
51625 * @param {String} target The target region key (north, south, east, west or center).
51626 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51627 * @return {Roo.ContentPanel} The removed panel
51629 remove : function(target, panel){
51630 target = target.toLowerCase();
51631 return this.regions[target].remove(panel);
51635 * Searches all regions for a panel with the specified id
51636 * @param {String} panelId
51637 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51639 findPanel : function(panelId){
51640 var rs = this.regions;
51641 for(var target in rs){
51642 if(typeof rs[target] != "function"){
51643 var p = rs[target].getPanel(panelId);
51653 * Searches all regions for a panel with the specified id and activates (shows) it.
51654 * @param {String/ContentPanel} panelId The panels id or the panel itself
51655 * @return {Roo.ContentPanel} The shown panel or null
51657 showPanel : function(panelId) {
51658 var rs = this.regions;
51659 for(var target in rs){
51660 var r = rs[target];
51661 if(typeof r != "function"){
51662 if(r.hasPanel(panelId)){
51663 return r.showPanel(panelId);
51671 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51672 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51674 restoreState : function(provider){
51676 provider = Roo.state.Manager;
51678 var sm = new Roo.LayoutStateManager();
51679 sm.init(this, provider);
51683 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51684 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51685 * a valid ContentPanel config object. Example:
51687 // Create the main layout
51688 var layout = new Roo.BorderLayout('main-ct', {
51699 // Create and add multiple ContentPanels at once via configs
51702 id: 'source-files',
51704 title:'Ext Source Files',
51717 * @param {Object} regions An object containing ContentPanel configs by region name
51719 batchAdd : function(regions){
51720 this.beginUpdate();
51721 for(var rname in regions){
51722 var lr = this.regions[rname];
51724 this.addTypedPanels(lr, regions[rname]);
51731 addTypedPanels : function(lr, ps){
51732 if(typeof ps == 'string'){
51733 lr.add(new Roo.ContentPanel(ps));
51735 else if(ps instanceof Array){
51736 for(var i =0, len = ps.length; i < len; i++){
51737 this.addTypedPanels(lr, ps[i]);
51740 else if(!ps.events){ // raw config?
51742 delete ps.el; // prevent conflict
51743 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51745 else { // panel object assumed!
51750 * Adds a xtype elements to the layout.
51754 xtype : 'ContentPanel',
51761 xtype : 'NestedLayoutPanel',
51767 items : [ ... list of content panels or nested layout panels.. ]
51771 * @param {Object} cfg Xtype definition of item to add.
51773 addxtype : function(cfg)
51775 // basically accepts a pannel...
51776 // can accept a layout region..!?!?
51777 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51779 if (!cfg.xtype.match(/Panel$/)) {
51784 if (typeof(cfg.region) == 'undefined') {
51785 Roo.log("Failed to add Panel, region was not set");
51789 var region = cfg.region;
51795 xitems = cfg.items;
51802 case 'ContentPanel': // ContentPanel (el, cfg)
51803 case 'ScrollPanel': // ContentPanel (el, cfg)
51805 if(cfg.autoCreate) {
51806 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51808 var el = this.el.createChild();
51809 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51812 this.add(region, ret);
51816 case 'TreePanel': // our new panel!
51817 cfg.el = this.el.createChild();
51818 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51819 this.add(region, ret);
51822 case 'NestedLayoutPanel':
51823 // create a new Layout (which is a Border Layout...
51824 var el = this.el.createChild();
51825 var clayout = cfg.layout;
51827 clayout.items = clayout.items || [];
51828 // replace this exitems with the clayout ones..
51829 xitems = clayout.items;
51832 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51833 cfg.background = false;
51835 var layout = new Roo.BorderLayout(el, clayout);
51837 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51838 //console.log('adding nested layout panel ' + cfg.toSource());
51839 this.add(region, ret);
51840 nb = {}; /// find first...
51845 // needs grid and region
51847 //var el = this.getRegion(region).el.createChild();
51848 var el = this.el.createChild();
51849 // create the grid first...
51851 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51853 if (region == 'center' && this.active ) {
51854 cfg.background = false;
51856 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51858 this.add(region, ret);
51859 if (cfg.background) {
51860 ret.on('activate', function(gp) {
51861 if (!gp.grid.rendered) {
51876 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51878 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51879 this.add(region, ret);
51882 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51886 // GridPanel (grid, cfg)
51889 this.beginUpdate();
51893 Roo.each(xitems, function(i) {
51894 region = nb && i.region ? i.region : false;
51896 var add = ret.addxtype(i);
51899 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51900 if (!i.background) {
51901 abn[region] = nb[region] ;
51908 // make the last non-background panel active..
51909 //if (nb) { Roo.log(abn); }
51912 for(var r in abn) {
51913 region = this.getRegion(r);
51915 // tried using nb[r], but it does not work..
51917 region.showPanel(abn[r]);
51928 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51929 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51930 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51931 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51934 var CP = Roo.ContentPanel;
51936 var layout = Roo.BorderLayout.create({
51940 panels: [new CP("north", "North")]
51949 panels: [new CP("west", {title: "West"})]
51958 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51967 panels: [new CP("south", {title: "South", closable: true})]
51974 preferredTabWidth: 150,
51976 new CP("center1", {title: "Close Me", closable: true}),
51977 new CP("center2", {title: "Center Panel", closable: false})
51982 layout.getRegion("center").showPanel("center1");
51987 Roo.BorderLayout.create = function(config, targetEl){
51988 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51989 layout.beginUpdate();
51990 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51991 for(var j = 0, jlen = regions.length; j < jlen; j++){
51992 var lr = regions[j];
51993 if(layout.regions[lr] && config[lr].panels){
51994 var r = layout.regions[lr];
51995 var ps = config[lr].panels;
51996 layout.addTypedPanels(r, ps);
51999 layout.endUpdate();
52004 Roo.BorderLayout.RegionFactory = {
52006 validRegions : ["north","south","east","west","center"],
52009 create : function(target, mgr, config){
52010 target = target.toLowerCase();
52011 if(config.lightweight || config.basic){
52012 return new Roo.BasicLayoutRegion(mgr, config, target);
52016 return new Roo.NorthLayoutRegion(mgr, config);
52018 return new Roo.SouthLayoutRegion(mgr, config);
52020 return new Roo.EastLayoutRegion(mgr, config);
52022 return new Roo.WestLayoutRegion(mgr, config);
52024 return new Roo.CenterLayoutRegion(mgr, config);
52026 throw 'Layout region "'+target+'" not supported.';
52030 * Ext JS Library 1.1.1
52031 * Copyright(c) 2006-2007, Ext JS, LLC.
52033 * Originally Released Under LGPL - original licence link has changed is not relivant.
52036 * <script type="text/javascript">
52040 * @class Roo.BasicLayoutRegion
52041 * @extends Roo.util.Observable
52042 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
52043 * and does not have a titlebar, tabs or any other features. All it does is size and position
52044 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
52046 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
52048 this.position = pos;
52051 * @scope Roo.BasicLayoutRegion
52055 * @event beforeremove
52056 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
52057 * @param {Roo.LayoutRegion} this
52058 * @param {Roo.ContentPanel} panel The panel
52059 * @param {Object} e The cancel event object
52061 "beforeremove" : true,
52063 * @event invalidated
52064 * Fires when the layout for this region is changed.
52065 * @param {Roo.LayoutRegion} this
52067 "invalidated" : true,
52069 * @event visibilitychange
52070 * Fires when this region is shown or hidden
52071 * @param {Roo.LayoutRegion} this
52072 * @param {Boolean} visibility true or false
52074 "visibilitychange" : true,
52076 * @event paneladded
52077 * Fires when a panel is added.
52078 * @param {Roo.LayoutRegion} this
52079 * @param {Roo.ContentPanel} panel The panel
52081 "paneladded" : true,
52083 * @event panelremoved
52084 * Fires when a panel is removed.
52085 * @param {Roo.LayoutRegion} this
52086 * @param {Roo.ContentPanel} panel The panel
52088 "panelremoved" : true,
52090 * @event beforecollapse
52091 * Fires when this region before collapse.
52092 * @param {Roo.LayoutRegion} this
52094 "beforecollapse" : true,
52097 * Fires when this region is collapsed.
52098 * @param {Roo.LayoutRegion} this
52100 "collapsed" : true,
52103 * Fires when this region is expanded.
52104 * @param {Roo.LayoutRegion} this
52109 * Fires when this region is slid into view.
52110 * @param {Roo.LayoutRegion} this
52112 "slideshow" : true,
52115 * Fires when this region slides out of view.
52116 * @param {Roo.LayoutRegion} this
52118 "slidehide" : true,
52120 * @event panelactivated
52121 * Fires when a panel is activated.
52122 * @param {Roo.LayoutRegion} this
52123 * @param {Roo.ContentPanel} panel The activated panel
52125 "panelactivated" : true,
52128 * Fires when the user resizes this region.
52129 * @param {Roo.LayoutRegion} this
52130 * @param {Number} newSize The new size (width for east/west, height for north/south)
52134 /** A collection of panels in this region. @type Roo.util.MixedCollection */
52135 this.panels = new Roo.util.MixedCollection();
52136 this.panels.getKey = this.getPanelId.createDelegate(this);
52138 this.activePanel = null;
52139 // ensure listeners are added...
52141 if (config.listeners || config.events) {
52142 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
52143 listeners : config.listeners || {},
52144 events : config.events || {}
52148 if(skipConfig !== true){
52149 this.applyConfig(config);
52153 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
52154 getPanelId : function(p){
52158 applyConfig : function(config){
52159 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52160 this.config = config;
52165 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
52166 * the width, for horizontal (north, south) the height.
52167 * @param {Number} newSize The new width or height
52169 resizeTo : function(newSize){
52170 var el = this.el ? this.el :
52171 (this.activePanel ? this.activePanel.getEl() : null);
52173 switch(this.position){
52176 el.setWidth(newSize);
52177 this.fireEvent("resized", this, newSize);
52181 el.setHeight(newSize);
52182 this.fireEvent("resized", this, newSize);
52188 getBox : function(){
52189 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
52192 getMargins : function(){
52193 return this.margins;
52196 updateBox : function(box){
52198 var el = this.activePanel.getEl();
52199 el.dom.style.left = box.x + "px";
52200 el.dom.style.top = box.y + "px";
52201 this.activePanel.setSize(box.width, box.height);
52205 * Returns the container element for this region.
52206 * @return {Roo.Element}
52208 getEl : function(){
52209 return this.activePanel;
52213 * Returns true if this region is currently visible.
52214 * @return {Boolean}
52216 isVisible : function(){
52217 return this.activePanel ? true : false;
52220 setActivePanel : function(panel){
52221 panel = this.getPanel(panel);
52222 if(this.activePanel && this.activePanel != panel){
52223 this.activePanel.setActiveState(false);
52224 this.activePanel.getEl().setLeftTop(-10000,-10000);
52226 this.activePanel = panel;
52227 panel.setActiveState(true);
52229 panel.setSize(this.box.width, this.box.height);
52231 this.fireEvent("panelactivated", this, panel);
52232 this.fireEvent("invalidated");
52236 * Show the specified panel.
52237 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
52238 * @return {Roo.ContentPanel} The shown panel or null
52240 showPanel : function(panel){
52241 if(panel = this.getPanel(panel)){
52242 this.setActivePanel(panel);
52248 * Get the active panel for this region.
52249 * @return {Roo.ContentPanel} The active panel or null
52251 getActivePanel : function(){
52252 return this.activePanel;
52256 * Add the passed ContentPanel(s)
52257 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52258 * @return {Roo.ContentPanel} The panel added (if only one was added)
52260 add : function(panel){
52261 if(arguments.length > 1){
52262 for(var i = 0, len = arguments.length; i < len; i++) {
52263 this.add(arguments[i]);
52267 if(this.hasPanel(panel)){
52268 this.showPanel(panel);
52271 var el = panel.getEl();
52272 if(el.dom.parentNode != this.mgr.el.dom){
52273 this.mgr.el.dom.appendChild(el.dom);
52275 if(panel.setRegion){
52276 panel.setRegion(this);
52278 this.panels.add(panel);
52279 el.setStyle("position", "absolute");
52280 if(!panel.background){
52281 this.setActivePanel(panel);
52282 if(this.config.initialSize && this.panels.getCount()==1){
52283 this.resizeTo(this.config.initialSize);
52286 this.fireEvent("paneladded", this, panel);
52291 * Returns true if the panel is in this region.
52292 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52293 * @return {Boolean}
52295 hasPanel : function(panel){
52296 if(typeof panel == "object"){ // must be panel obj
52297 panel = panel.getId();
52299 return this.getPanel(panel) ? true : false;
52303 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52304 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52305 * @param {Boolean} preservePanel Overrides the config preservePanel option
52306 * @return {Roo.ContentPanel} The panel that was removed
52308 remove : function(panel, preservePanel){
52309 panel = this.getPanel(panel);
52314 this.fireEvent("beforeremove", this, panel, e);
52315 if(e.cancel === true){
52318 var panelId = panel.getId();
52319 this.panels.removeKey(panelId);
52324 * Returns the panel specified or null if it's not in this region.
52325 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52326 * @return {Roo.ContentPanel}
52328 getPanel : function(id){
52329 if(typeof id == "object"){ // must be panel obj
52332 return this.panels.get(id);
52336 * Returns this regions position (north/south/east/west/center).
52339 getPosition: function(){
52340 return this.position;
52344 * Ext JS Library 1.1.1
52345 * Copyright(c) 2006-2007, Ext JS, LLC.
52347 * Originally Released Under LGPL - original licence link has changed is not relivant.
52350 * <script type="text/javascript">
52354 * @class Roo.LayoutRegion
52355 * @extends Roo.BasicLayoutRegion
52356 * This class represents a region in a layout manager.
52357 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
52358 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
52359 * @cfg {Boolean} floatable False to disable floating (defaults to true)
52360 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
52361 * @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})
52362 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
52363 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
52364 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
52365 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
52366 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
52367 * @cfg {String} title The title for the region (overrides panel titles)
52368 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
52369 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
52370 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
52371 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
52372 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
52373 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
52374 * the space available, similar to FireFox 1.5 tabs (defaults to false)
52375 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
52376 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
52377 * @cfg {Boolean} showPin True to show a pin button
52378 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
52379 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
52380 * @cfg {Boolean} disableTabTips True to disable tab tooltips
52381 * @cfg {Number} width For East/West panels
52382 * @cfg {Number} height For North/South panels
52383 * @cfg {Boolean} split To show the splitter
52384 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
52386 Roo.LayoutRegion = function(mgr, config, pos){
52387 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
52388 var dh = Roo.DomHelper;
52389 /** This region's container element
52390 * @type Roo.Element */
52391 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
52392 /** This region's title element
52393 * @type Roo.Element */
52395 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
52396 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
52397 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
52399 this.titleEl.enableDisplayMode();
52400 /** This region's title text element
52401 * @type HTMLElement */
52402 this.titleTextEl = this.titleEl.dom.firstChild;
52403 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
52404 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
52405 this.closeBtn.enableDisplayMode();
52406 this.closeBtn.on("click", this.closeClicked, this);
52407 this.closeBtn.hide();
52409 this.createBody(config);
52410 this.visible = true;
52411 this.collapsed = false;
52413 if(config.hideWhenEmpty){
52415 this.on("paneladded", this.validateVisibility, this);
52416 this.on("panelremoved", this.validateVisibility, this);
52418 this.applyConfig(config);
52421 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
52423 createBody : function(){
52424 /** This region's body element
52425 * @type Roo.Element */
52426 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
52429 applyConfig : function(c){
52430 if(c.collapsible && this.position != "center" && !this.collapsedEl){
52431 var dh = Roo.DomHelper;
52432 if(c.titlebar !== false){
52433 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
52434 this.collapseBtn.on("click", this.collapse, this);
52435 this.collapseBtn.enableDisplayMode();
52437 if(c.showPin === true || this.showPin){
52438 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
52439 this.stickBtn.enableDisplayMode();
52440 this.stickBtn.on("click", this.expand, this);
52441 this.stickBtn.hide();
52444 /** This region's collapsed element
52445 * @type Roo.Element */
52446 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
52447 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
52449 if(c.floatable !== false){
52450 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
52451 this.collapsedEl.on("click", this.collapseClick, this);
52454 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
52455 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
52456 id: "message", unselectable: "on", style:{"float":"left"}});
52457 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
52459 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
52460 this.expandBtn.on("click", this.expand, this);
52462 if(this.collapseBtn){
52463 this.collapseBtn.setVisible(c.collapsible == true);
52465 this.cmargins = c.cmargins || this.cmargins ||
52466 (this.position == "west" || this.position == "east" ?
52467 {top: 0, left: 2, right:2, bottom: 0} :
52468 {top: 2, left: 0, right:0, bottom: 2});
52469 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52470 this.bottomTabs = c.tabPosition != "top";
52471 this.autoScroll = c.autoScroll || false;
52472 if(this.autoScroll){
52473 this.bodyEl.setStyle("overflow", "auto");
52475 this.bodyEl.setStyle("overflow", "hidden");
52477 //if(c.titlebar !== false){
52478 if((!c.titlebar && !c.title) || c.titlebar === false){
52479 this.titleEl.hide();
52481 this.titleEl.show();
52483 this.titleTextEl.innerHTML = c.title;
52487 this.duration = c.duration || .30;
52488 this.slideDuration = c.slideDuration || .45;
52491 this.collapse(true);
52498 * Returns true if this region is currently visible.
52499 * @return {Boolean}
52501 isVisible : function(){
52502 return this.visible;
52506 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
52507 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
52509 setCollapsedTitle : function(title){
52510 title = title || " ";
52511 if(this.collapsedTitleTextEl){
52512 this.collapsedTitleTextEl.innerHTML = title;
52516 getBox : function(){
52518 if(!this.collapsed){
52519 b = this.el.getBox(false, true);
52521 b = this.collapsedEl.getBox(false, true);
52526 getMargins : function(){
52527 return this.collapsed ? this.cmargins : this.margins;
52530 highlight : function(){
52531 this.el.addClass("x-layout-panel-dragover");
52534 unhighlight : function(){
52535 this.el.removeClass("x-layout-panel-dragover");
52538 updateBox : function(box){
52540 if(!this.collapsed){
52541 this.el.dom.style.left = box.x + "px";
52542 this.el.dom.style.top = box.y + "px";
52543 this.updateBody(box.width, box.height);
52545 this.collapsedEl.dom.style.left = box.x + "px";
52546 this.collapsedEl.dom.style.top = box.y + "px";
52547 this.collapsedEl.setSize(box.width, box.height);
52550 this.tabs.autoSizeTabs();
52554 updateBody : function(w, h){
52556 this.el.setWidth(w);
52557 w -= this.el.getBorderWidth("rl");
52558 if(this.config.adjustments){
52559 w += this.config.adjustments[0];
52563 this.el.setHeight(h);
52564 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52565 h -= this.el.getBorderWidth("tb");
52566 if(this.config.adjustments){
52567 h += this.config.adjustments[1];
52569 this.bodyEl.setHeight(h);
52571 h = this.tabs.syncHeight(h);
52574 if(this.panelSize){
52575 w = w !== null ? w : this.panelSize.width;
52576 h = h !== null ? h : this.panelSize.height;
52578 if(this.activePanel){
52579 var el = this.activePanel.getEl();
52580 w = w !== null ? w : el.getWidth();
52581 h = h !== null ? h : el.getHeight();
52582 this.panelSize = {width: w, height: h};
52583 this.activePanel.setSize(w, h);
52585 if(Roo.isIE && this.tabs){
52586 this.tabs.el.repaint();
52591 * Returns the container element for this region.
52592 * @return {Roo.Element}
52594 getEl : function(){
52599 * Hides this region.
52602 if(!this.collapsed){
52603 this.el.dom.style.left = "-2000px";
52606 this.collapsedEl.dom.style.left = "-2000px";
52607 this.collapsedEl.hide();
52609 this.visible = false;
52610 this.fireEvent("visibilitychange", this, false);
52614 * Shows this region if it was previously hidden.
52617 if(!this.collapsed){
52620 this.collapsedEl.show();
52622 this.visible = true;
52623 this.fireEvent("visibilitychange", this, true);
52626 closeClicked : function(){
52627 if(this.activePanel){
52628 this.remove(this.activePanel);
52632 collapseClick : function(e){
52634 e.stopPropagation();
52637 e.stopPropagation();
52643 * Collapses this region.
52644 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52646 collapse : function(skipAnim, skipCheck){
52647 if(this.collapsed) {
52651 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52653 this.collapsed = true;
52655 this.split.el.hide();
52657 if(this.config.animate && skipAnim !== true){
52658 this.fireEvent("invalidated", this);
52659 this.animateCollapse();
52661 this.el.setLocation(-20000,-20000);
52663 this.collapsedEl.show();
52664 this.fireEvent("collapsed", this);
52665 this.fireEvent("invalidated", this);
52671 animateCollapse : function(){
52676 * Expands this region if it was previously collapsed.
52677 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52678 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52680 expand : function(e, skipAnim){
52682 e.stopPropagation();
52684 if(!this.collapsed || this.el.hasActiveFx()) {
52688 this.afterSlideIn();
52691 this.collapsed = false;
52692 if(this.config.animate && skipAnim !== true){
52693 this.animateExpand();
52697 this.split.el.show();
52699 this.collapsedEl.setLocation(-2000,-2000);
52700 this.collapsedEl.hide();
52701 this.fireEvent("invalidated", this);
52702 this.fireEvent("expanded", this);
52706 animateExpand : function(){
52710 initTabs : function()
52712 this.bodyEl.setStyle("overflow", "hidden");
52713 var ts = new Roo.TabPanel(
52716 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52717 disableTooltips: this.config.disableTabTips,
52718 toolbar : this.config.toolbar
52721 if(this.config.hideTabs){
52722 ts.stripWrap.setDisplayed(false);
52725 ts.resizeTabs = this.config.resizeTabs === true;
52726 ts.minTabWidth = this.config.minTabWidth || 40;
52727 ts.maxTabWidth = this.config.maxTabWidth || 250;
52728 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52729 ts.monitorResize = false;
52730 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52731 ts.bodyEl.addClass('x-layout-tabs-body');
52732 this.panels.each(this.initPanelAsTab, this);
52735 initPanelAsTab : function(panel){
52736 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52737 this.config.closeOnTab && panel.isClosable());
52738 if(panel.tabTip !== undefined){
52739 ti.setTooltip(panel.tabTip);
52741 ti.on("activate", function(){
52742 this.setActivePanel(panel);
52744 if(this.config.closeOnTab){
52745 ti.on("beforeclose", function(t, e){
52747 this.remove(panel);
52753 updatePanelTitle : function(panel, title){
52754 if(this.activePanel == panel){
52755 this.updateTitle(title);
52758 var ti = this.tabs.getTab(panel.getEl().id);
52760 if(panel.tabTip !== undefined){
52761 ti.setTooltip(panel.tabTip);
52766 updateTitle : function(title){
52767 if(this.titleTextEl && !this.config.title){
52768 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52772 setActivePanel : function(panel){
52773 panel = this.getPanel(panel);
52774 if(this.activePanel && this.activePanel != panel){
52775 this.activePanel.setActiveState(false);
52777 this.activePanel = panel;
52778 panel.setActiveState(true);
52779 if(this.panelSize){
52780 panel.setSize(this.panelSize.width, this.panelSize.height);
52783 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52785 this.updateTitle(panel.getTitle());
52787 this.fireEvent("invalidated", this);
52789 this.fireEvent("panelactivated", this, panel);
52793 * Shows the specified panel.
52794 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52795 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52797 showPanel : function(panel)
52799 panel = this.getPanel(panel);
52802 var tab = this.tabs.getTab(panel.getEl().id);
52803 if(tab.isHidden()){
52804 this.tabs.unhideTab(tab.id);
52808 this.setActivePanel(panel);
52815 * Get the active panel for this region.
52816 * @return {Roo.ContentPanel} The active panel or null
52818 getActivePanel : function(){
52819 return this.activePanel;
52822 validateVisibility : function(){
52823 if(this.panels.getCount() < 1){
52824 this.updateTitle(" ");
52825 this.closeBtn.hide();
52828 if(!this.isVisible()){
52835 * Adds the passed ContentPanel(s) to this region.
52836 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52837 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52839 add : function(panel){
52840 if(arguments.length > 1){
52841 for(var i = 0, len = arguments.length; i < len; i++) {
52842 this.add(arguments[i]);
52846 if(this.hasPanel(panel)){
52847 this.showPanel(panel);
52850 panel.setRegion(this);
52851 this.panels.add(panel);
52852 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52853 this.bodyEl.dom.appendChild(panel.getEl().dom);
52854 if(panel.background !== true){
52855 this.setActivePanel(panel);
52857 this.fireEvent("paneladded", this, panel);
52863 this.initPanelAsTab(panel);
52865 if(panel.background !== true){
52866 this.tabs.activate(panel.getEl().id);
52868 this.fireEvent("paneladded", this, panel);
52873 * Hides the tab for the specified panel.
52874 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52876 hidePanel : function(panel){
52877 if(this.tabs && (panel = this.getPanel(panel))){
52878 this.tabs.hideTab(panel.getEl().id);
52883 * Unhides the tab for a previously hidden panel.
52884 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52886 unhidePanel : function(panel){
52887 if(this.tabs && (panel = this.getPanel(panel))){
52888 this.tabs.unhideTab(panel.getEl().id);
52892 clearPanels : function(){
52893 while(this.panels.getCount() > 0){
52894 this.remove(this.panels.first());
52899 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52900 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52901 * @param {Boolean} preservePanel Overrides the config preservePanel option
52902 * @return {Roo.ContentPanel} The panel that was removed
52904 remove : function(panel, preservePanel){
52905 panel = this.getPanel(panel);
52910 this.fireEvent("beforeremove", this, panel, e);
52911 if(e.cancel === true){
52914 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52915 var panelId = panel.getId();
52916 this.panels.removeKey(panelId);
52918 document.body.appendChild(panel.getEl().dom);
52921 this.tabs.removeTab(panel.getEl().id);
52922 }else if (!preservePanel){
52923 this.bodyEl.dom.removeChild(panel.getEl().dom);
52925 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52926 var p = this.panels.first();
52927 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52928 tempEl.appendChild(p.getEl().dom);
52929 this.bodyEl.update("");
52930 this.bodyEl.dom.appendChild(p.getEl().dom);
52932 this.updateTitle(p.getTitle());
52934 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52935 this.setActivePanel(p);
52937 panel.setRegion(null);
52938 if(this.activePanel == panel){
52939 this.activePanel = null;
52941 if(this.config.autoDestroy !== false && preservePanel !== true){
52942 try{panel.destroy();}catch(e){}
52944 this.fireEvent("panelremoved", this, panel);
52949 * Returns the TabPanel component used by this region
52950 * @return {Roo.TabPanel}
52952 getTabs : function(){
52956 createTool : function(parentEl, className){
52957 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52958 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52959 btn.addClassOnOver("x-layout-tools-button-over");
52964 * Ext JS Library 1.1.1
52965 * Copyright(c) 2006-2007, Ext JS, LLC.
52967 * Originally Released Under LGPL - original licence link has changed is not relivant.
52970 * <script type="text/javascript">
52976 * @class Roo.SplitLayoutRegion
52977 * @extends Roo.LayoutRegion
52978 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52980 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52981 this.cursor = cursor;
52982 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52985 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52986 splitTip : "Drag to resize.",
52987 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52988 useSplitTips : false,
52990 applyConfig : function(config){
52991 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52994 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52995 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52996 /** The SplitBar for this region
52997 * @type Roo.SplitBar */
52998 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52999 this.split.on("moved", this.onSplitMove, this);
53000 this.split.useShim = config.useShim === true;
53001 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
53002 if(this.useSplitTips){
53003 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
53005 if(config.collapsible){
53006 this.split.el.on("dblclick", this.collapse, this);
53009 if(typeof config.minSize != "undefined"){
53010 this.split.minSize = config.minSize;
53012 if(typeof config.maxSize != "undefined"){
53013 this.split.maxSize = config.maxSize;
53015 if(config.hideWhenEmpty || config.hidden || config.collapsed){
53016 this.hideSplitter();
53021 getHMaxSize : function(){
53022 var cmax = this.config.maxSize || 10000;
53023 var center = this.mgr.getRegion("center");
53024 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
53027 getVMaxSize : function(){
53028 var cmax = this.config.maxSize || 10000;
53029 var center = this.mgr.getRegion("center");
53030 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
53033 onSplitMove : function(split, newSize){
53034 this.fireEvent("resized", this, newSize);
53038 * Returns the {@link Roo.SplitBar} for this region.
53039 * @return {Roo.SplitBar}
53041 getSplitBar : function(){
53046 this.hideSplitter();
53047 Roo.SplitLayoutRegion.superclass.hide.call(this);
53050 hideSplitter : function(){
53052 this.split.el.setLocation(-2000,-2000);
53053 this.split.el.hide();
53059 this.split.el.show();
53061 Roo.SplitLayoutRegion.superclass.show.call(this);
53064 beforeSlide: function(){
53065 if(Roo.isGecko){// firefox overflow auto bug workaround
53066 this.bodyEl.clip();
53068 this.tabs.bodyEl.clip();
53070 if(this.activePanel){
53071 this.activePanel.getEl().clip();
53073 if(this.activePanel.beforeSlide){
53074 this.activePanel.beforeSlide();
53080 afterSlide : function(){
53081 if(Roo.isGecko){// firefox overflow auto bug workaround
53082 this.bodyEl.unclip();
53084 this.tabs.bodyEl.unclip();
53086 if(this.activePanel){
53087 this.activePanel.getEl().unclip();
53088 if(this.activePanel.afterSlide){
53089 this.activePanel.afterSlide();
53095 initAutoHide : function(){
53096 if(this.autoHide !== false){
53097 if(!this.autoHideHd){
53098 var st = new Roo.util.DelayedTask(this.slideIn, this);
53099 this.autoHideHd = {
53100 "mouseout": function(e){
53101 if(!e.within(this.el, true)){
53105 "mouseover" : function(e){
53111 this.el.on(this.autoHideHd);
53115 clearAutoHide : function(){
53116 if(this.autoHide !== false){
53117 this.el.un("mouseout", this.autoHideHd.mouseout);
53118 this.el.un("mouseover", this.autoHideHd.mouseover);
53122 clearMonitor : function(){
53123 Roo.get(document).un("click", this.slideInIf, this);
53126 // these names are backwards but not changed for compat
53127 slideOut : function(){
53128 if(this.isSlid || this.el.hasActiveFx()){
53131 this.isSlid = true;
53132 if(this.collapseBtn){
53133 this.collapseBtn.hide();
53135 this.closeBtnState = this.closeBtn.getStyle('display');
53136 this.closeBtn.hide();
53138 this.stickBtn.show();
53141 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
53142 this.beforeSlide();
53143 this.el.setStyle("z-index", 10001);
53144 this.el.slideIn(this.getSlideAnchor(), {
53145 callback: function(){
53147 this.initAutoHide();
53148 Roo.get(document).on("click", this.slideInIf, this);
53149 this.fireEvent("slideshow", this);
53156 afterSlideIn : function(){
53157 this.clearAutoHide();
53158 this.isSlid = false;
53159 this.clearMonitor();
53160 this.el.setStyle("z-index", "");
53161 if(this.collapseBtn){
53162 this.collapseBtn.show();
53164 this.closeBtn.setStyle('display', this.closeBtnState);
53166 this.stickBtn.hide();
53168 this.fireEvent("slidehide", this);
53171 slideIn : function(cb){
53172 if(!this.isSlid || this.el.hasActiveFx()){
53176 this.isSlid = false;
53177 this.beforeSlide();
53178 this.el.slideOut(this.getSlideAnchor(), {
53179 callback: function(){
53180 this.el.setLeftTop(-10000, -10000);
53182 this.afterSlideIn();
53190 slideInIf : function(e){
53191 if(!e.within(this.el)){
53196 animateCollapse : function(){
53197 this.beforeSlide();
53198 this.el.setStyle("z-index", 20000);
53199 var anchor = this.getSlideAnchor();
53200 this.el.slideOut(anchor, {
53201 callback : function(){
53202 this.el.setStyle("z-index", "");
53203 this.collapsedEl.slideIn(anchor, {duration:.3});
53205 this.el.setLocation(-10000,-10000);
53207 this.fireEvent("collapsed", this);
53214 animateExpand : function(){
53215 this.beforeSlide();
53216 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
53217 this.el.setStyle("z-index", 20000);
53218 this.collapsedEl.hide({
53221 this.el.slideIn(this.getSlideAnchor(), {
53222 callback : function(){
53223 this.el.setStyle("z-index", "");
53226 this.split.el.show();
53228 this.fireEvent("invalidated", this);
53229 this.fireEvent("expanded", this);
53257 getAnchor : function(){
53258 return this.anchors[this.position];
53261 getCollapseAnchor : function(){
53262 return this.canchors[this.position];
53265 getSlideAnchor : function(){
53266 return this.sanchors[this.position];
53269 getAlignAdj : function(){
53270 var cm = this.cmargins;
53271 switch(this.position){
53287 getExpandAdj : function(){
53288 var c = this.collapsedEl, cm = this.cmargins;
53289 switch(this.position){
53291 return [-(cm.right+c.getWidth()+cm.left), 0];
53294 return [cm.right+c.getWidth()+cm.left, 0];
53297 return [0, -(cm.top+cm.bottom+c.getHeight())];
53300 return [0, cm.top+cm.bottom+c.getHeight()];
53306 * Ext JS Library 1.1.1
53307 * Copyright(c) 2006-2007, Ext JS, LLC.
53309 * Originally Released Under LGPL - original licence link has changed is not relivant.
53312 * <script type="text/javascript">
53315 * These classes are private internal classes
53317 Roo.CenterLayoutRegion = function(mgr, config){
53318 Roo.LayoutRegion.call(this, mgr, config, "center");
53319 this.visible = true;
53320 this.minWidth = config.minWidth || 20;
53321 this.minHeight = config.minHeight || 20;
53324 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
53326 // center panel can't be hidden
53330 // center panel can't be hidden
53333 getMinWidth: function(){
53334 return this.minWidth;
53337 getMinHeight: function(){
53338 return this.minHeight;
53343 Roo.NorthLayoutRegion = function(mgr, config){
53344 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
53346 this.split.placement = Roo.SplitBar.TOP;
53347 this.split.orientation = Roo.SplitBar.VERTICAL;
53348 this.split.el.addClass("x-layout-split-v");
53350 var size = config.initialSize || config.height;
53351 if(typeof size != "undefined"){
53352 this.el.setHeight(size);
53355 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
53356 orientation: Roo.SplitBar.VERTICAL,
53357 getBox : function(){
53358 if(this.collapsed){
53359 return this.collapsedEl.getBox();
53361 var box = this.el.getBox();
53363 box.height += this.split.el.getHeight();
53368 updateBox : function(box){
53369 if(this.split && !this.collapsed){
53370 box.height -= this.split.el.getHeight();
53371 this.split.el.setLeft(box.x);
53372 this.split.el.setTop(box.y+box.height);
53373 this.split.el.setWidth(box.width);
53375 if(this.collapsed){
53376 this.updateBody(box.width, null);
53378 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53382 Roo.SouthLayoutRegion = function(mgr, config){
53383 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
53385 this.split.placement = Roo.SplitBar.BOTTOM;
53386 this.split.orientation = Roo.SplitBar.VERTICAL;
53387 this.split.el.addClass("x-layout-split-v");
53389 var size = config.initialSize || config.height;
53390 if(typeof size != "undefined"){
53391 this.el.setHeight(size);
53394 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
53395 orientation: Roo.SplitBar.VERTICAL,
53396 getBox : function(){
53397 if(this.collapsed){
53398 return this.collapsedEl.getBox();
53400 var box = this.el.getBox();
53402 var sh = this.split.el.getHeight();
53409 updateBox : function(box){
53410 if(this.split && !this.collapsed){
53411 var sh = this.split.el.getHeight();
53414 this.split.el.setLeft(box.x);
53415 this.split.el.setTop(box.y-sh);
53416 this.split.el.setWidth(box.width);
53418 if(this.collapsed){
53419 this.updateBody(box.width, null);
53421 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53425 Roo.EastLayoutRegion = function(mgr, config){
53426 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
53428 this.split.placement = Roo.SplitBar.RIGHT;
53429 this.split.orientation = Roo.SplitBar.HORIZONTAL;
53430 this.split.el.addClass("x-layout-split-h");
53432 var size = config.initialSize || config.width;
53433 if(typeof size != "undefined"){
53434 this.el.setWidth(size);
53437 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
53438 orientation: Roo.SplitBar.HORIZONTAL,
53439 getBox : function(){
53440 if(this.collapsed){
53441 return this.collapsedEl.getBox();
53443 var box = this.el.getBox();
53445 var sw = this.split.el.getWidth();
53452 updateBox : function(box){
53453 if(this.split && !this.collapsed){
53454 var sw = this.split.el.getWidth();
53456 this.split.el.setLeft(box.x);
53457 this.split.el.setTop(box.y);
53458 this.split.el.setHeight(box.height);
53461 if(this.collapsed){
53462 this.updateBody(null, box.height);
53464 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53468 Roo.WestLayoutRegion = function(mgr, config){
53469 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
53471 this.split.placement = Roo.SplitBar.LEFT;
53472 this.split.orientation = Roo.SplitBar.HORIZONTAL;
53473 this.split.el.addClass("x-layout-split-h");
53475 var size = config.initialSize || config.width;
53476 if(typeof size != "undefined"){
53477 this.el.setWidth(size);
53480 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
53481 orientation: Roo.SplitBar.HORIZONTAL,
53482 getBox : function(){
53483 if(this.collapsed){
53484 return this.collapsedEl.getBox();
53486 var box = this.el.getBox();
53488 box.width += this.split.el.getWidth();
53493 updateBox : function(box){
53494 if(this.split && !this.collapsed){
53495 var sw = this.split.el.getWidth();
53497 this.split.el.setLeft(box.x+box.width);
53498 this.split.el.setTop(box.y);
53499 this.split.el.setHeight(box.height);
53501 if(this.collapsed){
53502 this.updateBody(null, box.height);
53504 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53509 * Ext JS Library 1.1.1
53510 * Copyright(c) 2006-2007, Ext JS, LLC.
53512 * Originally Released Under LGPL - original licence link has changed is not relivant.
53515 * <script type="text/javascript">
53520 * Private internal class for reading and applying state
53522 Roo.LayoutStateManager = function(layout){
53523 // default empty state
53532 Roo.LayoutStateManager.prototype = {
53533 init : function(layout, provider){
53534 this.provider = provider;
53535 var state = provider.get(layout.id+"-layout-state");
53537 var wasUpdating = layout.isUpdating();
53539 layout.beginUpdate();
53541 for(var key in state){
53542 if(typeof state[key] != "function"){
53543 var rstate = state[key];
53544 var r = layout.getRegion(key);
53547 r.resizeTo(rstate.size);
53549 if(rstate.collapsed == true){
53552 r.expand(null, true);
53558 layout.endUpdate();
53560 this.state = state;
53562 this.layout = layout;
53563 layout.on("regionresized", this.onRegionResized, this);
53564 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53565 layout.on("regionexpanded", this.onRegionExpanded, this);
53568 storeState : function(){
53569 this.provider.set(this.layout.id+"-layout-state", this.state);
53572 onRegionResized : function(region, newSize){
53573 this.state[region.getPosition()].size = newSize;
53577 onRegionCollapsed : function(region){
53578 this.state[region.getPosition()].collapsed = true;
53582 onRegionExpanded : function(region){
53583 this.state[region.getPosition()].collapsed = false;
53588 * Ext JS Library 1.1.1
53589 * Copyright(c) 2006-2007, Ext JS, LLC.
53591 * Originally Released Under LGPL - original licence link has changed is not relivant.
53594 * <script type="text/javascript">
53597 * @class Roo.ContentPanel
53598 * @extends Roo.util.Observable
53599 * A basic ContentPanel element.
53600 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53601 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53602 * @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
53603 * @cfg {Boolean} closable True if the panel can be closed/removed
53604 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53605 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53606 * @cfg {Toolbar} toolbar A toolbar for this panel
53607 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53608 * @cfg {String} title The title for this panel
53609 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53610 * @cfg {String} url Calls {@link #setUrl} with this value
53611 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53612 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53613 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53614 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53617 * Create a new ContentPanel.
53618 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53619 * @param {String/Object} config A string to set only the title or a config object
53620 * @param {String} content (optional) Set the HTML content for this panel
53621 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53623 Roo.ContentPanel = function(el, config, content){
53627 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53631 if (config && config.parentLayout) {
53632 el = config.parentLayout.el.createChild();
53635 if(el.autoCreate){ // xtype is available if this is called from factory
53639 this.el = Roo.get(el);
53640 if(!this.el && config && config.autoCreate){
53641 if(typeof config.autoCreate == "object"){
53642 if(!config.autoCreate.id){
53643 config.autoCreate.id = config.id||el;
53645 this.el = Roo.DomHelper.append(document.body,
53646 config.autoCreate, true);
53648 this.el = Roo.DomHelper.append(document.body,
53649 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53652 this.closable = false;
53653 this.loaded = false;
53654 this.active = false;
53655 if(typeof config == "string"){
53656 this.title = config;
53658 Roo.apply(this, config);
53661 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53662 this.wrapEl = this.el.wrap();
53663 this.toolbar.container = this.el.insertSibling(false, 'before');
53664 this.toolbar = new Roo.Toolbar(this.toolbar);
53667 // xtype created footer. - not sure if will work as we normally have to render first..
53668 if (this.footer && !this.footer.el && this.footer.xtype) {
53669 if (!this.wrapEl) {
53670 this.wrapEl = this.el.wrap();
53673 this.footer.container = this.wrapEl.createChild();
53675 this.footer = Roo.factory(this.footer, Roo);
53680 this.resizeEl = Roo.get(this.resizeEl, true);
53682 this.resizeEl = this.el;
53684 // handle view.xtype
53692 * Fires when this panel is activated.
53693 * @param {Roo.ContentPanel} this
53697 * @event deactivate
53698 * Fires when this panel is activated.
53699 * @param {Roo.ContentPanel} this
53701 "deactivate" : true,
53705 * Fires when this panel is resized if fitToFrame is true.
53706 * @param {Roo.ContentPanel} this
53707 * @param {Number} width The width after any component adjustments
53708 * @param {Number} height The height after any component adjustments
53714 * Fires when this tab is created
53715 * @param {Roo.ContentPanel} this
53725 if(this.autoScroll){
53726 this.resizeEl.setStyle("overflow", "auto");
53728 // fix randome scrolling
53729 this.el.on('scroll', function() {
53730 Roo.log('fix random scolling');
53731 this.scrollTo('top',0);
53734 content = content || this.content;
53736 this.setContent(content);
53738 if(config && config.url){
53739 this.setUrl(this.url, this.params, this.loadOnce);
53744 Roo.ContentPanel.superclass.constructor.call(this);
53746 if (this.view && typeof(this.view.xtype) != 'undefined') {
53747 this.view.el = this.el.appendChild(document.createElement("div"));
53748 this.view = Roo.factory(this.view);
53749 this.view.render && this.view.render(false, '');
53753 this.fireEvent('render', this);
53756 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53758 setRegion : function(region){
53759 this.region = region;
53761 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53763 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53768 * Returns the toolbar for this Panel if one was configured.
53769 * @return {Roo.Toolbar}
53771 getToolbar : function(){
53772 return this.toolbar;
53775 setActiveState : function(active){
53776 this.active = active;
53778 this.fireEvent("deactivate", this);
53780 this.fireEvent("activate", this);
53784 * Updates this panel's element
53785 * @param {String} content The new content
53786 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53788 setContent : function(content, loadScripts){
53789 this.el.update(content, loadScripts);
53792 ignoreResize : function(w, h){
53793 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53796 this.lastSize = {width: w, height: h};
53801 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53802 * @return {Roo.UpdateManager} The UpdateManager
53804 getUpdateManager : function(){
53805 return this.el.getUpdateManager();
53808 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53809 * @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:
53812 url: "your-url.php",
53813 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53814 callback: yourFunction,
53815 scope: yourObject, //(optional scope)
53818 text: "Loading...",
53823 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53824 * 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.
53825 * @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}
53826 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53827 * @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.
53828 * @return {Roo.ContentPanel} this
53831 var um = this.el.getUpdateManager();
53832 um.update.apply(um, arguments);
53838 * 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.
53839 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53840 * @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)
53841 * @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)
53842 * @return {Roo.UpdateManager} The UpdateManager
53844 setUrl : function(url, params, loadOnce){
53845 if(this.refreshDelegate){
53846 this.removeListener("activate", this.refreshDelegate);
53848 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53849 this.on("activate", this.refreshDelegate);
53850 return this.el.getUpdateManager();
53853 _handleRefresh : function(url, params, loadOnce){
53854 if(!loadOnce || !this.loaded){
53855 var updater = this.el.getUpdateManager();
53856 updater.update(url, params, this._setLoaded.createDelegate(this));
53860 _setLoaded : function(){
53861 this.loaded = true;
53865 * Returns this panel's id
53868 getId : function(){
53873 * Returns this panel's element - used by regiosn to add.
53874 * @return {Roo.Element}
53876 getEl : function(){
53877 return this.wrapEl || this.el;
53880 adjustForComponents : function(width, height)
53882 //Roo.log('adjustForComponents ');
53883 if(this.resizeEl != this.el){
53884 width -= this.el.getFrameWidth('lr');
53885 height -= this.el.getFrameWidth('tb');
53888 var te = this.toolbar.getEl();
53889 height -= te.getHeight();
53890 te.setWidth(width);
53893 var te = this.footer.getEl();
53894 //Roo.log("footer:" + te.getHeight());
53896 height -= te.getHeight();
53897 te.setWidth(width);
53901 if(this.adjustments){
53902 width += this.adjustments[0];
53903 height += this.adjustments[1];
53905 return {"width": width, "height": height};
53908 setSize : function(width, height){
53909 if(this.fitToFrame && !this.ignoreResize(width, height)){
53910 if(this.fitContainer && this.resizeEl != this.el){
53911 this.el.setSize(width, height);
53913 var size = this.adjustForComponents(width, height);
53914 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53915 this.fireEvent('resize', this, size.width, size.height);
53920 * Returns this panel's title
53923 getTitle : function(){
53928 * Set this panel's title
53929 * @param {String} title
53931 setTitle : function(title){
53932 this.title = title;
53934 this.region.updatePanelTitle(this, title);
53939 * Returns true is this panel was configured to be closable
53940 * @return {Boolean}
53942 isClosable : function(){
53943 return this.closable;
53946 beforeSlide : function(){
53948 this.resizeEl.clip();
53951 afterSlide : function(){
53953 this.resizeEl.unclip();
53957 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53958 * Will fail silently if the {@link #setUrl} method has not been called.
53959 * This does not activate the panel, just updates its content.
53961 refresh : function(){
53962 if(this.refreshDelegate){
53963 this.loaded = false;
53964 this.refreshDelegate();
53969 * Destroys this panel
53971 destroy : function(){
53972 this.el.removeAllListeners();
53973 var tempEl = document.createElement("span");
53974 tempEl.appendChild(this.el.dom);
53975 tempEl.innerHTML = "";
53981 * form - if the content panel contains a form - this is a reference to it.
53982 * @type {Roo.form.Form}
53986 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53987 * This contains a reference to it.
53993 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
54003 * @param {Object} cfg Xtype definition of item to add.
54006 addxtype : function(cfg) {
54008 if (cfg.xtype.match(/^Form$/)) {
54011 //if (this.footer) {
54012 // el = this.footer.container.insertSibling(false, 'before');
54014 el = this.el.createChild();
54017 this.form = new Roo.form.Form(cfg);
54020 if ( this.form.allItems.length) {
54021 this.form.render(el.dom);
54025 // should only have one of theses..
54026 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
54027 // views.. should not be just added - used named prop 'view''
54029 cfg.el = this.el.appendChild(document.createElement("div"));
54032 var ret = new Roo.factory(cfg);
54034 ret.render && ret.render(false, ''); // render blank..
54043 * @class Roo.GridPanel
54044 * @extends Roo.ContentPanel
54046 * Create a new GridPanel.
54047 * @param {Roo.grid.Grid} grid The grid for this panel
54048 * @param {String/Object} config A string to set only the panel's title, or a config object
54050 Roo.GridPanel = function(grid, config){
54053 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
54054 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
54056 this.wrapper.dom.appendChild(grid.getGridEl().dom);
54058 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
54061 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
54063 // xtype created footer. - not sure if will work as we normally have to render first..
54064 if (this.footer && !this.footer.el && this.footer.xtype) {
54066 this.footer.container = this.grid.getView().getFooterPanel(true);
54067 this.footer.dataSource = this.grid.dataSource;
54068 this.footer = Roo.factory(this.footer, Roo);
54072 grid.monitorWindowResize = false; // turn off autosizing
54073 grid.autoHeight = false;
54074 grid.autoWidth = false;
54076 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
54079 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
54080 getId : function(){
54081 return this.grid.id;
54085 * Returns the grid for this panel
54086 * @return {Roo.grid.Grid}
54088 getGrid : function(){
54092 setSize : function(width, height){
54093 if(!this.ignoreResize(width, height)){
54094 var grid = this.grid;
54095 var size = this.adjustForComponents(width, height);
54096 grid.getGridEl().setSize(size.width, size.height);
54101 beforeSlide : function(){
54102 this.grid.getView().scroller.clip();
54105 afterSlide : function(){
54106 this.grid.getView().scroller.unclip();
54109 destroy : function(){
54110 this.grid.destroy();
54112 Roo.GridPanel.superclass.destroy.call(this);
54118 * @class Roo.NestedLayoutPanel
54119 * @extends Roo.ContentPanel
54121 * Create a new NestedLayoutPanel.
54124 * @param {Roo.BorderLayout} layout The layout for this panel
54125 * @param {String/Object} config A string to set only the title or a config object
54127 Roo.NestedLayoutPanel = function(layout, config)
54129 // construct with only one argument..
54130 /* FIXME - implement nicer consturctors
54131 if (layout.layout) {
54133 layout = config.layout;
54134 delete config.layout;
54136 if (layout.xtype && !layout.getEl) {
54137 // then layout needs constructing..
54138 layout = Roo.factory(layout, Roo);
54143 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
54145 layout.monitorWindowResize = false; // turn off autosizing
54146 this.layout = layout;
54147 this.layout.getEl().addClass("x-layout-nested-layout");
54154 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
54156 setSize : function(width, height){
54157 if(!this.ignoreResize(width, height)){
54158 var size = this.adjustForComponents(width, height);
54159 var el = this.layout.getEl();
54160 el.setSize(size.width, size.height);
54161 var touch = el.dom.offsetWidth;
54162 this.layout.layout();
54163 // ie requires a double layout on the first pass
54164 if(Roo.isIE && !this.initialized){
54165 this.initialized = true;
54166 this.layout.layout();
54171 // activate all subpanels if not currently active..
54173 setActiveState : function(active){
54174 this.active = active;
54176 this.fireEvent("deactivate", this);
54180 this.fireEvent("activate", this);
54181 // not sure if this should happen before or after..
54182 if (!this.layout) {
54183 return; // should not happen..
54186 for (var r in this.layout.regions) {
54187 reg = this.layout.getRegion(r);
54188 if (reg.getActivePanel()) {
54189 //reg.showPanel(reg.getActivePanel()); // force it to activate..
54190 reg.setActivePanel(reg.getActivePanel());
54193 if (!reg.panels.length) {
54196 reg.showPanel(reg.getPanel(0));
54205 * Returns the nested BorderLayout for this panel
54206 * @return {Roo.BorderLayout}
54208 getLayout : function(){
54209 return this.layout;
54213 * Adds a xtype elements to the layout of the nested panel
54217 xtype : 'ContentPanel',
54224 xtype : 'NestedLayoutPanel',
54230 items : [ ... list of content panels or nested layout panels.. ]
54234 * @param {Object} cfg Xtype definition of item to add.
54236 addxtype : function(cfg) {
54237 return this.layout.addxtype(cfg);
54242 Roo.ScrollPanel = function(el, config, content){
54243 config = config || {};
54244 config.fitToFrame = true;
54245 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
54247 this.el.dom.style.overflow = "hidden";
54248 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
54249 this.el.removeClass("x-layout-inactive-content");
54250 this.el.on("mousewheel", this.onWheel, this);
54252 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
54253 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
54254 up.unselectable(); down.unselectable();
54255 up.on("click", this.scrollUp, this);
54256 down.on("click", this.scrollDown, this);
54257 up.addClassOnOver("x-scroller-btn-over");
54258 down.addClassOnOver("x-scroller-btn-over");
54259 up.addClassOnClick("x-scroller-btn-click");
54260 down.addClassOnClick("x-scroller-btn-click");
54261 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
54263 this.resizeEl = this.el;
54264 this.el = wrap; this.up = up; this.down = down;
54267 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
54269 wheelIncrement : 5,
54270 scrollUp : function(){
54271 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
54274 scrollDown : function(){
54275 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
54278 afterScroll : function(){
54279 var el = this.resizeEl;
54280 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
54281 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
54282 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
54285 setSize : function(){
54286 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
54287 this.afterScroll();
54290 onWheel : function(e){
54291 var d = e.getWheelDelta();
54292 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
54293 this.afterScroll();
54297 setContent : function(content, loadScripts){
54298 this.resizeEl.update(content, loadScripts);
54312 * @class Roo.TreePanel
54313 * @extends Roo.ContentPanel
54315 * Create a new TreePanel. - defaults to fit/scoll contents.
54316 * @param {String/Object} config A string to set only the panel's title, or a config object
54317 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
54319 Roo.TreePanel = function(config){
54320 var el = config.el;
54321 var tree = config.tree;
54322 delete config.tree;
54323 delete config.el; // hopefull!
54325 // wrapper for IE7 strict & safari scroll issue
54327 var treeEl = el.createChild();
54328 config.resizeEl = treeEl;
54332 Roo.TreePanel.superclass.constructor.call(this, el, config);
54335 this.tree = new Roo.tree.TreePanel(treeEl , tree);
54336 //console.log(tree);
54337 this.on('activate', function()
54339 if (this.tree.rendered) {
54342 //console.log('render tree');
54343 this.tree.render();
54345 // this should not be needed.. - it's actually the 'el' that resizes?
54346 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
54348 //this.on('resize', function (cp, w, h) {
54349 // this.tree.innerCt.setWidth(w);
54350 // this.tree.innerCt.setHeight(h);
54351 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
54358 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
54375 * Ext JS Library 1.1.1
54376 * Copyright(c) 2006-2007, Ext JS, LLC.
54378 * Originally Released Under LGPL - original licence link has changed is not relivant.
54381 * <script type="text/javascript">
54386 * @class Roo.ReaderLayout
54387 * @extends Roo.BorderLayout
54388 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
54389 * center region containing two nested regions (a top one for a list view and one for item preview below),
54390 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
54391 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
54392 * expedites the setup of the overall layout and regions for this common application style.
54395 var reader = new Roo.ReaderLayout();
54396 var CP = Roo.ContentPanel; // shortcut for adding
54398 reader.beginUpdate();
54399 reader.add("north", new CP("north", "North"));
54400 reader.add("west", new CP("west", {title: "West"}));
54401 reader.add("east", new CP("east", {title: "East"}));
54403 reader.regions.listView.add(new CP("listView", "List"));
54404 reader.regions.preview.add(new CP("preview", "Preview"));
54405 reader.endUpdate();
54408 * Create a new ReaderLayout
54409 * @param {Object} config Configuration options
54410 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
54411 * document.body if omitted)
54413 Roo.ReaderLayout = function(config, renderTo){
54414 var c = config || {size:{}};
54415 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
54416 north: c.north !== false ? Roo.apply({
54420 }, c.north) : false,
54421 west: c.west !== false ? Roo.apply({
54429 margins:{left:5,right:0,bottom:5,top:5},
54430 cmargins:{left:5,right:5,bottom:5,top:5}
54431 }, c.west) : false,
54432 east: c.east !== false ? Roo.apply({
54440 margins:{left:0,right:5,bottom:5,top:5},
54441 cmargins:{left:5,right:5,bottom:5,top:5}
54442 }, c.east) : false,
54443 center: Roo.apply({
54444 tabPosition: 'top',
54448 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
54452 this.el.addClass('x-reader');
54454 this.beginUpdate();
54456 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
54457 south: c.preview !== false ? Roo.apply({
54464 cmargins:{top:5,left:0, right:0, bottom:0}
54465 }, c.preview) : false,
54466 center: Roo.apply({
54472 this.add('center', new Roo.NestedLayoutPanel(inner,
54473 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
54477 this.regions.preview = inner.getRegion('south');
54478 this.regions.listView = inner.getRegion('center');
54481 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
54483 * Ext JS Library 1.1.1
54484 * Copyright(c) 2006-2007, Ext JS, LLC.
54486 * Originally Released Under LGPL - original licence link has changed is not relivant.
54489 * <script type="text/javascript">
54493 * @class Roo.grid.Grid
54494 * @extends Roo.util.Observable
54495 * This class represents the primary interface of a component based grid control.
54496 * <br><br>Usage:<pre><code>
54497 var grid = new Roo.grid.Grid("my-container-id", {
54500 selModel: mySelectionModel,
54501 autoSizeColumns: true,
54502 monitorWindowResize: false,
54503 trackMouseOver: true
54508 * <b>Common Problems:</b><br/>
54509 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
54510 * element will correct this<br/>
54511 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
54512 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
54513 * are unpredictable.<br/>
54514 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
54515 * grid to calculate dimensions/offsets.<br/>
54517 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54518 * The container MUST have some type of size defined for the grid to fill. The container will be
54519 * automatically set to position relative if it isn't already.
54520 * @param {Object} config A config object that sets properties on this grid.
54522 Roo.grid.Grid = function(container, config){
54523 // initialize the container
54524 this.container = Roo.get(container);
54525 this.container.update("");
54526 this.container.setStyle("overflow", "hidden");
54527 this.container.addClass('x-grid-container');
54529 this.id = this.container.id;
54531 Roo.apply(this, config);
54532 // check and correct shorthanded configs
54534 this.dataSource = this.ds;
54538 this.colModel = this.cm;
54542 this.selModel = this.sm;
54546 if (this.selModel) {
54547 this.selModel = Roo.factory(this.selModel, Roo.grid);
54548 this.sm = this.selModel;
54549 this.sm.xmodule = this.xmodule || false;
54551 if (typeof(this.colModel.config) == 'undefined') {
54552 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54553 this.cm = this.colModel;
54554 this.cm.xmodule = this.xmodule || false;
54556 if (this.dataSource) {
54557 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54558 this.ds = this.dataSource;
54559 this.ds.xmodule = this.xmodule || false;
54566 this.container.setWidth(this.width);
54570 this.container.setHeight(this.height);
54577 * The raw click event for the entire grid.
54578 * @param {Roo.EventObject} e
54583 * The raw dblclick event for the entire grid.
54584 * @param {Roo.EventObject} e
54588 * @event contextmenu
54589 * The raw contextmenu event for the entire grid.
54590 * @param {Roo.EventObject} e
54592 "contextmenu" : true,
54595 * The raw mousedown event for the entire grid.
54596 * @param {Roo.EventObject} e
54598 "mousedown" : true,
54601 * The raw mouseup event for the entire grid.
54602 * @param {Roo.EventObject} e
54607 * The raw mouseover event for the entire grid.
54608 * @param {Roo.EventObject} e
54610 "mouseover" : true,
54613 * The raw mouseout event for the entire grid.
54614 * @param {Roo.EventObject} e
54619 * The raw keypress event for the entire grid.
54620 * @param {Roo.EventObject} e
54625 * The raw keydown event for the entire grid.
54626 * @param {Roo.EventObject} e
54634 * Fires when a cell is clicked
54635 * @param {Grid} this
54636 * @param {Number} rowIndex
54637 * @param {Number} columnIndex
54638 * @param {Roo.EventObject} e
54640 "cellclick" : true,
54642 * @event celldblclick
54643 * Fires when a cell is double clicked
54644 * @param {Grid} this
54645 * @param {Number} rowIndex
54646 * @param {Number} columnIndex
54647 * @param {Roo.EventObject} e
54649 "celldblclick" : true,
54652 * Fires when a row is clicked
54653 * @param {Grid} this
54654 * @param {Number} rowIndex
54655 * @param {Roo.EventObject} e
54659 * @event rowdblclick
54660 * Fires when a row is double clicked
54661 * @param {Grid} this
54662 * @param {Number} rowIndex
54663 * @param {Roo.EventObject} e
54665 "rowdblclick" : true,
54667 * @event headerclick
54668 * Fires when a header is clicked
54669 * @param {Grid} this
54670 * @param {Number} columnIndex
54671 * @param {Roo.EventObject} e
54673 "headerclick" : true,
54675 * @event headerdblclick
54676 * Fires when a header cell is double clicked
54677 * @param {Grid} this
54678 * @param {Number} columnIndex
54679 * @param {Roo.EventObject} e
54681 "headerdblclick" : true,
54683 * @event rowcontextmenu
54684 * Fires when a row is right clicked
54685 * @param {Grid} this
54686 * @param {Number} rowIndex
54687 * @param {Roo.EventObject} e
54689 "rowcontextmenu" : true,
54691 * @event cellcontextmenu
54692 * Fires when a cell is right clicked
54693 * @param {Grid} this
54694 * @param {Number} rowIndex
54695 * @param {Number} cellIndex
54696 * @param {Roo.EventObject} e
54698 "cellcontextmenu" : true,
54700 * @event headercontextmenu
54701 * Fires when a header is right clicked
54702 * @param {Grid} this
54703 * @param {Number} columnIndex
54704 * @param {Roo.EventObject} e
54706 "headercontextmenu" : true,
54708 * @event bodyscroll
54709 * Fires when the body element is scrolled
54710 * @param {Number} scrollLeft
54711 * @param {Number} scrollTop
54713 "bodyscroll" : true,
54715 * @event columnresize
54716 * Fires when the user resizes a column
54717 * @param {Number} columnIndex
54718 * @param {Number} newSize
54720 "columnresize" : true,
54722 * @event columnmove
54723 * Fires when the user moves a column
54724 * @param {Number} oldIndex
54725 * @param {Number} newIndex
54727 "columnmove" : true,
54730 * Fires when row(s) start being dragged
54731 * @param {Grid} this
54732 * @param {Roo.GridDD} dd The drag drop object
54733 * @param {event} e The raw browser event
54735 "startdrag" : true,
54738 * Fires when a drag operation is complete
54739 * @param {Grid} this
54740 * @param {Roo.GridDD} dd The drag drop object
54741 * @param {event} e The raw browser event
54746 * Fires when dragged row(s) are dropped on a valid DD target
54747 * @param {Grid} this
54748 * @param {Roo.GridDD} dd The drag drop object
54749 * @param {String} targetId The target drag drop object
54750 * @param {event} e The raw browser event
54755 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54756 * @param {Grid} this
54757 * @param {Roo.GridDD} dd The drag drop object
54758 * @param {String} targetId The target drag drop object
54759 * @param {event} e The raw browser event
54764 * Fires when the dragged row(s) first cross another DD target while being dragged
54765 * @param {Grid} this
54766 * @param {Roo.GridDD} dd The drag drop object
54767 * @param {String} targetId The target drag drop object
54768 * @param {event} e The raw browser event
54770 "dragenter" : true,
54773 * Fires when the dragged row(s) leave another DD target while being dragged
54774 * @param {Grid} this
54775 * @param {Roo.GridDD} dd The drag drop object
54776 * @param {String} targetId The target drag drop object
54777 * @param {event} e The raw browser event
54782 * Fires when a row is rendered, so you can change add a style to it.
54783 * @param {GridView} gridview The grid view
54784 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54790 * Fires when the grid is rendered
54791 * @param {Grid} grid
54796 Roo.grid.Grid.superclass.constructor.call(this);
54798 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54801 * @cfg {String} ddGroup - drag drop group.
54805 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54807 minColumnWidth : 25,
54810 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54811 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54812 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54814 autoSizeColumns : false,
54817 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54819 autoSizeHeaders : true,
54822 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54824 monitorWindowResize : true,
54827 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54828 * rows measured to get a columns size. Default is 0 (all rows).
54830 maxRowsToMeasure : 0,
54833 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54835 trackMouseOver : true,
54838 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54842 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54844 enableDragDrop : false,
54847 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54849 enableColumnMove : true,
54852 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54854 enableColumnHide : true,
54857 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54859 enableRowHeightSync : false,
54862 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54867 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54869 autoHeight : false,
54872 * @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.
54874 autoExpandColumn : false,
54877 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54880 autoExpandMin : 50,
54883 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54885 autoExpandMax : 1000,
54888 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54893 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54897 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54907 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54908 * of a fixed width. Default is false.
54911 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54914 * Called once after all setup has been completed and the grid is ready to be rendered.
54915 * @return {Roo.grid.Grid} this
54917 render : function()
54919 var c = this.container;
54920 // try to detect autoHeight/width mode
54921 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54922 this.autoHeight = true;
54924 var view = this.getView();
54927 c.on("click", this.onClick, this);
54928 c.on("dblclick", this.onDblClick, this);
54929 c.on("contextmenu", this.onContextMenu, this);
54930 c.on("keydown", this.onKeyDown, this);
54932 c.on("touchstart", this.onTouchStart, this);
54935 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54937 this.getSelectionModel().init(this);
54942 this.loadMask = new Roo.LoadMask(this.container,
54943 Roo.apply({store:this.dataSource}, this.loadMask));
54947 if (this.toolbar && this.toolbar.xtype) {
54948 this.toolbar.container = this.getView().getHeaderPanel(true);
54949 this.toolbar = new Roo.Toolbar(this.toolbar);
54951 if (this.footer && this.footer.xtype) {
54952 this.footer.dataSource = this.getDataSource();
54953 this.footer.container = this.getView().getFooterPanel(true);
54954 this.footer = Roo.factory(this.footer, Roo);
54956 if (this.dropTarget && this.dropTarget.xtype) {
54957 delete this.dropTarget.xtype;
54958 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54962 this.rendered = true;
54963 this.fireEvent('render', this);
54968 * Reconfigures the grid to use a different Store and Column Model.
54969 * The View will be bound to the new objects and refreshed.
54970 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54971 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54973 reconfigure : function(dataSource, colModel){
54975 this.loadMask.destroy();
54976 this.loadMask = new Roo.LoadMask(this.container,
54977 Roo.apply({store:dataSource}, this.loadMask));
54979 this.view.bind(dataSource, colModel);
54980 this.dataSource = dataSource;
54981 this.colModel = colModel;
54982 this.view.refresh(true);
54986 onKeyDown : function(e){
54987 this.fireEvent("keydown", e);
54991 * Destroy this grid.
54992 * @param {Boolean} removeEl True to remove the element
54994 destroy : function(removeEl, keepListeners){
54996 this.loadMask.destroy();
54998 var c = this.container;
54999 c.removeAllListeners();
55000 this.view.destroy();
55001 this.colModel.purgeListeners();
55002 if(!keepListeners){
55003 this.purgeListeners();
55006 if(removeEl === true){
55012 processEvent : function(name, e){
55013 // does this fire select???
55014 //Roo.log('grid:processEvent ' + name);
55016 if (name != 'touchstart' ) {
55017 this.fireEvent(name, e);
55020 var t = e.getTarget();
55022 var header = v.findHeaderIndex(t);
55023 if(header !== false){
55024 var ename = name == 'touchstart' ? 'click' : name;
55026 this.fireEvent("header" + ename, this, header, e);
55028 var row = v.findRowIndex(t);
55029 var cell = v.findCellIndex(t);
55030 if (name == 'touchstart') {
55031 // first touch is always a click.
55032 // hopefull this happens after selection is updated.?
55035 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
55036 var cs = this.selModel.getSelectedCell();
55037 if (row == cs[0] && cell == cs[1]){
55041 if (typeof(this.selModel.getSelections) != 'undefined') {
55042 var cs = this.selModel.getSelections();
55043 var ds = this.dataSource;
55044 if (cs.length == 1 && ds.getAt(row) == cs[0]){
55055 this.fireEvent("row" + name, this, row, e);
55056 if(cell !== false){
55057 this.fireEvent("cell" + name, this, row, cell, e);
55064 onClick : function(e){
55065 this.processEvent("click", e);
55068 onTouchStart : function(e){
55069 this.processEvent("touchstart", e);
55073 onContextMenu : function(e, t){
55074 this.processEvent("contextmenu", e);
55078 onDblClick : function(e){
55079 this.processEvent("dblclick", e);
55083 walkCells : function(row, col, step, fn, scope){
55084 var cm = this.colModel, clen = cm.getColumnCount();
55085 var ds = this.dataSource, rlen = ds.getCount(), first = true;
55097 if(fn.call(scope || this, row, col, cm) === true){
55115 if(fn.call(scope || this, row, col, cm) === true){
55127 getSelections : function(){
55128 return this.selModel.getSelections();
55132 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
55133 * but if manual update is required this method will initiate it.
55135 autoSize : function(){
55137 this.view.layout();
55138 if(this.view.adjustForScroll){
55139 this.view.adjustForScroll();
55145 * Returns the grid's underlying element.
55146 * @return {Element} The element
55148 getGridEl : function(){
55149 return this.container;
55152 // private for compatibility, overridden by editor grid
55153 stopEditing : function(){},
55156 * Returns the grid's SelectionModel.
55157 * @return {SelectionModel}
55159 getSelectionModel : function(){
55160 if(!this.selModel){
55161 this.selModel = new Roo.grid.RowSelectionModel();
55163 return this.selModel;
55167 * Returns the grid's DataSource.
55168 * @return {DataSource}
55170 getDataSource : function(){
55171 return this.dataSource;
55175 * Returns the grid's ColumnModel.
55176 * @return {ColumnModel}
55178 getColumnModel : function(){
55179 return this.colModel;
55183 * Returns the grid's GridView object.
55184 * @return {GridView}
55186 getView : function(){
55188 this.view = new Roo.grid.GridView(this.viewConfig);
55193 * Called to get grid's drag proxy text, by default returns this.ddText.
55196 getDragDropText : function(){
55197 var count = this.selModel.getCount();
55198 return String.format(this.ddText, count, count == 1 ? '' : 's');
55202 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
55203 * %0 is replaced with the number of selected rows.
55206 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
55208 * Ext JS Library 1.1.1
55209 * Copyright(c) 2006-2007, Ext JS, LLC.
55211 * Originally Released Under LGPL - original licence link has changed is not relivant.
55214 * <script type="text/javascript">
55217 Roo.grid.AbstractGridView = function(){
55221 "beforerowremoved" : true,
55222 "beforerowsinserted" : true,
55223 "beforerefresh" : true,
55224 "rowremoved" : true,
55225 "rowsinserted" : true,
55226 "rowupdated" : true,
55229 Roo.grid.AbstractGridView.superclass.constructor.call(this);
55232 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
55233 rowClass : "x-grid-row",
55234 cellClass : "x-grid-cell",
55235 tdClass : "x-grid-td",
55236 hdClass : "x-grid-hd",
55237 splitClass : "x-grid-hd-split",
55239 init: function(grid){
55241 var cid = this.grid.getGridEl().id;
55242 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
55243 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
55244 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
55245 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
55248 getColumnRenderers : function(){
55249 var renderers = [];
55250 var cm = this.grid.colModel;
55251 var colCount = cm.getColumnCount();
55252 for(var i = 0; i < colCount; i++){
55253 renderers[i] = cm.getRenderer(i);
55258 getColumnIds : function(){
55260 var cm = this.grid.colModel;
55261 var colCount = cm.getColumnCount();
55262 for(var i = 0; i < colCount; i++){
55263 ids[i] = cm.getColumnId(i);
55268 getDataIndexes : function(){
55269 if(!this.indexMap){
55270 this.indexMap = this.buildIndexMap();
55272 return this.indexMap.colToData;
55275 getColumnIndexByDataIndex : function(dataIndex){
55276 if(!this.indexMap){
55277 this.indexMap = this.buildIndexMap();
55279 return this.indexMap.dataToCol[dataIndex];
55283 * Set a css style for a column dynamically.
55284 * @param {Number} colIndex The index of the column
55285 * @param {String} name The css property name
55286 * @param {String} value The css value
55288 setCSSStyle : function(colIndex, name, value){
55289 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
55290 Roo.util.CSS.updateRule(selector, name, value);
55293 generateRules : function(cm){
55294 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
55295 Roo.util.CSS.removeStyleSheet(rulesId);
55296 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55297 var cid = cm.getColumnId(i);
55298 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
55299 this.tdSelector, cid, " {\n}\n",
55300 this.hdSelector, cid, " {\n}\n",
55301 this.splitSelector, cid, " {\n}\n");
55303 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55307 * Ext JS Library 1.1.1
55308 * Copyright(c) 2006-2007, Ext JS, LLC.
55310 * Originally Released Under LGPL - original licence link has changed is not relivant.
55313 * <script type="text/javascript">
55317 // This is a support class used internally by the Grid components
55318 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
55320 this.view = grid.getView();
55321 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
55322 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
55324 this.setHandleElId(Roo.id(hd));
55325 this.setOuterHandleElId(Roo.id(hd2));
55327 this.scroll = false;
55329 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
55331 getDragData : function(e){
55332 var t = Roo.lib.Event.getTarget(e);
55333 var h = this.view.findHeaderCell(t);
55335 return {ddel: h.firstChild, header:h};
55340 onInitDrag : function(e){
55341 this.view.headersDisabled = true;
55342 var clone = this.dragData.ddel.cloneNode(true);
55343 clone.id = Roo.id();
55344 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
55345 this.proxy.update(clone);
55349 afterValidDrop : function(){
55351 setTimeout(function(){
55352 v.headersDisabled = false;
55356 afterInvalidDrop : function(){
55358 setTimeout(function(){
55359 v.headersDisabled = false;
55365 * Ext JS Library 1.1.1
55366 * Copyright(c) 2006-2007, Ext JS, LLC.
55368 * Originally Released Under LGPL - original licence link has changed is not relivant.
55371 * <script type="text/javascript">
55374 // This is a support class used internally by the Grid components
55375 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
55377 this.view = grid.getView();
55378 // split the proxies so they don't interfere with mouse events
55379 this.proxyTop = Roo.DomHelper.append(document.body, {
55380 cls:"col-move-top", html:" "
55382 this.proxyBottom = Roo.DomHelper.append(document.body, {
55383 cls:"col-move-bottom", html:" "
55385 this.proxyTop.hide = this.proxyBottom.hide = function(){
55386 this.setLeftTop(-100,-100);
55387 this.setStyle("visibility", "hidden");
55389 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
55390 // temporarily disabled
55391 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
55392 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
55394 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
55395 proxyOffsets : [-4, -9],
55396 fly: Roo.Element.fly,
55398 getTargetFromEvent : function(e){
55399 var t = Roo.lib.Event.getTarget(e);
55400 var cindex = this.view.findCellIndex(t);
55401 if(cindex !== false){
55402 return this.view.getHeaderCell(cindex);
55407 nextVisible : function(h){
55408 var v = this.view, cm = this.grid.colModel;
55411 if(!cm.isHidden(v.getCellIndex(h))){
55419 prevVisible : function(h){
55420 var v = this.view, cm = this.grid.colModel;
55423 if(!cm.isHidden(v.getCellIndex(h))){
55431 positionIndicator : function(h, n, e){
55432 var x = Roo.lib.Event.getPageX(e);
55433 var r = Roo.lib.Dom.getRegion(n.firstChild);
55434 var px, pt, py = r.top + this.proxyOffsets[1];
55435 if((r.right - x) <= (r.right-r.left)/2){
55436 px = r.right+this.view.borderWidth;
55442 var oldIndex = this.view.getCellIndex(h);
55443 var newIndex = this.view.getCellIndex(n);
55445 if(this.grid.colModel.isFixed(newIndex)){
55449 var locked = this.grid.colModel.isLocked(newIndex);
55454 if(oldIndex < newIndex){
55457 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
55460 px += this.proxyOffsets[0];
55461 this.proxyTop.setLeftTop(px, py);
55462 this.proxyTop.show();
55463 if(!this.bottomOffset){
55464 this.bottomOffset = this.view.mainHd.getHeight();
55466 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
55467 this.proxyBottom.show();
55471 onNodeEnter : function(n, dd, e, data){
55472 if(data.header != n){
55473 this.positionIndicator(data.header, n, e);
55477 onNodeOver : function(n, dd, e, data){
55478 var result = false;
55479 if(data.header != n){
55480 result = this.positionIndicator(data.header, n, e);
55483 this.proxyTop.hide();
55484 this.proxyBottom.hide();
55486 return result ? this.dropAllowed : this.dropNotAllowed;
55489 onNodeOut : function(n, dd, e, data){
55490 this.proxyTop.hide();
55491 this.proxyBottom.hide();
55494 onNodeDrop : function(n, dd, e, data){
55495 var h = data.header;
55497 var cm = this.grid.colModel;
55498 var x = Roo.lib.Event.getPageX(e);
55499 var r = Roo.lib.Dom.getRegion(n.firstChild);
55500 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
55501 var oldIndex = this.view.getCellIndex(h);
55502 var newIndex = this.view.getCellIndex(n);
55503 var locked = cm.isLocked(newIndex);
55507 if(oldIndex < newIndex){
55510 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
55513 cm.setLocked(oldIndex, locked, true);
55514 cm.moveColumn(oldIndex, newIndex);
55515 this.grid.fireEvent("columnmove", oldIndex, newIndex);
55523 * Ext JS Library 1.1.1
55524 * Copyright(c) 2006-2007, Ext JS, LLC.
55526 * Originally Released Under LGPL - original licence link has changed is not relivant.
55529 * <script type="text/javascript">
55533 * @class Roo.grid.GridView
55534 * @extends Roo.util.Observable
55537 * @param {Object} config
55539 Roo.grid.GridView = function(config){
55540 Roo.grid.GridView.superclass.constructor.call(this);
55543 Roo.apply(this, config);
55546 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
55548 unselectable : 'unselectable="on"',
55549 unselectableCls : 'x-unselectable',
55552 rowClass : "x-grid-row",
55554 cellClass : "x-grid-col",
55556 tdClass : "x-grid-td",
55558 hdClass : "x-grid-hd",
55560 splitClass : "x-grid-split",
55562 sortClasses : ["sort-asc", "sort-desc"],
55564 enableMoveAnim : false,
55568 dh : Roo.DomHelper,
55570 fly : Roo.Element.fly,
55572 css : Roo.util.CSS,
55578 scrollIncrement : 22,
55580 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55582 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55584 bind : function(ds, cm){
55586 this.ds.un("load", this.onLoad, this);
55587 this.ds.un("datachanged", this.onDataChange, this);
55588 this.ds.un("add", this.onAdd, this);
55589 this.ds.un("remove", this.onRemove, this);
55590 this.ds.un("update", this.onUpdate, this);
55591 this.ds.un("clear", this.onClear, this);
55594 ds.on("load", this.onLoad, this);
55595 ds.on("datachanged", this.onDataChange, this);
55596 ds.on("add", this.onAdd, this);
55597 ds.on("remove", this.onRemove, this);
55598 ds.on("update", this.onUpdate, this);
55599 ds.on("clear", this.onClear, this);
55604 this.cm.un("widthchange", this.onColWidthChange, this);
55605 this.cm.un("headerchange", this.onHeaderChange, this);
55606 this.cm.un("hiddenchange", this.onHiddenChange, this);
55607 this.cm.un("columnmoved", this.onColumnMove, this);
55608 this.cm.un("columnlockchange", this.onColumnLock, this);
55611 this.generateRules(cm);
55612 cm.on("widthchange", this.onColWidthChange, this);
55613 cm.on("headerchange", this.onHeaderChange, this);
55614 cm.on("hiddenchange", this.onHiddenChange, this);
55615 cm.on("columnmoved", this.onColumnMove, this);
55616 cm.on("columnlockchange", this.onColumnLock, this);
55621 init: function(grid){
55622 Roo.grid.GridView.superclass.init.call(this, grid);
55624 this.bind(grid.dataSource, grid.colModel);
55626 grid.on("headerclick", this.handleHeaderClick, this);
55628 if(grid.trackMouseOver){
55629 grid.on("mouseover", this.onRowOver, this);
55630 grid.on("mouseout", this.onRowOut, this);
55632 grid.cancelTextSelection = function(){};
55633 this.gridId = grid.id;
55635 var tpls = this.templates || {};
55638 tpls.master = new Roo.Template(
55639 '<div class="x-grid" hidefocus="true">',
55640 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55641 '<div class="x-grid-topbar"></div>',
55642 '<div class="x-grid-scroller"><div></div></div>',
55643 '<div class="x-grid-locked">',
55644 '<div class="x-grid-header">{lockedHeader}</div>',
55645 '<div class="x-grid-body">{lockedBody}</div>',
55647 '<div class="x-grid-viewport">',
55648 '<div class="x-grid-header">{header}</div>',
55649 '<div class="x-grid-body">{body}</div>',
55651 '<div class="x-grid-bottombar"></div>',
55653 '<div class="x-grid-resize-proxy"> </div>',
55656 tpls.master.disableformats = true;
55660 tpls.header = new Roo.Template(
55661 '<table border="0" cellspacing="0" cellpadding="0">',
55662 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55665 tpls.header.disableformats = true;
55667 tpls.header.compile();
55670 tpls.hcell = new Roo.Template(
55671 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55672 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55675 tpls.hcell.disableFormats = true;
55677 tpls.hcell.compile();
55680 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55681 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55682 tpls.hsplit.disableFormats = true;
55684 tpls.hsplit.compile();
55687 tpls.body = new Roo.Template(
55688 '<table border="0" cellspacing="0" cellpadding="0">',
55689 "<tbody>{rows}</tbody>",
55692 tpls.body.disableFormats = true;
55694 tpls.body.compile();
55697 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55698 tpls.row.disableFormats = true;
55700 tpls.row.compile();
55703 tpls.cell = new Roo.Template(
55704 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55705 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55706 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55709 tpls.cell.disableFormats = true;
55711 tpls.cell.compile();
55713 this.templates = tpls;
55716 // remap these for backwards compat
55717 onColWidthChange : function(){
55718 this.updateColumns.apply(this, arguments);
55720 onHeaderChange : function(){
55721 this.updateHeaders.apply(this, arguments);
55723 onHiddenChange : function(){
55724 this.handleHiddenChange.apply(this, arguments);
55726 onColumnMove : function(){
55727 this.handleColumnMove.apply(this, arguments);
55729 onColumnLock : function(){
55730 this.handleLockChange.apply(this, arguments);
55733 onDataChange : function(){
55735 this.updateHeaderSortState();
55738 onClear : function(){
55742 onUpdate : function(ds, record){
55743 this.refreshRow(record);
55746 refreshRow : function(record){
55747 var ds = this.ds, index;
55748 if(typeof record == 'number'){
55750 record = ds.getAt(index);
55752 index = ds.indexOf(record);
55754 this.insertRows(ds, index, index, true);
55755 this.onRemove(ds, record, index+1, true);
55756 this.syncRowHeights(index, index);
55758 this.fireEvent("rowupdated", this, index, record);
55761 onAdd : function(ds, records, index){
55762 this.insertRows(ds, index, index + (records.length-1));
55765 onRemove : function(ds, record, index, isUpdate){
55766 if(isUpdate !== true){
55767 this.fireEvent("beforerowremoved", this, index, record);
55769 var bt = this.getBodyTable(), lt = this.getLockedTable();
55770 if(bt.rows[index]){
55771 bt.firstChild.removeChild(bt.rows[index]);
55773 if(lt.rows[index]){
55774 lt.firstChild.removeChild(lt.rows[index]);
55776 if(isUpdate !== true){
55777 this.stripeRows(index);
55778 this.syncRowHeights(index, index);
55780 this.fireEvent("rowremoved", this, index, record);
55784 onLoad : function(){
55785 this.scrollToTop();
55789 * Scrolls the grid to the top
55791 scrollToTop : function(){
55793 this.scroller.dom.scrollTop = 0;
55799 * Gets a panel in the header of the grid that can be used for toolbars etc.
55800 * After modifying the contents of this panel a call to grid.autoSize() may be
55801 * required to register any changes in size.
55802 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55803 * @return Roo.Element
55805 getHeaderPanel : function(doShow){
55807 this.headerPanel.show();
55809 return this.headerPanel;
55813 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55814 * After modifying the contents of this panel a call to grid.autoSize() may be
55815 * required to register any changes in size.
55816 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55817 * @return Roo.Element
55819 getFooterPanel : function(doShow){
55821 this.footerPanel.show();
55823 return this.footerPanel;
55826 initElements : function(){
55827 var E = Roo.Element;
55828 var el = this.grid.getGridEl().dom.firstChild;
55829 var cs = el.childNodes;
55831 this.el = new E(el);
55833 this.focusEl = new E(el.firstChild);
55834 this.focusEl.swallowEvent("click", true);
55836 this.headerPanel = new E(cs[1]);
55837 this.headerPanel.enableDisplayMode("block");
55839 this.scroller = new E(cs[2]);
55840 this.scrollSizer = new E(this.scroller.dom.firstChild);
55842 this.lockedWrap = new E(cs[3]);
55843 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55844 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55846 this.mainWrap = new E(cs[4]);
55847 this.mainHd = new E(this.mainWrap.dom.firstChild);
55848 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55850 this.footerPanel = new E(cs[5]);
55851 this.footerPanel.enableDisplayMode("block");
55853 this.resizeProxy = new E(cs[6]);
55855 this.headerSelector = String.format(
55856 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55857 this.lockedHd.id, this.mainHd.id
55860 this.splitterSelector = String.format(
55861 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55862 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55865 idToCssName : function(s)
55867 return s.replace(/[^a-z0-9]+/ig, '-');
55870 getHeaderCell : function(index){
55871 return Roo.DomQuery.select(this.headerSelector)[index];
55874 getHeaderCellMeasure : function(index){
55875 return this.getHeaderCell(index).firstChild;
55878 getHeaderCellText : function(index){
55879 return this.getHeaderCell(index).firstChild.firstChild;
55882 getLockedTable : function(){
55883 return this.lockedBody.dom.firstChild;
55886 getBodyTable : function(){
55887 return this.mainBody.dom.firstChild;
55890 getLockedRow : function(index){
55891 return this.getLockedTable().rows[index];
55894 getRow : function(index){
55895 return this.getBodyTable().rows[index];
55898 getRowComposite : function(index){
55900 this.rowEl = new Roo.CompositeElementLite();
55902 var els = [], lrow, mrow;
55903 if(lrow = this.getLockedRow(index)){
55906 if(mrow = this.getRow(index)){
55909 this.rowEl.elements = els;
55913 * Gets the 'td' of the cell
55915 * @param {Integer} rowIndex row to select
55916 * @param {Integer} colIndex column to select
55920 getCell : function(rowIndex, colIndex){
55921 var locked = this.cm.getLockedCount();
55923 if(colIndex < locked){
55924 source = this.lockedBody.dom.firstChild;
55926 source = this.mainBody.dom.firstChild;
55927 colIndex -= locked;
55929 return source.rows[rowIndex].childNodes[colIndex];
55932 getCellText : function(rowIndex, colIndex){
55933 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55936 getCellBox : function(cell){
55937 var b = this.fly(cell).getBox();
55938 if(Roo.isOpera){ // opera fails to report the Y
55939 b.y = cell.offsetTop + this.mainBody.getY();
55944 getCellIndex : function(cell){
55945 var id = String(cell.className).match(this.cellRE);
55947 return parseInt(id[1], 10);
55952 findHeaderIndex : function(n){
55953 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55954 return r ? this.getCellIndex(r) : false;
55957 findHeaderCell : function(n){
55958 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55959 return r ? r : false;
55962 findRowIndex : function(n){
55966 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55967 return r ? r.rowIndex : false;
55970 findCellIndex : function(node){
55971 var stop = this.el.dom;
55972 while(node && node != stop){
55973 if(this.findRE.test(node.className)){
55974 return this.getCellIndex(node);
55976 node = node.parentNode;
55981 getColumnId : function(index){
55982 return this.cm.getColumnId(index);
55985 getSplitters : function()
55987 if(this.splitterSelector){
55988 return Roo.DomQuery.select(this.splitterSelector);
55994 getSplitter : function(index){
55995 return this.getSplitters()[index];
55998 onRowOver : function(e, t){
56000 if((row = this.findRowIndex(t)) !== false){
56001 this.getRowComposite(row).addClass("x-grid-row-over");
56005 onRowOut : function(e, t){
56007 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
56008 this.getRowComposite(row).removeClass("x-grid-row-over");
56012 renderHeaders : function(){
56014 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
56015 var cb = [], lb = [], sb = [], lsb = [], p = {};
56016 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56017 p.cellId = "x-grid-hd-0-" + i;
56018 p.splitId = "x-grid-csplit-0-" + i;
56019 p.id = cm.getColumnId(i);
56020 p.value = cm.getColumnHeader(i) || "";
56021 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
56022 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
56023 if(!cm.isLocked(i)){
56024 cb[cb.length] = ct.apply(p);
56025 sb[sb.length] = st.apply(p);
56027 lb[lb.length] = ct.apply(p);
56028 lsb[lsb.length] = st.apply(p);
56031 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
56032 ht.apply({cells: cb.join(""), splits:sb.join("")})];
56035 updateHeaders : function(){
56036 var html = this.renderHeaders();
56037 this.lockedHd.update(html[0]);
56038 this.mainHd.update(html[1]);
56042 * Focuses the specified row.
56043 * @param {Number} row The row index
56045 focusRow : function(row)
56047 //Roo.log('GridView.focusRow');
56048 var x = this.scroller.dom.scrollLeft;
56049 this.focusCell(row, 0, false);
56050 this.scroller.dom.scrollLeft = x;
56054 * Focuses the specified cell.
56055 * @param {Number} row The row index
56056 * @param {Number} col The column index
56057 * @param {Boolean} hscroll false to disable horizontal scrolling
56059 focusCell : function(row, col, hscroll)
56061 //Roo.log('GridView.focusCell');
56062 var el = this.ensureVisible(row, col, hscroll);
56063 this.focusEl.alignTo(el, "tl-tl");
56065 this.focusEl.focus();
56067 this.focusEl.focus.defer(1, this.focusEl);
56072 * Scrolls the specified cell into view
56073 * @param {Number} row The row index
56074 * @param {Number} col The column index
56075 * @param {Boolean} hscroll false to disable horizontal scrolling
56077 ensureVisible : function(row, col, hscroll)
56079 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
56080 //return null; //disable for testing.
56081 if(typeof row != "number"){
56082 row = row.rowIndex;
56084 if(row < 0 && row >= this.ds.getCount()){
56087 col = (col !== undefined ? col : 0);
56088 var cm = this.grid.colModel;
56089 while(cm.isHidden(col)){
56093 var el = this.getCell(row, col);
56097 var c = this.scroller.dom;
56099 var ctop = parseInt(el.offsetTop, 10);
56100 var cleft = parseInt(el.offsetLeft, 10);
56101 var cbot = ctop + el.offsetHeight;
56102 var cright = cleft + el.offsetWidth;
56104 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
56105 var stop = parseInt(c.scrollTop, 10);
56106 var sleft = parseInt(c.scrollLeft, 10);
56107 var sbot = stop + ch;
56108 var sright = sleft + c.clientWidth;
56110 Roo.log('GridView.ensureVisible:' +
56112 ' c.clientHeight:' + c.clientHeight +
56113 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
56121 c.scrollTop = ctop;
56122 //Roo.log("set scrolltop to ctop DISABLE?");
56123 }else if(cbot > sbot){
56124 //Roo.log("set scrolltop to cbot-ch");
56125 c.scrollTop = cbot-ch;
56128 if(hscroll !== false){
56130 c.scrollLeft = cleft;
56131 }else if(cright > sright){
56132 c.scrollLeft = cright-c.clientWidth;
56139 updateColumns : function(){
56140 this.grid.stopEditing();
56141 var cm = this.grid.colModel, colIds = this.getColumnIds();
56142 //var totalWidth = cm.getTotalWidth();
56144 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56145 //if(cm.isHidden(i)) continue;
56146 var w = cm.getColumnWidth(i);
56147 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56148 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56150 this.updateSplitters();
56153 generateRules : function(cm){
56154 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
56155 Roo.util.CSS.removeStyleSheet(rulesId);
56156 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56157 var cid = cm.getColumnId(i);
56159 if(cm.config[i].align){
56160 align = 'text-align:'+cm.config[i].align+';';
56163 if(cm.isHidden(i)){
56164 hidden = 'display:none;';
56166 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
56168 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
56169 this.hdSelector, cid, " {\n", align, width, "}\n",
56170 this.tdSelector, cid, " {\n",hidden,"\n}\n",
56171 this.splitSelector, cid, " {\n", hidden , "\n}\n");
56173 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56176 updateSplitters : function(){
56177 var cm = this.cm, s = this.getSplitters();
56178 if(s){ // splitters not created yet
56179 var pos = 0, locked = true;
56180 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56181 if(cm.isHidden(i)) {
56184 var w = cm.getColumnWidth(i); // make sure it's a number
56185 if(!cm.isLocked(i) && locked){
56190 s[i].style.left = (pos-this.splitOffset) + "px";
56195 handleHiddenChange : function(colModel, colIndex, hidden){
56197 this.hideColumn(colIndex);
56199 this.unhideColumn(colIndex);
56203 hideColumn : function(colIndex){
56204 var cid = this.getColumnId(colIndex);
56205 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
56206 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
56208 this.updateHeaders();
56210 this.updateSplitters();
56214 unhideColumn : function(colIndex){
56215 var cid = this.getColumnId(colIndex);
56216 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
56217 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
56220 this.updateHeaders();
56222 this.updateSplitters();
56226 insertRows : function(dm, firstRow, lastRow, isUpdate){
56227 if(firstRow == 0 && lastRow == dm.getCount()-1){
56231 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
56233 var s = this.getScrollState();
56234 var markup = this.renderRows(firstRow, lastRow);
56235 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
56236 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
56237 this.restoreScroll(s);
56239 this.fireEvent("rowsinserted", this, firstRow, lastRow);
56240 this.syncRowHeights(firstRow, lastRow);
56241 this.stripeRows(firstRow);
56247 bufferRows : function(markup, target, index){
56248 var before = null, trows = target.rows, tbody = target.tBodies[0];
56249 if(index < trows.length){
56250 before = trows[index];
56252 var b = document.createElement("div");
56253 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
56254 var rows = b.firstChild.rows;
56255 for(var i = 0, len = rows.length; i < len; i++){
56257 tbody.insertBefore(rows[0], before);
56259 tbody.appendChild(rows[0]);
56266 deleteRows : function(dm, firstRow, lastRow){
56267 if(dm.getRowCount()<1){
56268 this.fireEvent("beforerefresh", this);
56269 this.mainBody.update("");
56270 this.lockedBody.update("");
56271 this.fireEvent("refresh", this);
56273 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
56274 var bt = this.getBodyTable();
56275 var tbody = bt.firstChild;
56276 var rows = bt.rows;
56277 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
56278 tbody.removeChild(rows[firstRow]);
56280 this.stripeRows(firstRow);
56281 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
56285 updateRows : function(dataSource, firstRow, lastRow){
56286 var s = this.getScrollState();
56288 this.restoreScroll(s);
56291 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
56295 this.updateHeaderSortState();
56298 getScrollState : function(){
56300 var sb = this.scroller.dom;
56301 return {left: sb.scrollLeft, top: sb.scrollTop};
56304 stripeRows : function(startRow){
56305 if(!this.grid.stripeRows || this.ds.getCount() < 1){
56308 startRow = startRow || 0;
56309 var rows = this.getBodyTable().rows;
56310 var lrows = this.getLockedTable().rows;
56311 var cls = ' x-grid-row-alt ';
56312 for(var i = startRow, len = rows.length; i < len; i++){
56313 var row = rows[i], lrow = lrows[i];
56314 var isAlt = ((i+1) % 2 == 0);
56315 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
56316 if(isAlt == hasAlt){
56320 row.className += " x-grid-row-alt";
56322 row.className = row.className.replace("x-grid-row-alt", "");
56325 lrow.className = row.className;
56330 restoreScroll : function(state){
56331 //Roo.log('GridView.restoreScroll');
56332 var sb = this.scroller.dom;
56333 sb.scrollLeft = state.left;
56334 sb.scrollTop = state.top;
56338 syncScroll : function(){
56339 //Roo.log('GridView.syncScroll');
56340 var sb = this.scroller.dom;
56341 var sh = this.mainHd.dom;
56342 var bs = this.mainBody.dom;
56343 var lv = this.lockedBody.dom;
56344 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
56345 lv.scrollTop = bs.scrollTop = sb.scrollTop;
56348 handleScroll : function(e){
56350 var sb = this.scroller.dom;
56351 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
56355 handleWheel : function(e){
56356 var d = e.getWheelDelta();
56357 this.scroller.dom.scrollTop -= d*22;
56358 // set this here to prevent jumpy scrolling on large tables
56359 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
56363 renderRows : function(startRow, endRow){
56364 // pull in all the crap needed to render rows
56365 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
56366 var colCount = cm.getColumnCount();
56368 if(ds.getCount() < 1){
56372 // build a map for all the columns
56374 for(var i = 0; i < colCount; i++){
56375 var name = cm.getDataIndex(i);
56377 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
56378 renderer : cm.getRenderer(i),
56379 id : cm.getColumnId(i),
56380 locked : cm.isLocked(i),
56381 has_editor : cm.isCellEditable(i)
56385 startRow = startRow || 0;
56386 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
56388 // records to render
56389 var rs = ds.getRange(startRow, endRow);
56391 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
56394 // As much as I hate to duplicate code, this was branched because FireFox really hates
56395 // [].join("") on strings. The performance difference was substantial enough to
56396 // branch this function
56397 doRender : Roo.isGecko ?
56398 function(cs, rs, ds, startRow, colCount, stripe){
56399 var ts = this.templates, ct = ts.cell, rt = ts.row;
56401 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
56403 var hasListener = this.grid.hasListener('rowclass');
56405 for(var j = 0, len = rs.length; j < len; j++){
56406 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
56407 for(var i = 0; i < colCount; i++){
56409 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
56411 p.css = p.attr = "";
56412 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
56413 if(p.value == undefined || p.value === "") {
56414 p.value = " ";
56417 p.css += ' x-grid-editable-cell';
56419 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
56420 p.css += ' x-grid-dirty-cell';
56422 var markup = ct.apply(p);
56430 if(stripe && ((rowIndex+1) % 2 == 0)){
56431 alt.push("x-grid-row-alt")
56434 alt.push( " x-grid-dirty-row");
56437 if(this.getRowClass){
56438 alt.push(this.getRowClass(r, rowIndex));
56444 rowIndex : rowIndex,
56447 this.grid.fireEvent('rowclass', this, rowcfg);
56448 alt.push(rowcfg.rowClass);
56450 rp.alt = alt.join(" ");
56451 lbuf+= rt.apply(rp);
56453 buf+= rt.apply(rp);
56455 return [lbuf, buf];
56457 function(cs, rs, ds, startRow, colCount, stripe){
56458 var ts = this.templates, ct = ts.cell, rt = ts.row;
56460 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
56461 var hasListener = this.grid.hasListener('rowclass');
56464 for(var j = 0, len = rs.length; j < len; j++){
56465 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
56466 for(var i = 0; i < colCount; i++){
56468 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
56470 p.css = p.attr = "";
56471 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
56472 if(p.value == undefined || p.value === "") {
56473 p.value = " ";
56477 p.css += ' x-grid-editable-cell';
56479 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
56480 p.css += ' x-grid-dirty-cell'
56483 var markup = ct.apply(p);
56485 cb[cb.length] = markup;
56487 lcb[lcb.length] = markup;
56491 if(stripe && ((rowIndex+1) % 2 == 0)){
56492 alt.push( "x-grid-row-alt");
56495 alt.push(" x-grid-dirty-row");
56498 if(this.getRowClass){
56499 alt.push( this.getRowClass(r, rowIndex));
56505 rowIndex : rowIndex,
56508 this.grid.fireEvent('rowclass', this, rowcfg);
56509 alt.push(rowcfg.rowClass);
56512 rp.alt = alt.join(" ");
56513 rp.cells = lcb.join("");
56514 lbuf[lbuf.length] = rt.apply(rp);
56515 rp.cells = cb.join("");
56516 buf[buf.length] = rt.apply(rp);
56518 return [lbuf.join(""), buf.join("")];
56521 renderBody : function(){
56522 var markup = this.renderRows();
56523 var bt = this.templates.body;
56524 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
56528 * Refreshes the grid
56529 * @param {Boolean} headersToo
56531 refresh : function(headersToo){
56532 this.fireEvent("beforerefresh", this);
56533 this.grid.stopEditing();
56534 var result = this.renderBody();
56535 this.lockedBody.update(result[0]);
56536 this.mainBody.update(result[1]);
56537 if(headersToo === true){
56538 this.updateHeaders();
56539 this.updateColumns();
56540 this.updateSplitters();
56541 this.updateHeaderSortState();
56543 this.syncRowHeights();
56545 this.fireEvent("refresh", this);
56548 handleColumnMove : function(cm, oldIndex, newIndex){
56549 this.indexMap = null;
56550 var s = this.getScrollState();
56551 this.refresh(true);
56552 this.restoreScroll(s);
56553 this.afterMove(newIndex);
56556 afterMove : function(colIndex){
56557 if(this.enableMoveAnim && Roo.enableFx){
56558 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56560 // if multisort - fix sortOrder, and reload..
56561 if (this.grid.dataSource.multiSort) {
56562 // the we can call sort again..
56563 var dm = this.grid.dataSource;
56564 var cm = this.grid.colModel;
56566 for(var i = 0; i < cm.config.length; i++ ) {
56568 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56569 continue; // dont' bother, it's not in sort list or being set.
56572 so.push(cm.config[i].dataIndex);
56575 dm.load(dm.lastOptions);
56582 updateCell : function(dm, rowIndex, dataIndex){
56583 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56584 if(typeof colIndex == "undefined"){ // not present in grid
56587 var cm = this.grid.colModel;
56588 var cell = this.getCell(rowIndex, colIndex);
56589 var cellText = this.getCellText(rowIndex, colIndex);
56592 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56593 id : cm.getColumnId(colIndex),
56594 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56596 var renderer = cm.getRenderer(colIndex);
56597 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56598 if(typeof val == "undefined" || val === "") {
56601 cellText.innerHTML = val;
56602 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56603 this.syncRowHeights(rowIndex, rowIndex);
56606 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56608 if(this.grid.autoSizeHeaders){
56609 var h = this.getHeaderCellMeasure(colIndex);
56610 maxWidth = Math.max(maxWidth, h.scrollWidth);
56613 if(this.cm.isLocked(colIndex)){
56614 tb = this.getLockedTable();
56617 tb = this.getBodyTable();
56618 index = colIndex - this.cm.getLockedCount();
56621 var rows = tb.rows;
56622 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56623 for(var i = 0; i < stopIndex; i++){
56624 var cell = rows[i].childNodes[index].firstChild;
56625 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56628 return maxWidth + /*margin for error in IE*/ 5;
56631 * Autofit a column to its content.
56632 * @param {Number} colIndex
56633 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56635 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56636 if(this.cm.isHidden(colIndex)){
56637 return; // can't calc a hidden column
56640 var cid = this.cm.getColumnId(colIndex);
56641 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56642 if(this.grid.autoSizeHeaders){
56643 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56646 var newWidth = this.calcColumnWidth(colIndex);
56647 this.cm.setColumnWidth(colIndex,
56648 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56649 if(!suppressEvent){
56650 this.grid.fireEvent("columnresize", colIndex, newWidth);
56655 * Autofits all columns to their content and then expands to fit any extra space in the grid
56657 autoSizeColumns : function(){
56658 var cm = this.grid.colModel;
56659 var colCount = cm.getColumnCount();
56660 for(var i = 0; i < colCount; i++){
56661 this.autoSizeColumn(i, true, true);
56663 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56666 this.updateColumns();
56672 * Autofits all columns to the grid's width proportionate with their current size
56673 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56675 fitColumns : function(reserveScrollSpace){
56676 var cm = this.grid.colModel;
56677 var colCount = cm.getColumnCount();
56681 for (i = 0; i < colCount; i++){
56682 if(!cm.isHidden(i) && !cm.isFixed(i)){
56683 w = cm.getColumnWidth(i);
56689 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56690 if(reserveScrollSpace){
56693 var frac = (avail - cm.getTotalWidth())/width;
56694 while (cols.length){
56697 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56699 this.updateColumns();
56703 onRowSelect : function(rowIndex){
56704 var row = this.getRowComposite(rowIndex);
56705 row.addClass("x-grid-row-selected");
56708 onRowDeselect : function(rowIndex){
56709 var row = this.getRowComposite(rowIndex);
56710 row.removeClass("x-grid-row-selected");
56713 onCellSelect : function(row, col){
56714 var cell = this.getCell(row, col);
56716 Roo.fly(cell).addClass("x-grid-cell-selected");
56720 onCellDeselect : function(row, col){
56721 var cell = this.getCell(row, col);
56723 Roo.fly(cell).removeClass("x-grid-cell-selected");
56727 updateHeaderSortState : function(){
56729 // sort state can be single { field: xxx, direction : yyy}
56730 // or { xxx=>ASC , yyy : DESC ..... }
56733 if (!this.ds.multiSort) {
56734 var state = this.ds.getSortState();
56738 mstate[state.field] = state.direction;
56739 // FIXME... - this is not used here.. but might be elsewhere..
56740 this.sortState = state;
56743 mstate = this.ds.sortToggle;
56745 //remove existing sort classes..
56747 var sc = this.sortClasses;
56748 var hds = this.el.select(this.headerSelector).removeClass(sc);
56750 for(var f in mstate) {
56752 var sortColumn = this.cm.findColumnIndex(f);
56754 if(sortColumn != -1){
56755 var sortDir = mstate[f];
56756 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56765 handleHeaderClick : function(g, index,e){
56767 Roo.log("header click");
56770 // touch events on header are handled by context
56771 this.handleHdCtx(g,index,e);
56776 if(this.headersDisabled){
56779 var dm = g.dataSource, cm = g.colModel;
56780 if(!cm.isSortable(index)){
56785 if (dm.multiSort) {
56786 // update the sortOrder
56788 for(var i = 0; i < cm.config.length; i++ ) {
56790 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56791 continue; // dont' bother, it's not in sort list or being set.
56794 so.push(cm.config[i].dataIndex);
56800 dm.sort(cm.getDataIndex(index));
56804 destroy : function(){
56806 this.colMenu.removeAll();
56807 Roo.menu.MenuMgr.unregister(this.colMenu);
56808 this.colMenu.getEl().remove();
56809 delete this.colMenu;
56812 this.hmenu.removeAll();
56813 Roo.menu.MenuMgr.unregister(this.hmenu);
56814 this.hmenu.getEl().remove();
56817 if(this.grid.enableColumnMove){
56818 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56820 for(var dd in dds){
56821 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56822 var elid = dds[dd].dragElId;
56824 Roo.get(elid).remove();
56825 } else if(dds[dd].config.isTarget){
56826 dds[dd].proxyTop.remove();
56827 dds[dd].proxyBottom.remove();
56830 if(Roo.dd.DDM.locationCache[dd]){
56831 delete Roo.dd.DDM.locationCache[dd];
56834 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56837 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56838 this.bind(null, null);
56839 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56842 handleLockChange : function(){
56843 this.refresh(true);
56846 onDenyColumnLock : function(){
56850 onDenyColumnHide : function(){
56854 handleHdMenuClick : function(item){
56855 var index = this.hdCtxIndex;
56856 var cm = this.cm, ds = this.ds;
56859 ds.sort(cm.getDataIndex(index), "ASC");
56862 ds.sort(cm.getDataIndex(index), "DESC");
56865 var lc = cm.getLockedCount();
56866 if(cm.getColumnCount(true) <= lc+1){
56867 this.onDenyColumnLock();
56871 cm.setLocked(index, true, true);
56872 cm.moveColumn(index, lc);
56873 this.grid.fireEvent("columnmove", index, lc);
56875 cm.setLocked(index, true);
56879 var lc = cm.getLockedCount();
56880 if((lc-1) != index){
56881 cm.setLocked(index, false, true);
56882 cm.moveColumn(index, lc-1);
56883 this.grid.fireEvent("columnmove", index, lc-1);
56885 cm.setLocked(index, false);
56888 case 'wider': // used to expand cols on touch..
56890 var cw = cm.getColumnWidth(index);
56891 cw += (item.id == 'wider' ? 1 : -1) * 50;
56892 cw = Math.max(0, cw);
56893 cw = Math.min(cw,4000);
56894 cm.setColumnWidth(index, cw);
56898 index = cm.getIndexById(item.id.substr(4));
56900 if(item.checked && cm.getColumnCount(true) <= 1){
56901 this.onDenyColumnHide();
56904 cm.setHidden(index, item.checked);
56910 beforeColMenuShow : function(){
56911 var cm = this.cm, colCount = cm.getColumnCount();
56912 this.colMenu.removeAll();
56913 for(var i = 0; i < colCount; i++){
56914 this.colMenu.add(new Roo.menu.CheckItem({
56915 id: "col-"+cm.getColumnId(i),
56916 text: cm.getColumnHeader(i),
56917 checked: !cm.isHidden(i),
56923 handleHdCtx : function(g, index, e){
56925 var hd = this.getHeaderCell(index);
56926 this.hdCtxIndex = index;
56927 var ms = this.hmenu.items, cm = this.cm;
56928 ms.get("asc").setDisabled(!cm.isSortable(index));
56929 ms.get("desc").setDisabled(!cm.isSortable(index));
56930 if(this.grid.enableColLock !== false){
56931 ms.get("lock").setDisabled(cm.isLocked(index));
56932 ms.get("unlock").setDisabled(!cm.isLocked(index));
56934 this.hmenu.show(hd, "tl-bl");
56937 handleHdOver : function(e){
56938 var hd = this.findHeaderCell(e.getTarget());
56939 if(hd && !this.headersDisabled){
56940 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56941 this.fly(hd).addClass("x-grid-hd-over");
56946 handleHdOut : function(e){
56947 var hd = this.findHeaderCell(e.getTarget());
56949 this.fly(hd).removeClass("x-grid-hd-over");
56953 handleSplitDblClick : function(e, t){
56954 var i = this.getCellIndex(t);
56955 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56956 this.autoSizeColumn(i, true);
56961 render : function(){
56964 var colCount = cm.getColumnCount();
56966 if(this.grid.monitorWindowResize === true){
56967 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56969 var header = this.renderHeaders();
56970 var body = this.templates.body.apply({rows:""});
56971 var html = this.templates.master.apply({
56974 lockedHeader: header[0],
56978 //this.updateColumns();
56980 this.grid.getGridEl().dom.innerHTML = html;
56982 this.initElements();
56984 // a kludge to fix the random scolling effect in webkit
56985 this.el.on("scroll", function() {
56986 this.el.dom.scrollTop=0; // hopefully not recursive..
56989 this.scroller.on("scroll", this.handleScroll, this);
56990 this.lockedBody.on("mousewheel", this.handleWheel, this);
56991 this.mainBody.on("mousewheel", this.handleWheel, this);
56993 this.mainHd.on("mouseover", this.handleHdOver, this);
56994 this.mainHd.on("mouseout", this.handleHdOut, this);
56995 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56996 {delegate: "."+this.splitClass});
56998 this.lockedHd.on("mouseover", this.handleHdOver, this);
56999 this.lockedHd.on("mouseout", this.handleHdOut, this);
57000 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
57001 {delegate: "."+this.splitClass});
57003 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
57004 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57007 this.updateSplitters();
57009 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
57010 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57011 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57014 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
57015 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
57017 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
57018 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
57020 if(this.grid.enableColLock !== false){
57021 this.hmenu.add('-',
57022 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
57023 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
57027 this.hmenu.add('-',
57028 {id:"wider", text: this.columnsWiderText},
57029 {id:"narrow", text: this.columnsNarrowText }
57035 if(this.grid.enableColumnHide !== false){
57037 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
57038 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
57039 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
57041 this.hmenu.add('-',
57042 {id:"columns", text: this.columnsText, menu: this.colMenu}
57045 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
57047 this.grid.on("headercontextmenu", this.handleHdCtx, this);
57050 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
57051 this.dd = new Roo.grid.GridDragZone(this.grid, {
57052 ddGroup : this.grid.ddGroup || 'GridDD'
57058 for(var i = 0; i < colCount; i++){
57059 if(cm.isHidden(i)){
57060 this.hideColumn(i);
57062 if(cm.config[i].align){
57063 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
57064 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
57068 this.updateHeaderSortState();
57070 this.beforeInitialResize();
57073 // two part rendering gives faster view to the user
57074 this.renderPhase2.defer(1, this);
57077 renderPhase2 : function(){
57078 // render the rows now
57080 if(this.grid.autoSizeColumns){
57081 this.autoSizeColumns();
57085 beforeInitialResize : function(){
57089 onColumnSplitterMoved : function(i, w){
57090 this.userResized = true;
57091 var cm = this.grid.colModel;
57092 cm.setColumnWidth(i, w, true);
57093 var cid = cm.getColumnId(i);
57094 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57095 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57096 this.updateSplitters();
57098 this.grid.fireEvent("columnresize", i, w);
57101 syncRowHeights : function(startIndex, endIndex){
57102 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
57103 startIndex = startIndex || 0;
57104 var mrows = this.getBodyTable().rows;
57105 var lrows = this.getLockedTable().rows;
57106 var len = mrows.length-1;
57107 endIndex = Math.min(endIndex || len, len);
57108 for(var i = startIndex; i <= endIndex; i++){
57109 var m = mrows[i], l = lrows[i];
57110 var h = Math.max(m.offsetHeight, l.offsetHeight);
57111 m.style.height = l.style.height = h + "px";
57116 layout : function(initialRender, is2ndPass){
57118 var auto = g.autoHeight;
57119 var scrollOffset = 16;
57120 var c = g.getGridEl(), cm = this.cm,
57121 expandCol = g.autoExpandColumn,
57123 //c.beginMeasure();
57125 if(!c.dom.offsetWidth){ // display:none?
57127 this.lockedWrap.show();
57128 this.mainWrap.show();
57133 var hasLock = this.cm.isLocked(0);
57135 var tbh = this.headerPanel.getHeight();
57136 var bbh = this.footerPanel.getHeight();
57139 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
57140 var newHeight = ch + c.getBorderWidth("tb");
57142 newHeight = Math.min(g.maxHeight, newHeight);
57144 c.setHeight(newHeight);
57148 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
57151 var s = this.scroller;
57153 var csize = c.getSize(true);
57155 this.el.setSize(csize.width, csize.height);
57157 this.headerPanel.setWidth(csize.width);
57158 this.footerPanel.setWidth(csize.width);
57160 var hdHeight = this.mainHd.getHeight();
57161 var vw = csize.width;
57162 var vh = csize.height - (tbh + bbh);
57166 var bt = this.getBodyTable();
57168 if(cm.getLockedCount() == cm.config.length){
57169 bt = this.getLockedTable();
57172 var ltWidth = hasLock ?
57173 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
57175 var scrollHeight = bt.offsetHeight;
57176 var scrollWidth = ltWidth + bt.offsetWidth;
57177 var vscroll = false, hscroll = false;
57179 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
57181 var lw = this.lockedWrap, mw = this.mainWrap;
57182 var lb = this.lockedBody, mb = this.mainBody;
57184 setTimeout(function(){
57185 var t = s.dom.offsetTop;
57186 var w = s.dom.clientWidth,
57187 h = s.dom.clientHeight;
57190 lw.setSize(ltWidth, h);
57192 mw.setLeftTop(ltWidth, t);
57193 mw.setSize(w-ltWidth, h);
57195 lb.setHeight(h-hdHeight);
57196 mb.setHeight(h-hdHeight);
57198 if(is2ndPass !== true && !gv.userResized && expandCol){
57199 // high speed resize without full column calculation
57201 var ci = cm.getIndexById(expandCol);
57203 ci = cm.findColumnIndex(expandCol);
57205 ci = Math.max(0, ci); // make sure it's got at least the first col.
57206 var expandId = cm.getColumnId(ci);
57207 var tw = cm.getTotalWidth(false);
57208 var currentWidth = cm.getColumnWidth(ci);
57209 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
57210 if(currentWidth != cw){
57211 cm.setColumnWidth(ci, cw, true);
57212 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
57213 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
57214 gv.updateSplitters();
57215 gv.layout(false, true);
57227 onWindowResize : function(){
57228 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
57234 appendFooter : function(parentEl){
57238 sortAscText : "Sort Ascending",
57239 sortDescText : "Sort Descending",
57240 lockText : "Lock Column",
57241 unlockText : "Unlock Column",
57242 columnsText : "Columns",
57244 columnsWiderText : "Wider",
57245 columnsNarrowText : "Thinner"
57249 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
57250 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
57251 this.proxy.el.addClass('x-grid3-col-dd');
57254 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
57255 handleMouseDown : function(e){
57259 callHandleMouseDown : function(e){
57260 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
57265 * Ext JS Library 1.1.1
57266 * Copyright(c) 2006-2007, Ext JS, LLC.
57268 * Originally Released Under LGPL - original licence link has changed is not relivant.
57271 * <script type="text/javascript">
57275 // This is a support class used internally by the Grid components
57276 Roo.grid.SplitDragZone = function(grid, hd, hd2){
57278 this.view = grid.getView();
57279 this.proxy = this.view.resizeProxy;
57280 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
57281 "gridSplitters" + this.grid.getGridEl().id, {
57282 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
57284 this.setHandleElId(Roo.id(hd));
57285 this.setOuterHandleElId(Roo.id(hd2));
57286 this.scroll = false;
57288 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
57289 fly: Roo.Element.fly,
57291 b4StartDrag : function(x, y){
57292 this.view.headersDisabled = true;
57293 this.proxy.setHeight(this.view.mainWrap.getHeight());
57294 var w = this.cm.getColumnWidth(this.cellIndex);
57295 var minw = Math.max(w-this.grid.minColumnWidth, 0);
57296 this.resetConstraints();
57297 this.setXConstraint(minw, 1000);
57298 this.setYConstraint(0, 0);
57299 this.minX = x - minw;
57300 this.maxX = x + 1000;
57302 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
57306 handleMouseDown : function(e){
57307 ev = Roo.EventObject.setEvent(e);
57308 var t = this.fly(ev.getTarget());
57309 if(t.hasClass("x-grid-split")){
57310 this.cellIndex = this.view.getCellIndex(t.dom);
57311 this.split = t.dom;
57312 this.cm = this.grid.colModel;
57313 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
57314 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
57319 endDrag : function(e){
57320 this.view.headersDisabled = false;
57321 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
57322 var diff = endX - this.startPos;
57323 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
57326 autoOffset : function(){
57327 this.setDelta(0,0);
57331 * Ext JS Library 1.1.1
57332 * Copyright(c) 2006-2007, Ext JS, LLC.
57334 * Originally Released Under LGPL - original licence link has changed is not relivant.
57337 * <script type="text/javascript">
57341 // This is a support class used internally by the Grid components
57342 Roo.grid.GridDragZone = function(grid, config){
57343 this.view = grid.getView();
57344 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
57345 if(this.view.lockedBody){
57346 this.setHandleElId(Roo.id(this.view.mainBody.dom));
57347 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
57349 this.scroll = false;
57351 this.ddel = document.createElement('div');
57352 this.ddel.className = 'x-grid-dd-wrap';
57355 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
57356 ddGroup : "GridDD",
57358 getDragData : function(e){
57359 var t = Roo.lib.Event.getTarget(e);
57360 var rowIndex = this.view.findRowIndex(t);
57361 var sm = this.grid.selModel;
57363 //Roo.log(rowIndex);
57365 if (sm.getSelectedCell) {
57366 // cell selection..
57367 if (!sm.getSelectedCell()) {
57370 if (rowIndex != sm.getSelectedCell()[0]) {
57376 if(rowIndex !== false){
57381 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
57383 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
57386 if (e.hasModifier()){
57387 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
57390 Roo.log("getDragData");
57395 rowIndex: rowIndex,
57396 selections:sm.getSelections ? sm.getSelections() : (
57397 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
57404 onInitDrag : function(e){
57405 var data = this.dragData;
57406 this.ddel.innerHTML = this.grid.getDragDropText();
57407 this.proxy.update(this.ddel);
57408 // fire start drag?
57411 afterRepair : function(){
57412 this.dragging = false;
57415 getRepairXY : function(e, data){
57419 onEndDrag : function(data, e){
57423 onValidDrop : function(dd, e, id){
57428 beforeInvalidDrop : function(e, id){
57433 * Ext JS Library 1.1.1
57434 * Copyright(c) 2006-2007, Ext JS, LLC.
57436 * Originally Released Under LGPL - original licence link has changed is not relivant.
57439 * <script type="text/javascript">
57444 * @class Roo.grid.ColumnModel
57445 * @extends Roo.util.Observable
57446 * This is the default implementation of a ColumnModel used by the Grid. It defines
57447 * the columns in the grid.
57450 var colModel = new Roo.grid.ColumnModel([
57451 {header: "Ticker", width: 60, sortable: true, locked: true},
57452 {header: "Company Name", width: 150, sortable: true},
57453 {header: "Market Cap.", width: 100, sortable: true},
57454 {header: "$ Sales", width: 100, sortable: true, renderer: money},
57455 {header: "Employees", width: 100, sortable: true, resizable: false}
57460 * The config options listed for this class are options which may appear in each
57461 * individual column definition.
57462 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
57464 * @param {Object} config An Array of column config objects. See this class's
57465 * config objects for details.
57467 Roo.grid.ColumnModel = function(config){
57469 * The config passed into the constructor
57471 this.config = config;
57474 // if no id, create one
57475 // if the column does not have a dataIndex mapping,
57476 // map it to the order it is in the config
57477 for(var i = 0, len = config.length; i < len; i++){
57479 if(typeof c.dataIndex == "undefined"){
57482 if(typeof c.renderer == "string"){
57483 c.renderer = Roo.util.Format[c.renderer];
57485 if(typeof c.id == "undefined"){
57488 if(c.editor && c.editor.xtype){
57489 c.editor = Roo.factory(c.editor, Roo.grid);
57491 if(c.editor && c.editor.isFormField){
57492 c.editor = new Roo.grid.GridEditor(c.editor);
57494 this.lookup[c.id] = c;
57498 * The width of columns which have no width specified (defaults to 100)
57501 this.defaultWidth = 100;
57504 * Default sortable of columns which have no sortable specified (defaults to false)
57507 this.defaultSortable = false;
57511 * @event widthchange
57512 * Fires when the width of a column changes.
57513 * @param {ColumnModel} this
57514 * @param {Number} columnIndex The column index
57515 * @param {Number} newWidth The new width
57517 "widthchange": true,
57519 * @event headerchange
57520 * Fires when the text of a header changes.
57521 * @param {ColumnModel} this
57522 * @param {Number} columnIndex The column index
57523 * @param {Number} newText The new header text
57525 "headerchange": true,
57527 * @event hiddenchange
57528 * Fires when a column is hidden or "unhidden".
57529 * @param {ColumnModel} this
57530 * @param {Number} columnIndex The column index
57531 * @param {Boolean} hidden true if hidden, false otherwise
57533 "hiddenchange": true,
57535 * @event columnmoved
57536 * Fires when a column is moved.
57537 * @param {ColumnModel} this
57538 * @param {Number} oldIndex
57539 * @param {Number} newIndex
57541 "columnmoved" : true,
57543 * @event columlockchange
57544 * Fires when a column's locked state is changed
57545 * @param {ColumnModel} this
57546 * @param {Number} colIndex
57547 * @param {Boolean} locked true if locked
57549 "columnlockchange" : true
57551 Roo.grid.ColumnModel.superclass.constructor.call(this);
57553 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57555 * @cfg {String} header The header text to display in the Grid view.
57558 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57559 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57560 * specified, the column's index is used as an index into the Record's data Array.
57563 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57564 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57567 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57568 * Defaults to the value of the {@link #defaultSortable} property.
57569 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57572 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57575 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57578 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57581 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57584 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57585 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57586 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57587 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57590 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57593 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57596 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
57599 * @cfg {String} cursor (Optional)
57602 * @cfg {String} tooltip (Optional)
57605 * @cfg {Number} xs (Optional)
57608 * @cfg {Number} sm (Optional)
57611 * @cfg {Number} md (Optional)
57614 * @cfg {Number} lg (Optional)
57617 * Returns the id of the column at the specified index.
57618 * @param {Number} index The column index
57619 * @return {String} the id
57621 getColumnId : function(index){
57622 return this.config[index].id;
57626 * Returns the column for a specified id.
57627 * @param {String} id The column id
57628 * @return {Object} the column
57630 getColumnById : function(id){
57631 return this.lookup[id];
57636 * Returns the column for a specified dataIndex.
57637 * @param {String} dataIndex The column dataIndex
57638 * @return {Object|Boolean} the column or false if not found
57640 getColumnByDataIndex: function(dataIndex){
57641 var index = this.findColumnIndex(dataIndex);
57642 return index > -1 ? this.config[index] : false;
57646 * Returns the index for a specified column id.
57647 * @param {String} id The column id
57648 * @return {Number} the index, or -1 if not found
57650 getIndexById : function(id){
57651 for(var i = 0, len = this.config.length; i < len; i++){
57652 if(this.config[i].id == id){
57660 * Returns the index for a specified column dataIndex.
57661 * @param {String} dataIndex The column dataIndex
57662 * @return {Number} the index, or -1 if not found
57665 findColumnIndex : function(dataIndex){
57666 for(var i = 0, len = this.config.length; i < len; i++){
57667 if(this.config[i].dataIndex == dataIndex){
57675 moveColumn : function(oldIndex, newIndex){
57676 var c = this.config[oldIndex];
57677 this.config.splice(oldIndex, 1);
57678 this.config.splice(newIndex, 0, c);
57679 this.dataMap = null;
57680 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57683 isLocked : function(colIndex){
57684 return this.config[colIndex].locked === true;
57687 setLocked : function(colIndex, value, suppressEvent){
57688 if(this.isLocked(colIndex) == value){
57691 this.config[colIndex].locked = value;
57692 if(!suppressEvent){
57693 this.fireEvent("columnlockchange", this, colIndex, value);
57697 getTotalLockedWidth : function(){
57698 var totalWidth = 0;
57699 for(var i = 0; i < this.config.length; i++){
57700 if(this.isLocked(i) && !this.isHidden(i)){
57701 this.totalWidth += this.getColumnWidth(i);
57707 getLockedCount : function(){
57708 for(var i = 0, len = this.config.length; i < len; i++){
57709 if(!this.isLocked(i)){
57714 return this.config.length;
57718 * Returns the number of columns.
57721 getColumnCount : function(visibleOnly){
57722 if(visibleOnly === true){
57724 for(var i = 0, len = this.config.length; i < len; i++){
57725 if(!this.isHidden(i)){
57731 return this.config.length;
57735 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57736 * @param {Function} fn
57737 * @param {Object} scope (optional)
57738 * @return {Array} result
57740 getColumnsBy : function(fn, scope){
57742 for(var i = 0, len = this.config.length; i < len; i++){
57743 var c = this.config[i];
57744 if(fn.call(scope||this, c, i) === true){
57752 * Returns true if the specified column is sortable.
57753 * @param {Number} col The column index
57754 * @return {Boolean}
57756 isSortable : function(col){
57757 if(typeof this.config[col].sortable == "undefined"){
57758 return this.defaultSortable;
57760 return this.config[col].sortable;
57764 * Returns the rendering (formatting) function defined for the column.
57765 * @param {Number} col The column index.
57766 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57768 getRenderer : function(col){
57769 if(!this.config[col].renderer){
57770 return Roo.grid.ColumnModel.defaultRenderer;
57772 return this.config[col].renderer;
57776 * Sets the rendering (formatting) function for a column.
57777 * @param {Number} col The column index
57778 * @param {Function} fn The function to use to process the cell's raw data
57779 * to return HTML markup for the grid view. The render function is called with
57780 * the following parameters:<ul>
57781 * <li>Data value.</li>
57782 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57783 * <li>css A CSS style string to apply to the table cell.</li>
57784 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57785 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57786 * <li>Row index</li>
57787 * <li>Column index</li>
57788 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57790 setRenderer : function(col, fn){
57791 this.config[col].renderer = fn;
57795 * Returns the width for the specified column.
57796 * @param {Number} col The column index
57799 getColumnWidth : function(col){
57800 return this.config[col].width * 1 || this.defaultWidth;
57804 * Sets the width for a column.
57805 * @param {Number} col The column index
57806 * @param {Number} width The new width
57808 setColumnWidth : function(col, width, suppressEvent){
57809 this.config[col].width = width;
57810 this.totalWidth = null;
57811 if(!suppressEvent){
57812 this.fireEvent("widthchange", this, col, width);
57817 * Returns the total width of all columns.
57818 * @param {Boolean} includeHidden True to include hidden column widths
57821 getTotalWidth : function(includeHidden){
57822 if(!this.totalWidth){
57823 this.totalWidth = 0;
57824 for(var i = 0, len = this.config.length; i < len; i++){
57825 if(includeHidden || !this.isHidden(i)){
57826 this.totalWidth += this.getColumnWidth(i);
57830 return this.totalWidth;
57834 * Returns the header for the specified column.
57835 * @param {Number} col The column index
57838 getColumnHeader : function(col){
57839 return this.config[col].header;
57843 * Sets the header for a column.
57844 * @param {Number} col The column index
57845 * @param {String} header The new header
57847 setColumnHeader : function(col, header){
57848 this.config[col].header = header;
57849 this.fireEvent("headerchange", this, col, header);
57853 * Returns the tooltip for the specified column.
57854 * @param {Number} col The column index
57857 getColumnTooltip : function(col){
57858 return this.config[col].tooltip;
57861 * Sets the tooltip for a column.
57862 * @param {Number} col The column index
57863 * @param {String} tooltip The new tooltip
57865 setColumnTooltip : function(col, tooltip){
57866 this.config[col].tooltip = tooltip;
57870 * Returns the dataIndex for the specified column.
57871 * @param {Number} col The column index
57874 getDataIndex : function(col){
57875 return this.config[col].dataIndex;
57879 * Sets the dataIndex for a column.
57880 * @param {Number} col The column index
57881 * @param {Number} dataIndex The new dataIndex
57883 setDataIndex : function(col, dataIndex){
57884 this.config[col].dataIndex = dataIndex;
57890 * Returns true if the cell is editable.
57891 * @param {Number} colIndex The column index
57892 * @param {Number} rowIndex The row index - this is nto actually used..?
57893 * @return {Boolean}
57895 isCellEditable : function(colIndex, rowIndex){
57896 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57900 * Returns the editor defined for the cell/column.
57901 * return false or null to disable editing.
57902 * @param {Number} colIndex The column index
57903 * @param {Number} rowIndex The row index
57906 getCellEditor : function(colIndex, rowIndex){
57907 return this.config[colIndex].editor;
57911 * Sets if a column is editable.
57912 * @param {Number} col The column index
57913 * @param {Boolean} editable True if the column is editable
57915 setEditable : function(col, editable){
57916 this.config[col].editable = editable;
57921 * Returns true if the column is hidden.
57922 * @param {Number} colIndex The column index
57923 * @return {Boolean}
57925 isHidden : function(colIndex){
57926 return this.config[colIndex].hidden;
57931 * Returns true if the column width cannot be changed
57933 isFixed : function(colIndex){
57934 return this.config[colIndex].fixed;
57938 * Returns true if the column can be resized
57939 * @return {Boolean}
57941 isResizable : function(colIndex){
57942 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57945 * Sets if a column is hidden.
57946 * @param {Number} colIndex The column index
57947 * @param {Boolean} hidden True if the column is hidden
57949 setHidden : function(colIndex, hidden){
57950 this.config[colIndex].hidden = hidden;
57951 this.totalWidth = null;
57952 this.fireEvent("hiddenchange", this, colIndex, hidden);
57956 * Sets the editor for a column.
57957 * @param {Number} col The column index
57958 * @param {Object} editor The editor object
57960 setEditor : function(col, editor){
57961 this.config[col].editor = editor;
57965 Roo.grid.ColumnModel.defaultRenderer = function(value)
57967 if(typeof value == "object") {
57970 if(typeof value == "string" && value.length < 1){
57974 return String.format("{0}", value);
57977 // Alias for backwards compatibility
57978 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57981 * Ext JS Library 1.1.1
57982 * Copyright(c) 2006-2007, Ext JS, LLC.
57984 * Originally Released Under LGPL - original licence link has changed is not relivant.
57987 * <script type="text/javascript">
57991 * @class Roo.grid.AbstractSelectionModel
57992 * @extends Roo.util.Observable
57993 * Abstract base class for grid SelectionModels. It provides the interface that should be
57994 * implemented by descendant classes. This class should not be directly instantiated.
57997 Roo.grid.AbstractSelectionModel = function(){
57998 this.locked = false;
57999 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
58002 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
58003 /** @ignore Called by the grid automatically. Do not call directly. */
58004 init : function(grid){
58010 * Locks the selections.
58013 this.locked = true;
58017 * Unlocks the selections.
58019 unlock : function(){
58020 this.locked = false;
58024 * Returns true if the selections are locked.
58025 * @return {Boolean}
58027 isLocked : function(){
58028 return this.locked;
58032 * Ext JS Library 1.1.1
58033 * Copyright(c) 2006-2007, Ext JS, LLC.
58035 * Originally Released Under LGPL - original licence link has changed is not relivant.
58038 * <script type="text/javascript">
58041 * @extends Roo.grid.AbstractSelectionModel
58042 * @class Roo.grid.RowSelectionModel
58043 * The default SelectionModel used by {@link Roo.grid.Grid}.
58044 * It supports multiple selections and keyboard selection/navigation.
58046 * @param {Object} config
58048 Roo.grid.RowSelectionModel = function(config){
58049 Roo.apply(this, config);
58050 this.selections = new Roo.util.MixedCollection(false, function(o){
58055 this.lastActive = false;
58059 * @event selectionchange
58060 * Fires when the selection changes
58061 * @param {SelectionModel} this
58063 "selectionchange" : true,
58065 * @event afterselectionchange
58066 * Fires after the selection changes (eg. by key press or clicking)
58067 * @param {SelectionModel} this
58069 "afterselectionchange" : true,
58071 * @event beforerowselect
58072 * Fires when a row is selected being selected, return false to cancel.
58073 * @param {SelectionModel} this
58074 * @param {Number} rowIndex The selected index
58075 * @param {Boolean} keepExisting False if other selections will be cleared
58077 "beforerowselect" : true,
58080 * Fires when a row is selected.
58081 * @param {SelectionModel} this
58082 * @param {Number} rowIndex The selected index
58083 * @param {Roo.data.Record} r The record
58085 "rowselect" : true,
58087 * @event rowdeselect
58088 * Fires when a row is deselected.
58089 * @param {SelectionModel} this
58090 * @param {Number} rowIndex The selected index
58092 "rowdeselect" : true
58094 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
58095 this.locked = false;
58098 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
58100 * @cfg {Boolean} singleSelect
58101 * True to allow selection of only one row at a time (defaults to false)
58103 singleSelect : false,
58106 initEvents : function(){
58108 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
58109 this.grid.on("mousedown", this.handleMouseDown, this);
58110 }else{ // allow click to work like normal
58111 this.grid.on("rowclick", this.handleDragableRowClick, this);
58114 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
58115 "up" : function(e){
58117 this.selectPrevious(e.shiftKey);
58118 }else if(this.last !== false && this.lastActive !== false){
58119 var last = this.last;
58120 this.selectRange(this.last, this.lastActive-1);
58121 this.grid.getView().focusRow(this.lastActive);
58122 if(last !== false){
58126 this.selectFirstRow();
58128 this.fireEvent("afterselectionchange", this);
58130 "down" : function(e){
58132 this.selectNext(e.shiftKey);
58133 }else if(this.last !== false && this.lastActive !== false){
58134 var last = this.last;
58135 this.selectRange(this.last, this.lastActive+1);
58136 this.grid.getView().focusRow(this.lastActive);
58137 if(last !== false){
58141 this.selectFirstRow();
58143 this.fireEvent("afterselectionchange", this);
58148 var view = this.grid.view;
58149 view.on("refresh", this.onRefresh, this);
58150 view.on("rowupdated", this.onRowUpdated, this);
58151 view.on("rowremoved", this.onRemove, this);
58155 onRefresh : function(){
58156 var ds = this.grid.dataSource, i, v = this.grid.view;
58157 var s = this.selections;
58158 s.each(function(r){
58159 if((i = ds.indexOfId(r.id)) != -1){
58161 s.add(ds.getAt(i)); // updating the selection relate data
58169 onRemove : function(v, index, r){
58170 this.selections.remove(r);
58174 onRowUpdated : function(v, index, r){
58175 if(this.isSelected(r)){
58176 v.onRowSelect(index);
58182 * @param {Array} records The records to select
58183 * @param {Boolean} keepExisting (optional) True to keep existing selections
58185 selectRecords : function(records, keepExisting){
58187 this.clearSelections();
58189 var ds = this.grid.dataSource;
58190 for(var i = 0, len = records.length; i < len; i++){
58191 this.selectRow(ds.indexOf(records[i]), true);
58196 * Gets the number of selected rows.
58199 getCount : function(){
58200 return this.selections.length;
58204 * Selects the first row in the grid.
58206 selectFirstRow : function(){
58211 * Select the last row.
58212 * @param {Boolean} keepExisting (optional) True to keep existing selections
58214 selectLastRow : function(keepExisting){
58215 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
58219 * Selects the row immediately following the last selected row.
58220 * @param {Boolean} keepExisting (optional) True to keep existing selections
58222 selectNext : function(keepExisting){
58223 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
58224 this.selectRow(this.last+1, keepExisting);
58225 this.grid.getView().focusRow(this.last);
58230 * Selects the row that precedes the last selected row.
58231 * @param {Boolean} keepExisting (optional) True to keep existing selections
58233 selectPrevious : function(keepExisting){
58235 this.selectRow(this.last-1, keepExisting);
58236 this.grid.getView().focusRow(this.last);
58241 * Returns the selected records
58242 * @return {Array} Array of selected records
58244 getSelections : function(){
58245 return [].concat(this.selections.items);
58249 * Returns the first selected record.
58252 getSelected : function(){
58253 return this.selections.itemAt(0);
58258 * Clears all selections.
58260 clearSelections : function(fast){
58265 var ds = this.grid.dataSource;
58266 var s = this.selections;
58267 s.each(function(r){
58268 this.deselectRow(ds.indexOfId(r.id));
58272 this.selections.clear();
58279 * Selects all rows.
58281 selectAll : function(){
58285 this.selections.clear();
58286 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
58287 this.selectRow(i, true);
58292 * Returns True if there is a selection.
58293 * @return {Boolean}
58295 hasSelection : function(){
58296 return this.selections.length > 0;
58300 * Returns True if the specified row is selected.
58301 * @param {Number/Record} record The record or index of the record to check
58302 * @return {Boolean}
58304 isSelected : function(index){
58305 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
58306 return (r && this.selections.key(r.id) ? true : false);
58310 * Returns True if the specified record id is selected.
58311 * @param {String} id The id of record to check
58312 * @return {Boolean}
58314 isIdSelected : function(id){
58315 return (this.selections.key(id) ? true : false);
58319 handleMouseDown : function(e, t){
58320 var view = this.grid.getView(), rowIndex;
58321 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
58324 if(e.shiftKey && this.last !== false){
58325 var last = this.last;
58326 this.selectRange(last, rowIndex, e.ctrlKey);
58327 this.last = last; // reset the last
58328 view.focusRow(rowIndex);
58330 var isSelected = this.isSelected(rowIndex);
58331 if(e.button !== 0 && isSelected){
58332 view.focusRow(rowIndex);
58333 }else if(e.ctrlKey && isSelected){
58334 this.deselectRow(rowIndex);
58335 }else if(!isSelected){
58336 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
58337 view.focusRow(rowIndex);
58340 this.fireEvent("afterselectionchange", this);
58343 handleDragableRowClick : function(grid, rowIndex, e)
58345 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
58346 this.selectRow(rowIndex, false);
58347 grid.view.focusRow(rowIndex);
58348 this.fireEvent("afterselectionchange", this);
58353 * Selects multiple rows.
58354 * @param {Array} rows Array of the indexes of the row to select
58355 * @param {Boolean} keepExisting (optional) True to keep existing selections
58357 selectRows : function(rows, keepExisting){
58359 this.clearSelections();
58361 for(var i = 0, len = rows.length; i < len; i++){
58362 this.selectRow(rows[i], true);
58367 * Selects a range of rows. All rows in between startRow and endRow are also selected.
58368 * @param {Number} startRow The index of the first row in the range
58369 * @param {Number} endRow The index of the last row in the range
58370 * @param {Boolean} keepExisting (optional) True to retain existing selections
58372 selectRange : function(startRow, endRow, keepExisting){
58377 this.clearSelections();
58379 if(startRow <= endRow){
58380 for(var i = startRow; i <= endRow; i++){
58381 this.selectRow(i, true);
58384 for(var i = startRow; i >= endRow; i--){
58385 this.selectRow(i, true);
58391 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
58392 * @param {Number} startRow The index of the first row in the range
58393 * @param {Number} endRow The index of the last row in the range
58395 deselectRange : function(startRow, endRow, preventViewNotify){
58399 for(var i = startRow; i <= endRow; i++){
58400 this.deselectRow(i, preventViewNotify);
58406 * @param {Number} row The index of the row to select
58407 * @param {Boolean} keepExisting (optional) True to keep existing selections
58409 selectRow : function(index, keepExisting, preventViewNotify){
58410 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
58413 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
58414 if(!keepExisting || this.singleSelect){
58415 this.clearSelections();
58417 var r = this.grid.dataSource.getAt(index);
58418 this.selections.add(r);
58419 this.last = this.lastActive = index;
58420 if(!preventViewNotify){
58421 this.grid.getView().onRowSelect(index);
58423 this.fireEvent("rowselect", this, index, r);
58424 this.fireEvent("selectionchange", this);
58430 * @param {Number} row The index of the row to deselect
58432 deselectRow : function(index, preventViewNotify){
58436 if(this.last == index){
58439 if(this.lastActive == index){
58440 this.lastActive = false;
58442 var r = this.grid.dataSource.getAt(index);
58443 this.selections.remove(r);
58444 if(!preventViewNotify){
58445 this.grid.getView().onRowDeselect(index);
58447 this.fireEvent("rowdeselect", this, index);
58448 this.fireEvent("selectionchange", this);
58452 restoreLast : function(){
58454 this.last = this._last;
58459 acceptsNav : function(row, col, cm){
58460 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58464 onEditorKey : function(field, e){
58465 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
58470 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58472 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58474 }else if(k == e.ENTER && !e.ctrlKey){
58478 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
58480 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
58482 }else if(k == e.ESC){
58486 g.startEditing(newCell[0], newCell[1]);
58491 * Ext JS Library 1.1.1
58492 * Copyright(c) 2006-2007, Ext JS, LLC.
58494 * Originally Released Under LGPL - original licence link has changed is not relivant.
58497 * <script type="text/javascript">
58500 * @class Roo.grid.CellSelectionModel
58501 * @extends Roo.grid.AbstractSelectionModel
58502 * This class provides the basic implementation for cell selection in a grid.
58504 * @param {Object} config The object containing the configuration of this model.
58505 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
58507 Roo.grid.CellSelectionModel = function(config){
58508 Roo.apply(this, config);
58510 this.selection = null;
58514 * @event beforerowselect
58515 * Fires before a cell is selected.
58516 * @param {SelectionModel} this
58517 * @param {Number} rowIndex The selected row index
58518 * @param {Number} colIndex The selected cell index
58520 "beforecellselect" : true,
58522 * @event cellselect
58523 * Fires when a cell is selected.
58524 * @param {SelectionModel} this
58525 * @param {Number} rowIndex The selected row index
58526 * @param {Number} colIndex The selected cell index
58528 "cellselect" : true,
58530 * @event selectionchange
58531 * Fires when the active selection changes.
58532 * @param {SelectionModel} this
58533 * @param {Object} selection null for no selection or an object (o) with two properties
58535 <li>o.record: the record object for the row the selection is in</li>
58536 <li>o.cell: An array of [rowIndex, columnIndex]</li>
58539 "selectionchange" : true,
58542 * Fires when the tab (or enter) was pressed on the last editable cell
58543 * You can use this to trigger add new row.
58544 * @param {SelectionModel} this
58548 * @event beforeeditnext
58549 * Fires before the next editable sell is made active
58550 * You can use this to skip to another cell or fire the tabend
58551 * if you set cell to false
58552 * @param {Object} eventdata object : { cell : [ row, col ] }
58554 "beforeeditnext" : true
58556 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58559 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58561 enter_is_tab: false,
58564 initEvents : function(){
58565 this.grid.on("mousedown", this.handleMouseDown, this);
58566 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58567 var view = this.grid.view;
58568 view.on("refresh", this.onViewChange, this);
58569 view.on("rowupdated", this.onRowUpdated, this);
58570 view.on("beforerowremoved", this.clearSelections, this);
58571 view.on("beforerowsinserted", this.clearSelections, this);
58572 if(this.grid.isEditor){
58573 this.grid.on("beforeedit", this.beforeEdit, this);
58578 beforeEdit : function(e){
58579 this.select(e.row, e.column, false, true, e.record);
58583 onRowUpdated : function(v, index, r){
58584 if(this.selection && this.selection.record == r){
58585 v.onCellSelect(index, this.selection.cell[1]);
58590 onViewChange : function(){
58591 this.clearSelections(true);
58595 * Returns the currently selected cell,.
58596 * @return {Array} The selected cell (row, column) or null if none selected.
58598 getSelectedCell : function(){
58599 return this.selection ? this.selection.cell : null;
58603 * Clears all selections.
58604 * @param {Boolean} true to prevent the gridview from being notified about the change.
58606 clearSelections : function(preventNotify){
58607 var s = this.selection;
58609 if(preventNotify !== true){
58610 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58612 this.selection = null;
58613 this.fireEvent("selectionchange", this, null);
58618 * Returns true if there is a selection.
58619 * @return {Boolean}
58621 hasSelection : function(){
58622 return this.selection ? true : false;
58626 handleMouseDown : function(e, t){
58627 var v = this.grid.getView();
58628 if(this.isLocked()){
58631 var row = v.findRowIndex(t);
58632 var cell = v.findCellIndex(t);
58633 if(row !== false && cell !== false){
58634 this.select(row, cell);
58640 * @param {Number} rowIndex
58641 * @param {Number} collIndex
58643 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58644 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58645 this.clearSelections();
58646 r = r || this.grid.dataSource.getAt(rowIndex);
58649 cell : [rowIndex, colIndex]
58651 if(!preventViewNotify){
58652 var v = this.grid.getView();
58653 v.onCellSelect(rowIndex, colIndex);
58654 if(preventFocus !== true){
58655 v.focusCell(rowIndex, colIndex);
58658 this.fireEvent("cellselect", this, rowIndex, colIndex);
58659 this.fireEvent("selectionchange", this, this.selection);
58664 isSelectable : function(rowIndex, colIndex, cm){
58665 return !cm.isHidden(colIndex);
58669 handleKeyDown : function(e){
58670 //Roo.log('Cell Sel Model handleKeyDown');
58671 if(!e.isNavKeyPress()){
58674 var g = this.grid, s = this.selection;
58677 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58679 this.select(cell[0], cell[1]);
58684 var walk = function(row, col, step){
58685 return g.walkCells(row, col, step, sm.isSelectable, sm);
58687 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58694 // handled by onEditorKey
58695 if (g.isEditor && g.editing) {
58699 newCell = walk(r, c-1, -1);
58701 newCell = walk(r, c+1, 1);
58706 newCell = walk(r+1, c, 1);
58710 newCell = walk(r-1, c, -1);
58714 newCell = walk(r, c+1, 1);
58718 newCell = walk(r, c-1, -1);
58723 if(g.isEditor && !g.editing){
58724 g.startEditing(r, c);
58733 this.select(newCell[0], newCell[1]);
58739 acceptsNav : function(row, col, cm){
58740 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58744 * @param {Number} field (not used) - as it's normally used as a listener
58745 * @param {Number} e - event - fake it by using
58747 * var e = Roo.EventObjectImpl.prototype;
58748 * e.keyCode = e.TAB
58752 onEditorKey : function(field, e){
58754 var k = e.getKey(),
58757 ed = g.activeEditor,
58759 ///Roo.log('onEditorKey' + k);
58762 if (this.enter_is_tab && k == e.ENTER) {
58768 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58770 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58776 } else if(k == e.ENTER && !e.ctrlKey){
58779 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58781 } else if(k == e.ESC){
58786 var ecall = { cell : newCell, forward : forward };
58787 this.fireEvent('beforeeditnext', ecall );
58788 newCell = ecall.cell;
58789 forward = ecall.forward;
58793 //Roo.log('next cell after edit');
58794 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58795 } else if (forward) {
58796 // tabbed past last
58797 this.fireEvent.defer(100, this, ['tabend',this]);
58802 * Ext JS Library 1.1.1
58803 * Copyright(c) 2006-2007, Ext JS, LLC.
58805 * Originally Released Under LGPL - original licence link has changed is not relivant.
58808 * <script type="text/javascript">
58812 * @class Roo.grid.EditorGrid
58813 * @extends Roo.grid.Grid
58814 * Class for creating and editable grid.
58815 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58816 * The container MUST have some type of size defined for the grid to fill. The container will be
58817 * automatically set to position relative if it isn't already.
58818 * @param {Object} dataSource The data model to bind to
58819 * @param {Object} colModel The column model with info about this grid's columns
58821 Roo.grid.EditorGrid = function(container, config){
58822 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58823 this.getGridEl().addClass("xedit-grid");
58825 if(!this.selModel){
58826 this.selModel = new Roo.grid.CellSelectionModel();
58829 this.activeEditor = null;
58833 * @event beforeedit
58834 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58835 * <ul style="padding:5px;padding-left:16px;">
58836 * <li>grid - This grid</li>
58837 * <li>record - The record being edited</li>
58838 * <li>field - The field name being edited</li>
58839 * <li>value - The value for the field being edited.</li>
58840 * <li>row - The grid row index</li>
58841 * <li>column - The grid column index</li>
58842 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58844 * @param {Object} e An edit event (see above for description)
58846 "beforeedit" : true,
58849 * Fires after a cell is edited. <br />
58850 * <ul style="padding:5px;padding-left:16px;">
58851 * <li>grid - This grid</li>
58852 * <li>record - The record being edited</li>
58853 * <li>field - The field name being edited</li>
58854 * <li>value - The value being set</li>
58855 * <li>originalValue - The original value for the field, before the edit.</li>
58856 * <li>row - The grid row index</li>
58857 * <li>column - The grid column index</li>
58859 * @param {Object} e An edit event (see above for description)
58861 "afteredit" : true,
58863 * @event validateedit
58864 * Fires after a cell is edited, but before the value is set in the record.
58865 * You can use this to modify the value being set in the field, Return false
58866 * to cancel the change. The edit event object has the following properties <br />
58867 * <ul style="padding:5px;padding-left:16px;">
58868 * <li>editor - This editor</li>
58869 * <li>grid - This grid</li>
58870 * <li>record - The record being edited</li>
58871 * <li>field - The field name being edited</li>
58872 * <li>value - The value being set</li>
58873 * <li>originalValue - The original value for the field, before the edit.</li>
58874 * <li>row - The grid row index</li>
58875 * <li>column - The grid column index</li>
58876 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58878 * @param {Object} e An edit event (see above for description)
58880 "validateedit" : true
58882 this.on("bodyscroll", this.stopEditing, this);
58883 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58886 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58888 * @cfg {Number} clicksToEdit
58889 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58896 trackMouseOver: false, // causes very odd FF errors
58898 onCellDblClick : function(g, row, col){
58899 this.startEditing(row, col);
58902 onEditComplete : function(ed, value, startValue){
58903 this.editing = false;
58904 this.activeEditor = null;
58905 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58907 var field = this.colModel.getDataIndex(ed.col);
58912 originalValue: startValue,
58919 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58922 if(String(value) !== String(startValue)){
58924 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58925 r.set(field, e.value);
58926 // if we are dealing with a combo box..
58927 // then we also set the 'name' colum to be the displayField
58928 if (ed.field.displayField && ed.field.name) {
58929 r.set(ed.field.name, ed.field.el.dom.value);
58932 delete e.cancel; //?? why!!!
58933 this.fireEvent("afteredit", e);
58936 this.fireEvent("afteredit", e); // always fire it!
58938 this.view.focusCell(ed.row, ed.col);
58942 * Starts editing the specified for the specified row/column
58943 * @param {Number} rowIndex
58944 * @param {Number} colIndex
58946 startEditing : function(row, col){
58947 this.stopEditing();
58948 if(this.colModel.isCellEditable(col, row)){
58949 this.view.ensureVisible(row, col, true);
58951 var r = this.dataSource.getAt(row);
58952 var field = this.colModel.getDataIndex(col);
58953 var cell = Roo.get(this.view.getCell(row,col));
58958 value: r.data[field],
58963 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58964 this.editing = true;
58965 var ed = this.colModel.getCellEditor(col, row);
58971 ed.render(ed.parentEl || document.body);
58977 (function(){ // complex but required for focus issues in safari, ie and opera
58981 ed.on("complete", this.onEditComplete, this, {single: true});
58982 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58983 this.activeEditor = ed;
58984 var v = r.data[field];
58985 ed.startEdit(this.view.getCell(row, col), v);
58986 // combo's with 'displayField and name set
58987 if (ed.field.displayField && ed.field.name) {
58988 ed.field.el.dom.value = r.data[ed.field.name];
58992 }).defer(50, this);
58998 * Stops any active editing
59000 stopEditing : function(){
59001 if(this.activeEditor){
59002 this.activeEditor.completeEdit();
59004 this.activeEditor = null;
59008 * Called to get grid's drag proxy text, by default returns this.ddText.
59011 getDragDropText : function(){
59012 var count = this.selModel.getSelectedCell() ? 1 : 0;
59013 return String.format(this.ddText, count, count == 1 ? '' : 's');
59018 * Ext JS Library 1.1.1
59019 * Copyright(c) 2006-2007, Ext JS, LLC.
59021 * Originally Released Under LGPL - original licence link has changed is not relivant.
59024 * <script type="text/javascript">
59027 // private - not really -- you end up using it !
59028 // This is a support class used internally by the Grid components
59031 * @class Roo.grid.GridEditor
59032 * @extends Roo.Editor
59033 * Class for creating and editable grid elements.
59034 * @param {Object} config any settings (must include field)
59036 Roo.grid.GridEditor = function(field, config){
59037 if (!config && field.field) {
59039 field = Roo.factory(config.field, Roo.form);
59041 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
59042 field.monitorTab = false;
59045 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
59048 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
59051 alignment: "tl-tl",
59054 cls: "x-small-editor x-grid-editor",
59059 * Ext JS Library 1.1.1
59060 * Copyright(c) 2006-2007, Ext JS, LLC.
59062 * Originally Released Under LGPL - original licence link has changed is not relivant.
59065 * <script type="text/javascript">
59070 Roo.grid.PropertyRecord = Roo.data.Record.create([
59071 {name:'name',type:'string'}, 'value'
59075 Roo.grid.PropertyStore = function(grid, source){
59077 this.store = new Roo.data.Store({
59078 recordType : Roo.grid.PropertyRecord
59080 this.store.on('update', this.onUpdate, this);
59082 this.setSource(source);
59084 Roo.grid.PropertyStore.superclass.constructor.call(this);
59089 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
59090 setSource : function(o){
59092 this.store.removeAll();
59095 if(this.isEditableValue(o[k])){
59096 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
59099 this.store.loadRecords({records: data}, {}, true);
59102 onUpdate : function(ds, record, type){
59103 if(type == Roo.data.Record.EDIT){
59104 var v = record.data['value'];
59105 var oldValue = record.modified['value'];
59106 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
59107 this.source[record.id] = v;
59109 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
59116 getProperty : function(row){
59117 return this.store.getAt(row);
59120 isEditableValue: function(val){
59121 if(val && val instanceof Date){
59123 }else if(typeof val == 'object' || typeof val == 'function'){
59129 setValue : function(prop, value){
59130 this.source[prop] = value;
59131 this.store.getById(prop).set('value', value);
59134 getSource : function(){
59135 return this.source;
59139 Roo.grid.PropertyColumnModel = function(grid, store){
59142 g.PropertyColumnModel.superclass.constructor.call(this, [
59143 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
59144 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
59146 this.store = store;
59147 this.bselect = Roo.DomHelper.append(document.body, {
59148 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
59149 {tag: 'option', value: 'true', html: 'true'},
59150 {tag: 'option', value: 'false', html: 'false'}
59153 Roo.id(this.bselect);
59156 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
59157 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
59158 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
59159 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
59160 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
59162 this.renderCellDelegate = this.renderCell.createDelegate(this);
59163 this.renderPropDelegate = this.renderProp.createDelegate(this);
59166 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
59170 valueText : 'Value',
59172 dateFormat : 'm/j/Y',
59175 renderDate : function(dateVal){
59176 return dateVal.dateFormat(this.dateFormat);
59179 renderBool : function(bVal){
59180 return bVal ? 'true' : 'false';
59183 isCellEditable : function(colIndex, rowIndex){
59184 return colIndex == 1;
59187 getRenderer : function(col){
59189 this.renderCellDelegate : this.renderPropDelegate;
59192 renderProp : function(v){
59193 return this.getPropertyName(v);
59196 renderCell : function(val){
59198 if(val instanceof Date){
59199 rv = this.renderDate(val);
59200 }else if(typeof val == 'boolean'){
59201 rv = this.renderBool(val);
59203 return Roo.util.Format.htmlEncode(rv);
59206 getPropertyName : function(name){
59207 var pn = this.grid.propertyNames;
59208 return pn && pn[name] ? pn[name] : name;
59211 getCellEditor : function(colIndex, rowIndex){
59212 var p = this.store.getProperty(rowIndex);
59213 var n = p.data['name'], val = p.data['value'];
59215 if(typeof(this.grid.customEditors[n]) == 'string'){
59216 return this.editors[this.grid.customEditors[n]];
59218 if(typeof(this.grid.customEditors[n]) != 'undefined'){
59219 return this.grid.customEditors[n];
59221 if(val instanceof Date){
59222 return this.editors['date'];
59223 }else if(typeof val == 'number'){
59224 return this.editors['number'];
59225 }else if(typeof val == 'boolean'){
59226 return this.editors['boolean'];
59228 return this.editors['string'];
59234 * @class Roo.grid.PropertyGrid
59235 * @extends Roo.grid.EditorGrid
59236 * This class represents the interface of a component based property grid control.
59237 * <br><br>Usage:<pre><code>
59238 var grid = new Roo.grid.PropertyGrid("my-container-id", {
59246 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59247 * The container MUST have some type of size defined for the grid to fill. The container will be
59248 * automatically set to position relative if it isn't already.
59249 * @param {Object} config A config object that sets properties on this grid.
59251 Roo.grid.PropertyGrid = function(container, config){
59252 config = config || {};
59253 var store = new Roo.grid.PropertyStore(this);
59254 this.store = store;
59255 var cm = new Roo.grid.PropertyColumnModel(this, store);
59256 store.store.sort('name', 'ASC');
59257 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
59260 enableColLock:false,
59261 enableColumnMove:false,
59263 trackMouseOver: false,
59266 this.getGridEl().addClass('x-props-grid');
59267 this.lastEditRow = null;
59268 this.on('columnresize', this.onColumnResize, this);
59271 * @event beforepropertychange
59272 * Fires before a property changes (return false to stop?)
59273 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
59274 * @param {String} id Record Id
59275 * @param {String} newval New Value
59276 * @param {String} oldval Old Value
59278 "beforepropertychange": true,
59280 * @event propertychange
59281 * Fires after a property changes
59282 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
59283 * @param {String} id Record Id
59284 * @param {String} newval New Value
59285 * @param {String} oldval Old Value
59287 "propertychange": true
59289 this.customEditors = this.customEditors || {};
59291 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
59294 * @cfg {Object} customEditors map of colnames=> custom editors.
59295 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
59296 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
59297 * false disables editing of the field.
59301 * @cfg {Object} propertyNames map of property Names to their displayed value
59304 render : function(){
59305 Roo.grid.PropertyGrid.superclass.render.call(this);
59306 this.autoSize.defer(100, this);
59309 autoSize : function(){
59310 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
59312 this.view.fitColumns();
59316 onColumnResize : function(){
59317 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
59321 * Sets the data for the Grid
59322 * accepts a Key => Value object of all the elements avaiable.
59323 * @param {Object} data to appear in grid.
59325 setSource : function(source){
59326 this.store.setSource(source);
59330 * Gets all the data from the grid.
59331 * @return {Object} data data stored in grid
59333 getSource : function(){
59334 return this.store.getSource();
59343 * @class Roo.grid.Calendar
59344 * @extends Roo.util.Grid
59345 * This class extends the Grid to provide a calendar widget
59346 * <br><br>Usage:<pre><code>
59347 var grid = new Roo.grid.Calendar("my-container-id", {
59350 selModel: mySelectionModel,
59351 autoSizeColumns: true,
59352 monitorWindowResize: false,
59353 trackMouseOver: true
59354 eventstore : real data store..
59360 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59361 * The container MUST have some type of size defined for the grid to fill. The container will be
59362 * automatically set to position relative if it isn't already.
59363 * @param {Object} config A config object that sets properties on this grid.
59365 Roo.grid.Calendar = function(container, config){
59366 // initialize the container
59367 this.container = Roo.get(container);
59368 this.container.update("");
59369 this.container.setStyle("overflow", "hidden");
59370 this.container.addClass('x-grid-container');
59372 this.id = this.container.id;
59374 Roo.apply(this, config);
59375 // check and correct shorthanded configs
59379 for (var r = 0;r < 6;r++) {
59382 for (var c =0;c < 7;c++) {
59386 if (this.eventStore) {
59387 this.eventStore= Roo.factory(this.eventStore, Roo.data);
59388 this.eventStore.on('load',this.onLoad, this);
59389 this.eventStore.on('beforeload',this.clearEvents, this);
59393 this.dataSource = new Roo.data.Store({
59394 proxy: new Roo.data.MemoryProxy(rows),
59395 reader: new Roo.data.ArrayReader({}, [
59396 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
59399 this.dataSource.load();
59400 this.ds = this.dataSource;
59401 this.ds.xmodule = this.xmodule || false;
59404 var cellRender = function(v,x,r)
59406 return String.format(
59407 '<div class="fc-day fc-widget-content"><div>' +
59408 '<div class="fc-event-container"></div>' +
59409 '<div class="fc-day-number">{0}</div>'+
59411 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
59412 '</div></div>', v);
59417 this.colModel = new Roo.grid.ColumnModel( [
59419 xtype: 'ColumnModel',
59421 dataIndex : 'weekday0',
59423 renderer : cellRender
59426 xtype: 'ColumnModel',
59428 dataIndex : 'weekday1',
59430 renderer : cellRender
59433 xtype: 'ColumnModel',
59435 dataIndex : 'weekday2',
59436 header : 'Tuesday',
59437 renderer : cellRender
59440 xtype: 'ColumnModel',
59442 dataIndex : 'weekday3',
59443 header : 'Wednesday',
59444 renderer : cellRender
59447 xtype: 'ColumnModel',
59449 dataIndex : 'weekday4',
59450 header : 'Thursday',
59451 renderer : cellRender
59454 xtype: 'ColumnModel',
59456 dataIndex : 'weekday5',
59458 renderer : cellRender
59461 xtype: 'ColumnModel',
59463 dataIndex : 'weekday6',
59464 header : 'Saturday',
59465 renderer : cellRender
59468 this.cm = this.colModel;
59469 this.cm.xmodule = this.xmodule || false;
59473 //this.selModel = new Roo.grid.CellSelectionModel();
59474 //this.sm = this.selModel;
59475 //this.selModel.init(this);
59479 this.container.setWidth(this.width);
59483 this.container.setHeight(this.height);
59490 * The raw click event for the entire grid.
59491 * @param {Roo.EventObject} e
59496 * The raw dblclick event for the entire grid.
59497 * @param {Roo.EventObject} e
59501 * @event contextmenu
59502 * The raw contextmenu event for the entire grid.
59503 * @param {Roo.EventObject} e
59505 "contextmenu" : true,
59508 * The raw mousedown event for the entire grid.
59509 * @param {Roo.EventObject} e
59511 "mousedown" : true,
59514 * The raw mouseup event for the entire grid.
59515 * @param {Roo.EventObject} e
59520 * The raw mouseover event for the entire grid.
59521 * @param {Roo.EventObject} e
59523 "mouseover" : true,
59526 * The raw mouseout event for the entire grid.
59527 * @param {Roo.EventObject} e
59532 * The raw keypress event for the entire grid.
59533 * @param {Roo.EventObject} e
59538 * The raw keydown event for the entire grid.
59539 * @param {Roo.EventObject} e
59547 * Fires when a cell is clicked
59548 * @param {Grid} this
59549 * @param {Number} rowIndex
59550 * @param {Number} columnIndex
59551 * @param {Roo.EventObject} e
59553 "cellclick" : true,
59555 * @event celldblclick
59556 * Fires when a cell is double clicked
59557 * @param {Grid} this
59558 * @param {Number} rowIndex
59559 * @param {Number} columnIndex
59560 * @param {Roo.EventObject} e
59562 "celldblclick" : true,
59565 * Fires when a row is clicked
59566 * @param {Grid} this
59567 * @param {Number} rowIndex
59568 * @param {Roo.EventObject} e
59572 * @event rowdblclick
59573 * Fires when a row is double clicked
59574 * @param {Grid} this
59575 * @param {Number} rowIndex
59576 * @param {Roo.EventObject} e
59578 "rowdblclick" : true,
59580 * @event headerclick
59581 * Fires when a header is clicked
59582 * @param {Grid} this
59583 * @param {Number} columnIndex
59584 * @param {Roo.EventObject} e
59586 "headerclick" : true,
59588 * @event headerdblclick
59589 * Fires when a header cell is double clicked
59590 * @param {Grid} this
59591 * @param {Number} columnIndex
59592 * @param {Roo.EventObject} e
59594 "headerdblclick" : true,
59596 * @event rowcontextmenu
59597 * Fires when a row is right clicked
59598 * @param {Grid} this
59599 * @param {Number} rowIndex
59600 * @param {Roo.EventObject} e
59602 "rowcontextmenu" : true,
59604 * @event cellcontextmenu
59605 * Fires when a cell is right clicked
59606 * @param {Grid} this
59607 * @param {Number} rowIndex
59608 * @param {Number} cellIndex
59609 * @param {Roo.EventObject} e
59611 "cellcontextmenu" : true,
59613 * @event headercontextmenu
59614 * Fires when a header is right clicked
59615 * @param {Grid} this
59616 * @param {Number} columnIndex
59617 * @param {Roo.EventObject} e
59619 "headercontextmenu" : true,
59621 * @event bodyscroll
59622 * Fires when the body element is scrolled
59623 * @param {Number} scrollLeft
59624 * @param {Number} scrollTop
59626 "bodyscroll" : true,
59628 * @event columnresize
59629 * Fires when the user resizes a column
59630 * @param {Number} columnIndex
59631 * @param {Number} newSize
59633 "columnresize" : true,
59635 * @event columnmove
59636 * Fires when the user moves a column
59637 * @param {Number} oldIndex
59638 * @param {Number} newIndex
59640 "columnmove" : true,
59643 * Fires when row(s) start being dragged
59644 * @param {Grid} this
59645 * @param {Roo.GridDD} dd The drag drop object
59646 * @param {event} e The raw browser event
59648 "startdrag" : true,
59651 * Fires when a drag operation is complete
59652 * @param {Grid} this
59653 * @param {Roo.GridDD} dd The drag drop object
59654 * @param {event} e The raw browser event
59659 * Fires when dragged row(s) are dropped on a valid DD target
59660 * @param {Grid} this
59661 * @param {Roo.GridDD} dd The drag drop object
59662 * @param {String} targetId The target drag drop object
59663 * @param {event} e The raw browser event
59668 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59669 * @param {Grid} this
59670 * @param {Roo.GridDD} dd The drag drop object
59671 * @param {String} targetId The target drag drop object
59672 * @param {event} e The raw browser event
59677 * Fires when the dragged row(s) first cross another DD target while being dragged
59678 * @param {Grid} this
59679 * @param {Roo.GridDD} dd The drag drop object
59680 * @param {String} targetId The target drag drop object
59681 * @param {event} e The raw browser event
59683 "dragenter" : true,
59686 * Fires when the dragged row(s) leave another DD target while being dragged
59687 * @param {Grid} this
59688 * @param {Roo.GridDD} dd The drag drop object
59689 * @param {String} targetId The target drag drop object
59690 * @param {event} e The raw browser event
59695 * Fires when a row is rendered, so you can change add a style to it.
59696 * @param {GridView} gridview The grid view
59697 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59703 * Fires when the grid is rendered
59704 * @param {Grid} grid
59709 * Fires when a date is selected
59710 * @param {DatePicker} this
59711 * @param {Date} date The selected date
59715 * @event monthchange
59716 * Fires when the displayed month changes
59717 * @param {DatePicker} this
59718 * @param {Date} date The selected month
59720 'monthchange': true,
59722 * @event evententer
59723 * Fires when mouse over an event
59724 * @param {Calendar} this
59725 * @param {event} Event
59727 'evententer': true,
59729 * @event eventleave
59730 * Fires when the mouse leaves an
59731 * @param {Calendar} this
59734 'eventleave': true,
59736 * @event eventclick
59737 * Fires when the mouse click an
59738 * @param {Calendar} this
59741 'eventclick': true,
59743 * @event eventrender
59744 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59745 * @param {Calendar} this
59746 * @param {data} data to be modified
59748 'eventrender': true
59752 Roo.grid.Grid.superclass.constructor.call(this);
59753 this.on('render', function() {
59754 this.view.el.addClass('x-grid-cal');
59756 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59760 if (!Roo.grid.Calendar.style) {
59761 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59764 '.x-grid-cal .x-grid-col' : {
59765 height: 'auto !important',
59766 'vertical-align': 'top'
59768 '.x-grid-cal .fc-event-hori' : {
59779 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59781 * @cfg {Store} eventStore The store that loads events.
59786 activeDate : false,
59789 monitorWindowResize : false,
59792 resizeColumns : function() {
59793 var col = (this.view.el.getWidth() / 7) - 3;
59794 // loop through cols, and setWidth
59795 for(var i =0 ; i < 7 ; i++){
59796 this.cm.setColumnWidth(i, col);
59799 setDate :function(date) {
59801 Roo.log('setDate?');
59803 this.resizeColumns();
59804 var vd = this.activeDate;
59805 this.activeDate = date;
59806 // if(vd && this.el){
59807 // var t = date.getTime();
59808 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59809 // Roo.log('using add remove');
59811 // this.fireEvent('monthchange', this, date);
59813 // this.cells.removeClass("fc-state-highlight");
59814 // this.cells.each(function(c){
59815 // if(c.dateValue == t){
59816 // c.addClass("fc-state-highlight");
59817 // setTimeout(function(){
59818 // try{c.dom.firstChild.focus();}catch(e){}
59828 var days = date.getDaysInMonth();
59830 var firstOfMonth = date.getFirstDateOfMonth();
59831 var startingPos = firstOfMonth.getDay()-this.startDay;
59833 if(startingPos < this.startDay){
59837 var pm = date.add(Date.MONTH, -1);
59838 var prevStart = pm.getDaysInMonth()-startingPos;
59842 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59844 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59845 //this.cells.addClassOnOver('fc-state-hover');
59847 var cells = this.cells.elements;
59848 var textEls = this.textNodes;
59850 //Roo.each(cells, function(cell){
59851 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59854 days += startingPos;
59856 // convert everything to numbers so it's fast
59857 var day = 86400000;
59858 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59861 //Roo.log(prevStart);
59863 var today = new Date().clearTime().getTime();
59864 var sel = date.clearTime().getTime();
59865 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59866 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59867 var ddMatch = this.disabledDatesRE;
59868 var ddText = this.disabledDatesText;
59869 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59870 var ddaysText = this.disabledDaysText;
59871 var format = this.format;
59873 var setCellClass = function(cal, cell){
59875 //Roo.log('set Cell Class');
59877 var t = d.getTime();
59882 cell.dateValue = t;
59884 cell.className += " fc-today";
59885 cell.className += " fc-state-highlight";
59886 cell.title = cal.todayText;
59889 // disable highlight in other month..
59890 cell.className += " fc-state-highlight";
59895 //cell.className = " fc-state-disabled";
59896 cell.title = cal.minText;
59900 //cell.className = " fc-state-disabled";
59901 cell.title = cal.maxText;
59905 if(ddays.indexOf(d.getDay()) != -1){
59906 // cell.title = ddaysText;
59907 // cell.className = " fc-state-disabled";
59910 if(ddMatch && format){
59911 var fvalue = d.dateFormat(format);
59912 if(ddMatch.test(fvalue)){
59913 cell.title = ddText.replace("%0", fvalue);
59914 cell.className = " fc-state-disabled";
59918 if (!cell.initialClassName) {
59919 cell.initialClassName = cell.dom.className;
59922 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59927 for(; i < startingPos; i++) {
59928 cells[i].dayName = (++prevStart);
59929 Roo.log(textEls[i]);
59930 d.setDate(d.getDate()+1);
59932 //cells[i].className = "fc-past fc-other-month";
59933 setCellClass(this, cells[i]);
59938 for(; i < days; i++){
59939 intDay = i - startingPos + 1;
59940 cells[i].dayName = (intDay);
59941 d.setDate(d.getDate()+1);
59943 cells[i].className = ''; // "x-date-active";
59944 setCellClass(this, cells[i]);
59948 for(; i < 42; i++) {
59949 //textEls[i].innerHTML = (++extraDays);
59951 d.setDate(d.getDate()+1);
59952 cells[i].dayName = (++extraDays);
59953 cells[i].className = "fc-future fc-other-month";
59954 setCellClass(this, cells[i]);
59957 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59959 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59961 // this will cause all the cells to mis
59964 for (var r = 0;r < 6;r++) {
59965 for (var c =0;c < 7;c++) {
59966 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59970 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59971 for(i=0;i<cells.length;i++) {
59973 this.cells.elements[i].dayName = cells[i].dayName ;
59974 this.cells.elements[i].className = cells[i].className;
59975 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59976 this.cells.elements[i].title = cells[i].title ;
59977 this.cells.elements[i].dateValue = cells[i].dateValue ;
59983 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59984 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59986 ////if(totalRows != 6){
59987 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59988 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59991 this.fireEvent('monthchange', this, date);
59996 * Returns the grid's SelectionModel.
59997 * @return {SelectionModel}
59999 getSelectionModel : function(){
60000 if(!this.selModel){
60001 this.selModel = new Roo.grid.CellSelectionModel();
60003 return this.selModel;
60007 this.eventStore.load()
60013 findCell : function(dt) {
60014 dt = dt.clearTime().getTime();
60016 this.cells.each(function(c){
60017 //Roo.log("check " +c.dateValue + '?=' + dt);
60018 if(c.dateValue == dt){
60028 findCells : function(rec) {
60029 var s = rec.data.start_dt.clone().clearTime().getTime();
60031 var e= rec.data.end_dt.clone().clearTime().getTime();
60034 this.cells.each(function(c){
60035 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
60037 if(c.dateValue > e){
60040 if(c.dateValue < s){
60049 findBestRow: function(cells)
60053 for (var i =0 ; i < cells.length;i++) {
60054 ret = Math.max(cells[i].rows || 0,ret);
60061 addItem : function(rec)
60063 // look for vertical location slot in
60064 var cells = this.findCells(rec);
60066 rec.row = this.findBestRow(cells);
60068 // work out the location.
60072 for(var i =0; i < cells.length; i++) {
60080 if (crow.start.getY() == cells[i].getY()) {
60082 crow.end = cells[i];
60098 for (var i = 0; i < cells.length;i++) {
60099 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
60106 clearEvents: function() {
60108 if (!this.eventStore.getCount()) {
60111 // reset number of rows in cells.
60112 Roo.each(this.cells.elements, function(c){
60116 this.eventStore.each(function(e) {
60117 this.clearEvent(e);
60122 clearEvent : function(ev)
60125 Roo.each(ev.els, function(el) {
60126 el.un('mouseenter' ,this.onEventEnter, this);
60127 el.un('mouseleave' ,this.onEventLeave, this);
60135 renderEvent : function(ev,ctr) {
60137 ctr = this.view.el.select('.fc-event-container',true).first();
60141 this.clearEvent(ev);
60147 var cells = ev.cells;
60148 var rows = ev.rows;
60149 this.fireEvent('eventrender', this, ev);
60151 for(var i =0; i < rows.length; i++) {
60155 cls += ' fc-event-start';
60157 if ((i+1) == rows.length) {
60158 cls += ' fc-event-end';
60161 //Roo.log(ev.data);
60162 // how many rows should it span..
60163 var cg = this.eventTmpl.append(ctr,Roo.apply({
60166 }, ev.data) , true);
60169 cg.on('mouseenter' ,this.onEventEnter, this, ev);
60170 cg.on('mouseleave' ,this.onEventLeave, this, ev);
60171 cg.on('click', this.onEventClick, this, ev);
60175 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
60176 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
60179 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
60180 cg.setWidth(ebox.right - sbox.x -2);
60184 renderEvents: function()
60186 // first make sure there is enough space..
60188 if (!this.eventTmpl) {
60189 this.eventTmpl = new Roo.Template(
60190 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
60191 '<div class="fc-event-inner">' +
60192 '<span class="fc-event-time">{time}</span>' +
60193 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
60195 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
60203 this.cells.each(function(c) {
60204 //Roo.log(c.select('.fc-day-content div',true).first());
60205 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
60208 var ctr = this.view.el.select('.fc-event-container',true).first();
60211 this.eventStore.each(function(ev){
60213 this.renderEvent(ev);
60217 this.view.layout();
60221 onEventEnter: function (e, el,event,d) {
60222 this.fireEvent('evententer', this, el, event);
60225 onEventLeave: function (e, el,event,d) {
60226 this.fireEvent('eventleave', this, el, event);
60229 onEventClick: function (e, el,event,d) {
60230 this.fireEvent('eventclick', this, el, event);
60233 onMonthChange: function () {
60237 onLoad: function () {
60239 //Roo.log('calendar onload');
60241 if(this.eventStore.getCount() > 0){
60245 this.eventStore.each(function(d){
60250 if (typeof(add.end_dt) == 'undefined') {
60251 Roo.log("Missing End time in calendar data: ");
60255 if (typeof(add.start_dt) == 'undefined') {
60256 Roo.log("Missing Start time in calendar data: ");
60260 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
60261 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
60262 add.id = add.id || d.id;
60263 add.title = add.title || '??';
60271 this.renderEvents();
60281 render : function ()
60285 if (!this.view.el.hasClass('course-timesheet')) {
60286 this.view.el.addClass('course-timesheet');
60288 if (this.tsStyle) {
60293 Roo.log(_this.grid.view.el.getWidth());
60296 this.tsStyle = Roo.util.CSS.createStyleSheet({
60297 '.course-timesheet .x-grid-row' : {
60300 '.x-grid-row td' : {
60301 'vertical-align' : 0
60303 '.course-edit-link' : {
60305 'text-overflow' : 'ellipsis',
60306 'overflow' : 'hidden',
60307 'white-space' : 'nowrap',
60308 'cursor' : 'pointer'
60313 '.de-act-sup-link' : {
60314 'color' : 'purple',
60315 'text-decoration' : 'line-through'
60319 'text-decoration' : 'line-through'
60321 '.course-timesheet .course-highlight' : {
60322 'border-top-style': 'dashed !important',
60323 'border-bottom-bottom': 'dashed !important'
60325 '.course-timesheet .course-item' : {
60326 'font-family' : 'tahoma, arial, helvetica',
60327 'font-size' : '11px',
60328 'overflow' : 'hidden',
60329 'padding-left' : '10px',
60330 'padding-right' : '10px',
60331 'padding-top' : '10px'
60339 monitorWindowResize : false,
60340 cellrenderer : function(v,x,r)
60345 xtype: 'CellSelectionModel',
60352 beforeload : function (_self, options)
60354 options.params = options.params || {};
60355 options.params._month = _this.monthField.getValue();
60356 options.params.limit = 9999;
60357 options.params['sort'] = 'when_dt';
60358 options.params['dir'] = 'ASC';
60359 this.proxy.loadResponse = this.loadResponse;
60361 //this.addColumns();
60363 load : function (_self, records, options)
60365 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
60366 // if you click on the translation.. you can edit it...
60367 var el = Roo.get(this);
60368 var id = el.dom.getAttribute('data-id');
60369 var d = el.dom.getAttribute('data-date');
60370 var t = el.dom.getAttribute('data-time');
60371 //var id = this.child('span').dom.textContent;
60374 Pman.Dialog.CourseCalendar.show({
60378 productitem_active : id ? 1 : 0
60380 _this.grid.ds.load({});
60385 _this.panel.fireEvent('resize', [ '', '' ]);
60388 loadResponse : function(o, success, response){
60389 // this is overridden on before load..
60391 Roo.log("our code?");
60392 //Roo.log(success);
60393 //Roo.log(response)
60394 delete this.activeRequest;
60396 this.fireEvent("loadexception", this, o, response);
60397 o.request.callback.call(o.request.scope, null, o.request.arg, false);
60402 result = o.reader.read(response);
60404 Roo.log("load exception?");
60405 this.fireEvent("loadexception", this, o, response, e);
60406 o.request.callback.call(o.request.scope, null, o.request.arg, false);
60409 Roo.log("ready...");
60410 // loop through result.records;
60411 // and set this.tdate[date] = [] << array of records..
60413 Roo.each(result.records, function(r){
60415 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
60416 _this.tdata[r.data.when_dt.format('j')] = [];
60418 _this.tdata[r.data.when_dt.format('j')].push(r.data);
60421 //Roo.log(_this.tdata);
60423 result.records = [];
60424 result.totalRecords = 6;
60426 // let's generate some duumy records for the rows.
60427 //var st = _this.dateField.getValue();
60429 // work out monday..
60430 //st = st.add(Date.DAY, -1 * st.format('w'));
60432 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60434 var firstOfMonth = date.getFirstDayOfMonth();
60435 var days = date.getDaysInMonth();
60437 var firstAdded = false;
60438 for (var i = 0; i < result.totalRecords ; i++) {
60439 //var d= st.add(Date.DAY, i);
60442 for(var w = 0 ; w < 7 ; w++){
60443 if(!firstAdded && firstOfMonth != w){
60450 var dd = (d > 0 && d < 10) ? "0"+d : d;
60451 row['weekday'+w] = String.format(
60452 '<span style="font-size: 16px;"><b>{0}</b></span>'+
60453 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
60455 date.format('Y-m-')+dd
60458 if(typeof(_this.tdata[d]) != 'undefined'){
60459 Roo.each(_this.tdata[d], function(r){
60463 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
60464 if(r.parent_id*1>0){
60465 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
60468 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
60469 deactive = 'de-act-link';
60472 row['weekday'+w] += String.format(
60473 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
60475 r.product_id_name, //1
60476 r.when_dt.format('h:ia'), //2
60486 // only do this if something added..
60488 result.records.push(_this.grid.dataSource.reader.newRow(row));
60492 // push it twice. (second one with an hour..
60496 this.fireEvent("load", this, o, o.request.arg);
60497 o.request.callback.call(o.request.scope, result, o.request.arg, true);
60499 sortInfo : {field: 'when_dt', direction : 'ASC' },
60501 xtype: 'HttpProxy',
60504 url : baseURL + '/Roo/Shop_course.php'
60507 xtype: 'JsonReader',
60524 'name': 'parent_id',
60528 'name': 'product_id',
60532 'name': 'productitem_id',
60550 click : function (_self, e)
60552 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60553 sd.setMonth(sd.getMonth()-1);
60554 _this.monthField.setValue(sd.format('Y-m-d'));
60555 _this.grid.ds.load({});
60561 xtype: 'Separator',
60565 xtype: 'MonthField',
60568 render : function (_self)
60570 _this.monthField = _self;
60571 // _this.monthField.set today
60573 select : function (combo, date)
60575 _this.grid.ds.load({});
60578 value : (function() { return new Date(); })()
60581 xtype: 'Separator',
60587 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60597 click : function (_self, e)
60599 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60600 sd.setMonth(sd.getMonth()+1);
60601 _this.monthField.setValue(sd.format('Y-m-d'));
60602 _this.grid.ds.load({});
60615 * Ext JS Library 1.1.1
60616 * Copyright(c) 2006-2007, Ext JS, LLC.
60618 * Originally Released Under LGPL - original licence link has changed is not relivant.
60621 * <script type="text/javascript">
60625 * @class Roo.LoadMask
60626 * A simple utility class for generically masking elements while loading data. If the element being masked has
60627 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60628 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60629 * element's UpdateManager load indicator and will be destroyed after the initial load.
60631 * Create a new LoadMask
60632 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60633 * @param {Object} config The config object
60635 Roo.LoadMask = function(el, config){
60636 this.el = Roo.get(el);
60637 Roo.apply(this, config);
60639 this.store.on('beforeload', this.onBeforeLoad, this);
60640 this.store.on('load', this.onLoad, this);
60641 this.store.on('loadexception', this.onLoadException, this);
60642 this.removeMask = false;
60644 var um = this.el.getUpdateManager();
60645 um.showLoadIndicator = false; // disable the default indicator
60646 um.on('beforeupdate', this.onBeforeLoad, this);
60647 um.on('update', this.onLoad, this);
60648 um.on('failure', this.onLoad, this);
60649 this.removeMask = true;
60653 Roo.LoadMask.prototype = {
60655 * @cfg {Boolean} removeMask
60656 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60657 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60660 * @cfg {String} msg
60661 * The text to display in a centered loading message box (defaults to 'Loading...')
60663 msg : 'Loading...',
60665 * @cfg {String} msgCls
60666 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60668 msgCls : 'x-mask-loading',
60671 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60677 * Disables the mask to prevent it from being displayed
60679 disable : function(){
60680 this.disabled = true;
60684 * Enables the mask so that it can be displayed
60686 enable : function(){
60687 this.disabled = false;
60690 onLoadException : function()
60692 Roo.log(arguments);
60694 if (typeof(arguments[3]) != 'undefined') {
60695 Roo.MessageBox.alert("Error loading",arguments[3]);
60699 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60700 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60707 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60710 onLoad : function()
60712 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60716 onBeforeLoad : function(){
60717 if(!this.disabled){
60718 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
60723 destroy : function(){
60725 this.store.un('beforeload', this.onBeforeLoad, this);
60726 this.store.un('load', this.onLoad, this);
60727 this.store.un('loadexception', this.onLoadException, this);
60729 var um = this.el.getUpdateManager();
60730 um.un('beforeupdate', this.onBeforeLoad, this);
60731 um.un('update', this.onLoad, this);
60732 um.un('failure', this.onLoad, this);
60737 * Ext JS Library 1.1.1
60738 * Copyright(c) 2006-2007, Ext JS, LLC.
60740 * Originally Released Under LGPL - original licence link has changed is not relivant.
60743 * <script type="text/javascript">
60748 * @class Roo.XTemplate
60749 * @extends Roo.Template
60750 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60752 var t = new Roo.XTemplate(
60753 '<select name="{name}">',
60754 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60758 // then append, applying the master template values
60761 * Supported features:
60766 {a_variable} - output encoded.
60767 {a_variable.format:("Y-m-d")} - call a method on the variable
60768 {a_variable:raw} - unencoded output
60769 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60770 {a_variable:this.method_on_template(...)} - call a method on the template object.
60775 <tpl for="a_variable or condition.."></tpl>
60776 <tpl if="a_variable or condition"></tpl>
60777 <tpl exec="some javascript"></tpl>
60778 <tpl name="named_template"></tpl> (experimental)
60780 <tpl for="."></tpl> - just iterate the property..
60781 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60785 Roo.XTemplate = function()
60787 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60794 Roo.extend(Roo.XTemplate, Roo.Template, {
60797 * The various sub templates
60802 * basic tag replacing syntax
60805 * // you can fake an object call by doing this
60809 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60812 * compile the template
60814 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60817 compile: function()
60821 s = ['<tpl>', s, '</tpl>'].join('');
60823 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60824 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60825 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60826 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60827 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60832 while(true == !!(m = s.match(re))){
60833 var forMatch = m[0].match(nameRe),
60834 ifMatch = m[0].match(ifRe),
60835 execMatch = m[0].match(execRe),
60836 namedMatch = m[0].match(namedRe),
60841 name = forMatch && forMatch[1] ? forMatch[1] : '';
60844 // if - puts fn into test..
60845 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60847 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60852 // exec - calls a function... returns empty if true is returned.
60853 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60855 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60863 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60864 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60865 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60868 var uid = namedMatch ? namedMatch[1] : id;
60872 id: namedMatch ? namedMatch[1] : id,
60879 s = s.replace(m[0], '');
60881 s = s.replace(m[0], '{xtpl'+ id + '}');
60886 for(var i = tpls.length-1; i >= 0; --i){
60887 this.compileTpl(tpls[i]);
60888 this.tpls[tpls[i].id] = tpls[i];
60890 this.master = tpls[tpls.length-1];
60894 * same as applyTemplate, except it's done to one of the subTemplates
60895 * when using named templates, you can do:
60897 * var str = pl.applySubTemplate('your-name', values);
60900 * @param {Number} id of the template
60901 * @param {Object} values to apply to template
60902 * @param {Object} parent (normaly the instance of this object)
60904 applySubTemplate : function(id, values, parent)
60908 var t = this.tpls[id];
60912 if(t.test && !t.test.call(this, values, parent)){
60916 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60917 Roo.log(e.toString());
60923 if(t.exec && t.exec.call(this, values, parent)){
60927 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60928 Roo.log(e.toString());
60933 var vs = t.target ? t.target.call(this, values, parent) : values;
60934 parent = t.target ? values : parent;
60935 if(t.target && vs instanceof Array){
60937 for(var i = 0, len = vs.length; i < len; i++){
60938 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60940 return buf.join('');
60942 return t.compiled.call(this, vs, parent);
60944 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60945 Roo.log(e.toString());
60946 Roo.log(t.compiled);
60951 compileTpl : function(tpl)
60953 var fm = Roo.util.Format;
60954 var useF = this.disableFormats !== true;
60955 var sep = Roo.isGecko ? "+" : ",";
60956 var undef = function(str) {
60957 Roo.log("Property not found :" + str);
60961 var fn = function(m, name, format, args)
60963 //Roo.log(arguments);
60964 args = args ? args.replace(/\\'/g,"'") : args;
60965 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60966 if (typeof(format) == 'undefined') {
60967 format= 'htmlEncode';
60969 if (format == 'raw' ) {
60973 if(name.substr(0, 4) == 'xtpl'){
60974 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60977 // build an array of options to determine if value is undefined..
60979 // basically get 'xxxx.yyyy' then do
60980 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60981 // (function () { Roo.log("Property not found"); return ''; })() :
60986 Roo.each(name.split('.'), function(st) {
60987 lookfor += (lookfor.length ? '.': '') + st;
60988 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60991 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60994 if(format && useF){
60996 args = args ? ',' + args : "";
60998 if(format.substr(0, 5) != "this."){
60999 format = "fm." + format + '(';
61001 format = 'this.call("'+ format.substr(5) + '", ';
61005 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
61009 // called with xxyx.yuu:(test,test)
61011 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
61013 // raw.. - :raw modifier..
61014 return "'"+ sep + udef_st + name + ")"+sep+"'";
61018 // branched to use + in gecko and [].join() in others
61020 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
61021 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
61024 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
61025 body.push(tpl.body.replace(/(\r\n|\n)/g,
61026 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
61027 body.push("'].join('');};};");
61028 body = body.join('');
61031 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
61033 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
61039 applyTemplate : function(values){
61040 return this.master.compiled.call(this, values, {});
61041 //var s = this.subs;
61044 apply : function(){
61045 return this.applyTemplate.apply(this, arguments);
61050 Roo.XTemplate.from = function(el){
61051 el = Roo.getDom(el);
61052 return new Roo.XTemplate(el.value || el.innerHTML);