4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isGecko = !isSafari && ua.indexOf("gecko") > -1,
61 isBorderBox = isIE && !isStrict,
62 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64 isLinux = (ua.indexOf("linux") != -1),
65 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66 isIOS = /iphone|ipad/.test(ua),
67 isTouch = (function() {
69 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
70 window.addEventListener('touchstart', function __set_has_touch__ () {
72 window.removeEventListener('touchstart', __set_has_touch__);
74 return false; // no touch on chrome!?
76 document.createEvent("TouchEvent");
83 // remove css image flicker
86 document.execCommand("BackgroundImageCache", false, true);
92 * True if the browser is in strict mode
97 * True if the page is running over SSL
102 * True when the document is fully initialized and ready for action
107 * Turn on debugging output (currently only the factory uses this)
114 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117 enableGarbageCollector : true,
120 * True to automatically purge event listeners after uncaching an element (defaults to false).
121 * Note: this only happens if enableGarbageCollector is true.
124 enableListenerCollection:false,
127 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
128 * the IE insecure content warning (defaults to javascript:false).
131 SSL_SECURE_URL : "javascript:false",
134 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
135 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
140 emptyFn : function(){},
143 * Copies all the properties of config to obj if they don't already exist.
144 * @param {Object} obj The receiver of the properties
145 * @param {Object} config The source of the properties
146 * @return {Object} returns obj
148 applyIf : function(o, c){
151 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
158 * Applies event listeners to elements by selectors when the document is ready.
159 * The event name is specified with an @ suffix.
162 // add a listener for click on all anchors in element with id foo
163 '#foo a@click' : function(e, t){
167 // add the same listener to multiple selectors (separated by comma BEFORE the @)
168 '#foo a, #bar span.some-class@mouseover' : function(){
173 * @param {Object} obj The list of behaviors to apply
175 addBehaviors : function(o){
177 Roo.onReady(function(){
182 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
184 var parts = b.split('@');
185 if(parts[1]){ // for Object prototype breakers
188 cache[s] = Roo.select(s);
190 cache[s].on(parts[1], o[b]);
197 * Generates unique ids. If the element already has an id, it is unchanged
198 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
199 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
200 * @return {String} The generated Id.
202 id : function(el, prefix){
203 prefix = prefix || "roo-gen";
205 var id = prefix + (++idSeed);
206 return el ? (el.id ? el.id : (el.id = id)) : id;
211 * Extends one class with another class and optionally overrides members with the passed literal. This class
212 * also adds the function "override()" to the class that can be used to override
213 * members on an instance.
214 * @param {Object} subclass The class inheriting the functionality
215 * @param {Object} superclass The class being extended
216 * @param {Object} overrides (optional) A literal with members
221 var io = function(o){
226 return function(sb, sp, overrides){
227 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230 sb = function(){sp.apply(this, arguments);};
232 var F = function(){}, sbp, spp = sp.prototype;
234 sbp = sb.prototype = new F();
238 if(spp.constructor == Object.prototype.constructor){
243 sb.override = function(o){
247 Roo.override(sb, overrides);
253 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
255 Roo.override(MyClass, {
256 newMethod1: function(){
259 newMethod2: function(foo){
264 * @param {Object} origclass The class to override
265 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
266 * containing one or more methods.
269 override : function(origclass, overrides){
271 var p = origclass.prototype;
272 for(var method in overrides){
273 p[method] = overrides[method];
278 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
280 Roo.namespace('Company', 'Company.data');
281 Company.Widget = function() { ... }
282 Company.data.CustomStore = function(config) { ... }
284 * @param {String} namespace1
285 * @param {String} namespace2
286 * @param {String} etc
289 namespace : function(){
290 var a=arguments, o=null, i, j, d, rt;
291 for (i=0; i<a.length; ++i) {
295 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
296 for (j=1; j<d.length; ++j) {
297 o[d[j]]=o[d[j]] || {};
303 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
305 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
306 Roo.factory(conf, Roo.data);
308 * @param {String} classname
309 * @param {String} namespace (optional)
313 factory : function(c, ns)
315 // no xtype, no ns or c.xns - or forced off by c.xns
316 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
319 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
320 if (c.constructor == ns[c.xtype]) {// already created...
324 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
325 var ret = new ns[c.xtype](c);
329 c.xns = false; // prevent recursion..
333 * Logs to console if it can.
335 * @param {String|Object} string
340 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
347 * 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.
351 urlEncode : function(o){
357 var ov = o[key], k = Roo.encodeURIComponent(key);
358 var type = typeof ov;
359 if(type == 'undefined'){
361 }else if(type != "function" && type != "object"){
362 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
363 }else if(ov instanceof Array){
365 for(var i = 0, len = ov.length; i < len; i++) {
366 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
377 * Safe version of encodeURIComponent
378 * @param {String} data
382 encodeURIComponent : function (data)
385 return encodeURIComponent(data);
386 } catch(e) {} // should be an uri encode error.
388 if (data == '' || data == null){
391 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
392 function nibble_to_hex(nibble){
393 var chars = '0123456789ABCDEF';
394 return chars.charAt(nibble);
396 data = data.toString();
398 for(var i=0; i<data.length; i++){
399 var c = data.charCodeAt(i);
400 var bs = new Array();
403 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
404 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
405 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
406 bs[3] = 0x80 | (c & 0x3F);
407 }else if (c > 0x800){
409 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
410 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
411 bs[2] = 0x80 | (c & 0x3F);
414 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
415 bs[1] = 0x80 | (c & 0x3F);
420 for(var j=0; j<bs.length; j++){
422 var hex = nibble_to_hex((b & 0xF0) >>> 4)
423 + nibble_to_hex(b &0x0F);
432 * 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]}.
433 * @param {String} string
434 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
435 * @return {Object} A literal with members
437 urlDecode : function(string, overwrite){
438 if(!string || !string.length){
442 var pairs = string.split('&');
443 var pair, name, value;
444 for(var i = 0, len = pairs.length; i < len; i++){
445 pair = pairs[i].split('=');
446 name = decodeURIComponent(pair[0]);
447 value = decodeURIComponent(pair[1]);
448 if(overwrite !== true){
449 if(typeof obj[name] == "undefined"){
451 }else if(typeof obj[name] == "string"){
452 obj[name] = [obj[name]];
453 obj[name].push(value);
455 obj[name].push(value);
465 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
466 * passed array is not really an array, your function is called once with it.
467 * The supplied function is called with (Object item, Number index, Array allItems).
468 * @param {Array/NodeList/Mixed} array
469 * @param {Function} fn
470 * @param {Object} scope
472 each : function(array, fn, scope){
473 if(typeof array.length == "undefined" || typeof array == "string"){
476 for(var i = 0, len = array.length; i < len; i++){
477 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
482 combine : function(){
483 var as = arguments, l = as.length, r = [];
484 for(var i = 0; i < l; i++){
486 if(a instanceof Array){
488 }else if(a.length !== undefined && !a.substr){
489 r = r.concat(Array.prototype.slice.call(a, 0));
498 * Escapes the passed string for use in a regular expression
499 * @param {String} str
502 escapeRe : function(s) {
503 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
507 callback : function(cb, scope, args, delay){
508 if(typeof cb == "function"){
510 cb.defer(delay, scope, args || []);
512 cb.apply(scope, args || []);
518 * Return the dom node for the passed string (id), dom node, or Roo.Element
519 * @param {String/HTMLElement/Roo.Element} el
520 * @return HTMLElement
522 getDom : function(el){
526 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
530 * Shorthand for {@link Roo.ComponentMgr#get}
532 * @return Roo.Component
534 getCmp : function(id){
535 return Roo.ComponentMgr.get(id);
538 num : function(v, defaultValue){
539 if(typeof v != 'number'){
545 destroy : function(){
546 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
550 as.removeAllListeners();
554 if(typeof as.purgeListeners == 'function'){
557 if(typeof as.destroy == 'function'){
564 // inpired by a similar function in mootools library
566 * Returns the type of object that is passed in. If the object passed in is null or undefined it
567 * return false otherwise it returns one of the following values:<ul>
568 * <li><b>string</b>: If the object passed is a string</li>
569 * <li><b>number</b>: If the object passed is a number</li>
570 * <li><b>boolean</b>: If the object passed is a boolean value</li>
571 * <li><b>function</b>: If the object passed is a function reference</li>
572 * <li><b>object</b>: If the object passed is an object</li>
573 * <li><b>array</b>: If the object passed is an array</li>
574 * <li><b>regexp</b>: If the object passed is a regular expression</li>
575 * <li><b>element</b>: If the object passed is a DOM Element</li>
576 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
577 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
578 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
579 * @param {Mixed} object
583 if(o === undefined || o === null){
590 if(t == 'object' && o.nodeName) {
592 case 1: return 'element';
593 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596 if(t == 'object' || t == 'function') {
597 switch(o.constructor) {
598 case Array: return 'array';
599 case RegExp: return 'regexp';
601 if(typeof o.length == 'number' && typeof o.item == 'function') {
609 * Returns true if the passed value is null, undefined or an empty string (optional).
610 * @param {Mixed} value The value to test
611 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614 isEmpty : function(v, allowBlank){
615 return v === null || v === undefined || (!allowBlank ? v === '' : false);
623 isFirefox : isFirefox,
633 isBorderBox : isBorderBox,
635 isWindows : isWindows,
646 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
647 * you may want to set this to true.
650 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
655 * Selects a single element as a Roo Element
656 * This is about as close as you can get to jQuery's $('do crazy stuff')
657 * @param {String} selector The selector/xpath query
658 * @param {Node} root (optional) The start of the query (defaults to document).
659 * @return {Roo.Element}
661 selectNode : function(selector, root)
663 var node = Roo.DomQuery.selectNode(selector,root);
664 return node ? Roo.get(node) : new Roo.Element(false);
672 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
673 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
676 "Roo.bootstrap.dash");
679 * Ext JS Library 1.1.1
680 * Copyright(c) 2006-2007, Ext JS, LLC.
682 * Originally Released Under LGPL - original licence link has changed is not relivant.
685 * <script type="text/javascript">
689 // wrappedn so fnCleanup is not in global scope...
691 function fnCleanUp() {
692 var p = Function.prototype;
693 delete p.createSequence;
695 delete p.createDelegate;
696 delete p.createCallback;
697 delete p.createInterceptor;
699 window.detachEvent("onunload", fnCleanUp);
701 window.attachEvent("onunload", fnCleanUp);
708 * These functions are available on every Function object (any JavaScript function).
710 Roo.apply(Function.prototype, {
712 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
713 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
714 * Will create a function that is bound to those 2 args.
715 * @return {Function} The new function
717 createCallback : function(/*args...*/){
718 // make args available, in function below
719 var args = arguments;
722 return method.apply(window, args);
727 * Creates a delegate (callback) that sets the scope to obj.
728 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
729 * Will create a function that is automatically scoped to this.
730 * @param {Object} obj (optional) The object for which the scope is set
731 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
732 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
733 * if a number the args are inserted at the specified position
734 * @return {Function} The new function
736 createDelegate : function(obj, args, appendArgs){
739 var callArgs = args || arguments;
740 if(appendArgs === true){
741 callArgs = Array.prototype.slice.call(arguments, 0);
742 callArgs = callArgs.concat(args);
743 }else if(typeof appendArgs == "number"){
744 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
745 var applyArgs = [appendArgs, 0].concat(args); // create method call params
746 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
748 return method.apply(obj || window, callArgs);
753 * Calls this function after the number of millseconds specified.
754 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
755 * @param {Object} obj (optional) The object for which the scope is set
756 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
757 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
758 * if a number the args are inserted at the specified position
759 * @return {Number} The timeout id that can be used with clearTimeout
761 defer : function(millis, obj, args, appendArgs){
762 var fn = this.createDelegate(obj, args, appendArgs);
764 return setTimeout(fn, millis);
770 * Create a combined function call sequence of the original function + the passed function.
771 * The resulting function returns the results of the original function.
772 * The passed fcn is called with the parameters of the original function
773 * @param {Function} fcn The function to sequence
774 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
775 * @return {Function} The new function
777 createSequence : function(fcn, scope){
778 if(typeof fcn != "function"){
783 var retval = method.apply(this || window, arguments);
784 fcn.apply(scope || this || window, arguments);
790 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
791 * The resulting function returns the results of the original function.
792 * The passed fcn is called with the parameters of the original function.
794 * @param {Function} fcn The function to call before the original
795 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
796 * @return {Function} The new function
798 createInterceptor : function(fcn, scope){
799 if(typeof fcn != "function"){
806 if(fcn.apply(scope || this || window, arguments) === false){
809 return method.apply(this || window, arguments);
815 * Ext JS Library 1.1.1
816 * Copyright(c) 2006-2007, Ext JS, LLC.
818 * Originally Released Under LGPL - original licence link has changed is not relivant.
821 * <script type="text/javascript">
824 Roo.applyIf(String, {
829 * Escapes the passed string for ' and \
830 * @param {String} string The string to escape
831 * @return {String} The escaped string
834 escape : function(string) {
835 return string.replace(/('|\\)/g, "\\$1");
839 * Pads the left side of a string with a specified character. This is especially useful
840 * for normalizing number and date strings. Example usage:
842 var s = String.leftPad('123', 5, '0');
843 // s now contains the string: '00123'
845 * @param {String} string The original string
846 * @param {Number} size The total length of the output string
847 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
848 * @return {String} The padded string
851 leftPad : function (val, size, ch) {
852 var result = new String(val);
853 if(ch === null || ch === undefined || ch === '') {
856 while (result.length < size) {
857 result = ch + result;
863 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
864 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
866 var cls = 'my-class', text = 'Some text';
867 var s = String.format('<div class="{0}">{1}</div>', cls, text);
868 // s now contains the string: '<div class="my-class">Some text</div>'
870 * @param {String} string The tokenized string to be formatted
871 * @param {String} value1 The value to replace token {0}
872 * @param {String} value2 Etc...
873 * @return {String} The formatted string
876 format : function(format){
877 var args = Array.prototype.slice.call(arguments, 1);
878 return format.replace(/\{(\d+)\}/g, function(m, i){
879 return Roo.util.Format.htmlEncode(args[i]);
885 * Utility function that allows you to easily switch a string between two alternating values. The passed value
886 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
887 * they are already different, the first value passed in is returned. Note that this method returns the new value
888 * but does not change the current string.
890 // alternate sort directions
891 sort = sort.toggle('ASC', 'DESC');
893 // instead of conditional logic:
894 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
896 * @param {String} value The value to compare to the current string
897 * @param {String} other The new value to use if the string already equals the first value passed in
898 * @return {String} The new value
901 String.prototype.toggle = function(value, other){
902 return this == value ? other : value;
905 * Ext JS Library 1.1.1
906 * Copyright(c) 2006-2007, Ext JS, LLC.
908 * Originally Released Under LGPL - original licence link has changed is not relivant.
911 * <script type="text/javascript">
917 Roo.applyIf(Number.prototype, {
919 * Checks whether or not the current number is within a desired range. If the number is already within the
920 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
921 * exceeded. Note that this method returns the constrained value but does not change the current number.
922 * @param {Number} min The minimum number in the range
923 * @param {Number} max The maximum number in the range
924 * @return {Number} The constrained value if outside the range, otherwise the current value
926 constrain : function(min, max){
927 return Math.min(Math.max(this, min), max);
931 * Ext JS Library 1.1.1
932 * Copyright(c) 2006-2007, Ext JS, LLC.
934 * Originally Released Under LGPL - original licence link has changed is not relivant.
937 * <script type="text/javascript">
942 Roo.applyIf(Array.prototype, {
945 * Checks whether or not the specified object exists in the array.
946 * @param {Object} o The object to check for
947 * @return {Number} The index of o in the array (or -1 if it is not found)
949 indexOf : function(o){
950 for (var i = 0, len = this.length; i < len; i++){
951 if(this[i] == o) { return i; }
957 * Removes the specified object from the array. If the object is not found nothing happens.
958 * @param {Object} o The object to remove
960 remove : function(o){
961 var index = this.indexOf(o);
963 this.splice(index, 1);
967 * Map (JS 1.6 compatibility)
968 * @param {Function} function to call
972 var len = this.length >>> 0;
973 if (typeof fun != "function") {
974 throw new TypeError();
976 var res = new Array(len);
977 var thisp = arguments[1];
978 for (var i = 0; i < len; i++)
981 res[i] = fun.call(thisp, this[i], i, this);
994 * Ext JS Library 1.1.1
995 * Copyright(c) 2006-2007, Ext JS, LLC.
997 * Originally Released Under LGPL - original licence link has changed is not relivant.
1000 * <script type="text/javascript">
1006 * The date parsing and format syntax is a subset of
1007 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1008 * supported will provide results equivalent to their PHP versions.
1010 * Following is the list of all currently supported formats:
1013 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1015 Format Output Description
1016 ------ ---------- --------------------------------------------------------------
1017 d 10 Day of the month, 2 digits with leading zeros
1018 D Wed A textual representation of a day, three letters
1019 j 10 Day of the month without leading zeros
1020 l Wednesday A full textual representation of the day of the week
1021 S th English ordinal day of month suffix, 2 chars (use with j)
1022 w 3 Numeric representation of the day of the week
1023 z 9 The julian date, or day of the year (0-365)
1024 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1025 F January A full textual representation of the month
1026 m 01 Numeric representation of a month, with leading zeros
1027 M Jan Month name abbreviation, three letters
1028 n 1 Numeric representation of a month, without leading zeros
1029 t 31 Number of days in the given month
1030 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1031 Y 2007 A full numeric representation of a year, 4 digits
1032 y 07 A two digit representation of a year
1033 a pm Lowercase Ante meridiem and Post meridiem
1034 A PM Uppercase Ante meridiem and Post meridiem
1035 g 3 12-hour format of an hour without leading zeros
1036 G 15 24-hour format of an hour without leading zeros
1037 h 03 12-hour format of an hour with leading zeros
1038 H 15 24-hour format of an hour with leading zeros
1039 i 05 Minutes with leading zeros
1040 s 01 Seconds, with leading zeros
1041 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1042 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1043 T CST Timezone setting of the machine running the code
1044 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1047 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1049 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1050 document.write(dt.format('Y-m-d')); //2007-01-10
1051 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1052 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
1055 * Here are some standard date/time patterns that you might find helpful. They
1056 * are not part of the source of Date.js, but to use them you can simply copy this
1057 * block of code into any script that is included after Date.js and they will also become
1058 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1061 ISO8601Long:"Y-m-d H:i:s",
1062 ISO8601Short:"Y-m-d",
1064 LongDate: "l, F d, Y",
1065 FullDateTime: "l, F d, Y g:i:s A",
1068 LongTime: "g:i:s A",
1069 SortableDateTime: "Y-m-d\\TH:i:s",
1070 UniversalSortableDateTime: "Y-m-d H:i:sO",
1077 var dt = new Date();
1078 document.write(dt.format(Date.patterns.ShortDate));
1083 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1084 * They generate precompiled functions from date formats instead of parsing and
1085 * processing the pattern every time you format a date. These functions are available
1086 * on every Date object (any javascript function).
1088 * The original article and download are here:
1089 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1096 Returns the number of milliseconds between this date and date
1097 @param {Date} date (optional) Defaults to now
1098 @return {Number} The diff in milliseconds
1099 @member Date getElapsed
1101 Date.prototype.getElapsed = function(date) {
1102 return Math.abs((date || new Date()).getTime()-this.getTime());
1104 // was in date file..
1108 Date.parseFunctions = {count:0};
1110 Date.parseRegexes = [];
1112 Date.formatFunctions = {count:0};
1115 Date.prototype.dateFormat = function(format) {
1116 if (Date.formatFunctions[format] == null) {
1117 Date.createNewFormat(format);
1119 var func = Date.formatFunctions[format];
1120 return this[func]();
1125 * Formats a date given the supplied format string
1126 * @param {String} format The format string
1127 * @return {String} The formatted date
1130 Date.prototype.format = Date.prototype.dateFormat;
1133 Date.createNewFormat = function(format) {
1134 var funcName = "format" + Date.formatFunctions.count++;
1135 Date.formatFunctions[format] = funcName;
1136 var code = "Date.prototype." + funcName + " = function(){return ";
1137 var special = false;
1139 for (var i = 0; i < format.length; ++i) {
1140 ch = format.charAt(i);
1141 if (!special && ch == "\\") {
1146 code += "'" + String.escape(ch) + "' + ";
1149 code += Date.getFormatCode(ch);
1152 /** eval:var:zzzzzzzzzzzzz */
1153 eval(code.substring(0, code.length - 3) + ";}");
1157 Date.getFormatCode = function(character) {
1158 switch (character) {
1160 return "String.leftPad(this.getDate(), 2, '0') + ";
1162 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1164 return "this.getDate() + ";
1166 return "Date.dayNames[this.getDay()] + ";
1168 return "this.getSuffix() + ";
1170 return "this.getDay() + ";
1172 return "this.getDayOfYear() + ";
1174 return "this.getWeekOfYear() + ";
1176 return "Date.monthNames[this.getMonth()] + ";
1178 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1180 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1182 return "(this.getMonth() + 1) + ";
1184 return "this.getDaysInMonth() + ";
1186 return "(this.isLeapYear() ? 1 : 0) + ";
1188 return "this.getFullYear() + ";
1190 return "('' + this.getFullYear()).substring(2, 4) + ";
1192 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1194 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1196 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1198 return "this.getHours() + ";
1200 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1202 return "String.leftPad(this.getHours(), 2, '0') + ";
1204 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1206 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1208 return "this.getGMTOffset() + ";
1210 return "this.getGMTColonOffset() + ";
1212 return "this.getTimezone() + ";
1214 return "(this.getTimezoneOffset() * -60) + ";
1216 return "'" + String.escape(character) + "' + ";
1221 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1222 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1223 * the date format that is not specified will default to the current date value for that part. Time parts can also
1224 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1225 * string or the parse operation will fail.
1228 //dt = Fri May 25 2007 (current date)
1229 var dt = new Date();
1231 //dt = Thu May 25 2006 (today's month/day in 2006)
1232 dt = Date.parseDate("2006", "Y");
1234 //dt = Sun Jan 15 2006 (all date parts specified)
1235 dt = Date.parseDate("2006-1-15", "Y-m-d");
1237 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1238 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1240 * @param {String} input The unparsed date as a string
1241 * @param {String} format The format the date is in
1242 * @return {Date} The parsed date
1245 Date.parseDate = function(input, format) {
1246 if (Date.parseFunctions[format] == null) {
1247 Date.createParser(format);
1249 var func = Date.parseFunctions[format];
1250 return Date[func](input);
1256 Date.createParser = function(format) {
1257 var funcName = "parse" + Date.parseFunctions.count++;
1258 var regexNum = Date.parseRegexes.length;
1259 var currentGroup = 1;
1260 Date.parseFunctions[format] = funcName;
1262 var code = "Date." + funcName + " = function(input){\n"
1263 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1264 + "var d = new Date();\n"
1265 + "y = d.getFullYear();\n"
1266 + "m = d.getMonth();\n"
1267 + "d = d.getDate();\n"
1268 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1269 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1270 + "if (results && results.length > 0) {";
1273 var special = false;
1275 for (var i = 0; i < format.length; ++i) {
1276 ch = format.charAt(i);
1277 if (!special && ch == "\\") {
1282 regex += String.escape(ch);
1285 var obj = Date.formatCodeToRegex(ch, currentGroup);
1286 currentGroup += obj.g;
1288 if (obj.g && obj.c) {
1294 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1295 + "{v = new Date(y, m, d, h, i, s);}\n"
1296 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1297 + "{v = new Date(y, m, d, h, i);}\n"
1298 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1299 + "{v = new Date(y, m, d, h);}\n"
1300 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1301 + "{v = new Date(y, m, d);}\n"
1302 + "else if (y >= 0 && m >= 0)\n"
1303 + "{v = new Date(y, m);}\n"
1304 + "else if (y >= 0)\n"
1305 + "{v = new Date(y);}\n"
1306 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1307 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1308 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1311 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1312 /** eval:var:zzzzzzzzzzzzz */
1317 Date.formatCodeToRegex = function(character, currentGroup) {
1318 switch (character) {
1322 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1325 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1326 s:"(\\d{1,2})"}; // day of month without leading zeroes
1329 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1330 s:"(\\d{2})"}; // day of month with leading zeroes
1334 s:"(?:" + Date.dayNames.join("|") + ")"};
1338 s:"(?:st|nd|rd|th)"};
1353 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1354 s:"(" + Date.monthNames.join("|") + ")"};
1357 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1358 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1361 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1362 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1365 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1366 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1377 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1381 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1382 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1386 c:"if (results[" + currentGroup + "] == 'am') {\n"
1387 + "if (h == 12) { h = 0; }\n"
1388 + "} else { if (h < 12) { h += 12; }}",
1392 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1393 + "if (h == 12) { h = 0; }\n"
1394 + "} else { if (h < 12) { h += 12; }}",
1399 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1400 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1404 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1405 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1408 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1412 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1417 "o = results[", currentGroup, "];\n",
1418 "var sn = o.substring(0,1);\n", // get + / - sign
1419 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1420 "var mn = o.substring(3,5) % 60;\n", // get minutes
1421 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1422 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1424 s:"([+\-]\\d{2,4})"};
1430 "o = results[", currentGroup, "];\n",
1431 "var sn = o.substring(0,1);\n",
1432 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1433 "var mn = o.substring(4,6) % 60;\n",
1434 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1435 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1441 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1444 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1445 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1446 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1450 s:String.escape(character)};
1455 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1456 * @return {String} The abbreviated timezone name (e.g. 'CST')
1458 Date.prototype.getTimezone = function() {
1459 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1463 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1464 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1466 Date.prototype.getGMTOffset = function() {
1467 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1468 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1469 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1473 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1474 * @return {String} 2-characters representing hours and 2-characters representing minutes
1475 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1477 Date.prototype.getGMTColonOffset = function() {
1478 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1479 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1481 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1485 * Get the numeric day number of the year, adjusted for leap year.
1486 * @return {Number} 0 through 364 (365 in leap years)
1488 Date.prototype.getDayOfYear = function() {
1490 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1491 for (var i = 0; i < this.getMonth(); ++i) {
1492 num += Date.daysInMonth[i];
1494 return num + this.getDate() - 1;
1498 * Get the string representation of the numeric week number of the year
1499 * (equivalent to the format specifier 'W').
1500 * @return {String} '00' through '52'
1502 Date.prototype.getWeekOfYear = function() {
1503 // Skip to Thursday of this week
1504 var now = this.getDayOfYear() + (4 - this.getDay());
1505 // Find the first Thursday of the year
1506 var jan1 = new Date(this.getFullYear(), 0, 1);
1507 var then = (7 - jan1.getDay() + 4);
1508 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1512 * Whether or not the current date is in a leap year.
1513 * @return {Boolean} True if the current date is in a leap year, else false
1515 Date.prototype.isLeapYear = function() {
1516 var year = this.getFullYear();
1517 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1521 * Get the first day of the current month, adjusted for leap year. The returned value
1522 * is the numeric day index within the week (0-6) which can be used in conjunction with
1523 * the {@link #monthNames} array to retrieve the textual day name.
1526 var dt = new Date('1/10/2007');
1527 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1529 * @return {Number} The day number (0-6)
1531 Date.prototype.getFirstDayOfMonth = function() {
1532 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1533 return (day < 0) ? (day + 7) : day;
1537 * Get the last day of the current month, adjusted for leap year. The returned value
1538 * is the numeric day index within the week (0-6) which can be used in conjunction with
1539 * the {@link #monthNames} array to retrieve the textual day name.
1542 var dt = new Date('1/10/2007');
1543 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1545 * @return {Number} The day number (0-6)
1547 Date.prototype.getLastDayOfMonth = function() {
1548 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1549 return (day < 0) ? (day + 7) : day;
1554 * Get the first date of this date's month
1557 Date.prototype.getFirstDateOfMonth = function() {
1558 return new Date(this.getFullYear(), this.getMonth(), 1);
1562 * Get the last date of this date's month
1565 Date.prototype.getLastDateOfMonth = function() {
1566 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1569 * Get the number of days in the current month, adjusted for leap year.
1570 * @return {Number} The number of days in the month
1572 Date.prototype.getDaysInMonth = function() {
1573 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1574 return Date.daysInMonth[this.getMonth()];
1578 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1579 * @return {String} 'st, 'nd', 'rd' or 'th'
1581 Date.prototype.getSuffix = function() {
1582 switch (this.getDate()) {
1599 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1602 * An array of textual month names.
1603 * Override these values for international dates, for example...
1604 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1623 * An array of textual day names.
1624 * Override these values for international dates, for example...
1625 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1641 Date.monthNumbers = {
1656 * Creates and returns a new Date instance with the exact same date value as the called instance.
1657 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1658 * variable will also be changed. When the intention is to create a new variable that will not
1659 * modify the original instance, you should create a clone.
1661 * Example of correctly cloning a date:
1664 var orig = new Date('10/1/2006');
1667 document.write(orig); //returns 'Thu Oct 05 2006'!
1670 var orig = new Date('10/1/2006');
1671 var copy = orig.clone();
1673 document.write(orig); //returns 'Thu Oct 01 2006'
1675 * @return {Date} The new Date instance
1677 Date.prototype.clone = function() {
1678 return new Date(this.getTime());
1682 * Clears any time information from this date
1683 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1684 @return {Date} this or the clone
1686 Date.prototype.clearTime = function(clone){
1688 return this.clone().clearTime();
1693 this.setMilliseconds(0);
1698 // safari setMonth is broken -- check that this is only donw once...
1699 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1700 Date.brokenSetMonth = Date.prototype.setMonth;
1701 Date.prototype.setMonth = function(num){
1703 var n = Math.ceil(-num);
1704 var back_year = Math.ceil(n/12);
1705 var month = (n % 12) ? 12 - n % 12 : 0 ;
1706 this.setFullYear(this.getFullYear() - back_year);
1707 return Date.brokenSetMonth.call(this, month);
1709 return Date.brokenSetMonth.apply(this, arguments);
1714 /** Date interval constant
1718 /** Date interval constant
1722 /** Date interval constant
1726 /** Date interval constant
1730 /** Date interval constant
1734 /** Date interval constant
1738 /** Date interval constant
1744 * Provides a convenient method of performing basic date arithmetic. This method
1745 * does not modify the Date instance being called - it creates and returns
1746 * a new Date instance containing the resulting date value.
1751 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1752 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1754 //Negative values will subtract correctly:
1755 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1756 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1758 //You can even chain several calls together in one line!
1759 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1760 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1763 * @param {String} interval A valid date interval enum value
1764 * @param {Number} value The amount to add to the current date
1765 * @return {Date} The new Date instance
1767 Date.prototype.add = function(interval, value){
1768 var d = this.clone();
1769 if (!interval || value === 0) { return d; }
1770 switch(interval.toLowerCase()){
1772 d.setMilliseconds(this.getMilliseconds() + value);
1775 d.setSeconds(this.getSeconds() + value);
1778 d.setMinutes(this.getMinutes() + value);
1781 d.setHours(this.getHours() + value);
1784 d.setDate(this.getDate() + value);
1787 var day = this.getDate();
1789 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1792 d.setMonth(this.getMonth() + value);
1795 d.setFullYear(this.getFullYear() + value);
1802 * Ext JS Library 1.1.1
1803 * Copyright(c) 2006-2007, Ext JS, LLC.
1805 * Originally Released Under LGPL - original licence link has changed is not relivant.
1808 * <script type="text/javascript">
1812 * @class Roo.lib.Dom
1815 * Dom utils (from YIU afaik)
1820 * Get the view width
1821 * @param {Boolean} full True will get the full document, otherwise it's the view width
1822 * @return {Number} The width
1825 getViewWidth : function(full) {
1826 return full ? this.getDocumentWidth() : this.getViewportWidth();
1829 * Get the view height
1830 * @param {Boolean} full True will get the full document, otherwise it's the view height
1831 * @return {Number} The height
1833 getViewHeight : function(full) {
1834 return full ? this.getDocumentHeight() : this.getViewportHeight();
1837 getDocumentHeight: function() {
1838 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1839 return Math.max(scrollHeight, this.getViewportHeight());
1842 getDocumentWidth: function() {
1843 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1844 return Math.max(scrollWidth, this.getViewportWidth());
1847 getViewportHeight: function() {
1848 var height = self.innerHeight;
1849 var mode = document.compatMode;
1851 if ((mode || Roo.isIE) && !Roo.isOpera) {
1852 height = (mode == "CSS1Compat") ?
1853 document.documentElement.clientHeight :
1854 document.body.clientHeight;
1860 getViewportWidth: function() {
1861 var width = self.innerWidth;
1862 var mode = document.compatMode;
1864 if (mode || Roo.isIE) {
1865 width = (mode == "CSS1Compat") ?
1866 document.documentElement.clientWidth :
1867 document.body.clientWidth;
1872 isAncestor : function(p, c) {
1879 if (p.contains && !Roo.isSafari) {
1880 return p.contains(c);
1881 } else if (p.compareDocumentPosition) {
1882 return !!(p.compareDocumentPosition(c) & 16);
1884 var parent = c.parentNode;
1889 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1892 parent = parent.parentNode;
1898 getRegion : function(el) {
1899 return Roo.lib.Region.getRegion(el);
1902 getY : function(el) {
1903 return this.getXY(el)[1];
1906 getX : function(el) {
1907 return this.getXY(el)[0];
1910 getXY : function(el) {
1911 var p, pe, b, scroll, bd = document.body;
1912 el = Roo.getDom(el);
1913 var fly = Roo.lib.AnimBase.fly;
1914 if (el.getBoundingClientRect) {
1915 b = el.getBoundingClientRect();
1916 scroll = fly(document).getScroll();
1917 return [b.left + scroll.left, b.top + scroll.top];
1923 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1930 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1937 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1938 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1945 if (p != el && pe.getStyle('overflow') != 'visible') {
1953 if (Roo.isSafari && hasAbsolute) {
1958 if (Roo.isGecko && !hasAbsolute) {
1960 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1961 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1965 while (p && p != bd) {
1966 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1978 setXY : function(el, xy) {
1979 el = Roo.fly(el, '_setXY');
1981 var pts = el.translatePoints(xy);
1982 if (xy[0] !== false) {
1983 el.dom.style.left = pts.left + "px";
1985 if (xy[1] !== false) {
1986 el.dom.style.top = pts.top + "px";
1990 setX : function(el, x) {
1991 this.setXY(el, [x, false]);
1994 setY : function(el, y) {
1995 this.setXY(el, [false, y]);
1999 * Portions of this file are based on pieces of Yahoo User Interface Library
2000 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2001 * YUI licensed under the BSD License:
2002 * http://developer.yahoo.net/yui/license.txt
2003 * <script type="text/javascript">
2007 Roo.lib.Event = function() {
2008 var loadComplete = false;
2010 var unloadListeners = [];
2012 var onAvailStack = [];
2014 var lastError = null;
2027 startInterval: function() {
2028 if (!this._interval) {
2030 var callback = function() {
2031 self._tryPreloadAttach();
2033 this._interval = setInterval(callback, this.POLL_INTERVAL);
2038 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2039 onAvailStack.push({ id: p_id,
2042 override: p_override,
2043 checkReady: false });
2045 retryCount = this.POLL_RETRYS;
2046 this.startInterval();
2050 addListener: function(el, eventName, fn) {
2051 el = Roo.getDom(el);
2056 if ("unload" == eventName) {
2057 unloadListeners[unloadListeners.length] =
2058 [el, eventName, fn];
2062 var wrappedFn = function(e) {
2063 return fn(Roo.lib.Event.getEvent(e));
2066 var li = [el, eventName, fn, wrappedFn];
2068 var index = listeners.length;
2069 listeners[index] = li;
2071 this.doAdd(el, eventName, wrappedFn, false);
2077 removeListener: function(el, eventName, fn) {
2080 el = Roo.getDom(el);
2083 return this.purgeElement(el, false, eventName);
2087 if ("unload" == eventName) {
2089 for (i = 0,len = unloadListeners.length; i < len; i++) {
2090 var li = unloadListeners[i];
2093 li[1] == eventName &&
2095 unloadListeners.splice(i, 1);
2103 var cacheItem = null;
2106 var index = arguments[3];
2108 if ("undefined" == typeof index) {
2109 index = this._getCacheIndex(el, eventName, fn);
2113 cacheItem = listeners[index];
2116 if (!el || !cacheItem) {
2120 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2122 delete listeners[index][this.WFN];
2123 delete listeners[index][this.FN];
2124 listeners.splice(index, 1);
2131 getTarget: function(ev, resolveTextNode) {
2132 ev = ev.browserEvent || ev;
2133 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2134 var t = ev.target || ev.srcElement;
2135 return this.resolveTextNode(t);
2139 resolveTextNode: function(node) {
2140 if (Roo.isSafari && node && 3 == node.nodeType) {
2141 return node.parentNode;
2148 getPageX: function(ev) {
2149 ev = ev.browserEvent || ev;
2150 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2152 if (!x && 0 !== x) {
2153 x = ev.clientX || 0;
2156 x += this.getScroll()[1];
2164 getPageY: function(ev) {
2165 ev = ev.browserEvent || ev;
2166 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2168 if (!y && 0 !== y) {
2169 y = ev.clientY || 0;
2172 y += this.getScroll()[0];
2181 getXY: function(ev) {
2182 ev = ev.browserEvent || ev;
2183 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2184 return [this.getPageX(ev), this.getPageY(ev)];
2188 getRelatedTarget: function(ev) {
2189 ev = ev.browserEvent || ev;
2190 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2191 var t = ev.relatedTarget;
2193 if (ev.type == "mouseout") {
2195 } else if (ev.type == "mouseover") {
2200 return this.resolveTextNode(t);
2204 getTime: function(ev) {
2205 ev = ev.browserEvent || ev;
2206 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2208 var t = new Date().getTime();
2212 this.lastError = ex;
2221 stopEvent: function(ev) {
2222 this.stopPropagation(ev);
2223 this.preventDefault(ev);
2227 stopPropagation: function(ev) {
2228 ev = ev.browserEvent || ev;
2229 if (ev.stopPropagation) {
2230 ev.stopPropagation();
2232 ev.cancelBubble = true;
2237 preventDefault: function(ev) {
2238 ev = ev.browserEvent || ev;
2239 if(ev.preventDefault) {
2240 ev.preventDefault();
2242 ev.returnValue = false;
2247 getEvent: function(e) {
2248 var ev = e || window.event;
2250 var c = this.getEvent.caller;
2252 ev = c.arguments[0];
2253 if (ev && Event == ev.constructor) {
2263 getCharCode: function(ev) {
2264 ev = ev.browserEvent || ev;
2265 return ev.charCode || ev.keyCode || 0;
2269 _getCacheIndex: function(el, eventName, fn) {
2270 for (var i = 0,len = listeners.length; i < len; ++i) {
2271 var li = listeners[i];
2273 li[this.FN] == fn &&
2274 li[this.EL] == el &&
2275 li[this.TYPE] == eventName) {
2287 getEl: function(id) {
2288 return document.getElementById(id);
2292 clearCache: function() {
2296 _load: function(e) {
2297 loadComplete = true;
2298 var EU = Roo.lib.Event;
2302 EU.doRemove(window, "load", EU._load);
2307 _tryPreloadAttach: function() {
2316 var tryAgain = !loadComplete;
2318 tryAgain = (retryCount > 0);
2323 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2324 var item = onAvailStack[i];
2326 var el = this.getEl(item.id);
2329 if (!item.checkReady ||
2332 (document && document.body)) {
2335 if (item.override) {
2336 if (item.override === true) {
2339 scope = item.override;
2342 item.fn.call(scope, item.obj);
2343 onAvailStack[i] = null;
2346 notAvail.push(item);
2351 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2355 this.startInterval();
2357 clearInterval(this._interval);
2358 this._interval = null;
2361 this.locked = false;
2368 purgeElement: function(el, recurse, eventName) {
2369 var elListeners = this.getListeners(el, eventName);
2371 for (var i = 0,len = elListeners.length; i < len; ++i) {
2372 var l = elListeners[i];
2373 this.removeListener(el, l.type, l.fn);
2377 if (recurse && el && el.childNodes) {
2378 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2379 this.purgeElement(el.childNodes[i], recurse, eventName);
2385 getListeners: function(el, eventName) {
2386 var results = [], searchLists;
2388 searchLists = [listeners, unloadListeners];
2389 } else if (eventName == "unload") {
2390 searchLists = [unloadListeners];
2392 searchLists = [listeners];
2395 for (var j = 0; j < searchLists.length; ++j) {
2396 var searchList = searchLists[j];
2397 if (searchList && searchList.length > 0) {
2398 for (var i = 0,len = searchList.length; i < len; ++i) {
2399 var l = searchList[i];
2400 if (l && l[this.EL] === el &&
2401 (!eventName || eventName === l[this.TYPE])) {
2406 adjust: l[this.ADJ_SCOPE],
2414 return (results.length) ? results : null;
2418 _unload: function(e) {
2420 var EU = Roo.lib.Event, i, j, l, len, index;
2422 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2423 l = unloadListeners[i];
2426 if (l[EU.ADJ_SCOPE]) {
2427 if (l[EU.ADJ_SCOPE] === true) {
2430 scope = l[EU.ADJ_SCOPE];
2433 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2434 unloadListeners[i] = null;
2440 unloadListeners = null;
2442 if (listeners && listeners.length > 0) {
2443 j = listeners.length;
2446 l = listeners[index];
2448 EU.removeListener(l[EU.EL], l[EU.TYPE],
2458 EU.doRemove(window, "unload", EU._unload);
2463 getScroll: function() {
2464 var dd = document.documentElement, db = document.body;
2465 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2466 return [dd.scrollTop, dd.scrollLeft];
2468 return [db.scrollTop, db.scrollLeft];
2475 doAdd: function () {
2476 if (window.addEventListener) {
2477 return function(el, eventName, fn, capture) {
2478 el.addEventListener(eventName, fn, (capture));
2480 } else if (window.attachEvent) {
2481 return function(el, eventName, fn, capture) {
2482 el.attachEvent("on" + eventName, fn);
2491 doRemove: function() {
2492 if (window.removeEventListener) {
2493 return function (el, eventName, fn, capture) {
2494 el.removeEventListener(eventName, fn, (capture));
2496 } else if (window.detachEvent) {
2497 return function (el, eventName, fn) {
2498 el.detachEvent("on" + eventName, fn);
2510 var E = Roo.lib.Event;
2511 E.on = E.addListener;
2512 E.un = E.removeListener;
2514 if (document && document.body) {
2517 E.doAdd(window, "load", E._load);
2519 E.doAdd(window, "unload", E._unload);
2520 E._tryPreloadAttach();
2524 * Portions of this file are based on pieces of Yahoo User Interface Library
2525 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2526 * YUI licensed under the BSD License:
2527 * http://developer.yahoo.net/yui/license.txt
2528 * <script type="text/javascript">
2534 * @class Roo.lib.Ajax
2541 request : function(method, uri, cb, data, options) {
2543 var hs = options.headers;
2546 if(hs.hasOwnProperty(h)){
2547 this.initHeader(h, hs[h], false);
2551 if(options.xmlData){
2552 this.initHeader('Content-Type', 'text/xml', false);
2554 data = options.xmlData;
2558 return this.asyncRequest(method, uri, cb, data);
2561 serializeForm : function(form) {
2562 if(typeof form == 'string') {
2563 form = (document.getElementById(form) || document.forms[form]);
2566 var el, name, val, disabled, data = '', hasSubmit = false;
2567 for (var i = 0; i < form.elements.length; i++) {
2568 el = form.elements[i];
2569 disabled = form.elements[i].disabled;
2570 name = form.elements[i].name;
2571 val = form.elements[i].value;
2573 if (!disabled && name){
2577 case 'select-multiple':
2578 for (var j = 0; j < el.options.length; j++) {
2579 if (el.options[j].selected) {
2581 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2584 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2592 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2605 if(hasSubmit == false) {
2606 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2611 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2616 data = data.substr(0, data.length - 1);
2624 useDefaultHeader:true,
2626 defaultPostHeader:'application/x-www-form-urlencoded',
2628 useDefaultXhrHeader:true,
2630 defaultXhrHeader:'XMLHttpRequest',
2632 hasDefaultHeaders:true,
2644 setProgId:function(id)
2646 this.activeX.unshift(id);
2649 setDefaultPostHeader:function(b)
2651 this.useDefaultHeader = b;
2654 setDefaultXhrHeader:function(b)
2656 this.useDefaultXhrHeader = b;
2659 setPollingInterval:function(i)
2661 if (typeof i == 'number' && isFinite(i)) {
2662 this.pollInterval = i;
2666 createXhrObject:function(transactionId)
2672 http = new XMLHttpRequest();
2674 obj = { conn:http, tId:transactionId };
2678 for (var i = 0; i < this.activeX.length; ++i) {
2682 http = new ActiveXObject(this.activeX[i]);
2684 obj = { conn:http, tId:transactionId };
2697 getConnectionObject:function()
2700 var tId = this.transactionId;
2704 o = this.createXhrObject(tId);
2706 this.transactionId++;
2717 asyncRequest:function(method, uri, callback, postData)
2719 var o = this.getConnectionObject();
2725 o.conn.open(method, uri, true);
2727 if (this.useDefaultXhrHeader) {
2728 if (!this.defaultHeaders['X-Requested-With']) {
2729 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2733 if(postData && this.useDefaultHeader){
2734 this.initHeader('Content-Type', this.defaultPostHeader);
2737 if (this.hasDefaultHeaders || this.hasHeaders) {
2741 this.handleReadyState(o, callback);
2742 o.conn.send(postData || null);
2748 handleReadyState:function(o, callback)
2752 if (callback && callback.timeout) {
2754 this.timeout[o.tId] = window.setTimeout(function() {
2755 oConn.abort(o, callback, true);
2756 }, callback.timeout);
2759 this.poll[o.tId] = window.setInterval(
2761 if (o.conn && o.conn.readyState == 4) {
2762 window.clearInterval(oConn.poll[o.tId]);
2763 delete oConn.poll[o.tId];
2765 if(callback && callback.timeout) {
2766 window.clearTimeout(oConn.timeout[o.tId]);
2767 delete oConn.timeout[o.tId];
2770 oConn.handleTransactionResponse(o, callback);
2773 , this.pollInterval);
2776 handleTransactionResponse:function(o, callback, isAbort)
2780 this.releaseObject(o);
2784 var httpStatus, responseObject;
2788 if (o.conn.status !== undefined && o.conn.status != 0) {
2789 httpStatus = o.conn.status;
2801 if (httpStatus >= 200 && httpStatus < 300) {
2802 responseObject = this.createResponseObject(o, callback.argument);
2803 if (callback.success) {
2804 if (!callback.scope) {
2805 callback.success(responseObject);
2810 callback.success.apply(callback.scope, [responseObject]);
2815 switch (httpStatus) {
2823 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2824 if (callback.failure) {
2825 if (!callback.scope) {
2826 callback.failure(responseObject);
2829 callback.failure.apply(callback.scope, [responseObject]);
2834 responseObject = this.createResponseObject(o, callback.argument);
2835 if (callback.failure) {
2836 if (!callback.scope) {
2837 callback.failure(responseObject);
2840 callback.failure.apply(callback.scope, [responseObject]);
2846 this.releaseObject(o);
2847 responseObject = null;
2850 createResponseObject:function(o, callbackArg)
2857 var headerStr = o.conn.getAllResponseHeaders();
2858 var header = headerStr.split('\n');
2859 for (var i = 0; i < header.length; i++) {
2860 var delimitPos = header[i].indexOf(':');
2861 if (delimitPos != -1) {
2862 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2870 obj.status = o.conn.status;
2871 obj.statusText = o.conn.statusText;
2872 obj.getResponseHeader = headerObj;
2873 obj.getAllResponseHeaders = headerStr;
2874 obj.responseText = o.conn.responseText;
2875 obj.responseXML = o.conn.responseXML;
2877 if (typeof callbackArg !== undefined) {
2878 obj.argument = callbackArg;
2884 createExceptionObject:function(tId, callbackArg, isAbort)
2887 var COMM_ERROR = 'communication failure';
2888 var ABORT_CODE = -1;
2889 var ABORT_ERROR = 'transaction aborted';
2895 obj.status = ABORT_CODE;
2896 obj.statusText = ABORT_ERROR;
2899 obj.status = COMM_CODE;
2900 obj.statusText = COMM_ERROR;
2904 obj.argument = callbackArg;
2910 initHeader:function(label, value, isDefault)
2912 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2914 if (headerObj[label] === undefined) {
2915 headerObj[label] = value;
2920 headerObj[label] = value + "," + headerObj[label];
2924 this.hasDefaultHeaders = true;
2927 this.hasHeaders = true;
2932 setHeader:function(o)
2934 if (this.hasDefaultHeaders) {
2935 for (var prop in this.defaultHeaders) {
2936 if (this.defaultHeaders.hasOwnProperty(prop)) {
2937 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2942 if (this.hasHeaders) {
2943 for (var prop in this.headers) {
2944 if (this.headers.hasOwnProperty(prop)) {
2945 o.conn.setRequestHeader(prop, this.headers[prop]);
2949 this.hasHeaders = false;
2953 resetDefaultHeaders:function() {
2954 delete this.defaultHeaders;
2955 this.defaultHeaders = {};
2956 this.hasDefaultHeaders = false;
2959 abort:function(o, callback, isTimeout)
2961 if(this.isCallInProgress(o)) {
2963 window.clearInterval(this.poll[o.tId]);
2964 delete this.poll[o.tId];
2966 delete this.timeout[o.tId];
2969 this.handleTransactionResponse(o, callback, true);
2979 isCallInProgress:function(o)
2982 return o.conn.readyState != 4 && o.conn.readyState != 0;
2991 releaseObject:function(o)
3000 'MSXML2.XMLHTTP.3.0',
3008 * Portions of this file are based on pieces of Yahoo User Interface Library
3009 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3010 * YUI licensed under the BSD License:
3011 * http://developer.yahoo.net/yui/license.txt
3012 * <script type="text/javascript">
3016 Roo.lib.Region = function(t, r, b, l) {
3026 Roo.lib.Region.prototype = {
3027 contains : function(region) {
3028 return ( region.left >= this.left &&
3029 region.right <= this.right &&
3030 region.top >= this.top &&
3031 region.bottom <= this.bottom );
3035 getArea : function() {
3036 return ( (this.bottom - this.top) * (this.right - this.left) );
3039 intersect : function(region) {
3040 var t = Math.max(this.top, region.top);
3041 var r = Math.min(this.right, region.right);
3042 var b = Math.min(this.bottom, region.bottom);
3043 var l = Math.max(this.left, region.left);
3045 if (b >= t && r >= l) {
3046 return new Roo.lib.Region(t, r, b, l);
3051 union : function(region) {
3052 var t = Math.min(this.top, region.top);
3053 var r = Math.max(this.right, region.right);
3054 var b = Math.max(this.bottom, region.bottom);
3055 var l = Math.min(this.left, region.left);
3057 return new Roo.lib.Region(t, r, b, l);
3060 adjust : function(t, l, b, r) {
3069 Roo.lib.Region.getRegion = function(el) {
3070 var p = Roo.lib.Dom.getXY(el);
3073 var r = p[0] + el.offsetWidth;
3074 var b = p[1] + el.offsetHeight;
3077 return new Roo.lib.Region(t, r, b, l);
3080 * Portions of this file are based on pieces of Yahoo User Interface Library
3081 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3082 * YUI licensed under the BSD License:
3083 * http://developer.yahoo.net/yui/license.txt
3084 * <script type="text/javascript">
3087 //@@dep Roo.lib.Region
3090 Roo.lib.Point = function(x, y) {
3091 if (x instanceof Array) {
3095 this.x = this.right = this.left = this[0] = x;
3096 this.y = this.top = this.bottom = this[1] = y;
3099 Roo.lib.Point.prototype = new Roo.lib.Region();
3101 * Portions of this file are based on pieces of Yahoo User Interface Library
3102 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3103 * YUI licensed under the BSD License:
3104 * http://developer.yahoo.net/yui/license.txt
3105 * <script type="text/javascript">
3112 scroll : function(el, args, duration, easing, cb, scope) {
3113 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3116 motion : function(el, args, duration, easing, cb, scope) {
3117 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3120 color : function(el, args, duration, easing, cb, scope) {
3121 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3124 run : function(el, args, duration, easing, cb, scope, type) {
3125 type = type || Roo.lib.AnimBase;
3126 if (typeof easing == "string") {
3127 easing = Roo.lib.Easing[easing];
3129 var anim = new type(el, args, duration, easing);
3130 anim.animateX(function() {
3131 Roo.callback(cb, scope);
3137 * Portions of this file are based on pieces of Yahoo User Interface Library
3138 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3139 * YUI licensed under the BSD License:
3140 * http://developer.yahoo.net/yui/license.txt
3141 * <script type="text/javascript">
3149 if (!libFlyweight) {
3150 libFlyweight = new Roo.Element.Flyweight();
3152 libFlyweight.dom = el;
3153 return libFlyweight;
3156 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3160 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3162 this.init(el, attributes, duration, method);
3166 Roo.lib.AnimBase.fly = fly;
3170 Roo.lib.AnimBase.prototype = {
3172 toString: function() {
3173 var el = this.getEl();
3174 var id = el.id || el.tagName;
3175 return ("Anim " + id);
3179 noNegatives: /width|height|opacity|padding/i,
3180 offsetAttribute: /^((width|height)|(top|left))$/,
3181 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3182 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3186 doMethod: function(attr, start, end) {
3187 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3191 setAttribute: function(attr, val, unit) {
3192 if (this.patterns.noNegatives.test(attr)) {
3193 val = (val > 0) ? val : 0;
3196 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3200 getAttribute: function(attr) {
3201 var el = this.getEl();
3202 var val = fly(el).getStyle(attr);
3204 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3205 return parseFloat(val);
3208 var a = this.patterns.offsetAttribute.exec(attr) || [];
3209 var pos = !!( a[3] );
3210 var box = !!( a[2] );
3213 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3214 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3223 getDefaultUnit: function(attr) {
3224 if (this.patterns.defaultUnit.test(attr)) {
3231 animateX : function(callback, scope) {
3232 var f = function() {
3233 this.onComplete.removeListener(f);
3234 if (typeof callback == "function") {
3235 callback.call(scope || this, this);
3238 this.onComplete.addListener(f, this);
3243 setRuntimeAttribute: function(attr) {
3246 var attributes = this.attributes;
3248 this.runtimeAttributes[attr] = {};
3250 var isset = function(prop) {
3251 return (typeof prop !== 'undefined');
3254 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3258 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3261 if (isset(attributes[attr]['to'])) {
3262 end = attributes[attr]['to'];
3263 } else if (isset(attributes[attr]['by'])) {
3264 if (start.constructor == Array) {
3266 for (var i = 0, len = start.length; i < len; ++i) {
3267 end[i] = start[i] + attributes[attr]['by'][i];
3270 end = start + attributes[attr]['by'];
3274 this.runtimeAttributes[attr].start = start;
3275 this.runtimeAttributes[attr].end = end;
3278 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3282 init: function(el, attributes, duration, method) {
3284 var isAnimated = false;
3287 var startTime = null;
3290 var actualFrames = 0;
3293 el = Roo.getDom(el);
3296 this.attributes = attributes || {};
3299 this.duration = duration || 1;
3302 this.method = method || Roo.lib.Easing.easeNone;
3305 this.useSeconds = true;
3308 this.currentFrame = 0;
3311 this.totalFrames = Roo.lib.AnimMgr.fps;
3314 this.getEl = function() {
3319 this.isAnimated = function() {
3324 this.getStartTime = function() {
3328 this.runtimeAttributes = {};
3331 this.animate = function() {
3332 if (this.isAnimated()) {
3336 this.currentFrame = 0;
3338 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3340 Roo.lib.AnimMgr.registerElement(this);
3344 this.stop = function(finish) {
3346 this.currentFrame = this.totalFrames;
3347 this._onTween.fire();
3349 Roo.lib.AnimMgr.stop(this);
3352 var onStart = function() {
3353 this.onStart.fire();
3355 this.runtimeAttributes = {};
3356 for (var attr in this.attributes) {
3357 this.setRuntimeAttribute(attr);
3362 startTime = new Date();
3366 var onTween = function() {
3368 duration: new Date() - this.getStartTime(),
3369 currentFrame: this.currentFrame
3372 data.toString = function() {
3374 'duration: ' + data.duration +
3375 ', currentFrame: ' + data.currentFrame
3379 this.onTween.fire(data);
3381 var runtimeAttributes = this.runtimeAttributes;
3383 for (var attr in runtimeAttributes) {
3384 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3390 var onComplete = function() {
3391 var actual_duration = (new Date() - startTime) / 1000 ;
3394 duration: actual_duration,
3395 frames: actualFrames,
3396 fps: actualFrames / actual_duration
3399 data.toString = function() {
3401 'duration: ' + data.duration +
3402 ', frames: ' + data.frames +
3403 ', fps: ' + data.fps
3409 this.onComplete.fire(data);
3413 this._onStart = new Roo.util.Event(this);
3414 this.onStart = new Roo.util.Event(this);
3415 this.onTween = new Roo.util.Event(this);
3416 this._onTween = new Roo.util.Event(this);
3417 this.onComplete = new Roo.util.Event(this);
3418 this._onComplete = new Roo.util.Event(this);
3419 this._onStart.addListener(onStart);
3420 this._onTween.addListener(onTween);
3421 this._onComplete.addListener(onComplete);
3426 * Portions of this file are based on pieces of Yahoo User Interface Library
3427 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3428 * YUI licensed under the BSD License:
3429 * http://developer.yahoo.net/yui/license.txt
3430 * <script type="text/javascript">
3434 Roo.lib.AnimMgr = new function() {
3451 this.registerElement = function(tween) {
3452 queue[queue.length] = tween;
3454 tween._onStart.fire();
3459 this.unRegister = function(tween, index) {
3460 tween._onComplete.fire();
3461 index = index || getIndex(tween);
3463 queue.splice(index, 1);
3467 if (tweenCount <= 0) {
3473 this.start = function() {
3474 if (thread === null) {
3475 thread = setInterval(this.run, this.delay);
3480 this.stop = function(tween) {
3482 clearInterval(thread);
3484 for (var i = 0, len = queue.length; i < len; ++i) {
3485 if (queue[0].isAnimated()) {
3486 this.unRegister(queue[0], 0);
3495 this.unRegister(tween);
3500 this.run = function() {
3501 for (var i = 0, len = queue.length; i < len; ++i) {
3502 var tween = queue[i];
3503 if (!tween || !tween.isAnimated()) {
3507 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3509 tween.currentFrame += 1;
3511 if (tween.useSeconds) {
3512 correctFrame(tween);
3514 tween._onTween.fire();
3517 Roo.lib.AnimMgr.stop(tween, i);
3522 var getIndex = function(anim) {
3523 for (var i = 0, len = queue.length; i < len; ++i) {
3524 if (queue[i] == anim) {
3532 var correctFrame = function(tween) {
3533 var frames = tween.totalFrames;
3534 var frame = tween.currentFrame;
3535 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3536 var elapsed = (new Date() - tween.getStartTime());
3539 if (elapsed < tween.duration * 1000) {
3540 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3542 tweak = frames - (frame + 1);
3544 if (tweak > 0 && isFinite(tweak)) {
3545 if (tween.currentFrame + tweak >= frames) {
3546 tweak = frames - (frame + 1);
3549 tween.currentFrame += tweak;
3555 * Portions of this file are based on pieces of Yahoo User Interface Library
3556 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3557 * YUI licensed under the BSD License:
3558 * http://developer.yahoo.net/yui/license.txt
3559 * <script type="text/javascript">
3562 Roo.lib.Bezier = new function() {
3564 this.getPosition = function(points, t) {
3565 var n = points.length;
3568 for (var i = 0; i < n; ++i) {
3569 tmp[i] = [points[i][0], points[i][1]];
3572 for (var j = 1; j < n; ++j) {
3573 for (i = 0; i < n - j; ++i) {
3574 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3575 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3579 return [ tmp[0][0], tmp[0][1] ];
3583 * Portions of this file are based on pieces of Yahoo User Interface Library
3584 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3585 * YUI licensed under the BSD License:
3586 * http://developer.yahoo.net/yui/license.txt
3587 * <script type="text/javascript">
3592 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3593 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3596 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3598 var fly = Roo.lib.AnimBase.fly;
3600 var superclass = Y.ColorAnim.superclass;
3601 var proto = Y.ColorAnim.prototype;
3603 proto.toString = function() {
3604 var el = this.getEl();
3605 var id = el.id || el.tagName;
3606 return ("ColorAnim " + id);
3609 proto.patterns.color = /color$/i;
3610 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3611 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3612 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3613 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3616 proto.parseColor = function(s) {
3617 if (s.length == 3) {
3621 var c = this.patterns.hex.exec(s);
3622 if (c && c.length == 4) {
3623 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3626 c = this.patterns.rgb.exec(s);
3627 if (c && c.length == 4) {
3628 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3631 c = this.patterns.hex3.exec(s);
3632 if (c && c.length == 4) {
3633 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3638 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3639 proto.getAttribute = function(attr) {
3640 var el = this.getEl();
3641 if (this.patterns.color.test(attr)) {
3642 var val = fly(el).getStyle(attr);
3644 if (this.patterns.transparent.test(val)) {
3645 var parent = el.parentNode;
3646 val = fly(parent).getStyle(attr);
3648 while (parent && this.patterns.transparent.test(val)) {
3649 parent = parent.parentNode;
3650 val = fly(parent).getStyle(attr);
3651 if (parent.tagName.toUpperCase() == 'HTML') {
3657 val = superclass.getAttribute.call(this, attr);
3662 proto.getAttribute = function(attr) {
3663 var el = this.getEl();
3664 if (this.patterns.color.test(attr)) {
3665 var val = fly(el).getStyle(attr);
3667 if (this.patterns.transparent.test(val)) {
3668 var parent = el.parentNode;
3669 val = fly(parent).getStyle(attr);
3671 while (parent && this.patterns.transparent.test(val)) {
3672 parent = parent.parentNode;
3673 val = fly(parent).getStyle(attr);
3674 if (parent.tagName.toUpperCase() == 'HTML') {
3680 val = superclass.getAttribute.call(this, attr);
3686 proto.doMethod = function(attr, start, end) {
3689 if (this.patterns.color.test(attr)) {
3691 for (var i = 0, len = start.length; i < len; ++i) {
3692 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3695 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3698 val = superclass.doMethod.call(this, attr, start, end);
3704 proto.setRuntimeAttribute = function(attr) {
3705 superclass.setRuntimeAttribute.call(this, attr);
3707 if (this.patterns.color.test(attr)) {
3708 var attributes = this.attributes;
3709 var start = this.parseColor(this.runtimeAttributes[attr].start);
3710 var end = this.parseColor(this.runtimeAttributes[attr].end);
3712 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3713 end = this.parseColor(attributes[attr].by);
3715 for (var i = 0, len = start.length; i < len; ++i) {
3716 end[i] = start[i] + end[i];
3720 this.runtimeAttributes[attr].start = start;
3721 this.runtimeAttributes[attr].end = end;
3727 * Portions of this file are based on pieces of Yahoo User Interface Library
3728 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3729 * YUI licensed under the BSD License:
3730 * http://developer.yahoo.net/yui/license.txt
3731 * <script type="text/javascript">
3737 easeNone: function (t, b, c, d) {
3738 return c * t / d + b;
3742 easeIn: function (t, b, c, d) {
3743 return c * (t /= d) * t + b;
3747 easeOut: function (t, b, c, d) {
3748 return -c * (t /= d) * (t - 2) + b;
3752 easeBoth: function (t, b, c, d) {
3753 if ((t /= d / 2) < 1) {
3754 return c / 2 * t * t + b;
3757 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3761 easeInStrong: function (t, b, c, d) {
3762 return c * (t /= d) * t * t * t + b;
3766 easeOutStrong: function (t, b, c, d) {
3767 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3771 easeBothStrong: function (t, b, c, d) {
3772 if ((t /= d / 2) < 1) {
3773 return c / 2 * t * t * t * t + b;
3776 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3781 elasticIn: function (t, b, c, d, a, p) {
3785 if ((t /= d) == 1) {
3792 if (!a || a < Math.abs(c)) {
3797 var s = p / (2 * Math.PI) * Math.asin(c / a);
3800 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3804 elasticOut: function (t, b, c, d, a, p) {
3808 if ((t /= d) == 1) {
3815 if (!a || a < Math.abs(c)) {
3820 var s = p / (2 * Math.PI) * Math.asin(c / a);
3823 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3827 elasticBoth: function (t, b, c, d, a, p) {
3832 if ((t /= d / 2) == 2) {
3840 if (!a || a < Math.abs(c)) {
3845 var s = p / (2 * Math.PI) * Math.asin(c / a);
3849 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3850 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3852 return a * Math.pow(2, -10 * (t -= 1)) *
3853 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3858 backIn: function (t, b, c, d, s) {
3859 if (typeof s == 'undefined') {
3862 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3866 backOut: function (t, b, c, d, s) {
3867 if (typeof s == 'undefined') {
3870 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3874 backBoth: function (t, b, c, d, s) {
3875 if (typeof s == 'undefined') {
3879 if ((t /= d / 2 ) < 1) {
3880 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3882 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3886 bounceIn: function (t, b, c, d) {
3887 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3891 bounceOut: function (t, b, c, d) {
3892 if ((t /= d) < (1 / 2.75)) {
3893 return c * (7.5625 * t * t) + b;
3894 } else if (t < (2 / 2.75)) {
3895 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3896 } else if (t < (2.5 / 2.75)) {
3897 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3899 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3903 bounceBoth: function (t, b, c, d) {
3905 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3907 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3910 * Portions of this file are based on pieces of Yahoo User Interface Library
3911 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3912 * YUI licensed under the BSD License:
3913 * http://developer.yahoo.net/yui/license.txt
3914 * <script type="text/javascript">
3918 Roo.lib.Motion = function(el, attributes, duration, method) {
3920 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3924 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3928 var superclass = Y.Motion.superclass;
3929 var proto = Y.Motion.prototype;
3931 proto.toString = function() {
3932 var el = this.getEl();
3933 var id = el.id || el.tagName;
3934 return ("Motion " + id);
3937 proto.patterns.points = /^points$/i;
3939 proto.setAttribute = function(attr, val, unit) {
3940 if (this.patterns.points.test(attr)) {
3941 unit = unit || 'px';
3942 superclass.setAttribute.call(this, 'left', val[0], unit);
3943 superclass.setAttribute.call(this, 'top', val[1], unit);
3945 superclass.setAttribute.call(this, attr, val, unit);
3949 proto.getAttribute = function(attr) {
3950 if (this.patterns.points.test(attr)) {
3952 superclass.getAttribute.call(this, 'left'),
3953 superclass.getAttribute.call(this, 'top')
3956 val = superclass.getAttribute.call(this, attr);
3962 proto.doMethod = function(attr, start, end) {
3965 if (this.patterns.points.test(attr)) {
3966 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3967 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3969 val = superclass.doMethod.call(this, attr, start, end);
3974 proto.setRuntimeAttribute = function(attr) {
3975 if (this.patterns.points.test(attr)) {
3976 var el = this.getEl();
3977 var attributes = this.attributes;
3979 var control = attributes['points']['control'] || [];
3983 if (control.length > 0 && !(control[0] instanceof Array)) {
3984 control = [control];
3987 for (i = 0,len = control.length; i < len; ++i) {
3988 tmp[i] = control[i];
3993 Roo.fly(el).position();
3995 if (isset(attributes['points']['from'])) {
3996 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3999 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4002 start = this.getAttribute('points');
4005 if (isset(attributes['points']['to'])) {
4006 end = translateValues.call(this, attributes['points']['to'], start);
4008 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4009 for (i = 0,len = control.length; i < len; ++i) {
4010 control[i] = translateValues.call(this, control[i], start);
4014 } else if (isset(attributes['points']['by'])) {
4015 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4017 for (i = 0,len = control.length; i < len; ++i) {
4018 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4022 this.runtimeAttributes[attr] = [start];
4024 if (control.length > 0) {
4025 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4028 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4031 superclass.setRuntimeAttribute.call(this, attr);
4035 var translateValues = function(val, start) {
4036 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4037 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4042 var isset = function(prop) {
4043 return (typeof prop !== 'undefined');
4047 * Portions of this file are based on pieces of Yahoo User Interface Library
4048 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4049 * YUI licensed under the BSD License:
4050 * http://developer.yahoo.net/yui/license.txt
4051 * <script type="text/javascript">
4055 Roo.lib.Scroll = function(el, attributes, duration, method) {
4057 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4061 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4065 var superclass = Y.Scroll.superclass;
4066 var proto = Y.Scroll.prototype;
4068 proto.toString = function() {
4069 var el = this.getEl();
4070 var id = el.id || el.tagName;
4071 return ("Scroll " + id);
4074 proto.doMethod = function(attr, start, end) {
4077 if (attr == 'scroll') {
4079 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4080 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4084 val = superclass.doMethod.call(this, attr, start, end);
4089 proto.getAttribute = function(attr) {
4091 var el = this.getEl();
4093 if (attr == 'scroll') {
4094 val = [ el.scrollLeft, el.scrollTop ];
4096 val = superclass.getAttribute.call(this, attr);
4102 proto.setAttribute = function(attr, val, unit) {
4103 var el = this.getEl();
4105 if (attr == 'scroll') {
4106 el.scrollLeft = val[0];
4107 el.scrollTop = val[1];
4109 superclass.setAttribute.call(this, attr, val, unit);
4115 * Ext JS Library 1.1.1
4116 * Copyright(c) 2006-2007, Ext JS, LLC.
4118 * Originally Released Under LGPL - original licence link has changed is not relivant.
4121 * <script type="text/javascript">
4125 // nasty IE9 hack - what a pile of crap that is..
4127 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4128 Range.prototype.createContextualFragment = function (html) {
4129 var doc = window.document;
4130 var container = doc.createElement("div");
4131 container.innerHTML = html;
4132 var frag = doc.createDocumentFragment(), n;
4133 while ((n = container.firstChild)) {
4134 frag.appendChild(n);
4141 * @class Roo.DomHelper
4142 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4143 * 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>.
4146 Roo.DomHelper = function(){
4147 var tempTableEl = null;
4148 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4149 var tableRe = /^table|tbody|tr|td$/i;
4151 // build as innerHTML where available
4153 var createHtml = function(o){
4154 if(typeof o == 'string'){
4163 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4164 if(attr == "style"){
4166 if(typeof s == "function"){
4169 if(typeof s == "string"){
4170 b += ' style="' + s + '"';
4171 }else if(typeof s == "object"){
4174 if(typeof s[key] != "function"){
4175 b += key + ":" + s[key] + ";";
4182 b += ' class="' + o["cls"] + '"';
4183 }else if(attr == "htmlFor"){
4184 b += ' for="' + o["htmlFor"] + '"';
4186 b += " " + attr + '="' + o[attr] + '"';
4190 if(emptyTags.test(o.tag)){
4194 var cn = o.children || o.cn;
4196 //http://bugs.kde.org/show_bug.cgi?id=71506
4197 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4198 for(var i = 0, len = cn.length; i < len; i++) {
4199 b += createHtml(cn[i], b);
4202 b += createHtml(cn, b);
4208 b += "</" + o.tag + ">";
4215 var createDom = function(o, parentNode){
4217 // defininition craeted..
4219 if (o.ns && o.ns != 'html') {
4221 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4222 xmlns[o.ns] = o.xmlns;
4225 if (typeof(xmlns[o.ns]) == 'undefined') {
4226 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4232 if (typeof(o) == 'string') {
4233 return parentNode.appendChild(document.createTextNode(o));
4235 o.tag = o.tag || div;
4236 if (o.ns && Roo.isIE) {
4238 o.tag = o.ns + ':' + o.tag;
4241 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4242 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4245 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4246 attr == "style" || typeof o[attr] == "function") { continue; }
4248 if(attr=="cls" && Roo.isIE){
4249 el.className = o["cls"];
4251 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4257 Roo.DomHelper.applyStyles(el, o.style);
4258 var cn = o.children || o.cn;
4260 //http://bugs.kde.org/show_bug.cgi?id=71506
4261 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4262 for(var i = 0, len = cn.length; i < len; i++) {
4263 createDom(cn[i], el);
4270 el.innerHTML = o.html;
4273 parentNode.appendChild(el);
4278 var ieTable = function(depth, s, h, e){
4279 tempTableEl.innerHTML = [s, h, e].join('');
4280 var i = -1, el = tempTableEl;
4287 // kill repeat to save bytes
4291 tbe = '</tbody>'+te,
4297 * Nasty code for IE's broken table implementation
4299 var insertIntoTable = function(tag, where, el, html){
4301 tempTableEl = document.createElement('div');
4306 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4309 if(where == 'beforebegin'){
4313 before = el.nextSibling;
4316 node = ieTable(4, trs, html, tre);
4318 else if(tag == 'tr'){
4319 if(where == 'beforebegin'){
4322 node = ieTable(3, tbs, html, tbe);
4323 } else if(where == 'afterend'){
4324 before = el.nextSibling;
4326 node = ieTable(3, tbs, html, tbe);
4327 } else{ // INTO a TR
4328 if(where == 'afterbegin'){
4329 before = el.firstChild;
4331 node = ieTable(4, trs, html, tre);
4333 } else if(tag == 'tbody'){
4334 if(where == 'beforebegin'){
4337 node = ieTable(2, ts, html, te);
4338 } else if(where == 'afterend'){
4339 before = el.nextSibling;
4341 node = ieTable(2, ts, html, te);
4343 if(where == 'afterbegin'){
4344 before = el.firstChild;
4346 node = ieTable(3, tbs, html, tbe);
4349 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4352 if(where == 'afterbegin'){
4353 before = el.firstChild;
4355 node = ieTable(2, ts, html, te);
4357 el.insertBefore(node, before);
4362 /** True to force the use of DOM instead of html fragments @type Boolean */
4366 * Returns the markup for the passed Element(s) config
4367 * @param {Object} o The Dom object spec (and children)
4370 markup : function(o){
4371 return createHtml(o);
4375 * Applies a style specification to an element
4376 * @param {String/HTMLElement} el The element to apply styles to
4377 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4378 * a function which returns such a specification.
4380 applyStyles : function(el, styles){
4383 if(typeof styles == "string"){
4384 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4386 while ((matches = re.exec(styles)) != null){
4387 el.setStyle(matches[1], matches[2]);
4389 }else if (typeof styles == "object"){
4390 for (var style in styles){
4391 el.setStyle(style, styles[style]);
4393 }else if (typeof styles == "function"){
4394 Roo.DomHelper.applyStyles(el, styles.call());
4400 * Inserts an HTML fragment into the Dom
4401 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4402 * @param {HTMLElement} el The context element
4403 * @param {String} html The HTML fragmenet
4404 * @return {HTMLElement} The new node
4406 insertHtml : function(where, el, html){
4407 where = where.toLowerCase();
4408 if(el.insertAdjacentHTML){
4409 if(tableRe.test(el.tagName)){
4411 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4417 el.insertAdjacentHTML('BeforeBegin', html);
4418 return el.previousSibling;
4420 el.insertAdjacentHTML('AfterBegin', html);
4421 return el.firstChild;
4423 el.insertAdjacentHTML('BeforeEnd', html);
4424 return el.lastChild;
4426 el.insertAdjacentHTML('AfterEnd', html);
4427 return el.nextSibling;
4429 throw 'Illegal insertion point -> "' + where + '"';
4431 var range = el.ownerDocument.createRange();
4435 range.setStartBefore(el);
4436 frag = range.createContextualFragment(html);
4437 el.parentNode.insertBefore(frag, el);
4438 return el.previousSibling;
4441 range.setStartBefore(el.firstChild);
4442 frag = range.createContextualFragment(html);
4443 el.insertBefore(frag, el.firstChild);
4444 return el.firstChild;
4446 el.innerHTML = html;
4447 return el.firstChild;
4451 range.setStartAfter(el.lastChild);
4452 frag = range.createContextualFragment(html);
4453 el.appendChild(frag);
4454 return el.lastChild;
4456 el.innerHTML = html;
4457 return el.lastChild;
4460 range.setStartAfter(el);
4461 frag = range.createContextualFragment(html);
4462 el.parentNode.insertBefore(frag, el.nextSibling);
4463 return el.nextSibling;
4465 throw 'Illegal insertion point -> "' + where + '"';
4469 * Creates new Dom element(s) and inserts them before el
4470 * @param {String/HTMLElement/Element} el The context element
4471 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4472 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4473 * @return {HTMLElement/Roo.Element} The new node
4475 insertBefore : function(el, o, returnElement){
4476 return this.doInsert(el, o, returnElement, "beforeBegin");
4480 * Creates new Dom element(s) and inserts them after el
4481 * @param {String/HTMLElement/Element} el The context element
4482 * @param {Object} o The Dom object spec (and children)
4483 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4484 * @return {HTMLElement/Roo.Element} The new node
4486 insertAfter : function(el, o, returnElement){
4487 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4491 * Creates new Dom element(s) and inserts them as the first child of el
4492 * @param {String/HTMLElement/Element} el The context element
4493 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4494 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4495 * @return {HTMLElement/Roo.Element} The new node
4497 insertFirst : function(el, o, returnElement){
4498 return this.doInsert(el, o, returnElement, "afterBegin");
4502 doInsert : function(el, o, returnElement, pos, sibling){
4503 el = Roo.getDom(el);
4505 if(this.useDom || o.ns){
4506 newNode = createDom(o, null);
4507 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4509 var html = createHtml(o);
4510 newNode = this.insertHtml(pos, el, html);
4512 return returnElement ? Roo.get(newNode, true) : newNode;
4516 * Creates new Dom element(s) and appends them to el
4517 * @param {String/HTMLElement/Element} el The context element
4518 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4519 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4520 * @return {HTMLElement/Roo.Element} The new node
4522 append : function(el, o, returnElement){
4523 el = Roo.getDom(el);
4525 if(this.useDom || o.ns){
4526 newNode = createDom(o, null);
4527 el.appendChild(newNode);
4529 var html = createHtml(o);
4530 newNode = this.insertHtml("beforeEnd", el, html);
4532 return returnElement ? Roo.get(newNode, true) : newNode;
4536 * Creates new Dom element(s) and overwrites the contents of el with them
4537 * @param {String/HTMLElement/Element} el The context element
4538 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4539 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4540 * @return {HTMLElement/Roo.Element} The new node
4542 overwrite : function(el, o, returnElement){
4543 el = Roo.getDom(el);
4546 while (el.childNodes.length) {
4547 el.removeChild(el.firstChild);
4551 el.innerHTML = createHtml(o);
4554 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4558 * Creates a new Roo.DomHelper.Template from the Dom object spec
4559 * @param {Object} o The Dom object spec (and children)
4560 * @return {Roo.DomHelper.Template} The new template
4562 createTemplate : function(o){
4563 var html = createHtml(o);
4564 return new Roo.Template(html);
4570 * Ext JS Library 1.1.1
4571 * Copyright(c) 2006-2007, Ext JS, LLC.
4573 * Originally Released Under LGPL - original licence link has changed is not relivant.
4576 * <script type="text/javascript">
4580 * @class Roo.Template
4581 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4582 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4585 var t = new Roo.Template({
4586 html : '<div name="{id}">' +
4587 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4589 myformat: function (value, allValues) {
4590 return 'XX' + value;
4593 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4595 * For more information see this blog post with examples:
4596 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4597 - Create Elements using DOM, HTML fragments and Templates</a>.
4599 * @param {Object} cfg - Configuration object.
4601 Roo.Template = function(cfg){
4603 if(cfg instanceof Array){
4605 }else if(arguments.length > 1){
4606 cfg = Array.prototype.join.call(arguments, "");
4610 if (typeof(cfg) == 'object') {
4621 Roo.Template.prototype = {
4624 * @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..
4625 * it should be fixed so that template is observable...
4629 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4633 * Returns an HTML fragment of this template with the specified values applied.
4634 * @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'})
4635 * @return {String} The HTML fragment
4637 applyTemplate : function(values){
4641 return this.compiled(values);
4643 var useF = this.disableFormats !== true;
4644 var fm = Roo.util.Format, tpl = this;
4645 var fn = function(m, name, format, args){
4647 if(format.substr(0, 5) == "this."){
4648 return tpl.call(format.substr(5), values[name], values);
4651 // quoted values are required for strings in compiled templates,
4652 // but for non compiled we need to strip them
4653 // quoted reversed for jsmin
4654 var re = /^\s*['"](.*)["']\s*$/;
4655 args = args.split(',');
4656 for(var i = 0, len = args.length; i < len; i++){
4657 args[i] = args[i].replace(re, "$1");
4659 args = [values[name]].concat(args);
4661 args = [values[name]];
4663 return fm[format].apply(fm, args);
4666 return values[name] !== undefined ? values[name] : "";
4669 return this.html.replace(this.re, fn);
4687 this.loading = true;
4688 this.compiled = false;
4690 var cx = new Roo.data.Connection();
4694 success : function (response) {
4696 _t.html = response.responseText;
4700 failure : function(response) {
4701 Roo.log("Template failed to load from " + _t.url);
4708 * Sets the HTML used as the template and optionally compiles it.
4709 * @param {String} html
4710 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4711 * @return {Roo.Template} this
4713 set : function(html, compile){
4715 this.compiled = null;
4723 * True to disable format functions (defaults to false)
4726 disableFormats : false,
4729 * The regular expression used to match template variables
4733 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4736 * Compiles the template into an internal function, eliminating the RegEx overhead.
4737 * @return {Roo.Template} this
4739 compile : function(){
4740 var fm = Roo.util.Format;
4741 var useF = this.disableFormats !== true;
4742 var sep = Roo.isGecko ? "+" : ",";
4743 var fn = function(m, name, format, args){
4745 args = args ? ',' + args : "";
4746 if(format.substr(0, 5) != "this."){
4747 format = "fm." + format + '(';
4749 format = 'this.call("'+ format.substr(5) + '", ';
4753 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4755 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4758 // branched to use + in gecko and [].join() in others
4760 body = "this.compiled = function(values){ return '" +
4761 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4764 body = ["this.compiled = function(values){ return ['"];
4765 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4766 body.push("'].join('');};");
4767 body = body.join('');
4777 // private function used to call members
4778 call : function(fnName, value, allValues){
4779 return this[fnName](value, allValues);
4783 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4784 * @param {String/HTMLElement/Roo.Element} el The context element
4785 * @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'})
4786 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4787 * @return {HTMLElement/Roo.Element} The new node or Element
4789 insertFirst: function(el, values, returnElement){
4790 return this.doInsert('afterBegin', el, values, returnElement);
4794 * Applies the supplied values to the template and inserts the new node(s) before el.
4795 * @param {String/HTMLElement/Roo.Element} el The context element
4796 * @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'})
4797 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4798 * @return {HTMLElement/Roo.Element} The new node or Element
4800 insertBefore: function(el, values, returnElement){
4801 return this.doInsert('beforeBegin', el, values, returnElement);
4805 * Applies the supplied values to the template and inserts the new node(s) after el.
4806 * @param {String/HTMLElement/Roo.Element} el The context element
4807 * @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'})
4808 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4809 * @return {HTMLElement/Roo.Element} The new node or Element
4811 insertAfter : function(el, values, returnElement){
4812 return this.doInsert('afterEnd', el, values, returnElement);
4816 * Applies the supplied values to the template and appends the new node(s) to 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 append : function(el, values, returnElement){
4823 return this.doInsert('beforeEnd', el, values, returnElement);
4826 doInsert : function(where, el, values, returnEl){
4827 el = Roo.getDom(el);
4828 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4829 return returnEl ? Roo.get(newNode, true) : newNode;
4833 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4834 * @param {String/HTMLElement/Roo.Element} el The context element
4835 * @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'})
4836 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4837 * @return {HTMLElement/Roo.Element} The new node or Element
4839 overwrite : function(el, values, returnElement){
4840 el = Roo.getDom(el);
4841 el.innerHTML = this.applyTemplate(values);
4842 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4846 * Alias for {@link #applyTemplate}
4849 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4852 Roo.DomHelper.Template = Roo.Template;
4855 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4856 * @param {String/HTMLElement} el A DOM element or its id
4857 * @returns {Roo.Template} The created template
4860 Roo.Template.from = function(el){
4861 el = Roo.getDom(el);
4862 return new Roo.Template(el.value || el.innerHTML);
4865 * Ext JS Library 1.1.1
4866 * Copyright(c) 2006-2007, Ext JS, LLC.
4868 * Originally Released Under LGPL - original licence link has changed is not relivant.
4871 * <script type="text/javascript">
4876 * This is code is also distributed under MIT license for use
4877 * with jQuery and prototype JavaScript libraries.
4880 * @class Roo.DomQuery
4881 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).
4883 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>
4886 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.
4888 <h4>Element Selectors:</h4>
4890 <li> <b>*</b> any element</li>
4891 <li> <b>E</b> an element with the tag E</li>
4892 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4893 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4894 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4895 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4897 <h4>Attribute Selectors:</h4>
4898 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4900 <li> <b>E[foo]</b> has an attribute "foo"</li>
4901 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4902 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4903 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4904 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4905 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4906 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4908 <h4>Pseudo Classes:</h4>
4910 <li> <b>E:first-child</b> E is the first child of its parent</li>
4911 <li> <b>E:last-child</b> E is the last child of its parent</li>
4912 <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>
4913 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4914 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4915 <li> <b>E:only-child</b> E is the only child of its parent</li>
4916 <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>
4917 <li> <b>E:first</b> the first E in the resultset</li>
4918 <li> <b>E:last</b> the last E in the resultset</li>
4919 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4920 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4921 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4922 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4923 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4924 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4925 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4926 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4927 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4929 <h4>CSS Value Selectors:</h4>
4931 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4932 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4933 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4934 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4935 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4936 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4940 Roo.DomQuery = function(){
4941 var cache = {}, simpleCache = {}, valueCache = {};
4942 var nonSpace = /\S/;
4943 var trimRe = /^\s+|\s+$/g;
4944 var tplRe = /\{(\d+)\}/g;
4945 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4946 var tagTokenRe = /^(#)?([\w-\*]+)/;
4947 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4949 function child(p, index){
4951 var n = p.firstChild;
4953 if(n.nodeType == 1){
4964 while((n = n.nextSibling) && n.nodeType != 1);
4969 while((n = n.previousSibling) && n.nodeType != 1);
4973 function children(d){
4974 var n = d.firstChild, ni = -1;
4976 var nx = n.nextSibling;
4977 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4987 function byClassName(c, a, v){
4991 var r = [], ri = -1, cn;
4992 for(var i = 0, ci; ci = c[i]; i++){
4993 if((' '+ci.className+' ').indexOf(v) != -1){
5000 function attrValue(n, attr){
5001 if(!n.tagName && typeof n.length != "undefined"){
5010 if(attr == "class" || attr == "className"){
5013 return n.getAttribute(attr) || n[attr];
5017 function getNodes(ns, mode, tagName){
5018 var result = [], ri = -1, cs;
5022 tagName = tagName || "*";
5023 if(typeof ns.getElementsByTagName != "undefined"){
5027 for(var i = 0, ni; ni = ns[i]; i++){
5028 cs = ni.getElementsByTagName(tagName);
5029 for(var j = 0, ci; ci = cs[j]; j++){
5033 }else if(mode == "/" || mode == ">"){
5034 var utag = tagName.toUpperCase();
5035 for(var i = 0, ni, cn; ni = ns[i]; i++){
5036 cn = ni.children || ni.childNodes;
5037 for(var j = 0, cj; cj = cn[j]; j++){
5038 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5043 }else if(mode == "+"){
5044 var utag = tagName.toUpperCase();
5045 for(var i = 0, n; n = ns[i]; i++){
5046 while((n = n.nextSibling) && n.nodeType != 1);
5047 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5051 }else if(mode == "~"){
5052 for(var i = 0, n; n = ns[i]; i++){
5053 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5062 function concat(a, b){
5066 for(var i = 0, l = b.length; i < l; i++){
5072 function byTag(cs, tagName){
5073 if(cs.tagName || cs == document){
5079 var r = [], ri = -1;
5080 tagName = tagName.toLowerCase();
5081 for(var i = 0, ci; ci = cs[i]; i++){
5082 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5089 function byId(cs, attr, id){
5090 if(cs.tagName || cs == document){
5096 var r = [], ri = -1;
5097 for(var i = 0,ci; ci = cs[i]; i++){
5098 if(ci && ci.id == id){
5106 function byAttribute(cs, attr, value, op, custom){
5107 var r = [], ri = -1, st = custom=="{";
5108 var f = Roo.DomQuery.operators[op];
5109 for(var i = 0, ci; ci = cs[i]; i++){
5112 a = Roo.DomQuery.getStyle(ci, attr);
5114 else if(attr == "class" || attr == "className"){
5116 }else if(attr == "for"){
5118 }else if(attr == "href"){
5119 a = ci.getAttribute("href", 2);
5121 a = ci.getAttribute(attr);
5123 if((f && f(a, value)) || (!f && a)){
5130 function byPseudo(cs, name, value){
5131 return Roo.DomQuery.pseudos[name](cs, value);
5134 // This is for IE MSXML which does not support expandos.
5135 // IE runs the same speed using setAttribute, however FF slows way down
5136 // and Safari completely fails so they need to continue to use expandos.
5137 var isIE = window.ActiveXObject ? true : false;
5139 // this eval is stop the compressor from
5140 // renaming the variable to something shorter
5142 /** eval:var:batch */
5147 function nodupIEXml(cs){
5149 cs[0].setAttribute("_nodup", d);
5151 for(var i = 1, len = cs.length; i < len; i++){
5153 if(!c.getAttribute("_nodup") != d){
5154 c.setAttribute("_nodup", d);
5158 for(var i = 0, len = cs.length; i < len; i++){
5159 cs[i].removeAttribute("_nodup");
5168 var len = cs.length, c, i, r = cs, cj, ri = -1;
5169 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5172 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5173 return nodupIEXml(cs);
5177 for(i = 1; c = cs[i]; i++){
5182 for(var j = 0; j < i; j++){
5185 for(j = i+1; cj = cs[j]; j++){
5197 function quickDiffIEXml(c1, c2){
5199 for(var i = 0, len = c1.length; i < len; i++){
5200 c1[i].setAttribute("_qdiff", d);
5203 for(var i = 0, len = c2.length; i < len; i++){
5204 if(c2[i].getAttribute("_qdiff") != d){
5205 r[r.length] = c2[i];
5208 for(var i = 0, len = c1.length; i < len; i++){
5209 c1[i].removeAttribute("_qdiff");
5214 function quickDiff(c1, c2){
5215 var len1 = c1.length;
5219 if(isIE && c1[0].selectSingleNode){
5220 return quickDiffIEXml(c1, c2);
5223 for(var i = 0; i < len1; i++){
5227 for(var i = 0, len = c2.length; i < len; i++){
5228 if(c2[i]._qdiff != d){
5229 r[r.length] = c2[i];
5235 function quickId(ns, mode, root, id){
5237 var d = root.ownerDocument || root;
5238 return d.getElementById(id);
5240 ns = getNodes(ns, mode, "*");
5241 return byId(ns, null, id);
5245 getStyle : function(el, name){
5246 return Roo.fly(el).getStyle(name);
5249 * Compiles a selector/xpath query into a reusable function. The returned function
5250 * takes one parameter "root" (optional), which is the context node from where the query should start.
5251 * @param {String} selector The selector/xpath query
5252 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5253 * @return {Function}
5255 compile : function(path, type){
5256 type = type || "select";
5258 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5259 var q = path, mode, lq;
5260 var tk = Roo.DomQuery.matchers;
5261 var tklen = tk.length;
5264 // accept leading mode switch
5265 var lmode = q.match(modeRe);
5266 if(lmode && lmode[1]){
5267 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5268 q = q.replace(lmode[1], "");
5270 // strip leading slashes
5271 while(path.substr(0, 1)=="/"){
5272 path = path.substr(1);
5275 while(q && lq != q){
5277 var tm = q.match(tagTokenRe);
5278 if(type == "select"){
5281 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5283 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5285 q = q.replace(tm[0], "");
5286 }else if(q.substr(0, 1) != '@'){
5287 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5292 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5294 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5296 q = q.replace(tm[0], "");
5299 while(!(mm = q.match(modeRe))){
5300 var matched = false;
5301 for(var j = 0; j < tklen; j++){
5303 var m = q.match(t.re);
5305 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5308 q = q.replace(m[0], "");
5313 // prevent infinite loop on bad selector
5315 throw 'Error parsing selector, parsing failed at "' + q + '"';
5319 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5320 q = q.replace(mm[1], "");
5323 fn[fn.length] = "return nodup(n);\n}";
5326 * list of variables that need from compression as they are used by eval.
5336 * eval:var:byClassName
5338 * eval:var:byAttribute
5339 * eval:var:attrValue
5347 * Selects a group of elements.
5348 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5349 * @param {Node} root (optional) The start of the query (defaults to document).
5352 select : function(path, root, type){
5353 if(!root || root == document){
5356 if(typeof root == "string"){
5357 root = document.getElementById(root);
5359 var paths = path.split(",");
5361 for(var i = 0, len = paths.length; i < len; i++){
5362 var p = paths[i].replace(trimRe, "");
5364 cache[p] = Roo.DomQuery.compile(p);
5366 throw p + " is not a valid selector";
5369 var result = cache[p](root);
5370 if(result && result != document){
5371 results = results.concat(result);
5374 if(paths.length > 1){
5375 return nodup(results);
5381 * Selects a single element.
5382 * @param {String} selector The selector/xpath query
5383 * @param {Node} root (optional) The start of the query (defaults to document).
5386 selectNode : function(path, root){
5387 return Roo.DomQuery.select(path, root)[0];
5391 * Selects the value of a node, optionally replacing null with the defaultValue.
5392 * @param {String} selector The selector/xpath query
5393 * @param {Node} root (optional) The start of the query (defaults to document).
5394 * @param {String} defaultValue
5396 selectValue : function(path, root, defaultValue){
5397 path = path.replace(trimRe, "");
5398 if(!valueCache[path]){
5399 valueCache[path] = Roo.DomQuery.compile(path, "select");
5401 var n = valueCache[path](root);
5402 n = n[0] ? n[0] : n;
5403 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5404 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5408 * Selects the value of a node, parsing integers and floats.
5409 * @param {String} selector The selector/xpath query
5410 * @param {Node} root (optional) The start of the query (defaults to document).
5411 * @param {Number} defaultValue
5414 selectNumber : function(path, root, defaultValue){
5415 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5416 return parseFloat(v);
5420 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5421 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5422 * @param {String} selector The simple selector to test
5425 is : function(el, ss){
5426 if(typeof el == "string"){
5427 el = document.getElementById(el);
5429 var isArray = (el instanceof Array);
5430 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5431 return isArray ? (result.length == el.length) : (result.length > 0);
5435 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5436 * @param {Array} el An array of elements to filter
5437 * @param {String} selector The simple selector to test
5438 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5439 * the selector instead of the ones that match
5442 filter : function(els, ss, nonMatches){
5443 ss = ss.replace(trimRe, "");
5444 if(!simpleCache[ss]){
5445 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5447 var result = simpleCache[ss](els);
5448 return nonMatches ? quickDiff(result, els) : result;
5452 * Collection of matching regular expressions and code snippets.
5456 select: 'n = byClassName(n, null, " {1} ");'
5458 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5459 select: 'n = byPseudo(n, "{1}", "{2}");'
5461 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5462 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5465 select: 'n = byId(n, null, "{1}");'
5468 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5473 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5474 * 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, > <.
5477 "=" : function(a, v){
5480 "!=" : function(a, v){
5483 "^=" : function(a, v){
5484 return a && a.substr(0, v.length) == v;
5486 "$=" : function(a, v){
5487 return a && a.substr(a.length-v.length) == v;
5489 "*=" : function(a, v){
5490 return a && a.indexOf(v) !== -1;
5492 "%=" : function(a, v){
5493 return (a % v) == 0;
5495 "|=" : function(a, v){
5496 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5498 "~=" : function(a, v){
5499 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5504 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5505 * and the argument (if any) supplied in the selector.
5508 "first-child" : function(c){
5509 var r = [], ri = -1, n;
5510 for(var i = 0, ci; ci = n = c[i]; i++){
5511 while((n = n.previousSibling) && n.nodeType != 1);
5519 "last-child" : function(c){
5520 var r = [], ri = -1, n;
5521 for(var i = 0, ci; ci = n = c[i]; i++){
5522 while((n = n.nextSibling) && n.nodeType != 1);
5530 "nth-child" : function(c, a) {
5531 var r = [], ri = -1;
5532 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5533 var f = (m[1] || 1) - 0, l = m[2] - 0;
5534 for(var i = 0, n; n = c[i]; i++){
5535 var pn = n.parentNode;
5536 if (batch != pn._batch) {
5538 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5539 if(cn.nodeType == 1){
5546 if (l == 0 || n.nodeIndex == l){
5549 } else if ((n.nodeIndex + l) % f == 0){
5557 "only-child" : function(c){
5558 var r = [], ri = -1;;
5559 for(var i = 0, ci; ci = c[i]; i++){
5560 if(!prev(ci) && !next(ci)){
5567 "empty" : function(c){
5568 var r = [], ri = -1;
5569 for(var i = 0, ci; ci = c[i]; i++){
5570 var cns = ci.childNodes, j = 0, cn, empty = true;
5573 if(cn.nodeType == 1 || cn.nodeType == 3){
5585 "contains" : function(c, v){
5586 var r = [], ri = -1;
5587 for(var i = 0, ci; ci = c[i]; i++){
5588 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5595 "nodeValue" : function(c, v){
5596 var r = [], ri = -1;
5597 for(var i = 0, ci; ci = c[i]; i++){
5598 if(ci.firstChild && ci.firstChild.nodeValue == v){
5605 "checked" : function(c){
5606 var r = [], ri = -1;
5607 for(var i = 0, ci; ci = c[i]; i++){
5608 if(ci.checked == true){
5615 "not" : function(c, ss){
5616 return Roo.DomQuery.filter(c, ss, true);
5619 "odd" : function(c){
5620 return this["nth-child"](c, "odd");
5623 "even" : function(c){
5624 return this["nth-child"](c, "even");
5627 "nth" : function(c, a){
5628 return c[a-1] || [];
5631 "first" : function(c){
5635 "last" : function(c){
5636 return c[c.length-1] || [];
5639 "has" : function(c, ss){
5640 var s = Roo.DomQuery.select;
5641 var r = [], ri = -1;
5642 for(var i = 0, ci; ci = c[i]; i++){
5643 if(s(ss, ci).length > 0){
5650 "next" : function(c, ss){
5651 var is = Roo.DomQuery.is;
5652 var r = [], ri = -1;
5653 for(var i = 0, ci; ci = c[i]; i++){
5662 "prev" : function(c, ss){
5663 var is = Roo.DomQuery.is;
5664 var r = [], ri = -1;
5665 for(var i = 0, ci; ci = c[i]; i++){
5678 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5679 * @param {String} path The selector/xpath query
5680 * @param {Node} root (optional) The start of the query (defaults to document).
5685 Roo.query = Roo.DomQuery.select;
5688 * Ext JS Library 1.1.1
5689 * Copyright(c) 2006-2007, Ext JS, LLC.
5691 * Originally Released Under LGPL - original licence link has changed is not relivant.
5694 * <script type="text/javascript">
5698 * @class Roo.util.Observable
5699 * Base class that provides a common interface for publishing events. Subclasses are expected to
5700 * to have a property "events" with all the events defined.<br>
5703 Employee = function(name){
5710 Roo.extend(Employee, Roo.util.Observable);
5712 * @param {Object} config properties to use (incuding events / listeners)
5715 Roo.util.Observable = function(cfg){
5718 this.addEvents(cfg.events || {});
5720 delete cfg.events; // make sure
5723 Roo.apply(this, cfg);
5726 this.on(this.listeners);
5727 delete this.listeners;
5730 Roo.util.Observable.prototype = {
5732 * @cfg {Object} listeners list of events and functions to call for this object,
5736 'click' : function(e) {
5746 * Fires the specified event with the passed parameters (minus the event name).
5747 * @param {String} eventName
5748 * @param {Object...} args Variable number of parameters are passed to handlers
5749 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5751 fireEvent : function(){
5752 var ce = this.events[arguments[0].toLowerCase()];
5753 if(typeof ce == "object"){
5754 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5761 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5764 * Appends an event handler to this component
5765 * @param {String} eventName The type of event to listen for
5766 * @param {Function} handler The method the event invokes
5767 * @param {Object} scope (optional) The scope in which to execute the handler
5768 * function. The handler function's "this" context.
5769 * @param {Object} options (optional) An object containing handler configuration
5770 * properties. This may contain any of the following properties:<ul>
5771 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5772 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5773 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5774 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5775 * by the specified number of milliseconds. If the event fires again within that time, the original
5776 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5779 * <b>Combining Options</b><br>
5780 * Using the options argument, it is possible to combine different types of listeners:<br>
5782 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5784 el.on('click', this.onClick, this, {
5791 * <b>Attaching multiple handlers in 1 call</b><br>
5792 * The method also allows for a single argument to be passed which is a config object containing properties
5793 * which specify multiple handlers.
5802 fn: this.onMouseOver,
5806 fn: this.onMouseOut,
5812 * Or a shorthand syntax which passes the same scope object to all handlers:
5815 'click': this.onClick,
5816 'mouseover': this.onMouseOver,
5817 'mouseout': this.onMouseOut,
5822 addListener : function(eventName, fn, scope, o){
5823 if(typeof eventName == "object"){
5826 if(this.filterOptRe.test(e)){
5829 if(typeof o[e] == "function"){
5831 this.addListener(e, o[e], o.scope, o);
5833 // individual options
5834 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5839 o = (!o || typeof o == "boolean") ? {} : o;
5840 eventName = eventName.toLowerCase();
5841 var ce = this.events[eventName] || true;
5842 if(typeof ce == "boolean"){
5843 ce = new Roo.util.Event(this, eventName);
5844 this.events[eventName] = ce;
5846 ce.addListener(fn, scope, o);
5850 * Removes a listener
5851 * @param {String} eventName The type of event to listen for
5852 * @param {Function} handler The handler to remove
5853 * @param {Object} scope (optional) The scope (this object) for the handler
5855 removeListener : function(eventName, fn, scope){
5856 var ce = this.events[eventName.toLowerCase()];
5857 if(typeof ce == "object"){
5858 ce.removeListener(fn, scope);
5863 * Removes all listeners for this object
5865 purgeListeners : function(){
5866 for(var evt in this.events){
5867 if(typeof this.events[evt] == "object"){
5868 this.events[evt].clearListeners();
5873 relayEvents : function(o, events){
5874 var createHandler = function(ename){
5876 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5879 for(var i = 0, len = events.length; i < len; i++){
5880 var ename = events[i];
5881 if(!this.events[ename]){ this.events[ename] = true; };
5882 o.on(ename, createHandler(ename), this);
5887 * Used to define events on this Observable
5888 * @param {Object} object The object with the events defined
5890 addEvents : function(o){
5894 Roo.applyIf(this.events, o);
5898 * Checks to see if this object has any listeners for a specified event
5899 * @param {String} eventName The name of the event to check for
5900 * @return {Boolean} True if the event is being listened for, else false
5902 hasListener : function(eventName){
5903 var e = this.events[eventName];
5904 return typeof e == "object" && e.listeners.length > 0;
5908 * Appends an event handler to this element (shorthand for addListener)
5909 * @param {String} eventName The type of event to listen for
5910 * @param {Function} handler The method the event invokes
5911 * @param {Object} scope (optional) The scope in which to execute the handler
5912 * function. The handler function's "this" context.
5913 * @param {Object} options (optional)
5916 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5918 * Removes a listener (shorthand for removeListener)
5919 * @param {String} eventName The type of event to listen for
5920 * @param {Function} handler The handler to remove
5921 * @param {Object} scope (optional) The scope (this object) for the handler
5924 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5927 * Starts capture on the specified Observable. All events will be passed
5928 * to the supplied function with the event name + standard signature of the event
5929 * <b>before</b> the event is fired. If the supplied function returns false,
5930 * the event will not fire.
5931 * @param {Observable} o The Observable to capture
5932 * @param {Function} fn The function to call
5933 * @param {Object} scope (optional) The scope (this object) for the fn
5936 Roo.util.Observable.capture = function(o, fn, scope){
5937 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5941 * Removes <b>all</b> added captures from the Observable.
5942 * @param {Observable} o The Observable to release
5945 Roo.util.Observable.releaseCapture = function(o){
5946 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5951 var createBuffered = function(h, o, scope){
5952 var task = new Roo.util.DelayedTask();
5954 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5958 var createSingle = function(h, e, fn, scope){
5960 e.removeListener(fn, scope);
5961 return h.apply(scope, arguments);
5965 var createDelayed = function(h, o, scope){
5967 var args = Array.prototype.slice.call(arguments, 0);
5968 setTimeout(function(){
5969 h.apply(scope, args);
5974 Roo.util.Event = function(obj, name){
5977 this.listeners = [];
5980 Roo.util.Event.prototype = {
5981 addListener : function(fn, scope, options){
5982 var o = options || {};
5983 scope = scope || this.obj;
5984 if(!this.isListening(fn, scope)){
5985 var l = {fn: fn, scope: scope, options: o};
5988 h = createDelayed(h, o, scope);
5991 h = createSingle(h, this, fn, scope);
5994 h = createBuffered(h, o, scope);
5997 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5998 this.listeners.push(l);
6000 this.listeners = this.listeners.slice(0);
6001 this.listeners.push(l);
6006 findListener : function(fn, scope){
6007 scope = scope || this.obj;
6008 var ls = this.listeners;
6009 for(var i = 0, len = ls.length; i < len; i++){
6011 if(l.fn == fn && l.scope == scope){
6018 isListening : function(fn, scope){
6019 return this.findListener(fn, scope) != -1;
6022 removeListener : function(fn, scope){
6024 if((index = this.findListener(fn, scope)) != -1){
6026 this.listeners.splice(index, 1);
6028 this.listeners = this.listeners.slice(0);
6029 this.listeners.splice(index, 1);
6036 clearListeners : function(){
6037 this.listeners = [];
6041 var ls = this.listeners, scope, len = ls.length;
6044 var args = Array.prototype.slice.call(arguments, 0);
6045 for(var i = 0; i < len; i++){
6047 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6048 this.firing = false;
6052 this.firing = false;
6059 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6066 * @class Roo.Document
6067 * @extends Roo.util.Observable
6068 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6070 * @param {Object} config the methods and properties of the 'base' class for the application.
6072 * Generic Page handler - implement this to start your app..
6075 * MyProject = new Roo.Document({
6077 'load' : true // your events..
6080 'ready' : function() {
6081 // fired on Roo.onReady()
6086 Roo.Document = function(cfg) {
6091 Roo.util.Observable.call(this,cfg);
6095 Roo.onReady(function() {
6096 _this.fireEvent('ready');
6102 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6104 * Ext JS Library 1.1.1
6105 * Copyright(c) 2006-2007, Ext JS, LLC.
6107 * Originally Released Under LGPL - original licence link has changed is not relivant.
6110 * <script type="text/javascript">
6114 * @class Roo.EventManager
6115 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6116 * several useful events directly.
6117 * See {@link Roo.EventObject} for more details on normalized event objects.
6120 Roo.EventManager = function(){
6121 var docReadyEvent, docReadyProcId, docReadyState = false;
6122 var resizeEvent, resizeTask, textEvent, textSize;
6123 var E = Roo.lib.Event;
6124 var D = Roo.lib.Dom;
6129 var fireDocReady = function(){
6131 docReadyState = true;
6134 clearInterval(docReadyProcId);
6136 if(Roo.isGecko || Roo.isOpera) {
6137 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6140 var defer = document.getElementById("ie-deferred-loader");
6142 defer.onreadystatechange = null;
6143 defer.parentNode.removeChild(defer);
6147 docReadyEvent.fire();
6148 docReadyEvent.clearListeners();
6153 var initDocReady = function(){
6154 docReadyEvent = new Roo.util.Event();
6155 if(Roo.isGecko || Roo.isOpera) {
6156 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6158 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6159 var defer = document.getElementById("ie-deferred-loader");
6160 defer.onreadystatechange = function(){
6161 if(this.readyState == "complete"){
6165 }else if(Roo.isSafari){
6166 docReadyProcId = setInterval(function(){
6167 var rs = document.readyState;
6168 if(rs == "complete") {
6173 // no matter what, make sure it fires on load
6174 E.on(window, "load", fireDocReady);
6177 var createBuffered = function(h, o){
6178 var task = new Roo.util.DelayedTask(h);
6180 // create new event object impl so new events don't wipe out properties
6181 e = new Roo.EventObjectImpl(e);
6182 task.delay(o.buffer, h, null, [e]);
6186 var createSingle = function(h, el, ename, fn){
6188 Roo.EventManager.removeListener(el, ename, fn);
6193 var createDelayed = function(h, o){
6195 // create new event object impl so new events don't wipe out properties
6196 e = new Roo.EventObjectImpl(e);
6197 setTimeout(function(){
6202 var transitionEndVal = false;
6204 var transitionEnd = function()
6206 if (transitionEndVal) {
6207 return transitionEndVal;
6209 var el = document.createElement('div');
6211 var transEndEventNames = {
6212 WebkitTransition : 'webkitTransitionEnd',
6213 MozTransition : 'transitionend',
6214 OTransition : 'oTransitionEnd otransitionend',
6215 transition : 'transitionend'
6218 for (var name in transEndEventNames) {
6219 if (el.style[name] !== undefined) {
6220 transitionEndVal = transEndEventNames[name];
6221 return transitionEndVal ;
6227 var listen = function(element, ename, opt, fn, scope){
6228 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6229 fn = fn || o.fn; scope = scope || o.scope;
6230 var el = Roo.getDom(element);
6234 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6237 if (ename == 'transitionend') {
6238 ename = transitionEnd();
6240 var h = function(e){
6241 e = Roo.EventObject.setEvent(e);
6244 t = e.getTarget(o.delegate, el);
6251 if(o.stopEvent === true){
6254 if(o.preventDefault === true){
6257 if(o.stopPropagation === true){
6258 e.stopPropagation();
6261 if(o.normalized === false){
6265 fn.call(scope || el, e, t, o);
6268 h = createDelayed(h, o);
6271 h = createSingle(h, el, ename, fn);
6274 h = createBuffered(h, o);
6276 fn._handlers = fn._handlers || [];
6279 fn._handlers.push([Roo.id(el), ename, h]);
6284 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6285 el.addEventListener("DOMMouseScroll", h, false);
6286 E.on(window, 'unload', function(){
6287 el.removeEventListener("DOMMouseScroll", h, false);
6290 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6291 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6296 var stopListening = function(el, ename, fn){
6297 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6299 for(var i = 0, len = hds.length; i < len; i++){
6301 if(h[0] == id && h[1] == ename){
6308 E.un(el, ename, hd);
6309 el = Roo.getDom(el);
6310 if(ename == "mousewheel" && el.addEventListener){
6311 el.removeEventListener("DOMMouseScroll", hd, false);
6313 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6314 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6318 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6325 * @scope Roo.EventManager
6330 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6331 * object with a Roo.EventObject
6332 * @param {Function} fn The method the event invokes
6333 * @param {Object} scope An object that becomes the scope of the handler
6334 * @param {boolean} override If true, the obj passed in becomes
6335 * the execution scope of the listener
6336 * @return {Function} The wrapped function
6339 wrap : function(fn, scope, override){
6341 Roo.EventObject.setEvent(e);
6342 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6347 * Appends an event handler to an element (shorthand for addListener)
6348 * @param {String/HTMLElement} element The html element or id to assign the
6349 * @param {String} eventName The type of event to listen for
6350 * @param {Function} handler The method the event invokes
6351 * @param {Object} scope (optional) The scope in which to execute the handler
6352 * function. The handler function's "this" context.
6353 * @param {Object} options (optional) An object containing handler configuration
6354 * properties. This may contain any of the following properties:<ul>
6355 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6356 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6357 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6358 * <li>preventDefault {Boolean} True to prevent the default action</li>
6359 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6360 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6361 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6362 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6363 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6364 * by the specified number of milliseconds. If the event fires again within that time, the original
6365 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6368 * <b>Combining Options</b><br>
6369 * Using the options argument, it is possible to combine different types of listeners:<br>
6371 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6373 el.on('click', this.onClick, this, {
6380 * <b>Attaching multiple handlers in 1 call</b><br>
6381 * The method also allows for a single argument to be passed which is a config object containing properties
6382 * which specify multiple handlers.
6392 fn: this.onMouseOver
6401 * Or a shorthand syntax:<br>
6404 'click' : this.onClick,
6405 'mouseover' : this.onMouseOver,
6406 'mouseout' : this.onMouseOut
6410 addListener : function(element, eventName, fn, scope, options){
6411 if(typeof eventName == "object"){
6417 if(typeof o[e] == "function"){
6419 listen(element, e, o, o[e], o.scope);
6421 // individual options
6422 listen(element, e, o[e]);
6427 return listen(element, eventName, options, fn, scope);
6431 * Removes an event handler
6433 * @param {String/HTMLElement} element The id or html element to remove the
6435 * @param {String} eventName The type of event
6436 * @param {Function} fn
6437 * @return {Boolean} True if a listener was actually removed
6439 removeListener : function(element, eventName, fn){
6440 return stopListening(element, eventName, fn);
6444 * Fires when the document is ready (before onload and before images are loaded). Can be
6445 * accessed shorthanded Roo.onReady().
6446 * @param {Function} fn The method the event invokes
6447 * @param {Object} scope An object that becomes the scope of the handler
6448 * @param {boolean} options
6450 onDocumentReady : function(fn, scope, options){
6451 if(docReadyState){ // if it already fired
6452 docReadyEvent.addListener(fn, scope, options);
6453 docReadyEvent.fire();
6454 docReadyEvent.clearListeners();
6460 docReadyEvent.addListener(fn, scope, options);
6464 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6465 * @param {Function} fn The method the event invokes
6466 * @param {Object} scope An object that becomes the scope of the handler
6467 * @param {boolean} options
6469 onWindowResize : function(fn, scope, options){
6471 resizeEvent = new Roo.util.Event();
6472 resizeTask = new Roo.util.DelayedTask(function(){
6473 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6475 E.on(window, "resize", function(){
6477 resizeTask.delay(50);
6479 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6483 resizeEvent.addListener(fn, scope, options);
6487 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6488 * @param {Function} fn The method the event invokes
6489 * @param {Object} scope An object that becomes the scope of the handler
6490 * @param {boolean} options
6492 onTextResize : function(fn, scope, options){
6494 textEvent = new Roo.util.Event();
6495 var textEl = new Roo.Element(document.createElement('div'));
6496 textEl.dom.className = 'x-text-resize';
6497 textEl.dom.innerHTML = 'X';
6498 textEl.appendTo(document.body);
6499 textSize = textEl.dom.offsetHeight;
6500 setInterval(function(){
6501 if(textEl.dom.offsetHeight != textSize){
6502 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6504 }, this.textResizeInterval);
6506 textEvent.addListener(fn, scope, options);
6510 * Removes the passed window resize listener.
6511 * @param {Function} fn The method the event invokes
6512 * @param {Object} scope The scope of handler
6514 removeResizeListener : function(fn, scope){
6516 resizeEvent.removeListener(fn, scope);
6521 fireResize : function(){
6523 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6527 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6531 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6533 textResizeInterval : 50
6538 * @scopeAlias pub=Roo.EventManager
6542 * Appends an event handler to an element (shorthand for addListener)
6543 * @param {String/HTMLElement} element The html element or id to assign the
6544 * @param {String} eventName The type of event to listen for
6545 * @param {Function} handler The method the event invokes
6546 * @param {Object} scope (optional) The scope in which to execute the handler
6547 * function. The handler function's "this" context.
6548 * @param {Object} options (optional) An object containing handler configuration
6549 * properties. This may contain any of the following properties:<ul>
6550 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6551 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6552 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6553 * <li>preventDefault {Boolean} True to prevent the default action</li>
6554 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6555 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6556 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6557 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6558 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6559 * by the specified number of milliseconds. If the event fires again within that time, the original
6560 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6563 * <b>Combining Options</b><br>
6564 * Using the options argument, it is possible to combine different types of listeners:<br>
6566 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6568 el.on('click', this.onClick, this, {
6575 * <b>Attaching multiple handlers in 1 call</b><br>
6576 * The method also allows for a single argument to be passed which is a config object containing properties
6577 * which specify multiple handlers.
6587 fn: this.onMouseOver
6596 * Or a shorthand syntax:<br>
6599 'click' : this.onClick,
6600 'mouseover' : this.onMouseOver,
6601 'mouseout' : this.onMouseOut
6605 pub.on = pub.addListener;
6606 pub.un = pub.removeListener;
6608 pub.stoppedMouseDownEvent = new Roo.util.Event();
6612 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6613 * @param {Function} fn The method the event invokes
6614 * @param {Object} scope An object that becomes the scope of the handler
6615 * @param {boolean} override If true, the obj passed in becomes
6616 * the execution scope of the listener
6620 Roo.onReady = Roo.EventManager.onDocumentReady;
6622 Roo.onReady(function(){
6623 var bd = Roo.get(document.body);
6628 : Roo.isGecko ? "roo-gecko"
6629 : Roo.isOpera ? "roo-opera"
6630 : Roo.isSafari ? "roo-safari" : ""];
6633 cls.push("roo-mac");
6636 cls.push("roo-linux");
6639 cls.push("roo-ios");
6642 cls.push("roo-touch");
6644 if(Roo.isBorderBox){
6645 cls.push('roo-border-box');
6647 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6648 var p = bd.dom.parentNode;
6650 p.className += ' roo-strict';
6653 bd.addClass(cls.join(' '));
6657 * @class Roo.EventObject
6658 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6659 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6662 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6664 var target = e.getTarget();
6667 var myDiv = Roo.get("myDiv");
6668 myDiv.on("click", handleClick);
6670 Roo.EventManager.on("myDiv", 'click', handleClick);
6671 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6675 Roo.EventObject = function(){
6677 var E = Roo.lib.Event;
6679 // safari keypress events for special keys return bad keycodes
6682 63235 : 39, // right
6685 63276 : 33, // page up
6686 63277 : 34, // page down
6687 63272 : 46, // delete
6692 // normalize button clicks
6693 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6694 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6696 Roo.EventObjectImpl = function(e){
6698 this.setEvent(e.browserEvent || e);
6701 Roo.EventObjectImpl.prototype = {
6703 * Used to fix doc tools.
6704 * @scope Roo.EventObject.prototype
6710 /** The normal browser event */
6711 browserEvent : null,
6712 /** The button pressed in a mouse event */
6714 /** True if the shift key was down during the event */
6716 /** True if the control key was down during the event */
6718 /** True if the alt key was down during the event */
6777 setEvent : function(e){
6778 if(e == this || (e && e.browserEvent)){ // already wrapped
6781 this.browserEvent = e;
6783 // normalize buttons
6784 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6785 if(e.type == 'click' && this.button == -1){
6789 this.shiftKey = e.shiftKey;
6790 // mac metaKey behaves like ctrlKey
6791 this.ctrlKey = e.ctrlKey || e.metaKey;
6792 this.altKey = e.altKey;
6793 // in getKey these will be normalized for the mac
6794 this.keyCode = e.keyCode;
6795 // keyup warnings on firefox.
6796 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6797 // cache the target for the delayed and or buffered events
6798 this.target = E.getTarget(e);
6800 this.xy = E.getXY(e);
6803 this.shiftKey = false;
6804 this.ctrlKey = false;
6805 this.altKey = false;
6815 * Stop the event (preventDefault and stopPropagation)
6817 stopEvent : function(){
6818 if(this.browserEvent){
6819 if(this.browserEvent.type == 'mousedown'){
6820 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6822 E.stopEvent(this.browserEvent);
6827 * Prevents the browsers default handling of the event.
6829 preventDefault : function(){
6830 if(this.browserEvent){
6831 E.preventDefault(this.browserEvent);
6836 isNavKeyPress : function(){
6837 var k = this.keyCode;
6838 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6839 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6842 isSpecialKey : function(){
6843 var k = this.keyCode;
6844 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6845 (k == 16) || (k == 17) ||
6846 (k >= 18 && k <= 20) ||
6847 (k >= 33 && k <= 35) ||
6848 (k >= 36 && k <= 39) ||
6849 (k >= 44 && k <= 45);
6852 * Cancels bubbling of the event.
6854 stopPropagation : function(){
6855 if(this.browserEvent){
6856 if(this.type == 'mousedown'){
6857 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6859 E.stopPropagation(this.browserEvent);
6864 * Gets the key code for the event.
6867 getCharCode : function(){
6868 return this.charCode || this.keyCode;
6872 * Returns a normalized keyCode for the event.
6873 * @return {Number} The key code
6875 getKey : function(){
6876 var k = this.keyCode || this.charCode;
6877 return Roo.isSafari ? (safariKeys[k] || k) : k;
6881 * Gets the x coordinate of the event.
6884 getPageX : function(){
6889 * Gets the y coordinate of the event.
6892 getPageY : function(){
6897 * Gets the time of the event.
6900 getTime : function(){
6901 if(this.browserEvent){
6902 return E.getTime(this.browserEvent);
6908 * Gets the page coordinates of the event.
6909 * @return {Array} The xy values like [x, y]
6916 * Gets the target for the event.
6917 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6918 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6919 search as a number or element (defaults to 10 || document.body)
6920 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6921 * @return {HTMLelement}
6923 getTarget : function(selector, maxDepth, returnEl){
6924 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6927 * Gets the related target.
6928 * @return {HTMLElement}
6930 getRelatedTarget : function(){
6931 if(this.browserEvent){
6932 return E.getRelatedTarget(this.browserEvent);
6938 * Normalizes mouse wheel delta across browsers
6939 * @return {Number} The delta
6941 getWheelDelta : function(){
6942 var e = this.browserEvent;
6944 if(e.wheelDelta){ /* IE/Opera. */
6945 delta = e.wheelDelta/120;
6946 }else if(e.detail){ /* Mozilla case. */
6947 delta = -e.detail/3;
6953 * Returns true if the control, meta, shift or alt key was pressed during this event.
6956 hasModifier : function(){
6957 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6961 * Returns true if the target of this event equals el or is a child of el
6962 * @param {String/HTMLElement/Element} el
6963 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6966 within : function(el, related){
6967 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6968 return t && Roo.fly(el).contains(t);
6971 getPoint : function(){
6972 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6976 return new Roo.EventObjectImpl();
6981 * Ext JS Library 1.1.1
6982 * Copyright(c) 2006-2007, Ext JS, LLC.
6984 * Originally Released Under LGPL - original licence link has changed is not relivant.
6987 * <script type="text/javascript">
6991 // was in Composite Element!??!?!
6994 var D = Roo.lib.Dom;
6995 var E = Roo.lib.Event;
6996 var A = Roo.lib.Anim;
6998 // local style camelizing for speed
7000 var camelRe = /(-[a-z])/gi;
7001 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7002 var view = document.defaultView;
7005 * @class Roo.Element
7006 * Represents an Element in the DOM.<br><br>
7009 var el = Roo.get("my-div");
7012 var el = getEl("my-div");
7014 // or with a DOM element
7015 var el = Roo.get(myDivElement);
7017 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7018 * each call instead of constructing a new one.<br><br>
7019 * <b>Animations</b><br />
7020 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7021 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7023 Option Default Description
7024 --------- -------- ---------------------------------------------
7025 duration .35 The duration of the animation in seconds
7026 easing easeOut The YUI easing method
7027 callback none A function to execute when the anim completes
7028 scope this The scope (this) of the callback function
7030 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7031 * manipulate the animation. Here's an example:
7033 var el = Roo.get("my-div");
7038 // default animation
7039 el.setWidth(100, true);
7041 // animation with some options set
7048 // using the "anim" property to get the Anim object
7054 el.setWidth(100, opt);
7056 if(opt.anim.isAnimated()){
7060 * <b> Composite (Collections of) Elements</b><br />
7061 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7062 * @constructor Create a new Element directly.
7063 * @param {String/HTMLElement} element
7064 * @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).
7066 Roo.Element = function(element, forceNew){
7067 var dom = typeof element == "string" ?
7068 document.getElementById(element) : element;
7069 if(!dom){ // invalid id/element
7073 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7074 return Roo.Element.cache[id];
7084 * The DOM element ID
7087 this.id = id || Roo.id(dom);
7090 var El = Roo.Element;
7094 * The element's default display mode (defaults to "")
7097 originalDisplay : "",
7101 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7107 * Sets the element's visibility mode. When setVisible() is called it
7108 * will use this to determine whether to set the visibility or the display property.
7109 * @param visMode Element.VISIBILITY or Element.DISPLAY
7110 * @return {Roo.Element} this
7112 setVisibilityMode : function(visMode){
7113 this.visibilityMode = visMode;
7117 * Convenience method for setVisibilityMode(Element.DISPLAY)
7118 * @param {String} display (optional) What to set display to when visible
7119 * @return {Roo.Element} this
7121 enableDisplayMode : function(display){
7122 this.setVisibilityMode(El.DISPLAY);
7123 if(typeof display != "undefined") { this.originalDisplay = display; }
7128 * 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)
7129 * @param {String} selector The simple selector to test
7130 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7131 search as a number or element (defaults to 10 || document.body)
7132 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7133 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7135 findParent : function(simpleSelector, maxDepth, returnEl){
7136 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7137 maxDepth = maxDepth || 50;
7138 if(typeof maxDepth != "number"){
7139 stopEl = Roo.getDom(maxDepth);
7142 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7143 if(dq.is(p, simpleSelector)){
7144 return returnEl ? Roo.get(p) : p;
7154 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7155 * @param {String} selector The simple selector to test
7156 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7157 search as a number or element (defaults to 10 || document.body)
7158 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7159 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7161 findParentNode : function(simpleSelector, maxDepth, returnEl){
7162 var p = Roo.fly(this.dom.parentNode, '_internal');
7163 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7167 * Looks at the scrollable parent element
7169 findScrollableParent : function(){
7171 var el = Roo.get(this.el.dom.parentNode);;
7173 while (el && !el.isScrollable() && el.dom.nodeName.toLowerCase() != 'body'){
7174 el = Roo.get(el.dom.parentNode);
7177 if(!el.isScrollable()){
7185 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7186 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7187 * @param {String} selector The simple selector to test
7188 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7189 search as a number or element (defaults to 10 || document.body)
7190 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7192 up : function(simpleSelector, maxDepth){
7193 return this.findParentNode(simpleSelector, maxDepth, true);
7199 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7200 * @param {String} selector The simple selector to test
7201 * @return {Boolean} True if this element matches the selector, else false
7203 is : function(simpleSelector){
7204 return Roo.DomQuery.is(this.dom, simpleSelector);
7208 * Perform animation on this element.
7209 * @param {Object} args The YUI animation control args
7210 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7211 * @param {Function} onComplete (optional) Function to call when animation completes
7212 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7213 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7214 * @return {Roo.Element} this
7216 animate : function(args, duration, onComplete, easing, animType){
7217 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7222 * @private Internal animation call
7224 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7225 animType = animType || 'run';
7227 var anim = Roo.lib.Anim[animType](
7229 (opt.duration || defaultDur) || .35,
7230 (opt.easing || defaultEase) || 'easeOut',
7232 Roo.callback(cb, this);
7233 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7241 // private legacy anim prep
7242 preanim : function(a, i){
7243 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7247 * Removes worthless text nodes
7248 * @param {Boolean} forceReclean (optional) By default the element
7249 * keeps track if it has been cleaned already so
7250 * you can call this over and over. However, if you update the element and
7251 * need to force a reclean, you can pass true.
7253 clean : function(forceReclean){
7254 if(this.isCleaned && forceReclean !== true){
7258 var d = this.dom, n = d.firstChild, ni = -1;
7260 var nx = n.nextSibling;
7261 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7268 this.isCleaned = true;
7273 calcOffsetsTo : function(el){
7276 var restorePos = false;
7277 if(el.getStyle('position') == 'static'){
7278 el.position('relative');
7283 while(op && op != d && op.tagName != 'HTML'){
7286 op = op.offsetParent;
7289 el.position('static');
7295 * Scrolls this element into view within the passed container.
7296 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7297 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7298 * @return {Roo.Element} this
7300 scrollIntoView : function(container, hscroll){
7301 var c = Roo.getDom(container) || document.body;
7304 var o = this.calcOffsetsTo(c),
7307 b = t+el.offsetHeight,
7308 r = l+el.offsetWidth;
7310 var ch = c.clientHeight;
7311 var ct = parseInt(c.scrollTop, 10);
7312 var cl = parseInt(c.scrollLeft, 10);
7314 var cr = cl + c.clientWidth;
7322 if(hscroll !== false){
7326 c.scrollLeft = r-c.clientWidth;
7333 scrollChildIntoView : function(child, hscroll){
7334 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7338 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7339 * the new height may not be available immediately.
7340 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7341 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7342 * @param {Function} onComplete (optional) Function to call when animation completes
7343 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7344 * @return {Roo.Element} this
7346 autoHeight : function(animate, duration, onComplete, easing){
7347 var oldHeight = this.getHeight();
7349 this.setHeight(1); // force clipping
7350 setTimeout(function(){
7351 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7353 this.setHeight(height);
7355 if(typeof onComplete == "function"){
7359 this.setHeight(oldHeight); // restore original height
7360 this.setHeight(height, animate, duration, function(){
7362 if(typeof onComplete == "function") { onComplete(); }
7363 }.createDelegate(this), easing);
7365 }.createDelegate(this), 0);
7370 * Returns true if this element is an ancestor of the passed element
7371 * @param {HTMLElement/String} el The element to check
7372 * @return {Boolean} True if this element is an ancestor of el, else false
7374 contains : function(el){
7375 if(!el){return false;}
7376 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7380 * Checks whether the element is currently visible using both visibility and display properties.
7381 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7382 * @return {Boolean} True if the element is currently visible, else false
7384 isVisible : function(deep) {
7385 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7386 if(deep !== true || !vis){
7389 var p = this.dom.parentNode;
7390 while(p && p.tagName.toLowerCase() != "body"){
7391 if(!Roo.fly(p, '_isVisible').isVisible()){
7400 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7401 * @param {String} selector The CSS selector
7402 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7403 * @return {CompositeElement/CompositeElementLite} The composite element
7405 select : function(selector, unique){
7406 return El.select(selector, unique, this.dom);
7410 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7411 * @param {String} selector The CSS selector
7412 * @return {Array} An array of the matched nodes
7414 query : function(selector, unique){
7415 return Roo.DomQuery.select(selector, this.dom);
7419 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7420 * @param {String} selector The CSS selector
7421 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7422 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7424 child : function(selector, returnDom){
7425 var n = Roo.DomQuery.selectNode(selector, this.dom);
7426 return returnDom ? n : Roo.get(n);
7430 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7431 * @param {String} selector The CSS selector
7432 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7433 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7435 down : function(selector, returnDom){
7436 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7437 return returnDom ? n : Roo.get(n);
7441 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7442 * @param {String} group The group the DD object is member of
7443 * @param {Object} config The DD config object
7444 * @param {Object} overrides An object containing methods to override/implement on the DD object
7445 * @return {Roo.dd.DD} The DD object
7447 initDD : function(group, config, overrides){
7448 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7449 return Roo.apply(dd, overrides);
7453 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7454 * @param {String} group The group the DDProxy object is member of
7455 * @param {Object} config The DDProxy config object
7456 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7457 * @return {Roo.dd.DDProxy} The DDProxy object
7459 initDDProxy : function(group, config, overrides){
7460 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7461 return Roo.apply(dd, overrides);
7465 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7466 * @param {String} group The group the DDTarget object is member of
7467 * @param {Object} config The DDTarget config object
7468 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7469 * @return {Roo.dd.DDTarget} The DDTarget object
7471 initDDTarget : function(group, config, overrides){
7472 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7473 return Roo.apply(dd, overrides);
7477 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7478 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7479 * @param {Boolean} visible Whether the element is visible
7480 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7481 * @return {Roo.Element} this
7483 setVisible : function(visible, animate){
7485 if(this.visibilityMode == El.DISPLAY){
7486 this.setDisplayed(visible);
7489 this.dom.style.visibility = visible ? "visible" : "hidden";
7492 // closure for composites
7494 var visMode = this.visibilityMode;
7496 this.setOpacity(.01);
7497 this.setVisible(true);
7499 this.anim({opacity: { to: (visible?1:0) }},
7500 this.preanim(arguments, 1),
7501 null, .35, 'easeIn', function(){
7503 if(visMode == El.DISPLAY){
7504 dom.style.display = "none";
7506 dom.style.visibility = "hidden";
7508 Roo.get(dom).setOpacity(1);
7516 * Returns true if display is not "none"
7519 isDisplayed : function() {
7520 return this.getStyle("display") != "none";
7524 * Toggles the element's visibility or display, depending on visibility mode.
7525 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7526 * @return {Roo.Element} this
7528 toggle : function(animate){
7529 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7534 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7535 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7536 * @return {Roo.Element} this
7538 setDisplayed : function(value) {
7539 if(typeof value == "boolean"){
7540 value = value ? this.originalDisplay : "none";
7542 this.setStyle("display", value);
7547 * Tries to focus the element. Any exceptions are caught and ignored.
7548 * @return {Roo.Element} this
7550 focus : function() {
7558 * Tries to blur the element. Any exceptions are caught and ignored.
7559 * @return {Roo.Element} this
7569 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7570 * @param {String/Array} className The CSS class to add, or an array of classes
7571 * @return {Roo.Element} this
7573 addClass : function(className){
7574 if(className instanceof Array){
7575 for(var i = 0, len = className.length; i < len; i++) {
7576 this.addClass(className[i]);
7579 if(className && !this.hasClass(className)){
7580 this.dom.className = this.dom.className + " " + className;
7587 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7588 * @param {String/Array} className The CSS class to add, or an array of classes
7589 * @return {Roo.Element} this
7591 radioClass : function(className){
7592 var siblings = this.dom.parentNode.childNodes;
7593 for(var i = 0; i < siblings.length; i++) {
7594 var s = siblings[i];
7595 if(s.nodeType == 1){
7596 Roo.get(s).removeClass(className);
7599 this.addClass(className);
7604 * Removes one or more CSS classes from the element.
7605 * @param {String/Array} className The CSS class to remove, or an array of classes
7606 * @return {Roo.Element} this
7608 removeClass : function(className){
7609 if(!className || !this.dom.className){
7612 if(className instanceof Array){
7613 for(var i = 0, len = className.length; i < len; i++) {
7614 this.removeClass(className[i]);
7617 if(this.hasClass(className)){
7618 var re = this.classReCache[className];
7620 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7621 this.classReCache[className] = re;
7623 this.dom.className =
7624 this.dom.className.replace(re, " ");
7634 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7635 * @param {String} className The CSS class to toggle
7636 * @return {Roo.Element} this
7638 toggleClass : function(className){
7639 if(this.hasClass(className)){
7640 this.removeClass(className);
7642 this.addClass(className);
7648 * Checks if the specified CSS class exists on this element's DOM node.
7649 * @param {String} className The CSS class to check for
7650 * @return {Boolean} True if the class exists, else false
7652 hasClass : function(className){
7653 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7657 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7658 * @param {String} oldClassName The CSS class to replace
7659 * @param {String} newClassName The replacement CSS class
7660 * @return {Roo.Element} this
7662 replaceClass : function(oldClassName, newClassName){
7663 this.removeClass(oldClassName);
7664 this.addClass(newClassName);
7669 * Returns an object with properties matching the styles requested.
7670 * For example, el.getStyles('color', 'font-size', 'width') might return
7671 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7672 * @param {String} style1 A style name
7673 * @param {String} style2 A style name
7674 * @param {String} etc.
7675 * @return {Object} The style object
7677 getStyles : function(){
7678 var a = arguments, len = a.length, r = {};
7679 for(var i = 0; i < len; i++){
7680 r[a[i]] = this.getStyle(a[i]);
7686 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7687 * @param {String} property The style property whose value is returned.
7688 * @return {String} The current value of the style property for this element.
7690 getStyle : function(){
7691 return view && view.getComputedStyle ?
7693 var el = this.dom, v, cs, camel;
7694 if(prop == 'float'){
7697 if(el.style && (v = el.style[prop])){
7700 if(cs = view.getComputedStyle(el, "")){
7701 if(!(camel = propCache[prop])){
7702 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7709 var el = this.dom, v, cs, camel;
7710 if(prop == 'opacity'){
7711 if(typeof el.style.filter == 'string'){
7712 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7714 var fv = parseFloat(m[1]);
7716 return fv ? fv / 100 : 0;
7721 }else if(prop == 'float'){
7722 prop = "styleFloat";
7724 if(!(camel = propCache[prop])){
7725 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7727 if(v = el.style[camel]){
7730 if(cs = el.currentStyle){
7738 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7739 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7740 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7741 * @return {Roo.Element} this
7743 setStyle : function(prop, value){
7744 if(typeof prop == "string"){
7746 if (prop == 'float') {
7747 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7752 if(!(camel = propCache[prop])){
7753 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7756 if(camel == 'opacity') {
7757 this.setOpacity(value);
7759 this.dom.style[camel] = value;
7762 for(var style in prop){
7763 if(typeof prop[style] != "function"){
7764 this.setStyle(style, prop[style]);
7772 * More flexible version of {@link #setStyle} for setting style properties.
7773 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7774 * a function which returns such a specification.
7775 * @return {Roo.Element} this
7777 applyStyles : function(style){
7778 Roo.DomHelper.applyStyles(this.dom, style);
7783 * 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).
7784 * @return {Number} The X position of the element
7787 return D.getX(this.dom);
7791 * 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).
7792 * @return {Number} The Y position of the element
7795 return D.getY(this.dom);
7799 * 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).
7800 * @return {Array} The XY position of the element
7803 return D.getXY(this.dom);
7807 * 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).
7808 * @param {Number} The X position of the element
7809 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7810 * @return {Roo.Element} this
7812 setX : function(x, animate){
7814 D.setX(this.dom, x);
7816 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7822 * 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).
7823 * @param {Number} The Y position of the element
7824 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7825 * @return {Roo.Element} this
7827 setY : function(y, animate){
7829 D.setY(this.dom, y);
7831 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7837 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7838 * @param {String} left The left CSS property value
7839 * @return {Roo.Element} this
7841 setLeft : function(left){
7842 this.setStyle("left", this.addUnits(left));
7847 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7848 * @param {String} top The top CSS property value
7849 * @return {Roo.Element} this
7851 setTop : function(top){
7852 this.setStyle("top", this.addUnits(top));
7857 * Sets the element's CSS right style.
7858 * @param {String} right The right CSS property value
7859 * @return {Roo.Element} this
7861 setRight : function(right){
7862 this.setStyle("right", this.addUnits(right));
7867 * Sets the element's CSS bottom style.
7868 * @param {String} bottom The bottom CSS property value
7869 * @return {Roo.Element} this
7871 setBottom : function(bottom){
7872 this.setStyle("bottom", this.addUnits(bottom));
7877 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7878 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7879 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7880 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7881 * @return {Roo.Element} this
7883 setXY : function(pos, animate){
7885 D.setXY(this.dom, pos);
7887 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7893 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7894 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7895 * @param {Number} x X value for new position (coordinates are page-based)
7896 * @param {Number} y Y value for new position (coordinates are page-based)
7897 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7898 * @return {Roo.Element} this
7900 setLocation : function(x, y, animate){
7901 this.setXY([x, y], this.preanim(arguments, 2));
7906 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7907 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7908 * @param {Number} x X value for new position (coordinates are page-based)
7909 * @param {Number} y Y value for new position (coordinates are page-based)
7910 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7911 * @return {Roo.Element} this
7913 moveTo : function(x, y, animate){
7914 this.setXY([x, y], this.preanim(arguments, 2));
7919 * Returns the region of the given element.
7920 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7921 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7923 getRegion : function(){
7924 return D.getRegion(this.dom);
7928 * Returns the offset height of the element
7929 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7930 * @return {Number} The element's height
7932 getHeight : function(contentHeight){
7933 var h = this.dom.offsetHeight || 0;
7934 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7938 * Returns the offset width of the element
7939 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7940 * @return {Number} The element's width
7942 getWidth : function(contentWidth){
7943 var w = this.dom.offsetWidth || 0;
7944 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7948 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7949 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7950 * if a height has not been set using CSS.
7953 getComputedHeight : function(){
7954 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7956 h = parseInt(this.getStyle('height'), 10) || 0;
7957 if(!this.isBorderBox()){
7958 h += this.getFrameWidth('tb');
7965 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7966 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7967 * if a width has not been set using CSS.
7970 getComputedWidth : function(){
7971 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7973 w = parseInt(this.getStyle('width'), 10) || 0;
7974 if(!this.isBorderBox()){
7975 w += this.getFrameWidth('lr');
7982 * Returns the size of the element.
7983 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7984 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7986 getSize : function(contentSize){
7987 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7991 * Returns the width and height of the viewport.
7992 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7994 getViewSize : function(){
7995 var d = this.dom, doc = document, aw = 0, ah = 0;
7996 if(d == doc || d == doc.body){
7997 return {width : D.getViewWidth(), height: D.getViewHeight()};
8000 width : d.clientWidth,
8001 height: d.clientHeight
8007 * Returns the value of the "value" attribute
8008 * @param {Boolean} asNumber true to parse the value as a number
8009 * @return {String/Number}
8011 getValue : function(asNumber){
8012 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8016 adjustWidth : function(width){
8017 if(typeof width == "number"){
8018 if(this.autoBoxAdjust && !this.isBorderBox()){
8019 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8029 adjustHeight : function(height){
8030 if(typeof height == "number"){
8031 if(this.autoBoxAdjust && !this.isBorderBox()){
8032 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8042 * Set the width of the element
8043 * @param {Number} width The new width
8044 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8045 * @return {Roo.Element} this
8047 setWidth : function(width, animate){
8048 width = this.adjustWidth(width);
8050 this.dom.style.width = this.addUnits(width);
8052 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8058 * Set the height of the element
8059 * @param {Number} height The new height
8060 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8061 * @return {Roo.Element} this
8063 setHeight : function(height, animate){
8064 height = this.adjustHeight(height);
8066 this.dom.style.height = this.addUnits(height);
8068 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8074 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8075 * @param {Number} width The new width
8076 * @param {Number} height The new height
8077 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8078 * @return {Roo.Element} this
8080 setSize : function(width, height, animate){
8081 if(typeof width == "object"){ // in case of object from getSize()
8082 height = width.height; width = width.width;
8084 width = this.adjustWidth(width); height = this.adjustHeight(height);
8086 this.dom.style.width = this.addUnits(width);
8087 this.dom.style.height = this.addUnits(height);
8089 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8095 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8096 * @param {Number} x X value for new position (coordinates are page-based)
8097 * @param {Number} y Y value for new position (coordinates are page-based)
8098 * @param {Number} width The new width
8099 * @param {Number} height The new height
8100 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8101 * @return {Roo.Element} this
8103 setBounds : function(x, y, width, height, animate){
8105 this.setSize(width, height);
8106 this.setLocation(x, y);
8108 width = this.adjustWidth(width); height = this.adjustHeight(height);
8109 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8110 this.preanim(arguments, 4), 'motion');
8116 * 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.
8117 * @param {Roo.lib.Region} region The region to fill
8118 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8119 * @return {Roo.Element} this
8121 setRegion : function(region, animate){
8122 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8127 * Appends an event handler
8129 * @param {String} eventName The type of event to append
8130 * @param {Function} fn The method the event invokes
8131 * @param {Object} scope (optional) The scope (this object) of the fn
8132 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8134 addListener : function(eventName, fn, scope, options){
8136 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8141 * Removes an event handler from this element
8142 * @param {String} eventName the type of event to remove
8143 * @param {Function} fn the method the event invokes
8144 * @return {Roo.Element} this
8146 removeListener : function(eventName, fn){
8147 Roo.EventManager.removeListener(this.dom, eventName, fn);
8152 * Removes all previous added listeners from this element
8153 * @return {Roo.Element} this
8155 removeAllListeners : function(){
8156 E.purgeElement(this.dom);
8160 relayEvent : function(eventName, observable){
8161 this.on(eventName, function(e){
8162 observable.fireEvent(eventName, e);
8167 * Set the opacity of the element
8168 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8169 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8170 * @return {Roo.Element} this
8172 setOpacity : function(opacity, animate){
8174 var s = this.dom.style;
8177 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8178 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8180 s.opacity = opacity;
8183 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8189 * Gets the left X coordinate
8190 * @param {Boolean} local True to get the local css position instead of page coordinate
8193 getLeft : function(local){
8197 return parseInt(this.getStyle("left"), 10) || 0;
8202 * Gets the right X coordinate of the element (element X position + element width)
8203 * @param {Boolean} local True to get the local css position instead of page coordinate
8206 getRight : function(local){
8208 return this.getX() + this.getWidth();
8210 return (this.getLeft(true) + this.getWidth()) || 0;
8215 * Gets the top Y coordinate
8216 * @param {Boolean} local True to get the local css position instead of page coordinate
8219 getTop : function(local) {
8223 return parseInt(this.getStyle("top"), 10) || 0;
8228 * Gets the bottom Y coordinate of the element (element Y position + element height)
8229 * @param {Boolean} local True to get the local css position instead of page coordinate
8232 getBottom : function(local){
8234 return this.getY() + this.getHeight();
8236 return (this.getTop(true) + this.getHeight()) || 0;
8241 * Initializes positioning on this element. If a desired position is not passed, it will make the
8242 * the element positioned relative IF it is not already positioned.
8243 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8244 * @param {Number} zIndex (optional) The zIndex to apply
8245 * @param {Number} x (optional) Set the page X position
8246 * @param {Number} y (optional) Set the page Y position
8248 position : function(pos, zIndex, x, y){
8250 if(this.getStyle('position') == 'static'){
8251 this.setStyle('position', 'relative');
8254 this.setStyle("position", pos);
8257 this.setStyle("z-index", zIndex);
8259 if(x !== undefined && y !== undefined){
8261 }else if(x !== undefined){
8263 }else if(y !== undefined){
8269 * Clear positioning back to the default when the document was loaded
8270 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8271 * @return {Roo.Element} this
8273 clearPositioning : function(value){
8281 "position" : "static"
8287 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8288 * snapshot before performing an update and then restoring the element.
8291 getPositioning : function(){
8292 var l = this.getStyle("left");
8293 var t = this.getStyle("top");
8295 "position" : this.getStyle("position"),
8297 "right" : l ? "" : this.getStyle("right"),
8299 "bottom" : t ? "" : this.getStyle("bottom"),
8300 "z-index" : this.getStyle("z-index")
8305 * Gets the width of the border(s) for the specified side(s)
8306 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8307 * passing lr would get the border (l)eft width + the border (r)ight width.
8308 * @return {Number} The width of the sides passed added together
8310 getBorderWidth : function(side){
8311 return this.addStyles(side, El.borders);
8315 * Gets the width of the padding(s) for the specified side(s)
8316 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8317 * passing lr would get the padding (l)eft + the padding (r)ight.
8318 * @return {Number} The padding of the sides passed added together
8320 getPadding : function(side){
8321 return this.addStyles(side, El.paddings);
8325 * Set positioning with an object returned by getPositioning().
8326 * @param {Object} posCfg
8327 * @return {Roo.Element} this
8329 setPositioning : function(pc){
8330 this.applyStyles(pc);
8331 if(pc.right == "auto"){
8332 this.dom.style.right = "";
8334 if(pc.bottom == "auto"){
8335 this.dom.style.bottom = "";
8341 fixDisplay : function(){
8342 if(this.getStyle("display") == "none"){
8343 this.setStyle("visibility", "hidden");
8344 this.setStyle("display", this.originalDisplay); // first try reverting to default
8345 if(this.getStyle("display") == "none"){ // if that fails, default to block
8346 this.setStyle("display", "block");
8352 * Quick set left and top adding default units
8353 * @param {String} left The left CSS property value
8354 * @param {String} top The top CSS property value
8355 * @return {Roo.Element} this
8357 setLeftTop : function(left, top){
8358 this.dom.style.left = this.addUnits(left);
8359 this.dom.style.top = this.addUnits(top);
8364 * Move this element relative to its current position.
8365 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8366 * @param {Number} distance How far to move the element in pixels
8367 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8368 * @return {Roo.Element} this
8370 move : function(direction, distance, animate){
8371 var xy = this.getXY();
8372 direction = direction.toLowerCase();
8376 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8380 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8385 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8390 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8397 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8398 * @return {Roo.Element} this
8401 if(!this.isClipped){
8402 this.isClipped = true;
8403 this.originalClip = {
8404 "o": this.getStyle("overflow"),
8405 "x": this.getStyle("overflow-x"),
8406 "y": this.getStyle("overflow-y")
8408 this.setStyle("overflow", "hidden");
8409 this.setStyle("overflow-x", "hidden");
8410 this.setStyle("overflow-y", "hidden");
8416 * Return clipping (overflow) to original clipping before clip() was called
8417 * @return {Roo.Element} this
8419 unclip : function(){
8421 this.isClipped = false;
8422 var o = this.originalClip;
8423 if(o.o){this.setStyle("overflow", o.o);}
8424 if(o.x){this.setStyle("overflow-x", o.x);}
8425 if(o.y){this.setStyle("overflow-y", o.y);}
8432 * Gets the x,y coordinates specified by the anchor position on the element.
8433 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8434 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8435 * {width: (target width), height: (target height)} (defaults to the element's current size)
8436 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8437 * @return {Array} [x, y] An array containing the element's x and y coordinates
8439 getAnchorXY : function(anchor, local, s){
8440 //Passing a different size is useful for pre-calculating anchors,
8441 //especially for anchored animations that change the el size.
8443 var w, h, vp = false;
8446 if(d == document.body || d == document){
8448 w = D.getViewWidth(); h = D.getViewHeight();
8450 w = this.getWidth(); h = this.getHeight();
8453 w = s.width; h = s.height;
8455 var x = 0, y = 0, r = Math.round;
8456 switch((anchor || "tl").toLowerCase()){
8498 var sc = this.getScroll();
8499 return [x + sc.left, y + sc.top];
8501 //Add the element's offset xy
8502 var o = this.getXY();
8503 return [x+o[0], y+o[1]];
8507 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8508 * supported position values.
8509 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8510 * @param {String} position The position to align to.
8511 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8512 * @return {Array} [x, y]
8514 getAlignToXY : function(el, p, o){
8518 throw "Element.alignTo with an element that doesn't exist";
8520 var c = false; //constrain to viewport
8521 var p1 = "", p2 = "";
8528 }else if(p.indexOf("-") == -1){
8531 p = p.toLowerCase();
8532 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8534 throw "Element.alignTo with an invalid alignment " + p;
8536 p1 = m[1]; p2 = m[2]; c = !!m[3];
8538 //Subtract the aligned el's internal xy from the target's offset xy
8539 //plus custom offset to get the aligned el's new offset xy
8540 var a1 = this.getAnchorXY(p1, true);
8541 var a2 = el.getAnchorXY(p2, false);
8542 var x = a2[0] - a1[0] + o[0];
8543 var y = a2[1] - a1[1] + o[1];
8545 //constrain the aligned el to viewport if necessary
8546 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8547 // 5px of margin for ie
8548 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8550 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8551 //perpendicular to the vp border, allow the aligned el to slide on that border,
8552 //otherwise swap the aligned el to the opposite border of the target.
8553 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8554 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8555 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8556 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8559 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8560 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8562 if((x+w) > dw + scrollX){
8563 x = swapX ? r.left-w : dw+scrollX-w;
8566 x = swapX ? r.right : scrollX;
8568 if((y+h) > dh + scrollY){
8569 y = swapY ? r.top-h : dh+scrollY-h;
8572 y = swapY ? r.bottom : scrollY;
8579 getConstrainToXY : function(){
8580 var os = {top:0, left:0, bottom:0, right: 0};
8582 return function(el, local, offsets, proposedXY){
8584 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8586 var vw, vh, vx = 0, vy = 0;
8587 if(el.dom == document.body || el.dom == document){
8588 vw = Roo.lib.Dom.getViewWidth();
8589 vh = Roo.lib.Dom.getViewHeight();
8591 vw = el.dom.clientWidth;
8592 vh = el.dom.clientHeight;
8594 var vxy = el.getXY();
8600 var s = el.getScroll();
8602 vx += offsets.left + s.left;
8603 vy += offsets.top + s.top;
8605 vw -= offsets.right;
8606 vh -= offsets.bottom;
8611 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8612 var x = xy[0], y = xy[1];
8613 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8615 // only move it if it needs it
8618 // first validate right/bottom
8627 // then make sure top/left isn't negative
8636 return moved ? [x, y] : false;
8641 adjustForConstraints : function(xy, parent, offsets){
8642 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8646 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8647 * document it aligns it to the viewport.
8648 * The position parameter is optional, and can be specified in any one of the following formats:
8650 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8651 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8652 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8653 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8654 * <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
8655 * element's anchor point, and the second value is used as the target's anchor point.</li>
8657 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8658 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8659 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8660 * that specified in order to enforce the viewport constraints.
8661 * Following are all of the supported anchor positions:
8664 ----- -----------------------------
8665 tl The top left corner (default)
8666 t The center of the top edge
8667 tr The top right corner
8668 l The center of the left edge
8669 c In the center of the element
8670 r The center of the right edge
8671 bl The bottom left corner
8672 b The center of the bottom edge
8673 br The bottom right corner
8677 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8678 el.alignTo("other-el");
8680 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8681 el.alignTo("other-el", "tr?");
8683 // align the bottom right corner of el with the center left edge of other-el
8684 el.alignTo("other-el", "br-l?");
8686 // align the center of el with the bottom left corner of other-el and
8687 // adjust the x position by -6 pixels (and the y position by 0)
8688 el.alignTo("other-el", "c-bl", [-6, 0]);
8690 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8691 * @param {String} position The position to align to.
8692 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8693 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8694 * @return {Roo.Element} this
8696 alignTo : function(element, position, offsets, animate){
8697 var xy = this.getAlignToXY(element, position, offsets);
8698 this.setXY(xy, this.preanim(arguments, 3));
8703 * Anchors an element to another element and realigns it when the window is resized.
8704 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8705 * @param {String} position The position to align to.
8706 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8707 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8708 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8709 * is a number, it is used as the buffer delay (defaults to 50ms).
8710 * @param {Function} callback The function to call after the animation finishes
8711 * @return {Roo.Element} this
8713 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8714 var action = function(){
8715 this.alignTo(el, alignment, offsets, animate);
8716 Roo.callback(callback, this);
8718 Roo.EventManager.onWindowResize(action, this);
8719 var tm = typeof monitorScroll;
8720 if(tm != 'undefined'){
8721 Roo.EventManager.on(window, 'scroll', action, this,
8722 {buffer: tm == 'number' ? monitorScroll : 50});
8724 action.call(this); // align immediately
8728 * Clears any opacity settings from this element. Required in some cases for IE.
8729 * @return {Roo.Element} this
8731 clearOpacity : function(){
8732 if (window.ActiveXObject) {
8733 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8734 this.dom.style.filter = "";
8737 this.dom.style.opacity = "";
8738 this.dom.style["-moz-opacity"] = "";
8739 this.dom.style["-khtml-opacity"] = "";
8745 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8746 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8747 * @return {Roo.Element} this
8749 hide : function(animate){
8750 this.setVisible(false, this.preanim(arguments, 0));
8755 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8756 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8757 * @return {Roo.Element} this
8759 show : function(animate){
8760 this.setVisible(true, this.preanim(arguments, 0));
8765 * @private Test if size has a unit, otherwise appends the default
8767 addUnits : function(size){
8768 return Roo.Element.addUnits(size, this.defaultUnit);
8772 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8773 * @return {Roo.Element} this
8775 beginMeasure : function(){
8777 if(el.offsetWidth || el.offsetHeight){
8778 return this; // offsets work already
8781 var p = this.dom, b = document.body; // start with this element
8782 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8783 var pe = Roo.get(p);
8784 if(pe.getStyle('display') == 'none'){
8785 changed.push({el: p, visibility: pe.getStyle("visibility")});
8786 p.style.visibility = "hidden";
8787 p.style.display = "block";
8791 this._measureChanged = changed;
8797 * Restores displays to before beginMeasure was called
8798 * @return {Roo.Element} this
8800 endMeasure : function(){
8801 var changed = this._measureChanged;
8803 for(var i = 0, len = changed.length; i < len; i++) {
8805 r.el.style.visibility = r.visibility;
8806 r.el.style.display = "none";
8808 this._measureChanged = null;
8814 * Update the innerHTML of this element, optionally searching for and processing scripts
8815 * @param {String} html The new HTML
8816 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8817 * @param {Function} callback For async script loading you can be noticed when the update completes
8818 * @return {Roo.Element} this
8820 update : function(html, loadScripts, callback){
8821 if(typeof html == "undefined"){
8824 if(loadScripts !== true){
8825 this.dom.innerHTML = html;
8826 if(typeof callback == "function"){
8834 html += '<span id="' + id + '"></span>';
8836 E.onAvailable(id, function(){
8837 var hd = document.getElementsByTagName("head")[0];
8838 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8839 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8840 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8843 while(match = re.exec(html)){
8844 var attrs = match[1];
8845 var srcMatch = attrs ? attrs.match(srcRe) : false;
8846 if(srcMatch && srcMatch[2]){
8847 var s = document.createElement("script");
8848 s.src = srcMatch[2];
8849 var typeMatch = attrs.match(typeRe);
8850 if(typeMatch && typeMatch[2]){
8851 s.type = typeMatch[2];
8854 }else if(match[2] && match[2].length > 0){
8855 if(window.execScript) {
8856 window.execScript(match[2]);
8864 window.eval(match[2]);
8868 var el = document.getElementById(id);
8869 if(el){el.parentNode.removeChild(el);}
8870 if(typeof callback == "function"){
8874 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8879 * Direct access to the UpdateManager update() method (takes the same parameters).
8880 * @param {String/Function} url The url for this request or a function to call to get the url
8881 * @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}
8882 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8883 * @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.
8884 * @return {Roo.Element} this
8887 var um = this.getUpdateManager();
8888 um.update.apply(um, arguments);
8893 * Gets this element's UpdateManager
8894 * @return {Roo.UpdateManager} The UpdateManager
8896 getUpdateManager : function(){
8897 if(!this.updateManager){
8898 this.updateManager = new Roo.UpdateManager(this);
8900 return this.updateManager;
8904 * Disables text selection for this element (normalized across browsers)
8905 * @return {Roo.Element} this
8907 unselectable : function(){
8908 this.dom.unselectable = "on";
8909 this.swallowEvent("selectstart", true);
8910 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8911 this.addClass("x-unselectable");
8916 * Calculates the x, y to center this element on the screen
8917 * @return {Array} The x, y values [x, y]
8919 getCenterXY : function(){
8920 return this.getAlignToXY(document, 'c-c');
8924 * Centers the Element in either the viewport, or another Element.
8925 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8927 center : function(centerIn){
8928 this.alignTo(centerIn || document, 'c-c');
8933 * Tests various css rules/browsers to determine if this element uses a border box
8936 isBorderBox : function(){
8937 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8941 * Return a box {x, y, width, height} that can be used to set another elements
8942 * size/location to match this element.
8943 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8944 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8945 * @return {Object} box An object in the format {x, y, width, height}
8947 getBox : function(contentBox, local){
8952 var left = parseInt(this.getStyle("left"), 10) || 0;
8953 var top = parseInt(this.getStyle("top"), 10) || 0;
8956 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8958 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8960 var l = this.getBorderWidth("l")+this.getPadding("l");
8961 var r = this.getBorderWidth("r")+this.getPadding("r");
8962 var t = this.getBorderWidth("t")+this.getPadding("t");
8963 var b = this.getBorderWidth("b")+this.getPadding("b");
8964 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)};
8966 bx.right = bx.x + bx.width;
8967 bx.bottom = bx.y + bx.height;
8972 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8973 for more information about the sides.
8974 * @param {String} sides
8977 getFrameWidth : function(sides, onlyContentBox){
8978 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8982 * 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.
8983 * @param {Object} box The box to fill {x, y, width, height}
8984 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8985 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8986 * @return {Roo.Element} this
8988 setBox : function(box, adjust, animate){
8989 var w = box.width, h = box.height;
8990 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8991 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8992 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8994 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8999 * Forces the browser to repaint this element
9000 * @return {Roo.Element} this
9002 repaint : function(){
9004 this.addClass("x-repaint");
9005 setTimeout(function(){
9006 Roo.get(dom).removeClass("x-repaint");
9012 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9013 * then it returns the calculated width of the sides (see getPadding)
9014 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9015 * @return {Object/Number}
9017 getMargins : function(side){
9020 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9021 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9022 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9023 right: parseInt(this.getStyle("margin-right"), 10) || 0
9026 return this.addStyles(side, El.margins);
9031 addStyles : function(sides, styles){
9033 for(var i = 0, len = sides.length; i < len; i++){
9034 v = this.getStyle(styles[sides.charAt(i)]);
9036 w = parseInt(v, 10);
9044 * Creates a proxy element of this element
9045 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9046 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9047 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9048 * @return {Roo.Element} The new proxy element
9050 createProxy : function(config, renderTo, matchBox){
9052 renderTo = Roo.getDom(renderTo);
9054 renderTo = document.body;
9056 config = typeof config == "object" ?
9057 config : {tag : "div", cls: config};
9058 var proxy = Roo.DomHelper.append(renderTo, config, true);
9060 proxy.setBox(this.getBox());
9066 * Puts a mask over this element to disable user interaction. Requires core.css.
9067 * This method can only be applied to elements which accept child nodes.
9068 * @param {String} msg (optional) A message to display in the mask
9069 * @param {String} msgCls (optional) A css class to apply to the msg element
9070 * @return {Element} The mask element
9072 mask : function(msg, msgCls)
9074 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9075 this.setStyle("position", "relative");
9078 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9080 this.addClass("x-masked");
9081 this._mask.setDisplayed(true);
9086 while (dom && dom.style) {
9087 if (!isNaN(parseInt(dom.style.zIndex))) {
9088 z = Math.max(z, parseInt(dom.style.zIndex));
9090 dom = dom.parentNode;
9092 // if we are masking the body - then it hides everything..
9093 if (this.dom == document.body) {
9095 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9096 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9099 if(typeof msg == 'string'){
9101 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9103 var mm = this._maskMsg;
9104 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9105 if (mm.dom.firstChild) { // weird IE issue?
9106 mm.dom.firstChild.innerHTML = msg;
9108 mm.setDisplayed(true);
9110 mm.setStyle('z-index', z + 102);
9112 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9113 this._mask.setHeight(this.getHeight());
9115 this._mask.setStyle('z-index', z + 100);
9121 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9122 * it is cached for reuse.
9124 unmask : function(removeEl){
9126 if(removeEl === true){
9127 this._mask.remove();
9130 this._maskMsg.remove();
9131 delete this._maskMsg;
9134 this._mask.setDisplayed(false);
9136 this._maskMsg.setDisplayed(false);
9140 this.removeClass("x-masked");
9144 * Returns true if this element is masked
9147 isMasked : function(){
9148 return this._mask && this._mask.isVisible();
9152 * Creates an iframe shim for this element to keep selects and other windowed objects from
9154 * @return {Roo.Element} The new shim element
9156 createShim : function(){
9157 var el = document.createElement('iframe');
9158 el.frameBorder = 'no';
9159 el.className = 'roo-shim';
9160 if(Roo.isIE && Roo.isSecure){
9161 el.src = Roo.SSL_SECURE_URL;
9163 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9164 shim.autoBoxAdjust = false;
9169 * Removes this element from the DOM and deletes it from the cache
9171 remove : function(){
9172 if(this.dom.parentNode){
9173 this.dom.parentNode.removeChild(this.dom);
9175 delete El.cache[this.dom.id];
9179 * Sets up event handlers to add and remove a css class when the mouse is over this element
9180 * @param {String} className
9181 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9182 * mouseout events for children elements
9183 * @return {Roo.Element} this
9185 addClassOnOver : function(className, preventFlicker){
9186 this.on("mouseover", function(){
9187 Roo.fly(this, '_internal').addClass(className);
9189 var removeFn = function(e){
9190 if(preventFlicker !== true || !e.within(this, true)){
9191 Roo.fly(this, '_internal').removeClass(className);
9194 this.on("mouseout", removeFn, this.dom);
9199 * Sets up event handlers to add and remove a css class when this element has the focus
9200 * @param {String} className
9201 * @return {Roo.Element} this
9203 addClassOnFocus : function(className){
9204 this.on("focus", function(){
9205 Roo.fly(this, '_internal').addClass(className);
9207 this.on("blur", function(){
9208 Roo.fly(this, '_internal').removeClass(className);
9213 * 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)
9214 * @param {String} className
9215 * @return {Roo.Element} this
9217 addClassOnClick : function(className){
9219 this.on("mousedown", function(){
9220 Roo.fly(dom, '_internal').addClass(className);
9221 var d = Roo.get(document);
9222 var fn = function(){
9223 Roo.fly(dom, '_internal').removeClass(className);
9224 d.removeListener("mouseup", fn);
9226 d.on("mouseup", fn);
9232 * Stops the specified event from bubbling and optionally prevents the default action
9233 * @param {String} eventName
9234 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9235 * @return {Roo.Element} this
9237 swallowEvent : function(eventName, preventDefault){
9238 var fn = function(e){
9239 e.stopPropagation();
9244 if(eventName instanceof Array){
9245 for(var i = 0, len = eventName.length; i < len; i++){
9246 this.on(eventName[i], fn);
9250 this.on(eventName, fn);
9257 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9260 * Sizes this element to its parent element's dimensions performing
9261 * neccessary box adjustments.
9262 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9263 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9264 * @return {Roo.Element} this
9266 fitToParent : function(monitorResize, targetParent) {
9267 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9268 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9269 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9272 var p = Roo.get(targetParent || this.dom.parentNode);
9273 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9274 if (monitorResize === true) {
9275 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9276 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9282 * Gets the next sibling, skipping text nodes
9283 * @return {HTMLElement} The next sibling or null
9285 getNextSibling : function(){
9286 var n = this.dom.nextSibling;
9287 while(n && n.nodeType != 1){
9294 * Gets the previous sibling, skipping text nodes
9295 * @return {HTMLElement} The previous sibling or null
9297 getPrevSibling : function(){
9298 var n = this.dom.previousSibling;
9299 while(n && n.nodeType != 1){
9300 n = n.previousSibling;
9307 * Appends the passed element(s) to this element
9308 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9309 * @return {Roo.Element} this
9311 appendChild: function(el){
9318 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9319 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9320 * automatically generated with the specified attributes.
9321 * @param {HTMLElement} insertBefore (optional) a child element of this element
9322 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9323 * @return {Roo.Element} The new child element
9325 createChild: function(config, insertBefore, returnDom){
9326 config = config || {tag:'div'};
9328 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9330 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9334 * Appends this element to the passed element
9335 * @param {String/HTMLElement/Element} el The new parent element
9336 * @return {Roo.Element} this
9338 appendTo: function(el){
9339 el = Roo.getDom(el);
9340 el.appendChild(this.dom);
9345 * Inserts this element before the passed element in the DOM
9346 * @param {String/HTMLElement/Element} el The element to insert before
9347 * @return {Roo.Element} this
9349 insertBefore: function(el){
9350 el = Roo.getDom(el);
9351 el.parentNode.insertBefore(this.dom, el);
9356 * Inserts this element after the passed element in the DOM
9357 * @param {String/HTMLElement/Element} el The element to insert after
9358 * @return {Roo.Element} this
9360 insertAfter: function(el){
9361 el = Roo.getDom(el);
9362 el.parentNode.insertBefore(this.dom, el.nextSibling);
9367 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9368 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9369 * @return {Roo.Element} The new child
9371 insertFirst: function(el, returnDom){
9373 if(typeof el == 'object' && !el.nodeType){ // dh config
9374 return this.createChild(el, this.dom.firstChild, returnDom);
9376 el = Roo.getDom(el);
9377 this.dom.insertBefore(el, this.dom.firstChild);
9378 return !returnDom ? Roo.get(el) : el;
9383 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9384 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9385 * @param {String} where (optional) 'before' or 'after' defaults to before
9386 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9387 * @return {Roo.Element} the inserted Element
9389 insertSibling: function(el, where, returnDom){
9390 where = where ? where.toLowerCase() : 'before';
9392 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9394 if(typeof el == 'object' && !el.nodeType){ // dh config
9395 if(where == 'after' && !this.dom.nextSibling){
9396 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9398 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9402 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9403 where == 'before' ? this.dom : this.dom.nextSibling);
9412 * Creates and wraps this element with another element
9413 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9414 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9415 * @return {HTMLElement/Element} The newly created wrapper element
9417 wrap: function(config, returnDom){
9419 config = {tag: "div"};
9421 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9422 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9427 * Replaces the passed element with this element
9428 * @param {String/HTMLElement/Element} el The element to replace
9429 * @return {Roo.Element} this
9431 replace: function(el){
9433 this.insertBefore(el);
9439 * Inserts an html fragment into this element
9440 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9441 * @param {String} html The HTML fragment
9442 * @param {Boolean} returnEl True to return an Roo.Element
9443 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9445 insertHtml : function(where, html, returnEl){
9446 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9447 return returnEl ? Roo.get(el) : el;
9451 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9452 * @param {Object} o The object with the attributes
9453 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9454 * @return {Roo.Element} this
9456 set : function(o, useSet){
9458 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9460 if(attr == "style" || typeof o[attr] == "function") { continue; }
9462 el.className = o["cls"];
9465 el.setAttribute(attr, o[attr]);
9472 Roo.DomHelper.applyStyles(el, o.style);
9478 * Convenience method for constructing a KeyMap
9479 * @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:
9480 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9481 * @param {Function} fn The function to call
9482 * @param {Object} scope (optional) The scope of the function
9483 * @return {Roo.KeyMap} The KeyMap created
9485 addKeyListener : function(key, fn, scope){
9487 if(typeof key != "object" || key instanceof Array){
9503 return new Roo.KeyMap(this, config);
9507 * Creates a KeyMap for this element
9508 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9509 * @return {Roo.KeyMap} The KeyMap created
9511 addKeyMap : function(config){
9512 return new Roo.KeyMap(this, config);
9516 * Returns true if this element is scrollable.
9519 isScrollable : function(){
9521 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9525 * 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().
9526 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9527 * @param {Number} value The new scroll value
9528 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9529 * @return {Element} this
9532 scrollTo : function(side, value, animate){
9533 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9535 this.dom[prop] = value;
9537 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9538 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9544 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9545 * within this element's scrollable range.
9546 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9547 * @param {Number} distance How far to scroll the element in pixels
9548 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9549 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9550 * was scrolled as far as it could go.
9552 scroll : function(direction, distance, animate){
9553 if(!this.isScrollable()){
9557 var l = el.scrollLeft, t = el.scrollTop;
9558 var w = el.scrollWidth, h = el.scrollHeight;
9559 var cw = el.clientWidth, ch = el.clientHeight;
9560 direction = direction.toLowerCase();
9561 var scrolled = false;
9562 var a = this.preanim(arguments, 2);
9567 var v = Math.min(l + distance, w-cw);
9568 this.scrollTo("left", v, a);
9575 var v = Math.max(l - distance, 0);
9576 this.scrollTo("left", v, a);
9584 var v = Math.max(t - distance, 0);
9585 this.scrollTo("top", v, a);
9593 var v = Math.min(t + distance, h-ch);
9594 this.scrollTo("top", v, a);
9603 * Translates the passed page coordinates into left/top css values for this element
9604 * @param {Number/Array} x The page x or an array containing [x, y]
9605 * @param {Number} y The page y
9606 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9608 translatePoints : function(x, y){
9609 if(typeof x == 'object' || x instanceof Array){
9612 var p = this.getStyle('position');
9613 var o = this.getXY();
9615 var l = parseInt(this.getStyle('left'), 10);
9616 var t = parseInt(this.getStyle('top'), 10);
9619 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9622 t = (p == "relative") ? 0 : this.dom.offsetTop;
9625 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9629 * Returns the current scroll position of the element.
9630 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9632 getScroll : function(){
9633 var d = this.dom, doc = document;
9634 if(d == doc || d == doc.body){
9635 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9636 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9637 return {left: l, top: t};
9639 return {left: d.scrollLeft, top: d.scrollTop};
9644 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9645 * are convert to standard 6 digit hex color.
9646 * @param {String} attr The css attribute
9647 * @param {String} defaultValue The default value to use when a valid color isn't found
9648 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9651 getColor : function(attr, defaultValue, prefix){
9652 var v = this.getStyle(attr);
9653 if(!v || v == "transparent" || v == "inherit") {
9654 return defaultValue;
9656 var color = typeof prefix == "undefined" ? "#" : prefix;
9657 if(v.substr(0, 4) == "rgb("){
9658 var rvs = v.slice(4, v.length -1).split(",");
9659 for(var i = 0; i < 3; i++){
9660 var h = parseInt(rvs[i]).toString(16);
9667 if(v.substr(0, 1) == "#"){
9669 for(var i = 1; i < 4; i++){
9670 var c = v.charAt(i);
9673 }else if(v.length == 7){
9674 color += v.substr(1);
9678 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9682 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9683 * gradient background, rounded corners and a 4-way shadow.
9684 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9685 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9686 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9687 * @return {Roo.Element} this
9689 boxWrap : function(cls){
9690 cls = cls || 'x-box';
9691 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9692 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9697 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9698 * @param {String} namespace The namespace in which to look for the attribute
9699 * @param {String} name The attribute name
9700 * @return {String} The attribute value
9702 getAttributeNS : Roo.isIE ? function(ns, name){
9704 var type = typeof d[ns+":"+name];
9705 if(type != 'undefined' && type != 'unknown'){
9706 return d[ns+":"+name];
9709 } : function(ns, name){
9711 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9716 * Sets or Returns the value the dom attribute value
9717 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9718 * @param {String} value (optional) The value to set the attribute to
9719 * @return {String} The attribute value
9721 attr : function(name){
9722 if (arguments.length > 1) {
9723 this.dom.setAttribute(name, arguments[1]);
9724 return arguments[1];
9726 if (typeof(name) == 'object') {
9727 for(var i in name) {
9728 this.attr(i, name[i]);
9734 if (!this.dom.hasAttribute(name)) {
9737 return this.dom.getAttribute(name);
9744 var ep = El.prototype;
9747 * Appends an event handler (Shorthand for addListener)
9748 * @param {String} eventName The type of event to append
9749 * @param {Function} fn The method the event invokes
9750 * @param {Object} scope (optional) The scope (this object) of the fn
9751 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9754 ep.on = ep.addListener;
9756 ep.mon = ep.addListener;
9759 * Removes an event handler from this element (shorthand for removeListener)
9760 * @param {String} eventName the type of event to remove
9761 * @param {Function} fn the method the event invokes
9762 * @return {Roo.Element} this
9765 ep.un = ep.removeListener;
9768 * true to automatically adjust width and height settings for box-model issues (default to true)
9770 ep.autoBoxAdjust = true;
9773 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9776 El.addUnits = function(v, defaultUnit){
9777 if(v === "" || v == "auto"){
9780 if(v === undefined){
9783 if(typeof v == "number" || !El.unitPattern.test(v)){
9784 return v + (defaultUnit || 'px');
9789 // special markup used throughout Roo when box wrapping elements
9790 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>';
9792 * Visibility mode constant - Use visibility to hide element
9798 * Visibility mode constant - Use display to hide element
9804 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9805 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9806 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9818 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9819 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9820 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9821 * @return {Element} The Element object
9824 El.get = function(el){
9826 if(!el){ return null; }
9827 if(typeof el == "string"){ // element id
9828 if(!(elm = document.getElementById(el))){
9831 if(ex = El.cache[el]){
9834 ex = El.cache[el] = new El(elm);
9837 }else if(el.tagName){ // dom element
9841 if(ex = El.cache[id]){
9844 ex = El.cache[id] = new El(el);
9847 }else if(el instanceof El){
9849 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9850 // catch case where it hasn't been appended
9851 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9854 }else if(el.isComposite){
9856 }else if(el instanceof Array){
9857 return El.select(el);
9858 }else if(el == document){
9859 // create a bogus element object representing the document object
9861 var f = function(){};
9862 f.prototype = El.prototype;
9864 docEl.dom = document;
9872 El.uncache = function(el){
9873 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9875 delete El.cache[a[i].id || a[i]];
9881 // Garbage collection - uncache elements/purge listeners on orphaned elements
9882 // so we don't hold a reference and cause the browser to retain them
9883 El.garbageCollect = function(){
9884 if(!Roo.enableGarbageCollector){
9885 clearInterval(El.collectorThread);
9888 for(var eid in El.cache){
9889 var el = El.cache[eid], d = el.dom;
9890 // -------------------------------------------------------
9891 // Determining what is garbage:
9892 // -------------------------------------------------------
9894 // dom node is null, definitely garbage
9895 // -------------------------------------------------------
9897 // no parentNode == direct orphan, definitely garbage
9898 // -------------------------------------------------------
9899 // !d.offsetParent && !document.getElementById(eid)
9900 // display none elements have no offsetParent so we will
9901 // also try to look it up by it's id. However, check
9902 // offsetParent first so we don't do unneeded lookups.
9903 // This enables collection of elements that are not orphans
9904 // directly, but somewhere up the line they have an orphan
9906 // -------------------------------------------------------
9907 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9908 delete El.cache[eid];
9909 if(d && Roo.enableListenerCollection){
9915 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9919 El.Flyweight = function(dom){
9922 El.Flyweight.prototype = El.prototype;
9924 El._flyweights = {};
9926 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9927 * the dom node can be overwritten by other code.
9928 * @param {String/HTMLElement} el The dom node or id
9929 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9930 * prevent conflicts (e.g. internally Roo uses "_internal")
9932 * @return {Element} The shared Element object
9934 El.fly = function(el, named){
9935 named = named || '_global';
9936 el = Roo.getDom(el);
9940 if(!El._flyweights[named]){
9941 El._flyweights[named] = new El.Flyweight();
9943 El._flyweights[named].dom = el;
9944 return El._flyweights[named];
9948 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9949 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9950 * Shorthand of {@link Roo.Element#get}
9951 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9952 * @return {Element} The Element object
9958 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9959 * the dom node can be overwritten by other code.
9960 * Shorthand of {@link Roo.Element#fly}
9961 * @param {String/HTMLElement} el The dom node or id
9962 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9963 * prevent conflicts (e.g. internally Roo uses "_internal")
9965 * @return {Element} The shared Element object
9971 // speedy lookup for elements never to box adjust
9972 var noBoxAdjust = Roo.isStrict ? {
9975 input:1, select:1, textarea:1
9977 if(Roo.isIE || Roo.isGecko){
9978 noBoxAdjust['button'] = 1;
9982 Roo.EventManager.on(window, 'unload', function(){
9984 delete El._flyweights;
9992 Roo.Element.selectorFunction = Roo.DomQuery.select;
9995 Roo.Element.select = function(selector, unique, root){
9997 if(typeof selector == "string"){
9998 els = Roo.Element.selectorFunction(selector, root);
9999 }else if(selector.length !== undefined){
10002 throw "Invalid selector";
10004 if(unique === true){
10005 return new Roo.CompositeElement(els);
10007 return new Roo.CompositeElementLite(els);
10011 * Selects elements based on the passed CSS selector to enable working on them as 1.
10012 * @param {String/Array} selector The CSS selector or an array of elements
10013 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10014 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10015 * @return {CompositeElementLite/CompositeElement}
10019 Roo.select = Roo.Element.select;
10036 * Ext JS Library 1.1.1
10037 * Copyright(c) 2006-2007, Ext JS, LLC.
10039 * Originally Released Under LGPL - original licence link has changed is not relivant.
10042 * <script type="text/javascript">
10047 //Notifies Element that fx methods are available
10048 Roo.enableFx = true;
10052 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10053 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10054 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10055 * Element effects to work.</p><br/>
10057 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10058 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10059 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10060 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10061 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10062 * expected results and should be done with care.</p><br/>
10064 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10065 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10068 ----- -----------------------------
10069 tl The top left corner
10070 t The center of the top edge
10071 tr The top right corner
10072 l The center of the left edge
10073 r The center of the right edge
10074 bl The bottom left corner
10075 b The center of the bottom edge
10076 br The bottom right corner
10078 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10079 * below are common options that can be passed to any Fx method.</b>
10080 * @cfg {Function} callback A function called when the effect is finished
10081 * @cfg {Object} scope The scope of the effect function
10082 * @cfg {String} easing A valid Easing value for the effect
10083 * @cfg {String} afterCls A css class to apply after the effect
10084 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10085 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10086 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10087 * effects that end with the element being visually hidden, ignored otherwise)
10088 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10089 * a function which returns such a specification that will be applied to the Element after the effect finishes
10090 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10091 * @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
10092 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10096 * Slides the element into view. An anchor point can be optionally passed to set the point of
10097 * origin for the slide effect. This function automatically handles wrapping the element with
10098 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10101 // default: slide the element in from the top
10104 // custom: slide the element in from the right with a 2-second duration
10105 el.slideIn('r', { duration: 2 });
10107 // common config options shown with default values
10113 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10114 * @param {Object} options (optional) Object literal with any of the Fx config options
10115 * @return {Roo.Element} The Element
10117 slideIn : function(anchor, o){
10118 var el = this.getFxEl();
10121 el.queueFx(o, function(){
10123 anchor = anchor || "t";
10125 // fix display to visibility
10128 // restore values after effect
10129 var r = this.getFxRestore();
10130 var b = this.getBox();
10131 // fixed size for slide
10135 var wrap = this.fxWrap(r.pos, o, "hidden");
10137 var st = this.dom.style;
10138 st.visibility = "visible";
10139 st.position = "absolute";
10141 // clear out temp styles after slide and unwrap
10142 var after = function(){
10143 el.fxUnwrap(wrap, r.pos, o);
10144 st.width = r.width;
10145 st.height = r.height;
10148 // time to calc the positions
10149 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10151 switch(anchor.toLowerCase()){
10153 wrap.setSize(b.width, 0);
10154 st.left = st.bottom = "0";
10158 wrap.setSize(0, b.height);
10159 st.right = st.top = "0";
10163 wrap.setSize(0, b.height);
10164 wrap.setX(b.right);
10165 st.left = st.top = "0";
10166 a = {width: bw, points: pt};
10169 wrap.setSize(b.width, 0);
10170 wrap.setY(b.bottom);
10171 st.left = st.top = "0";
10172 a = {height: bh, points: pt};
10175 wrap.setSize(0, 0);
10176 st.right = st.bottom = "0";
10177 a = {width: bw, height: bh};
10180 wrap.setSize(0, 0);
10181 wrap.setY(b.y+b.height);
10182 st.right = st.top = "0";
10183 a = {width: bw, height: bh, points: pt};
10186 wrap.setSize(0, 0);
10187 wrap.setXY([b.right, b.bottom]);
10188 st.left = st.top = "0";
10189 a = {width: bw, height: bh, points: pt};
10192 wrap.setSize(0, 0);
10193 wrap.setX(b.x+b.width);
10194 st.left = st.bottom = "0";
10195 a = {width: bw, height: bh, points: pt};
10198 this.dom.style.visibility = "visible";
10201 arguments.callee.anim = wrap.fxanim(a,
10211 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10212 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10213 * 'hidden') but block elements will still take up space in the document. The element must be removed
10214 * from the DOM using the 'remove' config option if desired. This function automatically handles
10215 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10218 // default: slide the element out to the top
10221 // custom: slide the element out to the right with a 2-second duration
10222 el.slideOut('r', { duration: 2 });
10224 // common config options shown with default values
10232 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10233 * @param {Object} options (optional) Object literal with any of the Fx config options
10234 * @return {Roo.Element} The Element
10236 slideOut : function(anchor, o){
10237 var el = this.getFxEl();
10240 el.queueFx(o, function(){
10242 anchor = anchor || "t";
10244 // restore values after effect
10245 var r = this.getFxRestore();
10247 var b = this.getBox();
10248 // fixed size for slide
10252 var wrap = this.fxWrap(r.pos, o, "visible");
10254 var st = this.dom.style;
10255 st.visibility = "visible";
10256 st.position = "absolute";
10260 var after = function(){
10262 el.setDisplayed(false);
10267 el.fxUnwrap(wrap, r.pos, o);
10269 st.width = r.width;
10270 st.height = r.height;
10275 var a, zero = {to: 0};
10276 switch(anchor.toLowerCase()){
10278 st.left = st.bottom = "0";
10279 a = {height: zero};
10282 st.right = st.top = "0";
10286 st.left = st.top = "0";
10287 a = {width: zero, points: {to:[b.right, b.y]}};
10290 st.left = st.top = "0";
10291 a = {height: zero, points: {to:[b.x, b.bottom]}};
10294 st.right = st.bottom = "0";
10295 a = {width: zero, height: zero};
10298 st.right = st.top = "0";
10299 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10302 st.left = st.top = "0";
10303 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10306 st.left = st.bottom = "0";
10307 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10311 arguments.callee.anim = wrap.fxanim(a,
10321 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10322 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10323 * The element must be removed from the DOM using the 'remove' config option if desired.
10329 // common config options shown with default values
10337 * @param {Object} options (optional) Object literal with any of the Fx config options
10338 * @return {Roo.Element} The Element
10340 puff : function(o){
10341 var el = this.getFxEl();
10344 el.queueFx(o, function(){
10345 this.clearOpacity();
10348 // restore values after effect
10349 var r = this.getFxRestore();
10350 var st = this.dom.style;
10352 var after = function(){
10354 el.setDisplayed(false);
10361 el.setPositioning(r.pos);
10362 st.width = r.width;
10363 st.height = r.height;
10368 var width = this.getWidth();
10369 var height = this.getHeight();
10371 arguments.callee.anim = this.fxanim({
10372 width : {to: this.adjustWidth(width * 2)},
10373 height : {to: this.adjustHeight(height * 2)},
10374 points : {by: [-(width * .5), -(height * .5)]},
10376 fontSize: {to:200, unit: "%"}
10387 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10388 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10389 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10395 // all config options shown with default values
10403 * @param {Object} options (optional) Object literal with any of the Fx config options
10404 * @return {Roo.Element} The Element
10406 switchOff : function(o){
10407 var el = this.getFxEl();
10410 el.queueFx(o, function(){
10411 this.clearOpacity();
10414 // restore values after effect
10415 var r = this.getFxRestore();
10416 var st = this.dom.style;
10418 var after = function(){
10420 el.setDisplayed(false);
10426 el.setPositioning(r.pos);
10427 st.width = r.width;
10428 st.height = r.height;
10433 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10434 this.clearOpacity();
10438 points:{by:[0, this.getHeight() * .5]}
10439 }, o, 'motion', 0.3, 'easeIn', after);
10440 }).defer(100, this);
10447 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10448 * changed using the "attr" config option) and then fading back to the original color. If no original
10449 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10452 // default: highlight background to yellow
10455 // custom: highlight foreground text to blue for 2 seconds
10456 el.highlight("0000ff", { attr: 'color', duration: 2 });
10458 // common config options shown with default values
10459 el.highlight("ffff9c", {
10460 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10461 endColor: (current color) or "ffffff",
10466 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10467 * @param {Object} options (optional) Object literal with any of the Fx config options
10468 * @return {Roo.Element} The Element
10470 highlight : function(color, o){
10471 var el = this.getFxEl();
10474 el.queueFx(o, function(){
10475 color = color || "ffff9c";
10476 attr = o.attr || "backgroundColor";
10478 this.clearOpacity();
10481 var origColor = this.getColor(attr);
10482 var restoreColor = this.dom.style[attr];
10483 endColor = (o.endColor || origColor) || "ffffff";
10485 var after = function(){
10486 el.dom.style[attr] = restoreColor;
10491 a[attr] = {from: color, to: endColor};
10492 arguments.callee.anim = this.fxanim(a,
10502 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10505 // default: a single light blue ripple
10508 // custom: 3 red ripples lasting 3 seconds total
10509 el.frame("ff0000", 3, { duration: 3 });
10511 // common config options shown with default values
10512 el.frame("C3DAF9", 1, {
10513 duration: 1 //duration of entire animation (not each individual ripple)
10514 // Note: Easing is not configurable and will be ignored if included
10517 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10518 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10519 * @param {Object} options (optional) Object literal with any of the Fx config options
10520 * @return {Roo.Element} The Element
10522 frame : function(color, count, o){
10523 var el = this.getFxEl();
10526 el.queueFx(o, function(){
10527 color = color || "#C3DAF9";
10528 if(color.length == 6){
10529 color = "#" + color;
10531 count = count || 1;
10532 duration = o.duration || 1;
10535 var b = this.getBox();
10536 var animFn = function(){
10537 var proxy = this.createProxy({
10540 visbility:"hidden",
10541 position:"absolute",
10542 "z-index":"35000", // yee haw
10543 border:"0px solid " + color
10546 var scale = Roo.isBorderBox ? 2 : 1;
10548 top:{from:b.y, to:b.y - 20},
10549 left:{from:b.x, to:b.x - 20},
10550 borderWidth:{from:0, to:10},
10551 opacity:{from:1, to:0},
10552 height:{from:b.height, to:(b.height + (20*scale))},
10553 width:{from:b.width, to:(b.width + (20*scale))}
10554 }, duration, function(){
10558 animFn.defer((duration/2)*1000, this);
10569 * Creates a pause before any subsequent queued effects begin. If there are
10570 * no effects queued after the pause it will have no effect.
10575 * @param {Number} seconds The length of time to pause (in seconds)
10576 * @return {Roo.Element} The Element
10578 pause : function(seconds){
10579 var el = this.getFxEl();
10582 el.queueFx(o, function(){
10583 setTimeout(function(){
10585 }, seconds * 1000);
10591 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10592 * using the "endOpacity" config option.
10595 // default: fade in from opacity 0 to 100%
10598 // custom: fade in from opacity 0 to 75% over 2 seconds
10599 el.fadeIn({ endOpacity: .75, duration: 2});
10601 // common config options shown with default values
10603 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10608 * @param {Object} options (optional) Object literal with any of the Fx config options
10609 * @return {Roo.Element} The Element
10611 fadeIn : function(o){
10612 var el = this.getFxEl();
10614 el.queueFx(o, function(){
10615 this.setOpacity(0);
10617 this.dom.style.visibility = 'visible';
10618 var to = o.endOpacity || 1;
10619 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10620 o, null, .5, "easeOut", function(){
10622 this.clearOpacity();
10631 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10632 * using the "endOpacity" config option.
10635 // default: fade out from the element's current opacity to 0
10638 // custom: fade out from the element's current opacity to 25% over 2 seconds
10639 el.fadeOut({ endOpacity: .25, duration: 2});
10641 // common config options shown with default values
10643 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10650 * @param {Object} options (optional) Object literal with any of the Fx config options
10651 * @return {Roo.Element} The Element
10653 fadeOut : function(o){
10654 var el = this.getFxEl();
10656 el.queueFx(o, function(){
10657 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10658 o, null, .5, "easeOut", function(){
10659 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10660 this.dom.style.display = "none";
10662 this.dom.style.visibility = "hidden";
10664 this.clearOpacity();
10672 * Animates the transition of an element's dimensions from a starting height/width
10673 * to an ending height/width.
10676 // change height and width to 100x100 pixels
10677 el.scale(100, 100);
10679 // common config options shown with default values. The height and width will default to
10680 // the element's existing values if passed as null.
10683 [element's height], {
10688 * @param {Number} width The new width (pass undefined to keep the original width)
10689 * @param {Number} height The new height (pass undefined to keep the original height)
10690 * @param {Object} options (optional) Object literal with any of the Fx config options
10691 * @return {Roo.Element} The Element
10693 scale : function(w, h, o){
10694 this.shift(Roo.apply({}, o, {
10702 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10703 * Any of these properties not specified in the config object will not be changed. This effect
10704 * requires that at least one new dimension, position or opacity setting must be passed in on
10705 * the config object in order for the function to have any effect.
10708 // slide the element horizontally to x position 200 while changing the height and opacity
10709 el.shift({ x: 200, height: 50, opacity: .8 });
10711 // common config options shown with default values.
10713 width: [element's width],
10714 height: [element's height],
10715 x: [element's x position],
10716 y: [element's y position],
10717 opacity: [element's opacity],
10722 * @param {Object} options Object literal with any of the Fx config options
10723 * @return {Roo.Element} The Element
10725 shift : function(o){
10726 var el = this.getFxEl();
10728 el.queueFx(o, function(){
10729 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10730 if(w !== undefined){
10731 a.width = {to: this.adjustWidth(w)};
10733 if(h !== undefined){
10734 a.height = {to: this.adjustHeight(h)};
10736 if(x !== undefined || y !== undefined){
10738 x !== undefined ? x : this.getX(),
10739 y !== undefined ? y : this.getY()
10742 if(op !== undefined){
10743 a.opacity = {to: op};
10745 if(o.xy !== undefined){
10746 a.points = {to: o.xy};
10748 arguments.callee.anim = this.fxanim(a,
10749 o, 'motion', .35, "easeOut", function(){
10757 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10758 * ending point of the effect.
10761 // default: slide the element downward while fading out
10764 // custom: slide the element out to the right with a 2-second duration
10765 el.ghost('r', { duration: 2 });
10767 // common config options shown with default values
10775 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10776 * @param {Object} options (optional) Object literal with any of the Fx config options
10777 * @return {Roo.Element} The Element
10779 ghost : function(anchor, o){
10780 var el = this.getFxEl();
10783 el.queueFx(o, function(){
10784 anchor = anchor || "b";
10786 // restore values after effect
10787 var r = this.getFxRestore();
10788 var w = this.getWidth(),
10789 h = this.getHeight();
10791 var st = this.dom.style;
10793 var after = function(){
10795 el.setDisplayed(false);
10801 el.setPositioning(r.pos);
10802 st.width = r.width;
10803 st.height = r.height;
10808 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10809 switch(anchor.toLowerCase()){
10836 arguments.callee.anim = this.fxanim(a,
10846 * Ensures that all effects queued after syncFx is called on the element are
10847 * run concurrently. This is the opposite of {@link #sequenceFx}.
10848 * @return {Roo.Element} The Element
10850 syncFx : function(){
10851 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10860 * Ensures that all effects queued after sequenceFx is called on the element are
10861 * run in sequence. This is the opposite of {@link #syncFx}.
10862 * @return {Roo.Element} The Element
10864 sequenceFx : function(){
10865 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10867 concurrent : false,
10874 nextFx : function(){
10875 var ef = this.fxQueue[0];
10882 * Returns true if the element has any effects actively running or queued, else returns false.
10883 * @return {Boolean} True if element has active effects, else false
10885 hasActiveFx : function(){
10886 return this.fxQueue && this.fxQueue[0];
10890 * Stops any running effects and clears the element's internal effects queue if it contains
10891 * any additional effects that haven't started yet.
10892 * @return {Roo.Element} The Element
10894 stopFx : function(){
10895 if(this.hasActiveFx()){
10896 var cur = this.fxQueue[0];
10897 if(cur && cur.anim && cur.anim.isAnimated()){
10898 this.fxQueue = [cur]; // clear out others
10899 cur.anim.stop(true);
10906 beforeFx : function(o){
10907 if(this.hasActiveFx() && !o.concurrent){
10918 * Returns true if the element is currently blocking so that no other effect can be queued
10919 * until this effect is finished, else returns false if blocking is not set. This is commonly
10920 * used to ensure that an effect initiated by a user action runs to completion prior to the
10921 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10922 * @return {Boolean} True if blocking, else false
10924 hasFxBlock : function(){
10925 var q = this.fxQueue;
10926 return q && q[0] && q[0].block;
10930 queueFx : function(o, fn){
10934 if(!this.hasFxBlock()){
10935 Roo.applyIf(o, this.fxDefaults);
10937 var run = this.beforeFx(o);
10938 fn.block = o.block;
10939 this.fxQueue.push(fn);
10951 fxWrap : function(pos, o, vis){
10953 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10956 wrapXY = this.getXY();
10958 var div = document.createElement("div");
10959 div.style.visibility = vis;
10960 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10961 wrap.setPositioning(pos);
10962 if(wrap.getStyle("position") == "static"){
10963 wrap.position("relative");
10965 this.clearPositioning('auto');
10967 wrap.dom.appendChild(this.dom);
10969 wrap.setXY(wrapXY);
10976 fxUnwrap : function(wrap, pos, o){
10977 this.clearPositioning();
10978 this.setPositioning(pos);
10980 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10986 getFxRestore : function(){
10987 var st = this.dom.style;
10988 return {pos: this.getPositioning(), width: st.width, height : st.height};
10992 afterFx : function(o){
10994 this.applyStyles(o.afterStyle);
10997 this.addClass(o.afterCls);
10999 if(o.remove === true){
11002 Roo.callback(o.callback, o.scope, [this]);
11004 this.fxQueue.shift();
11010 getFxEl : function(){ // support for composite element fx
11011 return Roo.get(this.dom);
11015 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11016 animType = animType || 'run';
11018 var anim = Roo.lib.Anim[animType](
11020 (opt.duration || defaultDur) || .35,
11021 (opt.easing || defaultEase) || 'easeOut',
11023 Roo.callback(cb, this);
11032 // backwords compat
11033 Roo.Fx.resize = Roo.Fx.scale;
11035 //When included, Roo.Fx is automatically applied to Element so that all basic
11036 //effects are available directly via the Element API
11037 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11039 * Ext JS Library 1.1.1
11040 * Copyright(c) 2006-2007, Ext JS, LLC.
11042 * Originally Released Under LGPL - original licence link has changed is not relivant.
11045 * <script type="text/javascript">
11050 * @class Roo.CompositeElement
11051 * Standard composite class. Creates a Roo.Element for every element in the collection.
11053 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11054 * actions will be performed on all the elements in this collection.</b>
11056 * All methods return <i>this</i> and can be chained.
11058 var els = Roo.select("#some-el div.some-class", true);
11059 // or select directly from an existing element
11060 var el = Roo.get('some-el');
11061 el.select('div.some-class', true);
11063 els.setWidth(100); // all elements become 100 width
11064 els.hide(true); // all elements fade out and hide
11066 els.setWidth(100).hide(true);
11069 Roo.CompositeElement = function(els){
11070 this.elements = [];
11071 this.addElements(els);
11073 Roo.CompositeElement.prototype = {
11075 addElements : function(els){
11079 if(typeof els == "string"){
11080 els = Roo.Element.selectorFunction(els);
11082 var yels = this.elements;
11083 var index = yels.length-1;
11084 for(var i = 0, len = els.length; i < len; i++) {
11085 yels[++index] = Roo.get(els[i]);
11091 * Clears this composite and adds the elements returned by the passed selector.
11092 * @param {String/Array} els A string CSS selector, an array of elements or an element
11093 * @return {CompositeElement} this
11095 fill : function(els){
11096 this.elements = [];
11102 * Filters this composite to only elements that match the passed selector.
11103 * @param {String} selector A string CSS selector
11104 * @param {Boolean} inverse return inverse filter (not matches)
11105 * @return {CompositeElement} this
11107 filter : function(selector, inverse){
11109 inverse = inverse || false;
11110 this.each(function(el){
11111 var match = inverse ? !el.is(selector) : el.is(selector);
11113 els[els.length] = el.dom;
11120 invoke : function(fn, args){
11121 var els = this.elements;
11122 for(var i = 0, len = els.length; i < len; i++) {
11123 Roo.Element.prototype[fn].apply(els[i], args);
11128 * Adds elements to this composite.
11129 * @param {String/Array} els A string CSS selector, an array of elements or an element
11130 * @return {CompositeElement} this
11132 add : function(els){
11133 if(typeof els == "string"){
11134 this.addElements(Roo.Element.selectorFunction(els));
11135 }else if(els.length !== undefined){
11136 this.addElements(els);
11138 this.addElements([els]);
11143 * Calls the passed function passing (el, this, index) for each element in this composite.
11144 * @param {Function} fn The function to call
11145 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11146 * @return {CompositeElement} this
11148 each : function(fn, scope){
11149 var els = this.elements;
11150 for(var i = 0, len = els.length; i < len; i++){
11151 if(fn.call(scope || els[i], els[i], this, i) === false) {
11159 * Returns the Element object at the specified index
11160 * @param {Number} index
11161 * @return {Roo.Element}
11163 item : function(index){
11164 return this.elements[index] || null;
11168 * Returns the first Element
11169 * @return {Roo.Element}
11171 first : function(){
11172 return this.item(0);
11176 * Returns the last Element
11177 * @return {Roo.Element}
11180 return this.item(this.elements.length-1);
11184 * Returns the number of elements in this composite
11187 getCount : function(){
11188 return this.elements.length;
11192 * Returns true if this composite contains the passed element
11195 contains : function(el){
11196 return this.indexOf(el) !== -1;
11200 * Returns true if this composite contains the passed element
11203 indexOf : function(el){
11204 return this.elements.indexOf(Roo.get(el));
11209 * Removes the specified element(s).
11210 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11211 * or an array of any of those.
11212 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11213 * @return {CompositeElement} this
11215 removeElement : function(el, removeDom){
11216 if(el instanceof Array){
11217 for(var i = 0, len = el.length; i < len; i++){
11218 this.removeElement(el[i]);
11222 var index = typeof el == 'number' ? el : this.indexOf(el);
11225 var d = this.elements[index];
11229 d.parentNode.removeChild(d);
11232 this.elements.splice(index, 1);
11238 * Replaces the specified element with the passed element.
11239 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11241 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11242 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11243 * @return {CompositeElement} this
11245 replaceElement : function(el, replacement, domReplace){
11246 var index = typeof el == 'number' ? el : this.indexOf(el);
11249 this.elements[index].replaceWith(replacement);
11251 this.elements.splice(index, 1, Roo.get(replacement))
11258 * Removes all elements.
11260 clear : function(){
11261 this.elements = [];
11265 Roo.CompositeElement.createCall = function(proto, fnName){
11266 if(!proto[fnName]){
11267 proto[fnName] = function(){
11268 return this.invoke(fnName, arguments);
11272 for(var fnName in Roo.Element.prototype){
11273 if(typeof Roo.Element.prototype[fnName] == "function"){
11274 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11280 * Ext JS Library 1.1.1
11281 * Copyright(c) 2006-2007, Ext JS, LLC.
11283 * Originally Released Under LGPL - original licence link has changed is not relivant.
11286 * <script type="text/javascript">
11290 * @class Roo.CompositeElementLite
11291 * @extends Roo.CompositeElement
11292 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11294 var els = Roo.select("#some-el div.some-class");
11295 // or select directly from an existing element
11296 var el = Roo.get('some-el');
11297 el.select('div.some-class');
11299 els.setWidth(100); // all elements become 100 width
11300 els.hide(true); // all elements fade out and hide
11302 els.setWidth(100).hide(true);
11303 </code></pre><br><br>
11304 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11305 * actions will be performed on all the elements in this collection.</b>
11307 Roo.CompositeElementLite = function(els){
11308 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11309 this.el = new Roo.Element.Flyweight();
11311 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11312 addElements : function(els){
11314 if(els instanceof Array){
11315 this.elements = this.elements.concat(els);
11317 var yels = this.elements;
11318 var index = yels.length-1;
11319 for(var i = 0, len = els.length; i < len; i++) {
11320 yels[++index] = els[i];
11326 invoke : function(fn, args){
11327 var els = this.elements;
11329 for(var i = 0, len = els.length; i < len; i++) {
11331 Roo.Element.prototype[fn].apply(el, args);
11336 * Returns a flyweight Element of the dom element object at the specified index
11337 * @param {Number} index
11338 * @return {Roo.Element}
11340 item : function(index){
11341 if(!this.elements[index]){
11344 this.el.dom = this.elements[index];
11348 // fixes scope with flyweight
11349 addListener : function(eventName, handler, scope, opt){
11350 var els = this.elements;
11351 for(var i = 0, len = els.length; i < len; i++) {
11352 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11358 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11359 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11360 * a reference to the dom node, use el.dom.</b>
11361 * @param {Function} fn The function to call
11362 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11363 * @return {CompositeElement} this
11365 each : function(fn, scope){
11366 var els = this.elements;
11368 for(var i = 0, len = els.length; i < len; i++){
11370 if(fn.call(scope || el, el, this, i) === false){
11377 indexOf : function(el){
11378 return this.elements.indexOf(Roo.getDom(el));
11381 replaceElement : function(el, replacement, domReplace){
11382 var index = typeof el == 'number' ? el : this.indexOf(el);
11384 replacement = Roo.getDom(replacement);
11386 var d = this.elements[index];
11387 d.parentNode.insertBefore(replacement, d);
11388 d.parentNode.removeChild(d);
11390 this.elements.splice(index, 1, replacement);
11395 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11399 * Ext JS Library 1.1.1
11400 * Copyright(c) 2006-2007, Ext JS, LLC.
11402 * Originally Released Under LGPL - original licence link has changed is not relivant.
11405 * <script type="text/javascript">
11411 * @class Roo.data.Connection
11412 * @extends Roo.util.Observable
11413 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11414 * either to a configured URL, or to a URL specified at request time.<br><br>
11416 * Requests made by this class are asynchronous, and will return immediately. No data from
11417 * the server will be available to the statement immediately following the {@link #request} call.
11418 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11420 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11421 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11422 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11423 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11424 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11425 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11426 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11427 * standard DOM methods.
11429 * @param {Object} config a configuration object.
11431 Roo.data.Connection = function(config){
11432 Roo.apply(this, config);
11435 * @event beforerequest
11436 * Fires before a network request is made to retrieve a data object.
11437 * @param {Connection} conn This Connection object.
11438 * @param {Object} options The options config object passed to the {@link #request} method.
11440 "beforerequest" : true,
11442 * @event requestcomplete
11443 * Fires if the request was successfully completed.
11444 * @param {Connection} conn This Connection object.
11445 * @param {Object} response The XHR object containing the response data.
11446 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11447 * @param {Object} options The options config object passed to the {@link #request} method.
11449 "requestcomplete" : true,
11451 * @event requestexception
11452 * Fires if an error HTTP status was returned from the server.
11453 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11454 * @param {Connection} conn This Connection object.
11455 * @param {Object} response The XHR object containing the response data.
11456 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11457 * @param {Object} options The options config object passed to the {@link #request} method.
11459 "requestexception" : true
11461 Roo.data.Connection.superclass.constructor.call(this);
11464 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11466 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11469 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11470 * extra parameters to each request made by this object. (defaults to undefined)
11473 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11474 * to each request made by this object. (defaults to undefined)
11477 * @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)
11480 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11484 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11490 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11493 disableCaching: true,
11496 * Sends an HTTP request to a remote server.
11497 * @param {Object} options An object which may contain the following properties:<ul>
11498 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11499 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11500 * request, a url encoded string or a function to call to get either.</li>
11501 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11502 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11503 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11504 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11505 * <li>options {Object} The parameter to the request call.</li>
11506 * <li>success {Boolean} True if the request succeeded.</li>
11507 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11509 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11510 * The callback is passed the following parameters:<ul>
11511 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11512 * <li>options {Object} The parameter to the request call.</li>
11514 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11515 * The callback is passed the following parameters:<ul>
11516 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11517 * <li>options {Object} The parameter to the request call.</li>
11519 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11520 * for the callback function. Defaults to the browser window.</li>
11521 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11522 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11523 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11524 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11525 * params for the post data. Any params will be appended to the URL.</li>
11526 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11528 * @return {Number} transactionId
11530 request : function(o){
11531 if(this.fireEvent("beforerequest", this, o) !== false){
11534 if(typeof p == "function"){
11535 p = p.call(o.scope||window, o);
11537 if(typeof p == "object"){
11538 p = Roo.urlEncode(o.params);
11540 if(this.extraParams){
11541 var extras = Roo.urlEncode(this.extraParams);
11542 p = p ? (p + '&' + extras) : extras;
11545 var url = o.url || this.url;
11546 if(typeof url == 'function'){
11547 url = url.call(o.scope||window, o);
11551 var form = Roo.getDom(o.form);
11552 url = url || form.action;
11554 var enctype = form.getAttribute("enctype");
11555 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11556 return this.doFormUpload(o, p, url);
11558 var f = Roo.lib.Ajax.serializeForm(form);
11559 p = p ? (p + '&' + f) : f;
11562 var hs = o.headers;
11563 if(this.defaultHeaders){
11564 hs = Roo.apply(hs || {}, this.defaultHeaders);
11571 success: this.handleResponse,
11572 failure: this.handleFailure,
11574 argument: {options: o},
11575 timeout : o.timeout || this.timeout
11578 var method = o.method||this.method||(p ? "POST" : "GET");
11580 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11581 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11584 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11588 }else if(this.autoAbort !== false){
11592 if((method == 'GET' && p) || o.xmlData){
11593 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11596 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11597 return this.transId;
11599 Roo.callback(o.callback, o.scope, [o, null, null]);
11605 * Determine whether this object has a request outstanding.
11606 * @param {Number} transactionId (Optional) defaults to the last transaction
11607 * @return {Boolean} True if there is an outstanding request.
11609 isLoading : function(transId){
11611 return Roo.lib.Ajax.isCallInProgress(transId);
11613 return this.transId ? true : false;
11618 * Aborts any outstanding request.
11619 * @param {Number} transactionId (Optional) defaults to the last transaction
11621 abort : function(transId){
11622 if(transId || this.isLoading()){
11623 Roo.lib.Ajax.abort(transId || this.transId);
11628 handleResponse : function(response){
11629 this.transId = false;
11630 var options = response.argument.options;
11631 response.argument = options ? options.argument : null;
11632 this.fireEvent("requestcomplete", this, response, options);
11633 Roo.callback(options.success, options.scope, [response, options]);
11634 Roo.callback(options.callback, options.scope, [options, true, response]);
11638 handleFailure : function(response, e){
11639 this.transId = false;
11640 var options = response.argument.options;
11641 response.argument = options ? options.argument : null;
11642 this.fireEvent("requestexception", this, response, options, e);
11643 Roo.callback(options.failure, options.scope, [response, options]);
11644 Roo.callback(options.callback, options.scope, [options, false, response]);
11648 doFormUpload : function(o, ps, url){
11650 var frame = document.createElement('iframe');
11653 frame.className = 'x-hidden';
11655 frame.src = Roo.SSL_SECURE_URL;
11657 document.body.appendChild(frame);
11660 document.frames[id].name = id;
11663 var form = Roo.getDom(o.form);
11665 form.method = 'POST';
11666 form.enctype = form.encoding = 'multipart/form-data';
11672 if(ps){ // add dynamic params
11674 ps = Roo.urlDecode(ps, false);
11676 if(ps.hasOwnProperty(k)){
11677 hd = document.createElement('input');
11678 hd.type = 'hidden';
11681 form.appendChild(hd);
11688 var r = { // bogus response object
11693 r.argument = o ? o.argument : null;
11698 doc = frame.contentWindow.document;
11700 doc = (frame.contentDocument || window.frames[id].document);
11702 if(doc && doc.body){
11703 r.responseText = doc.body.innerHTML;
11705 if(doc && doc.XMLDocument){
11706 r.responseXML = doc.XMLDocument;
11708 r.responseXML = doc;
11715 Roo.EventManager.removeListener(frame, 'load', cb, this);
11717 this.fireEvent("requestcomplete", this, r, o);
11718 Roo.callback(o.success, o.scope, [r, o]);
11719 Roo.callback(o.callback, o.scope, [o, true, r]);
11721 setTimeout(function(){document.body.removeChild(frame);}, 100);
11724 Roo.EventManager.on(frame, 'load', cb, this);
11727 if(hiddens){ // remove dynamic params
11728 for(var i = 0, len = hiddens.length; i < len; i++){
11729 form.removeChild(hiddens[i]);
11736 * Ext JS Library 1.1.1
11737 * Copyright(c) 2006-2007, Ext JS, LLC.
11739 * Originally Released Under LGPL - original licence link has changed is not relivant.
11742 * <script type="text/javascript">
11746 * Global Ajax request class.
11749 * @extends Roo.data.Connection
11752 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11753 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11754 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11755 * @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)
11756 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11757 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11758 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11760 Roo.Ajax = new Roo.data.Connection({
11769 * Serialize the passed form into a url encoded string
11771 * @param {String/HTMLElement} form
11774 serializeForm : function(form){
11775 return Roo.lib.Ajax.serializeForm(form);
11779 * Ext JS Library 1.1.1
11780 * Copyright(c) 2006-2007, Ext JS, LLC.
11782 * Originally Released Under LGPL - original licence link has changed is not relivant.
11785 * <script type="text/javascript">
11790 * @class Roo.UpdateManager
11791 * @extends Roo.util.Observable
11792 * Provides AJAX-style update for Element object.<br><br>
11795 * // Get it from a Roo.Element object
11796 * var el = Roo.get("foo");
11797 * var mgr = el.getUpdateManager();
11798 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11800 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11802 * // or directly (returns the same UpdateManager instance)
11803 * var mgr = new Roo.UpdateManager("myElementId");
11804 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11805 * mgr.on("update", myFcnNeedsToKnow);
11807 // short handed call directly from the element object
11808 Roo.get("foo").load({
11812 text: "Loading Foo..."
11816 * Create new UpdateManager directly.
11817 * @param {String/HTMLElement/Roo.Element} el The element to update
11818 * @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).
11820 Roo.UpdateManager = function(el, forceNew){
11822 if(!forceNew && el.updateManager){
11823 return el.updateManager;
11826 * The Element object
11827 * @type Roo.Element
11831 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11834 this.defaultUrl = null;
11838 * @event beforeupdate
11839 * Fired before an update is made, return false from your handler and the update is cancelled.
11840 * @param {Roo.Element} el
11841 * @param {String/Object/Function} url
11842 * @param {String/Object} params
11844 "beforeupdate": true,
11847 * Fired after successful update is made.
11848 * @param {Roo.Element} el
11849 * @param {Object} oResponseObject The response Object
11854 * Fired on update failure.
11855 * @param {Roo.Element} el
11856 * @param {Object} oResponseObject The response Object
11860 var d = Roo.UpdateManager.defaults;
11862 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11865 this.sslBlankUrl = d.sslBlankUrl;
11867 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11870 this.disableCaching = d.disableCaching;
11872 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11875 this.indicatorText = d.indicatorText;
11877 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11880 this.showLoadIndicator = d.showLoadIndicator;
11882 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11885 this.timeout = d.timeout;
11888 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11891 this.loadScripts = d.loadScripts;
11894 * Transaction object of current executing transaction
11896 this.transaction = null;
11901 this.autoRefreshProcId = null;
11903 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11906 this.refreshDelegate = this.refresh.createDelegate(this);
11908 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11911 this.updateDelegate = this.update.createDelegate(this);
11913 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11916 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11920 this.successDelegate = this.processSuccess.createDelegate(this);
11924 this.failureDelegate = this.processFailure.createDelegate(this);
11926 if(!this.renderer){
11928 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11930 this.renderer = new Roo.UpdateManager.BasicRenderer();
11933 Roo.UpdateManager.superclass.constructor.call(this);
11936 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11938 * Get the Element this UpdateManager is bound to
11939 * @return {Roo.Element} The element
11941 getEl : function(){
11945 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11946 * @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:
11949 url: "your-url.php",<br/>
11950 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11951 callback: yourFunction,<br/>
11952 scope: yourObject, //(optional scope) <br/>
11953 discardUrl: false, <br/>
11954 nocache: false,<br/>
11955 text: "Loading...",<br/>
11957 scripts: false<br/>
11960 * The only required property is url. The optional properties nocache, text and scripts
11961 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11962 * @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}
11963 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11964 * @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.
11966 update : function(url, params, callback, discardUrl){
11967 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11968 var method = this.method,
11970 if(typeof url == "object"){ // must be config object
11973 params = params || cfg.params;
11974 callback = callback || cfg.callback;
11975 discardUrl = discardUrl || cfg.discardUrl;
11976 if(callback && cfg.scope){
11977 callback = callback.createDelegate(cfg.scope);
11979 if(typeof cfg.method != "undefined"){method = cfg.method;};
11980 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11981 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11982 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11983 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11985 this.showLoading();
11987 this.defaultUrl = url;
11989 if(typeof url == "function"){
11990 url = url.call(this);
11993 method = method || (params ? "POST" : "GET");
11994 if(method == "GET"){
11995 url = this.prepareUrl(url);
11998 var o = Roo.apply(cfg ||{}, {
12001 success: this.successDelegate,
12002 failure: this.failureDelegate,
12003 callback: undefined,
12004 timeout: (this.timeout*1000),
12005 argument: {"url": url, "form": null, "callback": callback, "params": params}
12007 Roo.log("updated manager called with timeout of " + o.timeout);
12008 this.transaction = Roo.Ajax.request(o);
12013 * 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.
12014 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12015 * @param {String/HTMLElement} form The form Id or form element
12016 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12017 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12018 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12020 formUpdate : function(form, url, reset, callback){
12021 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12022 if(typeof url == "function"){
12023 url = url.call(this);
12025 form = Roo.getDom(form);
12026 this.transaction = Roo.Ajax.request({
12029 success: this.successDelegate,
12030 failure: this.failureDelegate,
12031 timeout: (this.timeout*1000),
12032 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12034 this.showLoading.defer(1, this);
12039 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12040 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12042 refresh : function(callback){
12043 if(this.defaultUrl == null){
12046 this.update(this.defaultUrl, null, callback, true);
12050 * Set this element to auto refresh.
12051 * @param {Number} interval How often to update (in seconds).
12052 * @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)
12053 * @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}
12054 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12055 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12057 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12059 this.update(url || this.defaultUrl, params, callback, true);
12061 if(this.autoRefreshProcId){
12062 clearInterval(this.autoRefreshProcId);
12064 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12068 * Stop auto refresh on this element.
12070 stopAutoRefresh : function(){
12071 if(this.autoRefreshProcId){
12072 clearInterval(this.autoRefreshProcId);
12073 delete this.autoRefreshProcId;
12077 isAutoRefreshing : function(){
12078 return this.autoRefreshProcId ? true : false;
12081 * Called to update the element to "Loading" state. Override to perform custom action.
12083 showLoading : function(){
12084 if(this.showLoadIndicator){
12085 this.el.update(this.indicatorText);
12090 * Adds unique parameter to query string if disableCaching = true
12093 prepareUrl : function(url){
12094 if(this.disableCaching){
12095 var append = "_dc=" + (new Date().getTime());
12096 if(url.indexOf("?") !== -1){
12097 url += "&" + append;
12099 url += "?" + append;
12108 processSuccess : function(response){
12109 this.transaction = null;
12110 if(response.argument.form && response.argument.reset){
12111 try{ // put in try/catch since some older FF releases had problems with this
12112 response.argument.form.reset();
12115 if(this.loadScripts){
12116 this.renderer.render(this.el, response, this,
12117 this.updateComplete.createDelegate(this, [response]));
12119 this.renderer.render(this.el, response, this);
12120 this.updateComplete(response);
12124 updateComplete : function(response){
12125 this.fireEvent("update", this.el, response);
12126 if(typeof response.argument.callback == "function"){
12127 response.argument.callback(this.el, true, response);
12134 processFailure : function(response){
12135 this.transaction = null;
12136 this.fireEvent("failure", this.el, response);
12137 if(typeof response.argument.callback == "function"){
12138 response.argument.callback(this.el, false, response);
12143 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12144 * @param {Object} renderer The object implementing the render() method
12146 setRenderer : function(renderer){
12147 this.renderer = renderer;
12150 getRenderer : function(){
12151 return this.renderer;
12155 * Set the defaultUrl used for updates
12156 * @param {String/Function} defaultUrl The url or a function to call to get the url
12158 setDefaultUrl : function(defaultUrl){
12159 this.defaultUrl = defaultUrl;
12163 * Aborts the executing transaction
12165 abort : function(){
12166 if(this.transaction){
12167 Roo.Ajax.abort(this.transaction);
12172 * Returns true if an update is in progress
12173 * @return {Boolean}
12175 isUpdating : function(){
12176 if(this.transaction){
12177 return Roo.Ajax.isLoading(this.transaction);
12184 * @class Roo.UpdateManager.defaults
12185 * @static (not really - but it helps the doc tool)
12186 * The defaults collection enables customizing the default properties of UpdateManager
12188 Roo.UpdateManager.defaults = {
12190 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12196 * True to process scripts by default (Defaults to false).
12199 loadScripts : false,
12202 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12205 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12207 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12210 disableCaching : false,
12212 * Whether to show indicatorText when loading (Defaults to true).
12215 showLoadIndicator : true,
12217 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12220 indicatorText : '<div class="loading-indicator">Loading...</div>'
12224 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12226 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12227 * @param {String/HTMLElement/Roo.Element} el The element to update
12228 * @param {String} url The url
12229 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12230 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12233 * @member Roo.UpdateManager
12235 Roo.UpdateManager.updateElement = function(el, url, params, options){
12236 var um = Roo.get(el, true).getUpdateManager();
12237 Roo.apply(um, options);
12238 um.update(url, params, options ? options.callback : null);
12240 // alias for backwards compat
12241 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12243 * @class Roo.UpdateManager.BasicRenderer
12244 * Default Content renderer. Updates the elements innerHTML with the responseText.
12246 Roo.UpdateManager.BasicRenderer = function(){};
12248 Roo.UpdateManager.BasicRenderer.prototype = {
12250 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12251 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12252 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12253 * @param {Roo.Element} el The element being rendered
12254 * @param {Object} response The YUI Connect response object
12255 * @param {UpdateManager} updateManager The calling update manager
12256 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12258 render : function(el, response, updateManager, callback){
12259 el.update(response.responseText, updateManager.loadScripts, callback);
12265 * (c)) Alan Knowles
12271 * @class Roo.DomTemplate
12272 * @extends Roo.Template
12273 * An effort at a dom based template engine..
12275 * Similar to XTemplate, except it uses dom parsing to create the template..
12277 * Supported features:
12282 {a_variable} - output encoded.
12283 {a_variable.format:("Y-m-d")} - call a method on the variable
12284 {a_variable:raw} - unencoded output
12285 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12286 {a_variable:this.method_on_template(...)} - call a method on the template object.
12291 <div roo-for="a_variable or condition.."></div>
12292 <div roo-if="a_variable or condition"></div>
12293 <div roo-exec="some javascript"></div>
12294 <div roo-name="named_template"></div>
12299 Roo.DomTemplate = function()
12301 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12308 Roo.extend(Roo.DomTemplate, Roo.Template, {
12310 * id counter for sub templates.
12314 * flag to indicate if dom parser is inside a pre,
12315 * it will strip whitespace if not.
12320 * The various sub templates
12328 * basic tag replacing syntax
12331 * // you can fake an object call by doing this
12335 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12336 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12338 iterChild : function (node, method) {
12340 var oldPre = this.inPre;
12341 if (node.tagName == 'PRE') {
12344 for( var i = 0; i < node.childNodes.length; i++) {
12345 method.call(this, node.childNodes[i]);
12347 this.inPre = oldPre;
12353 * compile the template
12355 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12358 compile: function()
12362 // covert the html into DOM...
12366 doc = document.implementation.createHTMLDocument("");
12367 doc.documentElement.innerHTML = this.html ;
12368 div = doc.documentElement;
12370 // old IE... - nasty -- it causes all sorts of issues.. with
12371 // images getting pulled from server..
12372 div = document.createElement('div');
12373 div.innerHTML = this.html;
12375 //doc.documentElement.innerHTML = htmlBody
12381 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12383 var tpls = this.tpls;
12385 // create a top level template from the snippet..
12387 //Roo.log(div.innerHTML);
12394 body : div.innerHTML,
12407 Roo.each(tpls, function(tp){
12408 this.compileTpl(tp);
12409 this.tpls[tp.id] = tp;
12412 this.master = tpls[0];
12418 compileNode : function(node, istop) {
12423 // skip anything not a tag..
12424 if (node.nodeType != 1) {
12425 if (node.nodeType == 3 && !this.inPre) {
12426 // reduce white space..
12427 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12450 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12451 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12452 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12453 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12459 // just itterate children..
12460 this.iterChild(node,this.compileNode);
12463 tpl.uid = this.id++;
12464 tpl.value = node.getAttribute('roo-' + tpl.attr);
12465 node.removeAttribute('roo-'+ tpl.attr);
12466 if (tpl.attr != 'name') {
12467 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12468 node.parentNode.replaceChild(placeholder, node);
12471 var placeholder = document.createElement('span');
12472 placeholder.className = 'roo-tpl-' + tpl.value;
12473 node.parentNode.replaceChild(placeholder, node);
12476 // parent now sees '{domtplXXXX}
12477 this.iterChild(node,this.compileNode);
12479 // we should now have node body...
12480 var div = document.createElement('div');
12481 div.appendChild(node);
12483 // this has the unfortunate side effect of converting tagged attributes
12484 // eg. href="{...}" into %7C...%7D
12485 // this has been fixed by searching for those combo's although it's a bit hacky..
12488 tpl.body = div.innerHTML;
12495 switch (tpl.value) {
12496 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12497 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12498 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12503 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12507 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12511 tpl.id = tpl.value; // replace non characters???
12517 this.tpls.push(tpl);
12527 * Compile a segment of the template into a 'sub-template'
12533 compileTpl : function(tpl)
12535 var fm = Roo.util.Format;
12536 var useF = this.disableFormats !== true;
12538 var sep = Roo.isGecko ? "+\n" : ",\n";
12540 var undef = function(str) {
12541 Roo.debug && Roo.log("Property not found :" + str);
12545 //Roo.log(tpl.body);
12549 var fn = function(m, lbrace, name, format, args)
12552 //Roo.log(arguments);
12553 args = args ? args.replace(/\\'/g,"'") : args;
12554 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12555 if (typeof(format) == 'undefined') {
12556 format = 'htmlEncode';
12558 if (format == 'raw' ) {
12562 if(name.substr(0, 6) == 'domtpl'){
12563 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12566 // build an array of options to determine if value is undefined..
12568 // basically get 'xxxx.yyyy' then do
12569 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12570 // (function () { Roo.log("Property not found"); return ''; })() :
12575 Roo.each(name.split('.'), function(st) {
12576 lookfor += (lookfor.length ? '.': '') + st;
12577 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12580 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12583 if(format && useF){
12585 args = args ? ',' + args : "";
12587 if(format.substr(0, 5) != "this."){
12588 format = "fm." + format + '(';
12590 format = 'this.call("'+ format.substr(5) + '", ';
12594 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12597 if (args && args.length) {
12598 // called with xxyx.yuu:(test,test)
12600 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12602 // raw.. - :raw modifier..
12603 return "'"+ sep + udef_st + name + ")"+sep+"'";
12607 // branched to use + in gecko and [].join() in others
12609 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12610 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12613 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12614 body.push(tpl.body.replace(/(\r\n|\n)/g,
12615 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12616 body.push("'].join('');};};");
12617 body = body.join('');
12620 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12622 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12629 * same as applyTemplate, except it's done to one of the subTemplates
12630 * when using named templates, you can do:
12632 * var str = pl.applySubTemplate('your-name', values);
12635 * @param {Number} id of the template
12636 * @param {Object} values to apply to template
12637 * @param {Object} parent (normaly the instance of this object)
12639 applySubTemplate : function(id, values, parent)
12643 var t = this.tpls[id];
12647 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12648 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12652 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12659 if(t.execCall && t.execCall.call(this, values, parent)){
12663 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12669 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12670 parent = t.target ? values : parent;
12671 if(t.forCall && vs instanceof Array){
12673 for(var i = 0, len = vs.length; i < len; i++){
12675 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12677 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12679 //Roo.log(t.compiled);
12683 return buf.join('');
12686 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12691 return t.compiled.call(this, vs, parent);
12693 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12695 //Roo.log(t.compiled);
12703 applyTemplate : function(values){
12704 return this.master.compiled.call(this, values, {});
12705 //var s = this.subs;
12708 apply : function(){
12709 return this.applyTemplate.apply(this, arguments);
12714 Roo.DomTemplate.from = function(el){
12715 el = Roo.getDom(el);
12716 return new Roo.Domtemplate(el.value || el.innerHTML);
12719 * Ext JS Library 1.1.1
12720 * Copyright(c) 2006-2007, Ext JS, LLC.
12722 * Originally Released Under LGPL - original licence link has changed is not relivant.
12725 * <script type="text/javascript">
12729 * @class Roo.util.DelayedTask
12730 * Provides a convenient method of performing setTimeout where a new
12731 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12732 * You can use this class to buffer
12733 * the keypress events for a certain number of milliseconds, and perform only if they stop
12734 * for that amount of time.
12735 * @constructor The parameters to this constructor serve as defaults and are not required.
12736 * @param {Function} fn (optional) The default function to timeout
12737 * @param {Object} scope (optional) The default scope of that timeout
12738 * @param {Array} args (optional) The default Array of arguments
12740 Roo.util.DelayedTask = function(fn, scope, args){
12741 var id = null, d, t;
12743 var call = function(){
12744 var now = new Date().getTime();
12748 fn.apply(scope, args || []);
12752 * Cancels any pending timeout and queues a new one
12753 * @param {Number} delay The milliseconds to delay
12754 * @param {Function} newFn (optional) Overrides function passed to constructor
12755 * @param {Object} newScope (optional) Overrides scope passed to constructor
12756 * @param {Array} newArgs (optional) Overrides args passed to constructor
12758 this.delay = function(delay, newFn, newScope, newArgs){
12759 if(id && delay != d){
12763 t = new Date().getTime();
12765 scope = newScope || scope;
12766 args = newArgs || args;
12768 id = setInterval(call, d);
12773 * Cancel the last queued timeout
12775 this.cancel = function(){
12783 * Ext JS Library 1.1.1
12784 * Copyright(c) 2006-2007, Ext JS, LLC.
12786 * Originally Released Under LGPL - original licence link has changed is not relivant.
12789 * <script type="text/javascript">
12793 Roo.util.TaskRunner = function(interval){
12794 interval = interval || 10;
12795 var tasks = [], removeQueue = [];
12797 var running = false;
12799 var stopThread = function(){
12805 var startThread = function(){
12808 id = setInterval(runTasks, interval);
12812 var removeTask = function(task){
12813 removeQueue.push(task);
12819 var runTasks = function(){
12820 if(removeQueue.length > 0){
12821 for(var i = 0, len = removeQueue.length; i < len; i++){
12822 tasks.remove(removeQueue[i]);
12825 if(tasks.length < 1){
12830 var now = new Date().getTime();
12831 for(var i = 0, len = tasks.length; i < len; ++i){
12833 var itime = now - t.taskRunTime;
12834 if(t.interval <= itime){
12835 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12836 t.taskRunTime = now;
12837 if(rt === false || t.taskRunCount === t.repeat){
12842 if(t.duration && t.duration <= (now - t.taskStartTime)){
12849 * Queues a new task.
12850 * @param {Object} task
12852 this.start = function(task){
12854 task.taskStartTime = new Date().getTime();
12855 task.taskRunTime = 0;
12856 task.taskRunCount = 0;
12861 this.stop = function(task){
12866 this.stopAll = function(){
12868 for(var i = 0, len = tasks.length; i < len; i++){
12869 if(tasks[i].onStop){
12878 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12880 * Ext JS Library 1.1.1
12881 * Copyright(c) 2006-2007, Ext JS, LLC.
12883 * Originally Released Under LGPL - original licence link has changed is not relivant.
12886 * <script type="text/javascript">
12891 * @class Roo.util.MixedCollection
12892 * @extends Roo.util.Observable
12893 * A Collection class that maintains both numeric indexes and keys and exposes events.
12895 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12896 * collection (defaults to false)
12897 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12898 * and return the key value for that item. This is used when available to look up the key on items that
12899 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12900 * equivalent to providing an implementation for the {@link #getKey} method.
12902 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12910 * Fires when the collection is cleared.
12915 * Fires when an item is added to the collection.
12916 * @param {Number} index The index at which the item was added.
12917 * @param {Object} o The item added.
12918 * @param {String} key The key associated with the added item.
12923 * Fires when an item is replaced in the collection.
12924 * @param {String} key he key associated with the new added.
12925 * @param {Object} old The item being replaced.
12926 * @param {Object} new The new item.
12931 * Fires when an item is removed from the collection.
12932 * @param {Object} o The item being removed.
12933 * @param {String} key (optional) The key associated with the removed item.
12938 this.allowFunctions = allowFunctions === true;
12940 this.getKey = keyFn;
12942 Roo.util.MixedCollection.superclass.constructor.call(this);
12945 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12946 allowFunctions : false,
12949 * Adds an item to the collection.
12950 * @param {String} key The key to associate with the item
12951 * @param {Object} o The item to add.
12952 * @return {Object} The item added.
12954 add : function(key, o){
12955 if(arguments.length == 1){
12957 key = this.getKey(o);
12959 if(typeof key == "undefined" || key === null){
12961 this.items.push(o);
12962 this.keys.push(null);
12964 var old = this.map[key];
12966 return this.replace(key, o);
12969 this.items.push(o);
12971 this.keys.push(key);
12973 this.fireEvent("add", this.length-1, o, key);
12978 * MixedCollection has a generic way to fetch keys if you implement getKey.
12981 var mc = new Roo.util.MixedCollection();
12982 mc.add(someEl.dom.id, someEl);
12983 mc.add(otherEl.dom.id, otherEl);
12987 var mc = new Roo.util.MixedCollection();
12988 mc.getKey = function(el){
12994 // or via the constructor
12995 var mc = new Roo.util.MixedCollection(false, function(el){
13001 * @param o {Object} The item for which to find the key.
13002 * @return {Object} The key for the passed item.
13004 getKey : function(o){
13009 * Replaces an item in the collection.
13010 * @param {String} key The key associated with the item to replace, or the item to replace.
13011 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13012 * @return {Object} The new item.
13014 replace : function(key, o){
13015 if(arguments.length == 1){
13017 key = this.getKey(o);
13019 var old = this.item(key);
13020 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13021 return this.add(key, o);
13023 var index = this.indexOfKey(key);
13024 this.items[index] = o;
13026 this.fireEvent("replace", key, old, o);
13031 * Adds all elements of an Array or an Object to the collection.
13032 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13033 * an Array of values, each of which are added to the collection.
13035 addAll : function(objs){
13036 if(arguments.length > 1 || objs instanceof Array){
13037 var args = arguments.length > 1 ? arguments : objs;
13038 for(var i = 0, len = args.length; i < len; i++){
13042 for(var key in objs){
13043 if(this.allowFunctions || typeof objs[key] != "function"){
13044 this.add(key, objs[key]);
13051 * Executes the specified function once for every item in the collection, passing each
13052 * item as the first and only parameter. returning false from the function will stop the iteration.
13053 * @param {Function} fn The function to execute for each item.
13054 * @param {Object} scope (optional) The scope in which to execute the function.
13056 each : function(fn, scope){
13057 var items = [].concat(this.items); // each safe for removal
13058 for(var i = 0, len = items.length; i < len; i++){
13059 if(fn.call(scope || items[i], items[i], i, len) === false){
13066 * Executes the specified function once for every key in the collection, passing each
13067 * key, and its associated item as the first two parameters.
13068 * @param {Function} fn The function to execute for each item.
13069 * @param {Object} scope (optional) The scope in which to execute the function.
13071 eachKey : function(fn, scope){
13072 for(var i = 0, len = this.keys.length; i < len; i++){
13073 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13078 * Returns the first item in the collection which elicits a true return value from the
13079 * passed selection function.
13080 * @param {Function} fn The selection function to execute for each item.
13081 * @param {Object} scope (optional) The scope in which to execute the function.
13082 * @return {Object} The first item in the collection which returned true from the selection function.
13084 find : function(fn, scope){
13085 for(var i = 0, len = this.items.length; i < len; i++){
13086 if(fn.call(scope || window, this.items[i], this.keys[i])){
13087 return this.items[i];
13094 * Inserts an item at the specified index in the collection.
13095 * @param {Number} index The index to insert the item at.
13096 * @param {String} key The key to associate with the new item, or the item itself.
13097 * @param {Object} o (optional) If the second parameter was a key, the new item.
13098 * @return {Object} The item inserted.
13100 insert : function(index, key, o){
13101 if(arguments.length == 2){
13103 key = this.getKey(o);
13105 if(index >= this.length){
13106 return this.add(key, o);
13109 this.items.splice(index, 0, o);
13110 if(typeof key != "undefined" && key != null){
13113 this.keys.splice(index, 0, key);
13114 this.fireEvent("add", index, o, key);
13119 * Removed an item from the collection.
13120 * @param {Object} o The item to remove.
13121 * @return {Object} The item removed.
13123 remove : function(o){
13124 return this.removeAt(this.indexOf(o));
13128 * Remove an item from a specified index in the collection.
13129 * @param {Number} index The index within the collection of the item to remove.
13131 removeAt : function(index){
13132 if(index < this.length && index >= 0){
13134 var o = this.items[index];
13135 this.items.splice(index, 1);
13136 var key = this.keys[index];
13137 if(typeof key != "undefined"){
13138 delete this.map[key];
13140 this.keys.splice(index, 1);
13141 this.fireEvent("remove", o, key);
13146 * Removed an item associated with the passed key fom the collection.
13147 * @param {String} key The key of the item to remove.
13149 removeKey : function(key){
13150 return this.removeAt(this.indexOfKey(key));
13154 * Returns the number of items in the collection.
13155 * @return {Number} the number of items in the collection.
13157 getCount : function(){
13158 return this.length;
13162 * Returns index within the collection of the passed Object.
13163 * @param {Object} o The item to find the index of.
13164 * @return {Number} index of the item.
13166 indexOf : function(o){
13167 if(!this.items.indexOf){
13168 for(var i = 0, len = this.items.length; i < len; i++){
13169 if(this.items[i] == o) {
13175 return this.items.indexOf(o);
13180 * Returns index within the collection of the passed key.
13181 * @param {String} key The key to find the index of.
13182 * @return {Number} index of the key.
13184 indexOfKey : function(key){
13185 if(!this.keys.indexOf){
13186 for(var i = 0, len = this.keys.length; i < len; i++){
13187 if(this.keys[i] == key) {
13193 return this.keys.indexOf(key);
13198 * Returns the item associated with the passed key OR index. Key has priority over index.
13199 * @param {String/Number} key The key or index of the item.
13200 * @return {Object} The item associated with the passed key.
13202 item : function(key){
13203 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13204 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13208 * Returns the item at the specified index.
13209 * @param {Number} index The index of the item.
13212 itemAt : function(index){
13213 return this.items[index];
13217 * Returns the item associated with the passed key.
13218 * @param {String/Number} key The key of the item.
13219 * @return {Object} The item associated with the passed key.
13221 key : function(key){
13222 return this.map[key];
13226 * Returns true if the collection contains the passed Object as an item.
13227 * @param {Object} o The Object to look for in the collection.
13228 * @return {Boolean} True if the collection contains the Object as an item.
13230 contains : function(o){
13231 return this.indexOf(o) != -1;
13235 * Returns true if the collection contains the passed Object as a key.
13236 * @param {String} key The key to look for in the collection.
13237 * @return {Boolean} True if the collection contains the Object as a key.
13239 containsKey : function(key){
13240 return typeof this.map[key] != "undefined";
13244 * Removes all items from the collection.
13246 clear : function(){
13251 this.fireEvent("clear");
13255 * Returns the first item in the collection.
13256 * @return {Object} the first item in the collection..
13258 first : function(){
13259 return this.items[0];
13263 * Returns the last item in the collection.
13264 * @return {Object} the last item in the collection..
13267 return this.items[this.length-1];
13270 _sort : function(property, dir, fn){
13271 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13272 fn = fn || function(a, b){
13275 var c = [], k = this.keys, items = this.items;
13276 for(var i = 0, len = items.length; i < len; i++){
13277 c[c.length] = {key: k[i], value: items[i], index: i};
13279 c.sort(function(a, b){
13280 var v = fn(a[property], b[property]) * dsc;
13282 v = (a.index < b.index ? -1 : 1);
13286 for(var i = 0, len = c.length; i < len; i++){
13287 items[i] = c[i].value;
13290 this.fireEvent("sort", this);
13294 * Sorts this collection with the passed comparison function
13295 * @param {String} direction (optional) "ASC" or "DESC"
13296 * @param {Function} fn (optional) comparison function
13298 sort : function(dir, fn){
13299 this._sort("value", dir, fn);
13303 * Sorts this collection by keys
13304 * @param {String} direction (optional) "ASC" or "DESC"
13305 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13307 keySort : function(dir, fn){
13308 this._sort("key", dir, fn || function(a, b){
13309 return String(a).toUpperCase()-String(b).toUpperCase();
13314 * Returns a range of items in this collection
13315 * @param {Number} startIndex (optional) defaults to 0
13316 * @param {Number} endIndex (optional) default to the last item
13317 * @return {Array} An array of items
13319 getRange : function(start, end){
13320 var items = this.items;
13321 if(items.length < 1){
13324 start = start || 0;
13325 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13328 for(var i = start; i <= end; i++) {
13329 r[r.length] = items[i];
13332 for(var i = start; i >= end; i--) {
13333 r[r.length] = items[i];
13340 * Filter the <i>objects</i> in this collection by a specific property.
13341 * Returns a new collection that has been filtered.
13342 * @param {String} property A property on your objects
13343 * @param {String/RegExp} value Either string that the property values
13344 * should start with or a RegExp to test against the property
13345 * @return {MixedCollection} The new filtered collection
13347 filter : function(property, value){
13348 if(!value.exec){ // not a regex
13349 value = String(value);
13350 if(value.length == 0){
13351 return this.clone();
13353 value = new RegExp("^" + Roo.escapeRe(value), "i");
13355 return this.filterBy(function(o){
13356 return o && value.test(o[property]);
13361 * Filter by a function. * Returns a new collection that has been filtered.
13362 * The passed function will be called with each
13363 * object in the collection. If the function returns true, the value is included
13364 * otherwise it is filtered.
13365 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13366 * @param {Object} scope (optional) The scope of the function (defaults to this)
13367 * @return {MixedCollection} The new filtered collection
13369 filterBy : function(fn, scope){
13370 var r = new Roo.util.MixedCollection();
13371 r.getKey = this.getKey;
13372 var k = this.keys, it = this.items;
13373 for(var i = 0, len = it.length; i < len; i++){
13374 if(fn.call(scope||this, it[i], k[i])){
13375 r.add(k[i], it[i]);
13382 * Creates a duplicate of this collection
13383 * @return {MixedCollection}
13385 clone : function(){
13386 var r = new Roo.util.MixedCollection();
13387 var k = this.keys, it = this.items;
13388 for(var i = 0, len = it.length; i < len; i++){
13389 r.add(k[i], it[i]);
13391 r.getKey = this.getKey;
13396 * Returns the item associated with the passed key or index.
13398 * @param {String/Number} key The key or index of the item.
13399 * @return {Object} The item associated with the passed key.
13401 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13403 * Ext JS Library 1.1.1
13404 * Copyright(c) 2006-2007, Ext JS, LLC.
13406 * Originally Released Under LGPL - original licence link has changed is not relivant.
13409 * <script type="text/javascript">
13412 * @class Roo.util.JSON
13413 * Modified version of Douglas Crockford"s json.js that doesn"t
13414 * mess with the Object prototype
13415 * http://www.json.org/js.html
13418 Roo.util.JSON = new (function(){
13419 var useHasOwn = {}.hasOwnProperty ? true : false;
13421 // crashes Safari in some instances
13422 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13424 var pad = function(n) {
13425 return n < 10 ? "0" + n : n;
13438 var encodeString = function(s){
13439 if (/["\\\x00-\x1f]/.test(s)) {
13440 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13445 c = b.charCodeAt();
13447 Math.floor(c / 16).toString(16) +
13448 (c % 16).toString(16);
13451 return '"' + s + '"';
13454 var encodeArray = function(o){
13455 var a = ["["], b, i, l = o.length, v;
13456 for (i = 0; i < l; i += 1) {
13458 switch (typeof v) {
13467 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13475 var encodeDate = function(o){
13476 return '"' + o.getFullYear() + "-" +
13477 pad(o.getMonth() + 1) + "-" +
13478 pad(o.getDate()) + "T" +
13479 pad(o.getHours()) + ":" +
13480 pad(o.getMinutes()) + ":" +
13481 pad(o.getSeconds()) + '"';
13485 * Encodes an Object, Array or other value
13486 * @param {Mixed} o The variable to encode
13487 * @return {String} The JSON string
13489 this.encode = function(o)
13491 // should this be extended to fully wrap stringify..
13493 if(typeof o == "undefined" || o === null){
13495 }else if(o instanceof Array){
13496 return encodeArray(o);
13497 }else if(o instanceof Date){
13498 return encodeDate(o);
13499 }else if(typeof o == "string"){
13500 return encodeString(o);
13501 }else if(typeof o == "number"){
13502 return isFinite(o) ? String(o) : "null";
13503 }else if(typeof o == "boolean"){
13506 var a = ["{"], b, i, v;
13508 if(!useHasOwn || o.hasOwnProperty(i)) {
13510 switch (typeof v) {
13519 a.push(this.encode(i), ":",
13520 v === null ? "null" : this.encode(v));
13531 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13532 * @param {String} json The JSON string
13533 * @return {Object} The resulting object
13535 this.decode = function(json){
13537 return /** eval:var:json */ eval("(" + json + ')');
13541 * Shorthand for {@link Roo.util.JSON#encode}
13542 * @member Roo encode
13544 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13546 * Shorthand for {@link Roo.util.JSON#decode}
13547 * @member Roo decode
13549 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13552 * Ext JS Library 1.1.1
13553 * Copyright(c) 2006-2007, Ext JS, LLC.
13555 * Originally Released Under LGPL - original licence link has changed is not relivant.
13558 * <script type="text/javascript">
13562 * @class Roo.util.Format
13563 * Reusable data formatting functions
13566 Roo.util.Format = function(){
13567 var trimRe = /^\s+|\s+$/g;
13570 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13571 * @param {String} value The string to truncate
13572 * @param {Number} length The maximum length to allow before truncating
13573 * @return {String} The converted text
13575 ellipsis : function(value, len){
13576 if(value && value.length > len){
13577 return value.substr(0, len-3)+"...";
13583 * Checks a reference and converts it to empty string if it is undefined
13584 * @param {Mixed} value Reference to check
13585 * @return {Mixed} Empty string if converted, otherwise the original value
13587 undef : function(value){
13588 return typeof value != "undefined" ? value : "";
13592 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13593 * @param {String} value The string to encode
13594 * @return {String} The encoded text
13596 htmlEncode : function(value){
13597 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13601 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13602 * @param {String} value The string to decode
13603 * @return {String} The decoded text
13605 htmlDecode : function(value){
13606 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13610 * Trims any whitespace from either side of a string
13611 * @param {String} value The text to trim
13612 * @return {String} The trimmed text
13614 trim : function(value){
13615 return String(value).replace(trimRe, "");
13619 * Returns a substring from within an original string
13620 * @param {String} value The original text
13621 * @param {Number} start The start index of the substring
13622 * @param {Number} length The length of the substring
13623 * @return {String} The substring
13625 substr : function(value, start, length){
13626 return String(value).substr(start, length);
13630 * Converts a string to all lower case letters
13631 * @param {String} value The text to convert
13632 * @return {String} The converted text
13634 lowercase : function(value){
13635 return String(value).toLowerCase();
13639 * Converts a string to all upper case letters
13640 * @param {String} value The text to convert
13641 * @return {String} The converted text
13643 uppercase : function(value){
13644 return String(value).toUpperCase();
13648 * Converts the first character only of a string to upper case
13649 * @param {String} value The text to convert
13650 * @return {String} The converted text
13652 capitalize : function(value){
13653 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13657 call : function(value, fn){
13658 if(arguments.length > 2){
13659 var args = Array.prototype.slice.call(arguments, 2);
13660 args.unshift(value);
13662 return /** eval:var:value */ eval(fn).apply(window, args);
13664 /** eval:var:value */
13665 return /** eval:var:value */ eval(fn).call(window, value);
13671 * safer version of Math.toFixed..??/
13672 * @param {Number/String} value The numeric value to format
13673 * @param {Number/String} value Decimal places
13674 * @return {String} The formatted currency string
13676 toFixed : function(v, n)
13678 // why not use to fixed - precision is buggered???
13680 return Math.round(v-0);
13682 var fact = Math.pow(10,n+1);
13683 v = (Math.round((v-0)*fact))/fact;
13684 var z = (''+fact).substring(2);
13685 if (v == Math.floor(v)) {
13686 return Math.floor(v) + '.' + z;
13689 // now just padd decimals..
13690 var ps = String(v).split('.');
13691 var fd = (ps[1] + z);
13692 var r = fd.substring(0,n);
13693 var rm = fd.substring(n);
13695 return ps[0] + '.' + r;
13697 r*=1; // turn it into a number;
13699 if (String(r).length != n) {
13702 r = String(r).substring(1); // chop the end off.
13705 return ps[0] + '.' + r;
13710 * Format a number as US currency
13711 * @param {Number/String} value The numeric value to format
13712 * @return {String} The formatted currency string
13714 usMoney : function(v){
13715 return '$' + Roo.util.Format.number(v);
13720 * eventually this should probably emulate php's number_format
13721 * @param {Number/String} value The numeric value to format
13722 * @param {Number} decimals number of decimal places
13723 * @return {String} The formatted currency string
13725 number : function(v,decimals)
13727 // multiply and round.
13728 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13729 var mul = Math.pow(10, decimals);
13730 var zero = String(mul).substring(1);
13731 v = (Math.round((v-0)*mul))/mul;
13733 // if it's '0' number.. then
13735 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13737 var ps = v.split('.');
13741 var r = /(\d+)(\d{3})/;
13743 while (r.test(whole)) {
13744 whole = whole.replace(r, '$1' + ',' + '$2');
13750 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13751 // does not have decimals
13752 (decimals ? ('.' + zero) : '');
13755 return whole + sub ;
13759 * Parse a value into a formatted date using the specified format pattern.
13760 * @param {Mixed} value The value to format
13761 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13762 * @return {String} The formatted date string
13764 date : function(v, format){
13768 if(!(v instanceof Date)){
13769 v = new Date(Date.parse(v));
13771 return v.dateFormat(format || Roo.util.Format.defaults.date);
13775 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13776 * @param {String} format Any valid date format string
13777 * @return {Function} The date formatting function
13779 dateRenderer : function(format){
13780 return function(v){
13781 return Roo.util.Format.date(v, format);
13786 stripTagsRE : /<\/?[^>]+>/gi,
13789 * Strips all HTML tags
13790 * @param {Mixed} value The text from which to strip tags
13791 * @return {String} The stripped text
13793 stripTags : function(v){
13794 return !v ? v : String(v).replace(this.stripTagsRE, "");
13798 Roo.util.Format.defaults = {
13802 * Ext JS Library 1.1.1
13803 * Copyright(c) 2006-2007, Ext JS, LLC.
13805 * Originally Released Under LGPL - original licence link has changed is not relivant.
13808 * <script type="text/javascript">
13815 * @class Roo.MasterTemplate
13816 * @extends Roo.Template
13817 * Provides a template that can have child templates. The syntax is:
13819 var t = new Roo.MasterTemplate(
13820 '<select name="{name}">',
13821 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13824 t.add('options', {value: 'foo', text: 'bar'});
13825 // or you can add multiple child elements in one shot
13826 t.addAll('options', [
13827 {value: 'foo', text: 'bar'},
13828 {value: 'foo2', text: 'bar2'},
13829 {value: 'foo3', text: 'bar3'}
13831 // then append, applying the master template values
13832 t.append('my-form', {name: 'my-select'});
13834 * A name attribute for the child template is not required if you have only one child
13835 * template or you want to refer to them by index.
13837 Roo.MasterTemplate = function(){
13838 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13839 this.originalHtml = this.html;
13841 var m, re = this.subTemplateRe;
13844 while(m = re.exec(this.html)){
13845 var name = m[1], content = m[2];
13850 tpl : new Roo.Template(content)
13853 st[name] = st[subIndex];
13855 st[subIndex].tpl.compile();
13856 st[subIndex].tpl.call = this.call.createDelegate(this);
13859 this.subCount = subIndex;
13862 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13864 * The regular expression used to match sub templates
13868 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13871 * Applies the passed values to a child template.
13872 * @param {String/Number} name (optional) The name or index of the child template
13873 * @param {Array/Object} values The values to be applied to the template
13874 * @return {MasterTemplate} this
13876 add : function(name, values){
13877 if(arguments.length == 1){
13878 values = arguments[0];
13881 var s = this.subs[name];
13882 s.buffer[s.buffer.length] = s.tpl.apply(values);
13887 * Applies all the passed values to a child template.
13888 * @param {String/Number} name (optional) The name or index of the child template
13889 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13890 * @param {Boolean} reset (optional) True to reset the template first
13891 * @return {MasterTemplate} this
13893 fill : function(name, values, reset){
13895 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13903 for(var i = 0, len = values.length; i < len; i++){
13904 this.add(name, values[i]);
13910 * Resets the template for reuse
13911 * @return {MasterTemplate} this
13913 reset : function(){
13915 for(var i = 0; i < this.subCount; i++){
13921 applyTemplate : function(values){
13923 var replaceIndex = -1;
13924 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13925 return s[++replaceIndex].buffer.join("");
13927 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13930 apply : function(){
13931 return this.applyTemplate.apply(this, arguments);
13934 compile : function(){return this;}
13938 * Alias for fill().
13941 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13943 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13944 * var tpl = Roo.MasterTemplate.from('element-id');
13945 * @param {String/HTMLElement} el
13946 * @param {Object} config
13949 Roo.MasterTemplate.from = function(el, config){
13950 el = Roo.getDom(el);
13951 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13954 * Ext JS Library 1.1.1
13955 * Copyright(c) 2006-2007, Ext JS, LLC.
13957 * Originally Released Under LGPL - original licence link has changed is not relivant.
13960 * <script type="text/javascript">
13965 * @class Roo.util.CSS
13966 * Utility class for manipulating CSS rules
13969 Roo.util.CSS = function(){
13971 var doc = document;
13973 var camelRe = /(-[a-z])/gi;
13974 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13978 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13979 * tag and appended to the HEAD of the document.
13980 * @param {String|Object} cssText The text containing the css rules
13981 * @param {String} id An id to add to the stylesheet for later removal
13982 * @return {StyleSheet}
13984 createStyleSheet : function(cssText, id){
13986 var head = doc.getElementsByTagName("head")[0];
13987 var nrules = doc.createElement("style");
13988 nrules.setAttribute("type", "text/css");
13990 nrules.setAttribute("id", id);
13992 if (typeof(cssText) != 'string') {
13993 // support object maps..
13994 // not sure if this a good idea..
13995 // perhaps it should be merged with the general css handling
13996 // and handle js style props.
13997 var cssTextNew = [];
13998 for(var n in cssText) {
14000 for(var k in cssText[n]) {
14001 citems.push( k + ' : ' +cssText[n][k] + ';' );
14003 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14006 cssText = cssTextNew.join("\n");
14012 head.appendChild(nrules);
14013 ss = nrules.styleSheet;
14014 ss.cssText = cssText;
14017 nrules.appendChild(doc.createTextNode(cssText));
14019 nrules.cssText = cssText;
14021 head.appendChild(nrules);
14022 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14024 this.cacheStyleSheet(ss);
14029 * Removes a style or link tag by id
14030 * @param {String} id The id of the tag
14032 removeStyleSheet : function(id){
14033 var existing = doc.getElementById(id);
14035 existing.parentNode.removeChild(existing);
14040 * Dynamically swaps an existing stylesheet reference for a new one
14041 * @param {String} id The id of an existing link tag to remove
14042 * @param {String} url The href of the new stylesheet to include
14044 swapStyleSheet : function(id, url){
14045 this.removeStyleSheet(id);
14046 var ss = doc.createElement("link");
14047 ss.setAttribute("rel", "stylesheet");
14048 ss.setAttribute("type", "text/css");
14049 ss.setAttribute("id", id);
14050 ss.setAttribute("href", url);
14051 doc.getElementsByTagName("head")[0].appendChild(ss);
14055 * Refresh the rule cache if you have dynamically added stylesheets
14056 * @return {Object} An object (hash) of rules indexed by selector
14058 refreshCache : function(){
14059 return this.getRules(true);
14063 cacheStyleSheet : function(stylesheet){
14067 try{// try catch for cross domain access issue
14068 var ssRules = stylesheet.cssRules || stylesheet.rules;
14069 for(var j = ssRules.length-1; j >= 0; --j){
14070 rules[ssRules[j].selectorText] = ssRules[j];
14076 * Gets all css rules for the document
14077 * @param {Boolean} refreshCache true to refresh the internal cache
14078 * @return {Object} An object (hash) of rules indexed by selector
14080 getRules : function(refreshCache){
14081 if(rules == null || refreshCache){
14083 var ds = doc.styleSheets;
14084 for(var i =0, len = ds.length; i < len; i++){
14086 this.cacheStyleSheet(ds[i]);
14094 * Gets an an individual CSS rule by selector(s)
14095 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14096 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14097 * @return {CSSRule} The CSS rule or null if one is not found
14099 getRule : function(selector, refreshCache){
14100 var rs = this.getRules(refreshCache);
14101 if(!(selector instanceof Array)){
14102 return rs[selector];
14104 for(var i = 0; i < selector.length; i++){
14105 if(rs[selector[i]]){
14106 return rs[selector[i]];
14114 * Updates a rule property
14115 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14116 * @param {String} property The css property
14117 * @param {String} value The new value for the property
14118 * @return {Boolean} true If a rule was found and updated
14120 updateRule : function(selector, property, value){
14121 if(!(selector instanceof Array)){
14122 var rule = this.getRule(selector);
14124 rule.style[property.replace(camelRe, camelFn)] = value;
14128 for(var i = 0; i < selector.length; i++){
14129 if(this.updateRule(selector[i], property, value)){
14139 * Ext JS Library 1.1.1
14140 * Copyright(c) 2006-2007, Ext JS, LLC.
14142 * Originally Released Under LGPL - original licence link has changed is not relivant.
14145 * <script type="text/javascript">
14151 * @class Roo.util.ClickRepeater
14152 * @extends Roo.util.Observable
14154 * A wrapper class which can be applied to any element. Fires a "click" event while the
14155 * mouse is pressed. The interval between firings may be specified in the config but
14156 * defaults to 10 milliseconds.
14158 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14160 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14161 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14162 * Similar to an autorepeat key delay.
14163 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14164 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14165 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14166 * "interval" and "delay" are ignored. "immediate" is honored.
14167 * @cfg {Boolean} preventDefault True to prevent the default click event
14168 * @cfg {Boolean} stopDefault True to stop the default click event
14171 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14172 * 2007-02-02 jvs Renamed to ClickRepeater
14173 * 2007-02-03 jvs Modifications for FF Mac and Safari
14176 * @param {String/HTMLElement/Element} el The element to listen on
14177 * @param {Object} config
14179 Roo.util.ClickRepeater = function(el, config)
14181 this.el = Roo.get(el);
14182 this.el.unselectable();
14184 Roo.apply(this, config);
14189 * Fires when the mouse button is depressed.
14190 * @param {Roo.util.ClickRepeater} this
14192 "mousedown" : true,
14195 * Fires on a specified interval during the time the element is pressed.
14196 * @param {Roo.util.ClickRepeater} this
14201 * Fires when the mouse key is released.
14202 * @param {Roo.util.ClickRepeater} this
14207 this.el.on("mousedown", this.handleMouseDown, this);
14208 if(this.preventDefault || this.stopDefault){
14209 this.el.on("click", function(e){
14210 if(this.preventDefault){
14211 e.preventDefault();
14213 if(this.stopDefault){
14219 // allow inline handler
14221 this.on("click", this.handler, this.scope || this);
14224 Roo.util.ClickRepeater.superclass.constructor.call(this);
14227 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14230 preventDefault : true,
14231 stopDefault : false,
14235 handleMouseDown : function(){
14236 clearTimeout(this.timer);
14238 if(this.pressClass){
14239 this.el.addClass(this.pressClass);
14241 this.mousedownTime = new Date();
14243 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14244 this.el.on("mouseout", this.handleMouseOut, this);
14246 this.fireEvent("mousedown", this);
14247 this.fireEvent("click", this);
14249 this.timer = this.click.defer(this.delay || this.interval, this);
14253 click : function(){
14254 this.fireEvent("click", this);
14255 this.timer = this.click.defer(this.getInterval(), this);
14259 getInterval: function(){
14260 if(!this.accelerate){
14261 return this.interval;
14263 var pressTime = this.mousedownTime.getElapsed();
14264 if(pressTime < 500){
14266 }else if(pressTime < 1700){
14268 }else if(pressTime < 2600){
14270 }else if(pressTime < 3500){
14272 }else if(pressTime < 4400){
14274 }else if(pressTime < 5300){
14276 }else if(pressTime < 6200){
14284 handleMouseOut : function(){
14285 clearTimeout(this.timer);
14286 if(this.pressClass){
14287 this.el.removeClass(this.pressClass);
14289 this.el.on("mouseover", this.handleMouseReturn, this);
14293 handleMouseReturn : function(){
14294 this.el.un("mouseover", this.handleMouseReturn);
14295 if(this.pressClass){
14296 this.el.addClass(this.pressClass);
14302 handleMouseUp : function(){
14303 clearTimeout(this.timer);
14304 this.el.un("mouseover", this.handleMouseReturn);
14305 this.el.un("mouseout", this.handleMouseOut);
14306 Roo.get(document).un("mouseup", this.handleMouseUp);
14307 this.el.removeClass(this.pressClass);
14308 this.fireEvent("mouseup", this);
14312 * Ext JS Library 1.1.1
14313 * Copyright(c) 2006-2007, Ext JS, LLC.
14315 * Originally Released Under LGPL - original licence link has changed is not relivant.
14318 * <script type="text/javascript">
14323 * @class Roo.KeyNav
14324 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14325 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14326 * way to implement custom navigation schemes for any UI component.</p>
14327 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14328 * pageUp, pageDown, del, home, end. Usage:</p>
14330 var nav = new Roo.KeyNav("my-element", {
14331 "left" : function(e){
14332 this.moveLeft(e.ctrlKey);
14334 "right" : function(e){
14335 this.moveRight(e.ctrlKey);
14337 "enter" : function(e){
14344 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14345 * @param {Object} config The config
14347 Roo.KeyNav = function(el, config){
14348 this.el = Roo.get(el);
14349 Roo.apply(this, config);
14350 if(!this.disabled){
14351 this.disabled = true;
14356 Roo.KeyNav.prototype = {
14358 * @cfg {Boolean} disabled
14359 * True to disable this KeyNav instance (defaults to false)
14363 * @cfg {String} defaultEventAction
14364 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14365 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14366 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14368 defaultEventAction: "stopEvent",
14370 * @cfg {Boolean} forceKeyDown
14371 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14372 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14373 * handle keydown instead of keypress.
14375 forceKeyDown : false,
14378 prepareEvent : function(e){
14379 var k = e.getKey();
14380 var h = this.keyToHandler[k];
14381 //if(h && this[h]){
14382 // e.stopPropagation();
14384 if(Roo.isSafari && h && k >= 37 && k <= 40){
14390 relay : function(e){
14391 var k = e.getKey();
14392 var h = this.keyToHandler[k];
14394 if(this.doRelay(e, this[h], h) !== true){
14395 e[this.defaultEventAction]();
14401 doRelay : function(e, h, hname){
14402 return h.call(this.scope || this, e);
14405 // possible handlers
14419 // quick lookup hash
14436 * Enable this KeyNav
14438 enable: function(){
14440 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14441 // the EventObject will normalize Safari automatically
14442 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14443 this.el.on("keydown", this.relay, this);
14445 this.el.on("keydown", this.prepareEvent, this);
14446 this.el.on("keypress", this.relay, this);
14448 this.disabled = false;
14453 * Disable this KeyNav
14455 disable: function(){
14456 if(!this.disabled){
14457 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14458 this.el.un("keydown", this.relay);
14460 this.el.un("keydown", this.prepareEvent);
14461 this.el.un("keypress", this.relay);
14463 this.disabled = true;
14468 * Ext JS Library 1.1.1
14469 * Copyright(c) 2006-2007, Ext JS, LLC.
14471 * Originally Released Under LGPL - original licence link has changed is not relivant.
14474 * <script type="text/javascript">
14479 * @class Roo.KeyMap
14480 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14481 * The constructor accepts the same config object as defined by {@link #addBinding}.
14482 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14483 * combination it will call the function with this signature (if the match is a multi-key
14484 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14485 * A KeyMap can also handle a string representation of keys.<br />
14488 // map one key by key code
14489 var map = new Roo.KeyMap("my-element", {
14490 key: 13, // or Roo.EventObject.ENTER
14495 // map multiple keys to one action by string
14496 var map = new Roo.KeyMap("my-element", {
14502 // map multiple keys to multiple actions by strings and array of codes
14503 var map = new Roo.KeyMap("my-element", [
14506 fn: function(){ alert("Return was pressed"); }
14509 fn: function(){ alert('a, b or c was pressed'); }
14514 fn: function(){ alert('Control + shift + tab was pressed.'); }
14518 * <b>Note: A KeyMap starts enabled</b>
14520 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14521 * @param {Object} config The config (see {@link #addBinding})
14522 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14524 Roo.KeyMap = function(el, config, eventName){
14525 this.el = Roo.get(el);
14526 this.eventName = eventName || "keydown";
14527 this.bindings = [];
14529 this.addBinding(config);
14534 Roo.KeyMap.prototype = {
14536 * True to stop the event from bubbling and prevent the default browser action if the
14537 * key was handled by the KeyMap (defaults to false)
14543 * Add a new binding to this KeyMap. The following config object properties are supported:
14545 Property Type Description
14546 ---------- --------------- ----------------------------------------------------------------------
14547 key String/Array A single keycode or an array of keycodes to handle
14548 shift Boolean True to handle key only when shift is pressed (defaults to false)
14549 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14550 alt Boolean True to handle key only when alt is pressed (defaults to false)
14551 fn Function The function to call when KeyMap finds the expected key combination
14552 scope Object The scope of the callback function
14558 var map = new Roo.KeyMap(document, {
14559 key: Roo.EventObject.ENTER,
14564 //Add a new binding to the existing KeyMap later
14572 * @param {Object/Array} config A single KeyMap config or an array of configs
14574 addBinding : function(config){
14575 if(config instanceof Array){
14576 for(var i = 0, len = config.length; i < len; i++){
14577 this.addBinding(config[i]);
14581 var keyCode = config.key,
14582 shift = config.shift,
14583 ctrl = config.ctrl,
14586 scope = config.scope;
14587 if(typeof keyCode == "string"){
14589 var keyString = keyCode.toUpperCase();
14590 for(var j = 0, len = keyString.length; j < len; j++){
14591 ks.push(keyString.charCodeAt(j));
14595 var keyArray = keyCode instanceof Array;
14596 var handler = function(e){
14597 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14598 var k = e.getKey();
14600 for(var i = 0, len = keyCode.length; i < len; i++){
14601 if(keyCode[i] == k){
14602 if(this.stopEvent){
14605 fn.call(scope || window, k, e);
14611 if(this.stopEvent){
14614 fn.call(scope || window, k, e);
14619 this.bindings.push(handler);
14623 * Shorthand for adding a single key listener
14624 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14625 * following options:
14626 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14627 * @param {Function} fn The function to call
14628 * @param {Object} scope (optional) The scope of the function
14630 on : function(key, fn, scope){
14631 var keyCode, shift, ctrl, alt;
14632 if(typeof key == "object" && !(key instanceof Array)){
14651 handleKeyDown : function(e){
14652 if(this.enabled){ //just in case
14653 var b = this.bindings;
14654 for(var i = 0, len = b.length; i < len; i++){
14655 b[i].call(this, e);
14661 * Returns true if this KeyMap is enabled
14662 * @return {Boolean}
14664 isEnabled : function(){
14665 return this.enabled;
14669 * Enables this KeyMap
14671 enable: function(){
14673 this.el.on(this.eventName, this.handleKeyDown, this);
14674 this.enabled = true;
14679 * Disable this KeyMap
14681 disable: function(){
14683 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14684 this.enabled = false;
14689 * Ext JS Library 1.1.1
14690 * Copyright(c) 2006-2007, Ext JS, LLC.
14692 * Originally Released Under LGPL - original licence link has changed is not relivant.
14695 * <script type="text/javascript">
14700 * @class Roo.util.TextMetrics
14701 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14702 * wide, in pixels, a given block of text will be.
14705 Roo.util.TextMetrics = function(){
14709 * Measures the size of the specified text
14710 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14711 * that can affect the size of the rendered text
14712 * @param {String} text The text to measure
14713 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14714 * in order to accurately measure the text height
14715 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14717 measure : function(el, text, fixedWidth){
14719 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14722 shared.setFixedWidth(fixedWidth || 'auto');
14723 return shared.getSize(text);
14727 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14728 * the overhead of multiple calls to initialize the style properties on each measurement.
14729 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14730 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14731 * in order to accurately measure the text height
14732 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14734 createInstance : function(el, fixedWidth){
14735 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14742 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14743 var ml = new Roo.Element(document.createElement('div'));
14744 document.body.appendChild(ml.dom);
14745 ml.position('absolute');
14746 ml.setLeftTop(-1000, -1000);
14750 ml.setWidth(fixedWidth);
14755 * Returns the size of the specified text based on the internal element's style and width properties
14756 * @memberOf Roo.util.TextMetrics.Instance#
14757 * @param {String} text The text to measure
14758 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14760 getSize : function(text){
14762 var s = ml.getSize();
14768 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14769 * that can affect the size of the rendered text
14770 * @memberOf Roo.util.TextMetrics.Instance#
14771 * @param {String/HTMLElement} el The element, dom node or id
14773 bind : function(el){
14775 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14780 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14781 * to set a fixed width in order to accurately measure the text height.
14782 * @memberOf Roo.util.TextMetrics.Instance#
14783 * @param {Number} width The width to set on the element
14785 setFixedWidth : function(width){
14786 ml.setWidth(width);
14790 * Returns the measured width of the specified text
14791 * @memberOf Roo.util.TextMetrics.Instance#
14792 * @param {String} text The text to measure
14793 * @return {Number} width The width in pixels
14795 getWidth : function(text){
14796 ml.dom.style.width = 'auto';
14797 return this.getSize(text).width;
14801 * Returns the measured height of the specified text. For multiline text, be sure to call
14802 * {@link #setFixedWidth} if necessary.
14803 * @memberOf Roo.util.TextMetrics.Instance#
14804 * @param {String} text The text to measure
14805 * @return {Number} height The height in pixels
14807 getHeight : function(text){
14808 return this.getSize(text).height;
14812 instance.bind(bindTo);
14817 // backwards compat
14818 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14820 * Ext JS Library 1.1.1
14821 * Copyright(c) 2006-2007, Ext JS, LLC.
14823 * Originally Released Under LGPL - original licence link has changed is not relivant.
14826 * <script type="text/javascript">
14830 * @class Roo.state.Provider
14831 * Abstract base class for state provider implementations. This class provides methods
14832 * for encoding and decoding <b>typed</b> variables including dates and defines the
14833 * Provider interface.
14835 Roo.state.Provider = function(){
14837 * @event statechange
14838 * Fires when a state change occurs.
14839 * @param {Provider} this This state provider
14840 * @param {String} key The state key which was changed
14841 * @param {String} value The encoded value for the state
14844 "statechange": true
14847 Roo.state.Provider.superclass.constructor.call(this);
14849 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14851 * Returns the current value for a key
14852 * @param {String} name The key name
14853 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14854 * @return {Mixed} The state data
14856 get : function(name, defaultValue){
14857 return typeof this.state[name] == "undefined" ?
14858 defaultValue : this.state[name];
14862 * Clears a value from the state
14863 * @param {String} name The key name
14865 clear : function(name){
14866 delete this.state[name];
14867 this.fireEvent("statechange", this, name, null);
14871 * Sets the value for a key
14872 * @param {String} name The key name
14873 * @param {Mixed} value The value to set
14875 set : function(name, value){
14876 this.state[name] = value;
14877 this.fireEvent("statechange", this, name, value);
14881 * Decodes a string previously encoded with {@link #encodeValue}.
14882 * @param {String} value The value to decode
14883 * @return {Mixed} The decoded value
14885 decodeValue : function(cookie){
14886 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14887 var matches = re.exec(unescape(cookie));
14888 if(!matches || !matches[1]) {
14889 return; // non state cookie
14891 var type = matches[1];
14892 var v = matches[2];
14895 return parseFloat(v);
14897 return new Date(Date.parse(v));
14902 var values = v.split("^");
14903 for(var i = 0, len = values.length; i < len; i++){
14904 all.push(this.decodeValue(values[i]));
14909 var values = v.split("^");
14910 for(var i = 0, len = values.length; i < len; i++){
14911 var kv = values[i].split("=");
14912 all[kv[0]] = this.decodeValue(kv[1]);
14921 * Encodes a value including type information. Decode with {@link #decodeValue}.
14922 * @param {Mixed} value The value to encode
14923 * @return {String} The encoded value
14925 encodeValue : function(v){
14927 if(typeof v == "number"){
14929 }else if(typeof v == "boolean"){
14930 enc = "b:" + (v ? "1" : "0");
14931 }else if(v instanceof Date){
14932 enc = "d:" + v.toGMTString();
14933 }else if(v instanceof Array){
14935 for(var i = 0, len = v.length; i < len; i++){
14936 flat += this.encodeValue(v[i]);
14942 }else if(typeof v == "object"){
14945 if(typeof v[key] != "function"){
14946 flat += key + "=" + this.encodeValue(v[key]) + "^";
14949 enc = "o:" + flat.substring(0, flat.length-1);
14953 return escape(enc);
14959 * Ext JS Library 1.1.1
14960 * Copyright(c) 2006-2007, Ext JS, LLC.
14962 * Originally Released Under LGPL - original licence link has changed is not relivant.
14965 * <script type="text/javascript">
14968 * @class Roo.state.Manager
14969 * This is the global state manager. By default all components that are "state aware" check this class
14970 * for state information if you don't pass them a custom state provider. In order for this class
14971 * to be useful, it must be initialized with a provider when your application initializes.
14973 // in your initialization function
14975 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14977 // supposed you have a {@link Roo.BorderLayout}
14978 var layout = new Roo.BorderLayout(...);
14979 layout.restoreState();
14980 // or a {Roo.BasicDialog}
14981 var dialog = new Roo.BasicDialog(...);
14982 dialog.restoreState();
14986 Roo.state.Manager = function(){
14987 var provider = new Roo.state.Provider();
14991 * Configures the default state provider for your application
14992 * @param {Provider} stateProvider The state provider to set
14994 setProvider : function(stateProvider){
14995 provider = stateProvider;
14999 * Returns the current value for a key
15000 * @param {String} name The key name
15001 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15002 * @return {Mixed} The state data
15004 get : function(key, defaultValue){
15005 return provider.get(key, defaultValue);
15009 * Sets the value for a key
15010 * @param {String} name The key name
15011 * @param {Mixed} value The state data
15013 set : function(key, value){
15014 provider.set(key, value);
15018 * Clears a value from the state
15019 * @param {String} name The key name
15021 clear : function(key){
15022 provider.clear(key);
15026 * Gets the currently configured state provider
15027 * @return {Provider} The state provider
15029 getProvider : function(){
15036 * Ext JS Library 1.1.1
15037 * Copyright(c) 2006-2007, Ext JS, LLC.
15039 * Originally Released Under LGPL - original licence link has changed is not relivant.
15042 * <script type="text/javascript">
15045 * @class Roo.state.CookieProvider
15046 * @extends Roo.state.Provider
15047 * The default Provider implementation which saves state via cookies.
15050 var cp = new Roo.state.CookieProvider({
15052 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15053 domain: "roojs.com"
15055 Roo.state.Manager.setProvider(cp);
15057 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15058 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15059 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15060 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15061 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15062 * domain the page is running on including the 'www' like 'www.roojs.com')
15063 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15065 * Create a new CookieProvider
15066 * @param {Object} config The configuration object
15068 Roo.state.CookieProvider = function(config){
15069 Roo.state.CookieProvider.superclass.constructor.call(this);
15071 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15072 this.domain = null;
15073 this.secure = false;
15074 Roo.apply(this, config);
15075 this.state = this.readCookies();
15078 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15080 set : function(name, value){
15081 if(typeof value == "undefined" || value === null){
15085 this.setCookie(name, value);
15086 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15090 clear : function(name){
15091 this.clearCookie(name);
15092 Roo.state.CookieProvider.superclass.clear.call(this, name);
15096 readCookies : function(){
15098 var c = document.cookie + ";";
15099 var re = /\s?(.*?)=(.*?);/g;
15101 while((matches = re.exec(c)) != null){
15102 var name = matches[1];
15103 var value = matches[2];
15104 if(name && name.substring(0,3) == "ys-"){
15105 cookies[name.substr(3)] = this.decodeValue(value);
15112 setCookie : function(name, value){
15113 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15114 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15115 ((this.path == null) ? "" : ("; path=" + this.path)) +
15116 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15117 ((this.secure == true) ? "; secure" : "");
15121 clearCookie : function(name){
15122 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15123 ((this.path == null) ? "" : ("; path=" + this.path)) +
15124 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15125 ((this.secure == true) ? "; secure" : "");
15129 * Ext JS Library 1.1.1
15130 * Copyright(c) 2006-2007, Ext JS, LLC.
15132 * Originally Released Under LGPL - original licence link has changed is not relivant.
15135 * <script type="text/javascript">
15140 * @class Roo.ComponentMgr
15141 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15144 Roo.ComponentMgr = function(){
15145 var all = new Roo.util.MixedCollection();
15149 * Registers a component.
15150 * @param {Roo.Component} c The component
15152 register : function(c){
15157 * Unregisters a component.
15158 * @param {Roo.Component} c The component
15160 unregister : function(c){
15165 * Returns a component by id
15166 * @param {String} id The component id
15168 get : function(id){
15169 return all.get(id);
15173 * Registers a function that will be called when a specified component is added to ComponentMgr
15174 * @param {String} id The component id
15175 * @param {Funtction} fn The callback function
15176 * @param {Object} scope The scope of the callback
15178 onAvailable : function(id, fn, scope){
15179 all.on("add", function(index, o){
15181 fn.call(scope || o, o);
15182 all.un("add", fn, scope);
15189 * Ext JS Library 1.1.1
15190 * Copyright(c) 2006-2007, Ext JS, LLC.
15192 * Originally Released Under LGPL - original licence link has changed is not relivant.
15195 * <script type="text/javascript">
15199 * @class Roo.Component
15200 * @extends Roo.util.Observable
15201 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15202 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15203 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15204 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15205 * All visual components (widgets) that require rendering into a layout should subclass Component.
15207 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15208 * 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
15209 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15211 Roo.Component = function(config){
15212 config = config || {};
15213 if(config.tagName || config.dom || typeof config == "string"){ // element object
15214 config = {el: config, id: config.id || config};
15216 this.initialConfig = config;
15218 Roo.apply(this, config);
15222 * Fires after the component is disabled.
15223 * @param {Roo.Component} this
15228 * Fires after the component is enabled.
15229 * @param {Roo.Component} this
15233 * @event beforeshow
15234 * Fires before the component is shown. Return false to stop the show.
15235 * @param {Roo.Component} this
15240 * Fires after the component is shown.
15241 * @param {Roo.Component} this
15245 * @event beforehide
15246 * Fires before the component is hidden. Return false to stop the hide.
15247 * @param {Roo.Component} this
15252 * Fires after the component is hidden.
15253 * @param {Roo.Component} this
15257 * @event beforerender
15258 * Fires before the component is rendered. Return false to stop the render.
15259 * @param {Roo.Component} this
15261 beforerender : true,
15264 * Fires after the component is rendered.
15265 * @param {Roo.Component} this
15269 * @event beforedestroy
15270 * Fires before the component is destroyed. Return false to stop the destroy.
15271 * @param {Roo.Component} this
15273 beforedestroy : true,
15276 * Fires after the component is destroyed.
15277 * @param {Roo.Component} this
15282 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15284 Roo.ComponentMgr.register(this);
15285 Roo.Component.superclass.constructor.call(this);
15286 this.initComponent();
15287 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15288 this.render(this.renderTo);
15289 delete this.renderTo;
15294 Roo.Component.AUTO_ID = 1000;
15296 Roo.extend(Roo.Component, Roo.util.Observable, {
15298 * @scope Roo.Component.prototype
15300 * true if this component is hidden. Read-only.
15305 * true if this component is disabled. Read-only.
15310 * true if this component has been rendered. Read-only.
15314 /** @cfg {String} disableClass
15315 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15317 disabledClass : "x-item-disabled",
15318 /** @cfg {Boolean} allowDomMove
15319 * Whether the component can move the Dom node when rendering (defaults to true).
15321 allowDomMove : true,
15322 /** @cfg {String} hideMode (display|visibility)
15323 * How this component should hidden. Supported values are
15324 * "visibility" (css visibility), "offsets" (negative offset position) and
15325 * "display" (css display) - defaults to "display".
15327 hideMode: 'display',
15330 ctype : "Roo.Component",
15333 * @cfg {String} actionMode
15334 * which property holds the element that used for hide() / show() / disable() / enable()
15340 getActionEl : function(){
15341 return this[this.actionMode];
15344 initComponent : Roo.emptyFn,
15346 * If this is a lazy rendering component, render it to its container element.
15347 * @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.
15349 render : function(container, position){
15350 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15351 if(!container && this.el){
15352 this.el = Roo.get(this.el);
15353 container = this.el.dom.parentNode;
15354 this.allowDomMove = false;
15356 this.container = Roo.get(container);
15357 this.rendered = true;
15358 if(position !== undefined){
15359 if(typeof position == 'number'){
15360 position = this.container.dom.childNodes[position];
15362 position = Roo.getDom(position);
15365 this.onRender(this.container, position || null);
15367 this.el.addClass(this.cls);
15371 this.el.applyStyles(this.style);
15374 this.fireEvent("render", this);
15375 this.afterRender(this.container);
15387 // default function is not really useful
15388 onRender : function(ct, position){
15390 this.el = Roo.get(this.el);
15391 if(this.allowDomMove !== false){
15392 ct.dom.insertBefore(this.el.dom, position);
15398 getAutoCreate : function(){
15399 var cfg = typeof this.autoCreate == "object" ?
15400 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15401 if(this.id && !cfg.id){
15408 afterRender : Roo.emptyFn,
15411 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15412 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15414 destroy : function(){
15415 if(this.fireEvent("beforedestroy", this) !== false){
15416 this.purgeListeners();
15417 this.beforeDestroy();
15419 this.el.removeAllListeners();
15421 if(this.actionMode == "container"){
15422 this.container.remove();
15426 Roo.ComponentMgr.unregister(this);
15427 this.fireEvent("destroy", this);
15432 beforeDestroy : function(){
15437 onDestroy : function(){
15442 * Returns the underlying {@link Roo.Element}.
15443 * @return {Roo.Element} The element
15445 getEl : function(){
15450 * Returns the id of this component.
15453 getId : function(){
15458 * Try to focus this component.
15459 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15460 * @return {Roo.Component} this
15462 focus : function(selectText){
15465 if(selectText === true){
15466 this.el.dom.select();
15481 * Disable this component.
15482 * @return {Roo.Component} this
15484 disable : function(){
15488 this.disabled = true;
15489 this.fireEvent("disable", this);
15494 onDisable : function(){
15495 this.getActionEl().addClass(this.disabledClass);
15496 this.el.dom.disabled = true;
15500 * Enable this component.
15501 * @return {Roo.Component} this
15503 enable : function(){
15507 this.disabled = false;
15508 this.fireEvent("enable", this);
15513 onEnable : function(){
15514 this.getActionEl().removeClass(this.disabledClass);
15515 this.el.dom.disabled = false;
15519 * Convenience function for setting disabled/enabled by boolean.
15520 * @param {Boolean} disabled
15522 setDisabled : function(disabled){
15523 this[disabled ? "disable" : "enable"]();
15527 * Show this component.
15528 * @return {Roo.Component} this
15531 if(this.fireEvent("beforeshow", this) !== false){
15532 this.hidden = false;
15536 this.fireEvent("show", this);
15542 onShow : function(){
15543 var ae = this.getActionEl();
15544 if(this.hideMode == 'visibility'){
15545 ae.dom.style.visibility = "visible";
15546 }else if(this.hideMode == 'offsets'){
15547 ae.removeClass('x-hidden');
15549 ae.dom.style.display = "";
15554 * Hide this component.
15555 * @return {Roo.Component} this
15558 if(this.fireEvent("beforehide", this) !== false){
15559 this.hidden = true;
15563 this.fireEvent("hide", this);
15569 onHide : function(){
15570 var ae = this.getActionEl();
15571 if(this.hideMode == 'visibility'){
15572 ae.dom.style.visibility = "hidden";
15573 }else if(this.hideMode == 'offsets'){
15574 ae.addClass('x-hidden');
15576 ae.dom.style.display = "none";
15581 * Convenience function to hide or show this component by boolean.
15582 * @param {Boolean} visible True to show, false to hide
15583 * @return {Roo.Component} this
15585 setVisible: function(visible){
15595 * Returns true if this component is visible.
15597 isVisible : function(){
15598 return this.getActionEl().isVisible();
15601 cloneConfig : function(overrides){
15602 overrides = overrides || {};
15603 var id = overrides.id || Roo.id();
15604 var cfg = Roo.applyIf(overrides, this.initialConfig);
15605 cfg.id = id; // prevent dup id
15606 return new this.constructor(cfg);
15610 * Ext JS Library 1.1.1
15611 * Copyright(c) 2006-2007, Ext JS, LLC.
15613 * Originally Released Under LGPL - original licence link has changed is not relivant.
15616 * <script type="text/javascript">
15620 * @class Roo.BoxComponent
15621 * @extends Roo.Component
15622 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15623 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15624 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15625 * layout containers.
15627 * @param {Roo.Element/String/Object} config The configuration options.
15629 Roo.BoxComponent = function(config){
15630 Roo.Component.call(this, config);
15634 * Fires after the component is resized.
15635 * @param {Roo.Component} this
15636 * @param {Number} adjWidth The box-adjusted width that was set
15637 * @param {Number} adjHeight The box-adjusted height that was set
15638 * @param {Number} rawWidth The width that was originally specified
15639 * @param {Number} rawHeight The height that was originally specified
15644 * Fires after the component is moved.
15645 * @param {Roo.Component} this
15646 * @param {Number} x The new x position
15647 * @param {Number} y The new y position
15653 Roo.extend(Roo.BoxComponent, Roo.Component, {
15654 // private, set in afterRender to signify that the component has been rendered
15656 // private, used to defer height settings to subclasses
15657 deferHeight: false,
15658 /** @cfg {Number} width
15659 * width (optional) size of component
15661 /** @cfg {Number} height
15662 * height (optional) size of component
15666 * Sets the width and height of the component. This method fires the resize event. This method can accept
15667 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15668 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15669 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15670 * @return {Roo.BoxComponent} this
15672 setSize : function(w, h){
15673 // support for standard size objects
15674 if(typeof w == 'object'){
15679 if(!this.boxReady){
15685 // prevent recalcs when not needed
15686 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15689 this.lastSize = {width: w, height: h};
15691 var adj = this.adjustSize(w, h);
15692 var aw = adj.width, ah = adj.height;
15693 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15694 var rz = this.getResizeEl();
15695 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15696 rz.setSize(aw, ah);
15697 }else if(!this.deferHeight && ah !== undefined){
15699 }else if(aw !== undefined){
15702 this.onResize(aw, ah, w, h);
15703 this.fireEvent('resize', this, aw, ah, w, h);
15709 * Gets the current size of the component's underlying element.
15710 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15712 getSize : function(){
15713 return this.el.getSize();
15717 * Gets the current XY position of the component's underlying element.
15718 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15719 * @return {Array} The XY position of the element (e.g., [100, 200])
15721 getPosition : function(local){
15722 if(local === true){
15723 return [this.el.getLeft(true), this.el.getTop(true)];
15725 return this.xy || this.el.getXY();
15729 * Gets the current box measurements of the component's underlying element.
15730 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15731 * @returns {Object} box An object in the format {x, y, width, height}
15733 getBox : function(local){
15734 var s = this.el.getSize();
15736 s.x = this.el.getLeft(true);
15737 s.y = this.el.getTop(true);
15739 var xy = this.xy || this.el.getXY();
15747 * Sets the current box measurements of the component's underlying element.
15748 * @param {Object} box An object in the format {x, y, width, height}
15749 * @returns {Roo.BoxComponent} this
15751 updateBox : function(box){
15752 this.setSize(box.width, box.height);
15753 this.setPagePosition(box.x, box.y);
15758 getResizeEl : function(){
15759 return this.resizeEl || this.el;
15763 getPositionEl : function(){
15764 return this.positionEl || this.el;
15768 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15769 * This method fires the move event.
15770 * @param {Number} left The new left
15771 * @param {Number} top The new top
15772 * @returns {Roo.BoxComponent} this
15774 setPosition : function(x, y){
15777 if(!this.boxReady){
15780 var adj = this.adjustPosition(x, y);
15781 var ax = adj.x, ay = adj.y;
15783 var el = this.getPositionEl();
15784 if(ax !== undefined || ay !== undefined){
15785 if(ax !== undefined && ay !== undefined){
15786 el.setLeftTop(ax, ay);
15787 }else if(ax !== undefined){
15789 }else if(ay !== undefined){
15792 this.onPosition(ax, ay);
15793 this.fireEvent('move', this, ax, ay);
15799 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15800 * This method fires the move event.
15801 * @param {Number} x The new x position
15802 * @param {Number} y The new y position
15803 * @returns {Roo.BoxComponent} this
15805 setPagePosition : function(x, y){
15808 if(!this.boxReady){
15811 if(x === undefined || y === undefined){ // cannot translate undefined points
15814 var p = this.el.translatePoints(x, y);
15815 this.setPosition(p.left, p.top);
15820 onRender : function(ct, position){
15821 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15823 this.resizeEl = Roo.get(this.resizeEl);
15825 if(this.positionEl){
15826 this.positionEl = Roo.get(this.positionEl);
15831 afterRender : function(){
15832 Roo.BoxComponent.superclass.afterRender.call(this);
15833 this.boxReady = true;
15834 this.setSize(this.width, this.height);
15835 if(this.x || this.y){
15836 this.setPosition(this.x, this.y);
15838 if(this.pageX || this.pageY){
15839 this.setPagePosition(this.pageX, this.pageY);
15844 * Force the component's size to recalculate based on the underlying element's current height and width.
15845 * @returns {Roo.BoxComponent} this
15847 syncSize : function(){
15848 delete this.lastSize;
15849 this.setSize(this.el.getWidth(), this.el.getHeight());
15854 * Called after the component is resized, this method is empty by default but can be implemented by any
15855 * subclass that needs to perform custom logic after a resize occurs.
15856 * @param {Number} adjWidth The box-adjusted width that was set
15857 * @param {Number} adjHeight The box-adjusted height that was set
15858 * @param {Number} rawWidth The width that was originally specified
15859 * @param {Number} rawHeight The height that was originally specified
15861 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15866 * Called after the component is moved, this method is empty by default but can be implemented by any
15867 * subclass that needs to perform custom logic after a move occurs.
15868 * @param {Number} x The new x position
15869 * @param {Number} y The new y position
15871 onPosition : function(x, y){
15876 adjustSize : function(w, h){
15877 if(this.autoWidth){
15880 if(this.autoHeight){
15883 return {width : w, height: h};
15887 adjustPosition : function(x, y){
15888 return {x : x, y: y};
15891 * Original code for Roojs - LGPL
15892 * <script type="text/javascript">
15896 * @class Roo.XComponent
15897 * A delayed Element creator...
15898 * Or a way to group chunks of interface together.
15899 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15900 * used in conjunction with XComponent.build() it will create an instance of each element,
15901 * then call addxtype() to build the User interface.
15903 * Mypart.xyx = new Roo.XComponent({
15905 parent : 'Mypart.xyz', // empty == document.element.!!
15909 disabled : function() {}
15911 tree : function() { // return an tree of xtype declared components
15915 xtype : 'NestedLayoutPanel',
15922 * It can be used to build a big heiracy, with parent etc.
15923 * or you can just use this to render a single compoent to a dom element
15924 * MYPART.render(Roo.Element | String(id) | dom_element )
15931 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15932 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15934 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15936 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15937 * - if mulitple topModules exist, the last one is defined as the top module.
15941 * When the top level or multiple modules are to embedded into a existing HTML page,
15942 * the parent element can container '#id' of the element where the module will be drawn.
15946 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15947 * it relies more on a include mechanism, where sub modules are included into an outer page.
15948 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15950 * Bootstrap Roo Included elements
15952 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15953 * hence confusing the component builder as it thinks there are multiple top level elements.
15957 * @extends Roo.util.Observable
15959 * @param cfg {Object} configuration of component
15962 Roo.XComponent = function(cfg) {
15963 Roo.apply(this, cfg);
15967 * Fires when this the componnt is built
15968 * @param {Roo.XComponent} c the component
15973 this.region = this.region || 'center'; // default..
15974 Roo.XComponent.register(this);
15975 this.modules = false;
15976 this.el = false; // where the layout goes..
15980 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15983 * The created element (with Roo.factory())
15984 * @type {Roo.Layout}
15990 * for BC - use el in new code
15991 * @type {Roo.Layout}
15997 * for BC - use el in new code
15998 * @type {Roo.Layout}
16003 * @cfg {Function|boolean} disabled
16004 * If this module is disabled by some rule, return true from the funtion
16009 * @cfg {String} parent
16010 * Name of parent element which it get xtype added to..
16015 * @cfg {String} order
16016 * Used to set the order in which elements are created (usefull for multiple tabs)
16021 * @cfg {String} name
16022 * String to display while loading.
16026 * @cfg {String} region
16027 * Region to render component to (defaults to center)
16032 * @cfg {Array} items
16033 * A single item array - the first element is the root of the tree..
16034 * It's done this way to stay compatible with the Xtype system...
16040 * The method that retuns the tree of parts that make up this compoennt
16047 * render element to dom or tree
16048 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16051 render : function(el)
16055 var hp = this.parent ? 1 : 0;
16056 Roo.debug && Roo.log(this);
16058 var tree = this._tree ? this._tree() : this.tree();
16061 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16062 // if parent is a '#.....' string, then let's use that..
16063 var ename = this.parent.substr(1);
16064 this.parent = false;
16065 Roo.debug && Roo.log(ename);
16067 case 'bootstrap-body':
16068 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16069 // this is the BorderLayout standard?
16070 this.parent = { el : true };
16073 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16074 // need to insert stuff...
16076 el : new Roo.bootstrap.layout.Border({
16077 el : document.body,
16083 tabPosition: 'top',
16084 //resizeTabs: true,
16085 alwaysShowTabs: true,
16095 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16096 this.parent = { el : new Roo.bootstrap.Body() };
16097 Roo.debug && Roo.log("setting el to doc body");
16100 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16104 this.parent = { el : true};
16107 el = Roo.get(ename);
16108 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16109 this.parent = { el : true};
16116 if (!el && !this.parent) {
16117 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16122 Roo.debug && Roo.log("EL:");
16123 Roo.debug && Roo.log(el);
16124 Roo.debug && Roo.log("this.parent.el:");
16125 Roo.debug && Roo.log(this.parent.el);
16128 // altertive root elements ??? - we need a better way to indicate these.
16129 var is_alt = Roo.XComponent.is_alt ||
16130 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16131 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16132 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16136 if (!this.parent && is_alt) {
16137 //el = Roo.get(document.body);
16138 this.parent = { el : true };
16143 if (!this.parent) {
16145 Roo.debug && Roo.log("no parent - creating one");
16147 el = el ? Roo.get(el) : false;
16149 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16152 el : new Roo.bootstrap.layout.Border({
16153 el: el || document.body,
16159 tabPosition: 'top',
16160 //resizeTabs: true,
16161 alwaysShowTabs: false,
16164 overflow: 'visible'
16170 // it's a top level one..
16172 el : new Roo.BorderLayout(el || document.body, {
16177 tabPosition: 'top',
16178 //resizeTabs: true,
16179 alwaysShowTabs: el && hp? false : true,
16180 hideTabs: el || !hp ? true : false,
16188 if (!this.parent.el) {
16189 // probably an old style ctor, which has been disabled.
16193 // The 'tree' method is '_tree now'
16195 tree.region = tree.region || this.region;
16196 var is_body = false;
16197 if (this.parent.el === true) {
16198 // bootstrap... - body..
16202 this.parent.el = Roo.factory(tree);
16206 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16207 this.fireEvent('built', this);
16209 this.panel = this.el;
16210 this.layout = this.panel.layout;
16211 this.parentLayout = this.parent.layout || false;
16217 Roo.apply(Roo.XComponent, {
16219 * @property hideProgress
16220 * true to disable the building progress bar.. usefull on single page renders.
16223 hideProgress : false,
16225 * @property buildCompleted
16226 * True when the builder has completed building the interface.
16229 buildCompleted : false,
16232 * @property topModule
16233 * the upper most module - uses document.element as it's constructor.
16240 * @property modules
16241 * array of modules to be created by registration system.
16242 * @type {Array} of Roo.XComponent
16247 * @property elmodules
16248 * array of modules to be created by which use #ID
16249 * @type {Array} of Roo.XComponent
16256 * Is an alternative Root - normally used by bootstrap or other systems,
16257 * where the top element in the tree can wrap 'body'
16258 * @type {boolean} (default false)
16263 * @property build_from_html
16264 * Build elements from html - used by bootstrap HTML stuff
16265 * - this is cleared after build is completed
16266 * @type {boolean} (default false)
16269 build_from_html : false,
16271 * Register components to be built later.
16273 * This solves the following issues
16274 * - Building is not done on page load, but after an authentication process has occured.
16275 * - Interface elements are registered on page load
16276 * - Parent Interface elements may not be loaded before child, so this handles that..
16283 module : 'Pman.Tab.projectMgr',
16285 parent : 'Pman.layout',
16286 disabled : false, // or use a function..
16289 * * @param {Object} details about module
16291 register : function(obj) {
16293 Roo.XComponent.event.fireEvent('register', obj);
16294 switch(typeof(obj.disabled) ) {
16300 if ( obj.disabled() ) {
16306 if (obj.disabled) {
16312 this.modules.push(obj);
16316 * convert a string to an object..
16317 * eg. 'AAA.BBB' -> finds AAA.BBB
16321 toObject : function(str)
16323 if (!str || typeof(str) == 'object') {
16326 if (str.substring(0,1) == '#') {
16330 var ar = str.split('.');
16335 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16337 throw "Module not found : " + str;
16341 throw "Module not found : " + str;
16343 Roo.each(ar, function(e) {
16344 if (typeof(o[e]) == 'undefined') {
16345 throw "Module not found : " + str;
16356 * move modules into their correct place in the tree..
16359 preBuild : function ()
16362 Roo.each(this.modules , function (obj)
16364 Roo.XComponent.event.fireEvent('beforebuild', obj);
16366 var opar = obj.parent;
16368 obj.parent = this.toObject(opar);
16370 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16375 Roo.debug && Roo.log("GOT top level module");
16376 Roo.debug && Roo.log(obj);
16377 obj.modules = new Roo.util.MixedCollection(false,
16378 function(o) { return o.order + '' }
16380 this.topModule = obj;
16383 // parent is a string (usually a dom element name..)
16384 if (typeof(obj.parent) == 'string') {
16385 this.elmodules.push(obj);
16388 if (obj.parent.constructor != Roo.XComponent) {
16389 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16391 if (!obj.parent.modules) {
16392 obj.parent.modules = new Roo.util.MixedCollection(false,
16393 function(o) { return o.order + '' }
16396 if (obj.parent.disabled) {
16397 obj.disabled = true;
16399 obj.parent.modules.add(obj);
16404 * make a list of modules to build.
16405 * @return {Array} list of modules.
16408 buildOrder : function()
16411 var cmp = function(a,b) {
16412 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16414 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16415 throw "No top level modules to build";
16418 // make a flat list in order of modules to build.
16419 var mods = this.topModule ? [ this.topModule ] : [];
16422 // elmodules (is a list of DOM based modules )
16423 Roo.each(this.elmodules, function(e) {
16425 if (!this.topModule &&
16426 typeof(e.parent) == 'string' &&
16427 e.parent.substring(0,1) == '#' &&
16428 Roo.get(e.parent.substr(1))
16431 _this.topModule = e;
16437 // add modules to their parents..
16438 var addMod = function(m) {
16439 Roo.debug && Roo.log("build Order: add: " + m.name);
16442 if (m.modules && !m.disabled) {
16443 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16444 m.modules.keySort('ASC', cmp );
16445 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16447 m.modules.each(addMod);
16449 Roo.debug && Roo.log("build Order: no child modules");
16451 // not sure if this is used any more..
16453 m.finalize.name = m.name + " (clean up) ";
16454 mods.push(m.finalize);
16458 if (this.topModule && this.topModule.modules) {
16459 this.topModule.modules.keySort('ASC', cmp );
16460 this.topModule.modules.each(addMod);
16466 * Build the registered modules.
16467 * @param {Object} parent element.
16468 * @param {Function} optional method to call after module has been added.
16472 build : function(opts)
16475 if (typeof(opts) != 'undefined') {
16476 Roo.apply(this,opts);
16480 var mods = this.buildOrder();
16482 //this.allmods = mods;
16483 //Roo.debug && Roo.log(mods);
16485 if (!mods.length) { // should not happen
16486 throw "NO modules!!!";
16490 var msg = "Building Interface...";
16491 // flash it up as modal - so we store the mask!?
16492 if (!this.hideProgress && Roo.MessageBox) {
16493 Roo.MessageBox.show({ title: 'loading' });
16494 Roo.MessageBox.show({
16495 title: "Please wait...",
16504 var total = mods.length;
16507 var progressRun = function() {
16508 if (!mods.length) {
16509 Roo.debug && Roo.log('hide?');
16510 if (!this.hideProgress && Roo.MessageBox) {
16511 Roo.MessageBox.hide();
16513 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16515 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16521 var m = mods.shift();
16524 Roo.debug && Roo.log(m);
16525 // not sure if this is supported any more.. - modules that are are just function
16526 if (typeof(m) == 'function') {
16528 return progressRun.defer(10, _this);
16532 msg = "Building Interface " + (total - mods.length) +
16534 (m.name ? (' - ' + m.name) : '');
16535 Roo.debug && Roo.log(msg);
16536 if (!_this.hideProgress && Roo.MessageBox) {
16537 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16541 // is the module disabled?
16542 var disabled = (typeof(m.disabled) == 'function') ?
16543 m.disabled.call(m.module.disabled) : m.disabled;
16547 return progressRun(); // we do not update the display!
16555 // it's 10 on top level, and 1 on others??? why...
16556 return progressRun.defer(10, _this);
16559 progressRun.defer(1, _this);
16573 * wrapper for event.on - aliased later..
16574 * Typically use to register a event handler for register:
16576 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16585 Roo.XComponent.event = new Roo.util.Observable({
16589 * Fires when an Component is registered,
16590 * set the disable property on the Component to stop registration.
16591 * @param {Roo.XComponent} c the component being registerd.
16596 * @event beforebuild
16597 * Fires before each Component is built
16598 * can be used to apply permissions.
16599 * @param {Roo.XComponent} c the component being registerd.
16602 'beforebuild' : true,
16604 * @event buildcomplete
16605 * Fires on the top level element when all elements have been built
16606 * @param {Roo.XComponent} the top level component.
16608 'buildcomplete' : true
16613 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16616 * marked - a markdown parser
16617 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16618 * https://github.com/chjj/marked
16624 * Roo.Markdown - is a very crude wrapper around marked..
16628 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16630 * Note: move the sample code to the bottom of this
16631 * file before uncommenting it.
16636 Roo.Markdown.toHtml = function(text) {
16638 var c = new Roo.Markdown.marked.setOptions({
16639 renderer: new Roo.Markdown.marked.Renderer(),
16650 text = text.replace(/\\\n/g,' ');
16651 return Roo.Markdown.marked(text);
16656 // Wraps all "globals" so that the only thing
16657 // exposed is makeHtml().
16662 * Block-Level Grammar
16667 code: /^( {4}[^\n]+\n*)+/,
16669 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16670 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16672 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16673 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16674 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16675 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16676 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16678 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16682 block.bullet = /(?:[*+-]|\d+\.)/;
16683 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16684 block.item = replace(block.item, 'gm')
16685 (/bull/g, block.bullet)
16688 block.list = replace(block.list)
16689 (/bull/g, block.bullet)
16690 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16691 ('def', '\\n+(?=' + block.def.source + ')')
16694 block.blockquote = replace(block.blockquote)
16698 block._tag = '(?!(?:'
16699 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16700 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16701 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16703 block.html = replace(block.html)
16704 ('comment', /<!--[\s\S]*?-->/)
16705 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16706 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16707 (/tag/g, block._tag)
16710 block.paragraph = replace(block.paragraph)
16712 ('heading', block.heading)
16713 ('lheading', block.lheading)
16714 ('blockquote', block.blockquote)
16715 ('tag', '<' + block._tag)
16720 * Normal Block Grammar
16723 block.normal = merge({}, block);
16726 * GFM Block Grammar
16729 block.gfm = merge({}, block.normal, {
16730 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16732 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16735 block.gfm.paragraph = replace(block.paragraph)
16737 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16738 + block.list.source.replace('\\1', '\\3') + '|')
16742 * GFM + Tables Block Grammar
16745 block.tables = merge({}, block.gfm, {
16746 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16747 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16754 function Lexer(options) {
16756 this.tokens.links = {};
16757 this.options = options || marked.defaults;
16758 this.rules = block.normal;
16760 if (this.options.gfm) {
16761 if (this.options.tables) {
16762 this.rules = block.tables;
16764 this.rules = block.gfm;
16770 * Expose Block Rules
16773 Lexer.rules = block;
16776 * Static Lex Method
16779 Lexer.lex = function(src, options) {
16780 var lexer = new Lexer(options);
16781 return lexer.lex(src);
16788 Lexer.prototype.lex = function(src) {
16790 .replace(/\r\n|\r/g, '\n')
16791 .replace(/\t/g, ' ')
16792 .replace(/\u00a0/g, ' ')
16793 .replace(/\u2424/g, '\n');
16795 return this.token(src, true);
16802 Lexer.prototype.token = function(src, top, bq) {
16803 var src = src.replace(/^ +$/gm, '')
16816 if (cap = this.rules.newline.exec(src)) {
16817 src = src.substring(cap[0].length);
16818 if (cap[0].length > 1) {
16826 if (cap = this.rules.code.exec(src)) {
16827 src = src.substring(cap[0].length);
16828 cap = cap[0].replace(/^ {4}/gm, '');
16831 text: !this.options.pedantic
16832 ? cap.replace(/\n+$/, '')
16839 if (cap = this.rules.fences.exec(src)) {
16840 src = src.substring(cap[0].length);
16850 if (cap = this.rules.heading.exec(src)) {
16851 src = src.substring(cap[0].length);
16854 depth: cap[1].length,
16860 // table no leading pipe (gfm)
16861 if (top && (cap = this.rules.nptable.exec(src))) {
16862 src = src.substring(cap[0].length);
16866 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16867 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16868 cells: cap[3].replace(/\n$/, '').split('\n')
16871 for (i = 0; i < item.align.length; i++) {
16872 if (/^ *-+: *$/.test(item.align[i])) {
16873 item.align[i] = 'right';
16874 } else if (/^ *:-+: *$/.test(item.align[i])) {
16875 item.align[i] = 'center';
16876 } else if (/^ *:-+ *$/.test(item.align[i])) {
16877 item.align[i] = 'left';
16879 item.align[i] = null;
16883 for (i = 0; i < item.cells.length; i++) {
16884 item.cells[i] = item.cells[i].split(/ *\| */);
16887 this.tokens.push(item);
16893 if (cap = this.rules.lheading.exec(src)) {
16894 src = src.substring(cap[0].length);
16897 depth: cap[2] === '=' ? 1 : 2,
16904 if (cap = this.rules.hr.exec(src)) {
16905 src = src.substring(cap[0].length);
16913 if (cap = this.rules.blockquote.exec(src)) {
16914 src = src.substring(cap[0].length);
16917 type: 'blockquote_start'
16920 cap = cap[0].replace(/^ *> ?/gm, '');
16922 // Pass `top` to keep the current
16923 // "toplevel" state. This is exactly
16924 // how markdown.pl works.
16925 this.token(cap, top, true);
16928 type: 'blockquote_end'
16935 if (cap = this.rules.list.exec(src)) {
16936 src = src.substring(cap[0].length);
16940 type: 'list_start',
16941 ordered: bull.length > 1
16944 // Get each top-level item.
16945 cap = cap[0].match(this.rules.item);
16951 for (; i < l; i++) {
16954 // Remove the list item's bullet
16955 // so it is seen as the next token.
16956 space = item.length;
16957 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16959 // Outdent whatever the
16960 // list item contains. Hacky.
16961 if (~item.indexOf('\n ')) {
16962 space -= item.length;
16963 item = !this.options.pedantic
16964 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16965 : item.replace(/^ {1,4}/gm, '');
16968 // Determine whether the next list item belongs here.
16969 // Backpedal if it does not belong in this list.
16970 if (this.options.smartLists && i !== l - 1) {
16971 b = block.bullet.exec(cap[i + 1])[0];
16972 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16973 src = cap.slice(i + 1).join('\n') + src;
16978 // Determine whether item is loose or not.
16979 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16980 // for discount behavior.
16981 loose = next || /\n\n(?!\s*$)/.test(item);
16983 next = item.charAt(item.length - 1) === '\n';
16984 if (!loose) { loose = next; }
16989 ? 'loose_item_start'
16990 : 'list_item_start'
16994 this.token(item, false, bq);
16997 type: 'list_item_end'
17009 if (cap = this.rules.html.exec(src)) {
17010 src = src.substring(cap[0].length);
17012 type: this.options.sanitize
17015 pre: !this.options.sanitizer
17016 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17023 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17024 src = src.substring(cap[0].length);
17025 this.tokens.links[cap[1].toLowerCase()] = {
17033 if (top && (cap = this.rules.table.exec(src))) {
17034 src = src.substring(cap[0].length);
17038 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17039 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17040 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17043 for (i = 0; i < item.align.length; i++) {
17044 if (/^ *-+: *$/.test(item.align[i])) {
17045 item.align[i] = 'right';
17046 } else if (/^ *:-+: *$/.test(item.align[i])) {
17047 item.align[i] = 'center';
17048 } else if (/^ *:-+ *$/.test(item.align[i])) {
17049 item.align[i] = 'left';
17051 item.align[i] = null;
17055 for (i = 0; i < item.cells.length; i++) {
17056 item.cells[i] = item.cells[i]
17057 .replace(/^ *\| *| *\| *$/g, '')
17061 this.tokens.push(item);
17066 // top-level paragraph
17067 if (top && (cap = this.rules.paragraph.exec(src))) {
17068 src = src.substring(cap[0].length);
17071 text: cap[1].charAt(cap[1].length - 1) === '\n'
17072 ? cap[1].slice(0, -1)
17079 if (cap = this.rules.text.exec(src)) {
17080 // Top-level should never reach here.
17081 src = src.substring(cap[0].length);
17091 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17095 return this.tokens;
17099 * Inline-Level Grammar
17103 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17104 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17106 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17107 link: /^!?\[(inside)\]\(href\)/,
17108 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17109 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17110 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17111 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17112 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17113 br: /^ {2,}\n(?!\s*$)/,
17115 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17118 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17119 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17121 inline.link = replace(inline.link)
17122 ('inside', inline._inside)
17123 ('href', inline._href)
17126 inline.reflink = replace(inline.reflink)
17127 ('inside', inline._inside)
17131 * Normal Inline Grammar
17134 inline.normal = merge({}, inline);
17137 * Pedantic Inline Grammar
17140 inline.pedantic = merge({}, inline.normal, {
17141 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17142 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17146 * GFM Inline Grammar
17149 inline.gfm = merge({}, inline.normal, {
17150 escape: replace(inline.escape)('])', '~|])')(),
17151 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17152 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17153 text: replace(inline.text)
17155 ('|', '|https?://|')
17160 * GFM + Line Breaks Inline Grammar
17163 inline.breaks = merge({}, inline.gfm, {
17164 br: replace(inline.br)('{2,}', '*')(),
17165 text: replace(inline.gfm.text)('{2,}', '*')()
17169 * Inline Lexer & Compiler
17172 function InlineLexer(links, options) {
17173 this.options = options || marked.defaults;
17174 this.links = links;
17175 this.rules = inline.normal;
17176 this.renderer = this.options.renderer || new Renderer;
17177 this.renderer.options = this.options;
17181 Error('Tokens array requires a `links` property.');
17184 if (this.options.gfm) {
17185 if (this.options.breaks) {
17186 this.rules = inline.breaks;
17188 this.rules = inline.gfm;
17190 } else if (this.options.pedantic) {
17191 this.rules = inline.pedantic;
17196 * Expose Inline Rules
17199 InlineLexer.rules = inline;
17202 * Static Lexing/Compiling Method
17205 InlineLexer.output = function(src, links, options) {
17206 var inline = new InlineLexer(links, options);
17207 return inline.output(src);
17214 InlineLexer.prototype.output = function(src) {
17223 if (cap = this.rules.escape.exec(src)) {
17224 src = src.substring(cap[0].length);
17230 if (cap = this.rules.autolink.exec(src)) {
17231 src = src.substring(cap[0].length);
17232 if (cap[2] === '@') {
17233 text = cap[1].charAt(6) === ':'
17234 ? this.mangle(cap[1].substring(7))
17235 : this.mangle(cap[1]);
17236 href = this.mangle('mailto:') + text;
17238 text = escape(cap[1]);
17241 out += this.renderer.link(href, null, text);
17246 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17247 src = src.substring(cap[0].length);
17248 text = escape(cap[1]);
17250 out += this.renderer.link(href, null, text);
17255 if (cap = this.rules.tag.exec(src)) {
17256 if (!this.inLink && /^<a /i.test(cap[0])) {
17257 this.inLink = true;
17258 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17259 this.inLink = false;
17261 src = src.substring(cap[0].length);
17262 out += this.options.sanitize
17263 ? this.options.sanitizer
17264 ? this.options.sanitizer(cap[0])
17271 if (cap = this.rules.link.exec(src)) {
17272 src = src.substring(cap[0].length);
17273 this.inLink = true;
17274 out += this.outputLink(cap, {
17278 this.inLink = false;
17283 if ((cap = this.rules.reflink.exec(src))
17284 || (cap = this.rules.nolink.exec(src))) {
17285 src = src.substring(cap[0].length);
17286 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17287 link = this.links[link.toLowerCase()];
17288 if (!link || !link.href) {
17289 out += cap[0].charAt(0);
17290 src = cap[0].substring(1) + src;
17293 this.inLink = true;
17294 out += this.outputLink(cap, link);
17295 this.inLink = false;
17300 if (cap = this.rules.strong.exec(src)) {
17301 src = src.substring(cap[0].length);
17302 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17307 if (cap = this.rules.em.exec(src)) {
17308 src = src.substring(cap[0].length);
17309 out += this.renderer.em(this.output(cap[2] || cap[1]));
17314 if (cap = this.rules.code.exec(src)) {
17315 src = src.substring(cap[0].length);
17316 out += this.renderer.codespan(escape(cap[2], true));
17321 if (cap = this.rules.br.exec(src)) {
17322 src = src.substring(cap[0].length);
17323 out += this.renderer.br();
17328 if (cap = this.rules.del.exec(src)) {
17329 src = src.substring(cap[0].length);
17330 out += this.renderer.del(this.output(cap[1]));
17335 if (cap = this.rules.text.exec(src)) {
17336 src = src.substring(cap[0].length);
17337 out += this.renderer.text(escape(this.smartypants(cap[0])));
17343 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17354 InlineLexer.prototype.outputLink = function(cap, link) {
17355 var href = escape(link.href)
17356 , title = link.title ? escape(link.title) : null;
17358 return cap[0].charAt(0) !== '!'
17359 ? this.renderer.link(href, title, this.output(cap[1]))
17360 : this.renderer.image(href, title, escape(cap[1]));
17364 * Smartypants Transformations
17367 InlineLexer.prototype.smartypants = function(text) {
17368 if (!this.options.smartypants) { return text; }
17371 .replace(/---/g, '\u2014')
17373 .replace(/--/g, '\u2013')
17375 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17376 // closing singles & apostrophes
17377 .replace(/'/g, '\u2019')
17379 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17381 .replace(/"/g, '\u201d')
17383 .replace(/\.{3}/g, '\u2026');
17390 InlineLexer.prototype.mangle = function(text) {
17391 if (!this.options.mangle) { return text; }
17397 for (; i < l; i++) {
17398 ch = text.charCodeAt(i);
17399 if (Math.random() > 0.5) {
17400 ch = 'x' + ch.toString(16);
17402 out += '&#' + ch + ';';
17412 function Renderer(options) {
17413 this.options = options || {};
17416 Renderer.prototype.code = function(code, lang, escaped) {
17417 if (this.options.highlight) {
17418 var out = this.options.highlight(code, lang);
17419 if (out != null && out !== code) {
17424 // hack!!! - it's already escapeD?
17429 return '<pre><code>'
17430 + (escaped ? code : escape(code, true))
17431 + '\n</code></pre>';
17434 return '<pre><code class="'
17435 + this.options.langPrefix
17436 + escape(lang, true)
17438 + (escaped ? code : escape(code, true))
17439 + '\n</code></pre>\n';
17442 Renderer.prototype.blockquote = function(quote) {
17443 return '<blockquote>\n' + quote + '</blockquote>\n';
17446 Renderer.prototype.html = function(html) {
17450 Renderer.prototype.heading = function(text, level, raw) {
17454 + this.options.headerPrefix
17455 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17463 Renderer.prototype.hr = function() {
17464 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17467 Renderer.prototype.list = function(body, ordered) {
17468 var type = ordered ? 'ol' : 'ul';
17469 return '<' + type + '>\n' + body + '</' + type + '>\n';
17472 Renderer.prototype.listitem = function(text) {
17473 return '<li>' + text + '</li>\n';
17476 Renderer.prototype.paragraph = function(text) {
17477 return '<p>' + text + '</p>\n';
17480 Renderer.prototype.table = function(header, body) {
17481 return '<table class="table table-striped">\n'
17491 Renderer.prototype.tablerow = function(content) {
17492 return '<tr>\n' + content + '</tr>\n';
17495 Renderer.prototype.tablecell = function(content, flags) {
17496 var type = flags.header ? 'th' : 'td';
17497 var tag = flags.align
17498 ? '<' + type + ' style="text-align:' + flags.align + '">'
17499 : '<' + type + '>';
17500 return tag + content + '</' + type + '>\n';
17503 // span level renderer
17504 Renderer.prototype.strong = function(text) {
17505 return '<strong>' + text + '</strong>';
17508 Renderer.prototype.em = function(text) {
17509 return '<em>' + text + '</em>';
17512 Renderer.prototype.codespan = function(text) {
17513 return '<code>' + text + '</code>';
17516 Renderer.prototype.br = function() {
17517 return this.options.xhtml ? '<br/>' : '<br>';
17520 Renderer.prototype.del = function(text) {
17521 return '<del>' + text + '</del>';
17524 Renderer.prototype.link = function(href, title, text) {
17525 if (this.options.sanitize) {
17527 var prot = decodeURIComponent(unescape(href))
17528 .replace(/[^\w:]/g, '')
17533 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17537 var out = '<a href="' + href + '"';
17539 out += ' title="' + title + '"';
17541 out += '>' + text + '</a>';
17545 Renderer.prototype.image = function(href, title, text) {
17546 var out = '<img src="' + href + '" alt="' + text + '"';
17548 out += ' title="' + title + '"';
17550 out += this.options.xhtml ? '/>' : '>';
17554 Renderer.prototype.text = function(text) {
17559 * Parsing & Compiling
17562 function Parser(options) {
17565 this.options = options || marked.defaults;
17566 this.options.renderer = this.options.renderer || new Renderer;
17567 this.renderer = this.options.renderer;
17568 this.renderer.options = this.options;
17572 * Static Parse Method
17575 Parser.parse = function(src, options, renderer) {
17576 var parser = new Parser(options, renderer);
17577 return parser.parse(src);
17584 Parser.prototype.parse = function(src) {
17585 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17586 this.tokens = src.reverse();
17589 while (this.next()) {
17600 Parser.prototype.next = function() {
17601 return this.token = this.tokens.pop();
17605 * Preview Next Token
17608 Parser.prototype.peek = function() {
17609 return this.tokens[this.tokens.length - 1] || 0;
17613 * Parse Text Tokens
17616 Parser.prototype.parseText = function() {
17617 var body = this.token.text;
17619 while (this.peek().type === 'text') {
17620 body += '\n' + this.next().text;
17623 return this.inline.output(body);
17627 * Parse Current Token
17630 Parser.prototype.tok = function() {
17631 switch (this.token.type) {
17636 return this.renderer.hr();
17639 return this.renderer.heading(
17640 this.inline.output(this.token.text),
17645 return this.renderer.code(this.token.text,
17647 this.token.escaped);
17660 for (i = 0; i < this.token.header.length; i++) {
17661 flags = { header: true, align: this.token.align[i] };
17662 cell += this.renderer.tablecell(
17663 this.inline.output(this.token.header[i]),
17664 { header: true, align: this.token.align[i] }
17667 header += this.renderer.tablerow(cell);
17669 for (i = 0; i < this.token.cells.length; i++) {
17670 row = this.token.cells[i];
17673 for (j = 0; j < row.length; j++) {
17674 cell += this.renderer.tablecell(
17675 this.inline.output(row[j]),
17676 { header: false, align: this.token.align[j] }
17680 body += this.renderer.tablerow(cell);
17682 return this.renderer.table(header, body);
17684 case 'blockquote_start': {
17687 while (this.next().type !== 'blockquote_end') {
17688 body += this.tok();
17691 return this.renderer.blockquote(body);
17693 case 'list_start': {
17695 , ordered = this.token.ordered;
17697 while (this.next().type !== 'list_end') {
17698 body += this.tok();
17701 return this.renderer.list(body, ordered);
17703 case 'list_item_start': {
17706 while (this.next().type !== 'list_item_end') {
17707 body += this.token.type === 'text'
17712 return this.renderer.listitem(body);
17714 case 'loose_item_start': {
17717 while (this.next().type !== 'list_item_end') {
17718 body += this.tok();
17721 return this.renderer.listitem(body);
17724 var html = !this.token.pre && !this.options.pedantic
17725 ? this.inline.output(this.token.text)
17727 return this.renderer.html(html);
17729 case 'paragraph': {
17730 return this.renderer.paragraph(this.inline.output(this.token.text));
17733 return this.renderer.paragraph(this.parseText());
17742 function escape(html, encode) {
17744 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17745 .replace(/</g, '<')
17746 .replace(/>/g, '>')
17747 .replace(/"/g, '"')
17748 .replace(/'/g, ''');
17751 function unescape(html) {
17752 // explicitly match decimal, hex, and named HTML entities
17753 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17754 n = n.toLowerCase();
17755 if (n === 'colon') { return ':'; }
17756 if (n.charAt(0) === '#') {
17757 return n.charAt(1) === 'x'
17758 ? String.fromCharCode(parseInt(n.substring(2), 16))
17759 : String.fromCharCode(+n.substring(1));
17765 function replace(regex, opt) {
17766 regex = regex.source;
17768 return function self(name, val) {
17769 if (!name) { return new RegExp(regex, opt); }
17770 val = val.source || val;
17771 val = val.replace(/(^|[^\[])\^/g, '$1');
17772 regex = regex.replace(name, val);
17780 function merge(obj) {
17785 for (; i < arguments.length; i++) {
17786 target = arguments[i];
17787 for (key in target) {
17788 if (Object.prototype.hasOwnProperty.call(target, key)) {
17789 obj[key] = target[key];
17802 function marked(src, opt, callback) {
17803 if (callback || typeof opt === 'function') {
17809 opt = merge({}, marked.defaults, opt || {});
17811 var highlight = opt.highlight
17817 tokens = Lexer.lex(src, opt)
17819 return callback(e);
17822 pending = tokens.length;
17824 var done = function(err) {
17826 opt.highlight = highlight;
17827 return callback(err);
17833 out = Parser.parse(tokens, opt);
17838 opt.highlight = highlight;
17842 : callback(null, out);
17845 if (!highlight || highlight.length < 3) {
17849 delete opt.highlight;
17851 if (!pending) { return done(); }
17853 for (; i < tokens.length; i++) {
17855 if (token.type !== 'code') {
17856 return --pending || done();
17858 return highlight(token.text, token.lang, function(err, code) {
17859 if (err) { return done(err); }
17860 if (code == null || code === token.text) {
17861 return --pending || done();
17864 token.escaped = true;
17865 --pending || done();
17873 if (opt) { opt = merge({}, marked.defaults, opt); }
17874 return Parser.parse(Lexer.lex(src, opt), opt);
17876 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17877 if ((opt || marked.defaults).silent) {
17878 return '<p>An error occured:</p><pre>'
17879 + escape(e.message + '', true)
17891 marked.setOptions = function(opt) {
17892 merge(marked.defaults, opt);
17896 marked.defaults = {
17907 langPrefix: 'lang-',
17908 smartypants: false,
17910 renderer: new Renderer,
17918 marked.Parser = Parser;
17919 marked.parser = Parser.parse;
17921 marked.Renderer = Renderer;
17923 marked.Lexer = Lexer;
17924 marked.lexer = Lexer.lex;
17926 marked.InlineLexer = InlineLexer;
17927 marked.inlineLexer = InlineLexer.output;
17929 marked.parse = marked;
17931 Roo.Markdown.marked = marked;
17935 * Ext JS Library 1.1.1
17936 * Copyright(c) 2006-2007, Ext JS, LLC.
17938 * Originally Released Under LGPL - original licence link has changed is not relivant.
17941 * <script type="text/javascript">
17947 * These classes are derivatives of the similarly named classes in the YUI Library.
17948 * The original license:
17949 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17950 * Code licensed under the BSD License:
17951 * http://developer.yahoo.net/yui/license.txt
17956 var Event=Roo.EventManager;
17957 var Dom=Roo.lib.Dom;
17960 * @class Roo.dd.DragDrop
17961 * @extends Roo.util.Observable
17962 * Defines the interface and base operation of items that that can be
17963 * dragged or can be drop targets. It was designed to be extended, overriding
17964 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17965 * Up to three html elements can be associated with a DragDrop instance:
17967 * <li>linked element: the element that is passed into the constructor.
17968 * This is the element which defines the boundaries for interaction with
17969 * other DragDrop objects.</li>
17970 * <li>handle element(s): The drag operation only occurs if the element that
17971 * was clicked matches a handle element. By default this is the linked
17972 * element, but there are times that you will want only a portion of the
17973 * linked element to initiate the drag operation, and the setHandleElId()
17974 * method provides a way to define this.</li>
17975 * <li>drag element: this represents the element that would be moved along
17976 * with the cursor during a drag operation. By default, this is the linked
17977 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
17978 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17981 * This class should not be instantiated until the onload event to ensure that
17982 * the associated elements are available.
17983 * The following would define a DragDrop obj that would interact with any
17984 * other DragDrop obj in the "group1" group:
17986 * dd = new Roo.dd.DragDrop("div1", "group1");
17988 * Since none of the event handlers have been implemented, nothing would
17989 * actually happen if you were to run the code above. Normally you would
17990 * override this class or one of the default implementations, but you can
17991 * also override the methods you want on an instance of the class...
17993 * dd.onDragDrop = function(e, id) {
17994 * alert("dd was dropped on " + id);
17998 * @param {String} id of the element that is linked to this instance
17999 * @param {String} sGroup the group of related DragDrop objects
18000 * @param {object} config an object containing configurable attributes
18001 * Valid properties for DragDrop:
18002 * padding, isTarget, maintainOffset, primaryButtonOnly
18004 Roo.dd.DragDrop = function(id, sGroup, config) {
18006 this.init(id, sGroup, config);
18011 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18014 * The id of the element associated with this object. This is what we
18015 * refer to as the "linked element" because the size and position of
18016 * this element is used to determine when the drag and drop objects have
18024 * Configuration attributes passed into the constructor
18031 * The id of the element that will be dragged. By default this is same
18032 * as the linked element , but could be changed to another element. Ex:
18034 * @property dragElId
18041 * the id of the element that initiates the drag operation. By default
18042 * this is the linked element, but could be changed to be a child of this
18043 * element. This lets us do things like only starting the drag when the
18044 * header element within the linked html element is clicked.
18045 * @property handleElId
18052 * An associative array of HTML tags that will be ignored if clicked.
18053 * @property invalidHandleTypes
18054 * @type {string: string}
18056 invalidHandleTypes: null,
18059 * An associative array of ids for elements that will be ignored if clicked
18060 * @property invalidHandleIds
18061 * @type {string: string}
18063 invalidHandleIds: null,
18066 * An indexted array of css class names for elements that will be ignored
18068 * @property invalidHandleClasses
18071 invalidHandleClasses: null,
18074 * The linked element's absolute X position at the time the drag was
18076 * @property startPageX
18083 * The linked element's absolute X position at the time the drag was
18085 * @property startPageY
18092 * The group defines a logical collection of DragDrop objects that are
18093 * related. Instances only get events when interacting with other
18094 * DragDrop object in the same group. This lets us define multiple
18095 * groups using a single DragDrop subclass if we want.
18097 * @type {string: string}
18102 * Individual drag/drop instances can be locked. This will prevent
18103 * onmousedown start drag.
18111 * Lock this instance
18114 lock: function() { this.locked = true; },
18117 * Unlock this instace
18120 unlock: function() { this.locked = false; },
18123 * By default, all insances can be a drop target. This can be disabled by
18124 * setting isTarget to false.
18131 * The padding configured for this drag and drop object for calculating
18132 * the drop zone intersection with this object.
18139 * Cached reference to the linked element
18140 * @property _domRef
18146 * Internal typeof flag
18147 * @property __ygDragDrop
18150 __ygDragDrop: true,
18153 * Set to true when horizontal contraints are applied
18154 * @property constrainX
18161 * Set to true when vertical contraints are applied
18162 * @property constrainY
18169 * The left constraint
18177 * The right constraint
18185 * The up constraint
18194 * The down constraint
18202 * Maintain offsets when we resetconstraints. Set to true when you want
18203 * the position of the element relative to its parent to stay the same
18204 * when the page changes
18206 * @property maintainOffset
18209 maintainOffset: false,
18212 * Array of pixel locations the element will snap to if we specified a
18213 * horizontal graduation/interval. This array is generated automatically
18214 * when you define a tick interval.
18221 * Array of pixel locations the element will snap to if we specified a
18222 * vertical graduation/interval. This array is generated automatically
18223 * when you define a tick interval.
18230 * By default the drag and drop instance will only respond to the primary
18231 * button click (left button for a right-handed mouse). Set to true to
18232 * allow drag and drop to start with any mouse click that is propogated
18234 * @property primaryButtonOnly
18237 primaryButtonOnly: true,
18240 * The availabe property is false until the linked dom element is accessible.
18241 * @property available
18247 * By default, drags can only be initiated if the mousedown occurs in the
18248 * region the linked element is. This is done in part to work around a
18249 * bug in some browsers that mis-report the mousedown if the previous
18250 * mouseup happened outside of the window. This property is set to true
18251 * if outer handles are defined.
18253 * @property hasOuterHandles
18257 hasOuterHandles: false,
18260 * Code that executes immediately before the startDrag event
18261 * @method b4StartDrag
18264 b4StartDrag: function(x, y) { },
18267 * Abstract method called after a drag/drop object is clicked
18268 * and the drag or mousedown time thresholds have beeen met.
18269 * @method startDrag
18270 * @param {int} X click location
18271 * @param {int} Y click location
18273 startDrag: function(x, y) { /* override this */ },
18276 * Code that executes immediately before the onDrag event
18280 b4Drag: function(e) { },
18283 * Abstract method called during the onMouseMove event while dragging an
18286 * @param {Event} e the mousemove event
18288 onDrag: function(e) { /* override this */ },
18291 * Abstract method called when this element fist begins hovering over
18292 * another DragDrop obj
18293 * @method onDragEnter
18294 * @param {Event} e the mousemove event
18295 * @param {String|DragDrop[]} id In POINT mode, the element
18296 * id this is hovering over. In INTERSECT mode, an array of one or more
18297 * dragdrop items being hovered over.
18299 onDragEnter: function(e, id) { /* override this */ },
18302 * Code that executes immediately before the onDragOver event
18303 * @method b4DragOver
18306 b4DragOver: function(e) { },
18309 * Abstract method called when this element is hovering over another
18311 * @method onDragOver
18312 * @param {Event} e the mousemove event
18313 * @param {String|DragDrop[]} id In POINT mode, the element
18314 * id this is hovering over. In INTERSECT mode, an array of dd items
18315 * being hovered over.
18317 onDragOver: function(e, id) { /* override this */ },
18320 * Code that executes immediately before the onDragOut event
18321 * @method b4DragOut
18324 b4DragOut: function(e) { },
18327 * Abstract method called when we are no longer hovering over an element
18328 * @method onDragOut
18329 * @param {Event} e the mousemove event
18330 * @param {String|DragDrop[]} id In POINT mode, the element
18331 * id this was hovering over. In INTERSECT mode, an array of dd items
18332 * that the mouse is no longer over.
18334 onDragOut: function(e, id) { /* override this */ },
18337 * Code that executes immediately before the onDragDrop event
18338 * @method b4DragDrop
18341 b4DragDrop: function(e) { },
18344 * Abstract method called when this item is dropped on another DragDrop
18346 * @method onDragDrop
18347 * @param {Event} e the mouseup event
18348 * @param {String|DragDrop[]} id In POINT mode, the element
18349 * id this was dropped on. In INTERSECT mode, an array of dd items this
18352 onDragDrop: function(e, id) { /* override this */ },
18355 * Abstract method called when this item is dropped on an area with no
18357 * @method onInvalidDrop
18358 * @param {Event} e the mouseup event
18360 onInvalidDrop: function(e) { /* override this */ },
18363 * Code that executes immediately before the endDrag event
18364 * @method b4EndDrag
18367 b4EndDrag: function(e) { },
18370 * Fired when we are done dragging the object
18372 * @param {Event} e the mouseup event
18374 endDrag: function(e) { /* override this */ },
18377 * Code executed immediately before the onMouseDown event
18378 * @method b4MouseDown
18379 * @param {Event} e the mousedown event
18382 b4MouseDown: function(e) { },
18385 * Event handler that fires when a drag/drop obj gets a mousedown
18386 * @method onMouseDown
18387 * @param {Event} e the mousedown event
18389 onMouseDown: function(e) { /* override this */ },
18392 * Event handler that fires when a drag/drop obj gets a mouseup
18393 * @method onMouseUp
18394 * @param {Event} e the mouseup event
18396 onMouseUp: function(e) { /* override this */ },
18399 * Override the onAvailable method to do what is needed after the initial
18400 * position was determined.
18401 * @method onAvailable
18403 onAvailable: function () {
18407 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18410 defaultPadding : {left:0, right:0, top:0, bottom:0},
18413 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18417 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18418 { dragElId: "existingProxyDiv" });
18419 dd.startDrag = function(){
18420 this.constrainTo("parent-id");
18423 * Or you can initalize it using the {@link Roo.Element} object:
18425 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18426 startDrag : function(){
18427 this.constrainTo("parent-id");
18431 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18432 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18433 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18434 * an object containing the sides to pad. For example: {right:10, bottom:10}
18435 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18437 constrainTo : function(constrainTo, pad, inContent){
18438 if(typeof pad == "number"){
18439 pad = {left: pad, right:pad, top:pad, bottom:pad};
18441 pad = pad || this.defaultPadding;
18442 var b = Roo.get(this.getEl()).getBox();
18443 var ce = Roo.get(constrainTo);
18444 var s = ce.getScroll();
18445 var c, cd = ce.dom;
18446 if(cd == document.body){
18447 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18450 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18454 var topSpace = b.y - c.y;
18455 var leftSpace = b.x - c.x;
18457 this.resetConstraints();
18458 this.setXConstraint(leftSpace - (pad.left||0), // left
18459 c.width - leftSpace - b.width - (pad.right||0) //right
18461 this.setYConstraint(topSpace - (pad.top||0), //top
18462 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18467 * Returns a reference to the linked element
18469 * @return {HTMLElement} the html element
18471 getEl: function() {
18472 if (!this._domRef) {
18473 this._domRef = Roo.getDom(this.id);
18476 return this._domRef;
18480 * Returns a reference to the actual element to drag. By default this is
18481 * the same as the html element, but it can be assigned to another
18482 * element. An example of this can be found in Roo.dd.DDProxy
18483 * @method getDragEl
18484 * @return {HTMLElement} the html element
18486 getDragEl: function() {
18487 return Roo.getDom(this.dragElId);
18491 * Sets up the DragDrop object. Must be called in the constructor of any
18492 * Roo.dd.DragDrop subclass
18494 * @param id the id of the linked element
18495 * @param {String} sGroup the group of related items
18496 * @param {object} config configuration attributes
18498 init: function(id, sGroup, config) {
18499 this.initTarget(id, sGroup, config);
18500 if (!Roo.isTouch) {
18501 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18503 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18504 // Event.on(this.id, "selectstart", Event.preventDefault);
18508 * Initializes Targeting functionality only... the object does not
18509 * get a mousedown handler.
18510 * @method initTarget
18511 * @param id the id of the linked element
18512 * @param {String} sGroup the group of related items
18513 * @param {object} config configuration attributes
18515 initTarget: function(id, sGroup, config) {
18517 // configuration attributes
18518 this.config = config || {};
18520 // create a local reference to the drag and drop manager
18521 this.DDM = Roo.dd.DDM;
18522 // initialize the groups array
18525 // assume that we have an element reference instead of an id if the
18526 // parameter is not a string
18527 if (typeof id !== "string") {
18534 // add to an interaction group
18535 this.addToGroup((sGroup) ? sGroup : "default");
18537 // We don't want to register this as the handle with the manager
18538 // so we just set the id rather than calling the setter.
18539 this.handleElId = id;
18541 // the linked element is the element that gets dragged by default
18542 this.setDragElId(id);
18544 // by default, clicked anchors will not start drag operations.
18545 this.invalidHandleTypes = { A: "A" };
18546 this.invalidHandleIds = {};
18547 this.invalidHandleClasses = [];
18549 this.applyConfig();
18551 this.handleOnAvailable();
18555 * Applies the configuration parameters that were passed into the constructor.
18556 * This is supposed to happen at each level through the inheritance chain. So
18557 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18558 * DragDrop in order to get all of the parameters that are available in
18560 * @method applyConfig
18562 applyConfig: function() {
18564 // configurable properties:
18565 // padding, isTarget, maintainOffset, primaryButtonOnly
18566 this.padding = this.config.padding || [0, 0, 0, 0];
18567 this.isTarget = (this.config.isTarget !== false);
18568 this.maintainOffset = (this.config.maintainOffset);
18569 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18574 * Executed when the linked element is available
18575 * @method handleOnAvailable
18578 handleOnAvailable: function() {
18579 this.available = true;
18580 this.resetConstraints();
18581 this.onAvailable();
18585 * Configures the padding for the target zone in px. Effectively expands
18586 * (or reduces) the virtual object size for targeting calculations.
18587 * Supports css-style shorthand; if only one parameter is passed, all sides
18588 * will have that padding, and if only two are passed, the top and bottom
18589 * will have the first param, the left and right the second.
18590 * @method setPadding
18591 * @param {int} iTop Top pad
18592 * @param {int} iRight Right pad
18593 * @param {int} iBot Bot pad
18594 * @param {int} iLeft Left pad
18596 setPadding: function(iTop, iRight, iBot, iLeft) {
18597 // this.padding = [iLeft, iRight, iTop, iBot];
18598 if (!iRight && 0 !== iRight) {
18599 this.padding = [iTop, iTop, iTop, iTop];
18600 } else if (!iBot && 0 !== iBot) {
18601 this.padding = [iTop, iRight, iTop, iRight];
18603 this.padding = [iTop, iRight, iBot, iLeft];
18608 * Stores the initial placement of the linked element.
18609 * @method setInitialPosition
18610 * @param {int} diffX the X offset, default 0
18611 * @param {int} diffY the Y offset, default 0
18613 setInitPosition: function(diffX, diffY) {
18614 var el = this.getEl();
18616 if (!this.DDM.verifyEl(el)) {
18620 var dx = diffX || 0;
18621 var dy = diffY || 0;
18623 var p = Dom.getXY( el );
18625 this.initPageX = p[0] - dx;
18626 this.initPageY = p[1] - dy;
18628 this.lastPageX = p[0];
18629 this.lastPageY = p[1];
18632 this.setStartPosition(p);
18636 * Sets the start position of the element. This is set when the obj
18637 * is initialized, the reset when a drag is started.
18638 * @method setStartPosition
18639 * @param pos current position (from previous lookup)
18642 setStartPosition: function(pos) {
18643 var p = pos || Dom.getXY( this.getEl() );
18644 this.deltaSetXY = null;
18646 this.startPageX = p[0];
18647 this.startPageY = p[1];
18651 * Add this instance to a group of related drag/drop objects. All
18652 * instances belong to at least one group, and can belong to as many
18653 * groups as needed.
18654 * @method addToGroup
18655 * @param sGroup {string} the name of the group
18657 addToGroup: function(sGroup) {
18658 this.groups[sGroup] = true;
18659 this.DDM.regDragDrop(this, sGroup);
18663 * Remove's this instance from the supplied interaction group
18664 * @method removeFromGroup
18665 * @param {string} sGroup The group to drop
18667 removeFromGroup: function(sGroup) {
18668 if (this.groups[sGroup]) {
18669 delete this.groups[sGroup];
18672 this.DDM.removeDDFromGroup(this, sGroup);
18676 * Allows you to specify that an element other than the linked element
18677 * will be moved with the cursor during a drag
18678 * @method setDragElId
18679 * @param id {string} the id of the element that will be used to initiate the drag
18681 setDragElId: function(id) {
18682 this.dragElId = id;
18686 * Allows you to specify a child of the linked element that should be
18687 * used to initiate the drag operation. An example of this would be if
18688 * you have a content div with text and links. Clicking anywhere in the
18689 * content area would normally start the drag operation. Use this method
18690 * to specify that an element inside of the content div is the element
18691 * that starts the drag operation.
18692 * @method setHandleElId
18693 * @param id {string} the id of the element that will be used to
18694 * initiate the drag.
18696 setHandleElId: function(id) {
18697 if (typeof id !== "string") {
18700 this.handleElId = id;
18701 this.DDM.regHandle(this.id, id);
18705 * Allows you to set an element outside of the linked element as a drag
18707 * @method setOuterHandleElId
18708 * @param id the id of the element that will be used to initiate the drag
18710 setOuterHandleElId: function(id) {
18711 if (typeof id !== "string") {
18714 Event.on(id, "mousedown",
18715 this.handleMouseDown, this);
18716 this.setHandleElId(id);
18718 this.hasOuterHandles = true;
18722 * Remove all drag and drop hooks for this element
18725 unreg: function() {
18726 Event.un(this.id, "mousedown",
18727 this.handleMouseDown);
18728 Event.un(this.id, "touchstart",
18729 this.handleMouseDown);
18730 this._domRef = null;
18731 this.DDM._remove(this);
18734 destroy : function(){
18739 * Returns true if this instance is locked, or the drag drop mgr is locked
18740 * (meaning that all drag/drop is disabled on the page.)
18742 * @return {boolean} true if this obj or all drag/drop is locked, else
18745 isLocked: function() {
18746 return (this.DDM.isLocked() || this.locked);
18750 * Fired when this object is clicked
18751 * @method handleMouseDown
18753 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18756 handleMouseDown: function(e, oDD){
18758 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18759 //Roo.log('not touch/ button !=0');
18762 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18763 return; // double touch..
18767 if (this.isLocked()) {
18768 //Roo.log('locked');
18772 this.DDM.refreshCache(this.groups);
18773 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18774 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18775 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18776 //Roo.log('no outer handes or not over target');
18779 // Roo.log('check validator');
18780 if (this.clickValidator(e)) {
18781 // Roo.log('validate success');
18782 // set the initial element position
18783 this.setStartPosition();
18786 this.b4MouseDown(e);
18787 this.onMouseDown(e);
18789 this.DDM.handleMouseDown(e, this);
18791 this.DDM.stopEvent(e);
18799 clickValidator: function(e) {
18800 var target = e.getTarget();
18801 return ( this.isValidHandleChild(target) &&
18802 (this.id == this.handleElId ||
18803 this.DDM.handleWasClicked(target, this.id)) );
18807 * Allows you to specify a tag name that should not start a drag operation
18808 * when clicked. This is designed to facilitate embedding links within a
18809 * drag handle that do something other than start the drag.
18810 * @method addInvalidHandleType
18811 * @param {string} tagName the type of element to exclude
18813 addInvalidHandleType: function(tagName) {
18814 var type = tagName.toUpperCase();
18815 this.invalidHandleTypes[type] = type;
18819 * Lets you to specify an element id for a child of a drag handle
18820 * that should not initiate a drag
18821 * @method addInvalidHandleId
18822 * @param {string} id the element id of the element you wish to ignore
18824 addInvalidHandleId: function(id) {
18825 if (typeof id !== "string") {
18828 this.invalidHandleIds[id] = id;
18832 * Lets you specify a css class of elements that will not initiate a drag
18833 * @method addInvalidHandleClass
18834 * @param {string} cssClass the class of the elements you wish to ignore
18836 addInvalidHandleClass: function(cssClass) {
18837 this.invalidHandleClasses.push(cssClass);
18841 * Unsets an excluded tag name set by addInvalidHandleType
18842 * @method removeInvalidHandleType
18843 * @param {string} tagName the type of element to unexclude
18845 removeInvalidHandleType: function(tagName) {
18846 var type = tagName.toUpperCase();
18847 // this.invalidHandleTypes[type] = null;
18848 delete this.invalidHandleTypes[type];
18852 * Unsets an invalid handle id
18853 * @method removeInvalidHandleId
18854 * @param {string} id the id of the element to re-enable
18856 removeInvalidHandleId: function(id) {
18857 if (typeof id !== "string") {
18860 delete this.invalidHandleIds[id];
18864 * Unsets an invalid css class
18865 * @method removeInvalidHandleClass
18866 * @param {string} cssClass the class of the element(s) you wish to
18869 removeInvalidHandleClass: function(cssClass) {
18870 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18871 if (this.invalidHandleClasses[i] == cssClass) {
18872 delete this.invalidHandleClasses[i];
18878 * Checks the tag exclusion list to see if this click should be ignored
18879 * @method isValidHandleChild
18880 * @param {HTMLElement} node the HTMLElement to evaluate
18881 * @return {boolean} true if this is a valid tag type, false if not
18883 isValidHandleChild: function(node) {
18886 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18889 nodeName = node.nodeName.toUpperCase();
18891 nodeName = node.nodeName;
18893 valid = valid && !this.invalidHandleTypes[nodeName];
18894 valid = valid && !this.invalidHandleIds[node.id];
18896 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18897 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18906 * Create the array of horizontal tick marks if an interval was specified
18907 * in setXConstraint().
18908 * @method setXTicks
18911 setXTicks: function(iStartX, iTickSize) {
18913 this.xTickSize = iTickSize;
18917 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18919 this.xTicks[this.xTicks.length] = i;
18924 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18926 this.xTicks[this.xTicks.length] = i;
18931 this.xTicks.sort(this.DDM.numericSort) ;
18935 * Create the array of vertical tick marks if an interval was specified in
18936 * setYConstraint().
18937 * @method setYTicks
18940 setYTicks: function(iStartY, iTickSize) {
18942 this.yTickSize = iTickSize;
18946 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18948 this.yTicks[this.yTicks.length] = i;
18953 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18955 this.yTicks[this.yTicks.length] = i;
18960 this.yTicks.sort(this.DDM.numericSort) ;
18964 * By default, the element can be dragged any place on the screen. Use
18965 * this method to limit the horizontal travel of the element. Pass in
18966 * 0,0 for the parameters if you want to lock the drag to the y axis.
18967 * @method setXConstraint
18968 * @param {int} iLeft the number of pixels the element can move to the left
18969 * @param {int} iRight the number of pixels the element can move to the
18971 * @param {int} iTickSize optional parameter for specifying that the
18973 * should move iTickSize pixels at a time.
18975 setXConstraint: function(iLeft, iRight, iTickSize) {
18976 this.leftConstraint = iLeft;
18977 this.rightConstraint = iRight;
18979 this.minX = this.initPageX - iLeft;
18980 this.maxX = this.initPageX + iRight;
18981 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18983 this.constrainX = true;
18987 * Clears any constraints applied to this instance. Also clears ticks
18988 * since they can't exist independent of a constraint at this time.
18989 * @method clearConstraints
18991 clearConstraints: function() {
18992 this.constrainX = false;
18993 this.constrainY = false;
18998 * Clears any tick interval defined for this instance
18999 * @method clearTicks
19001 clearTicks: function() {
19002 this.xTicks = null;
19003 this.yTicks = null;
19004 this.xTickSize = 0;
19005 this.yTickSize = 0;
19009 * By default, the element can be dragged any place on the screen. Set
19010 * this to limit the vertical travel of the element. Pass in 0,0 for the
19011 * parameters if you want to lock the drag to the x axis.
19012 * @method setYConstraint
19013 * @param {int} iUp the number of pixels the element can move up
19014 * @param {int} iDown the number of pixels the element can move down
19015 * @param {int} iTickSize optional parameter for specifying that the
19016 * element should move iTickSize pixels at a time.
19018 setYConstraint: function(iUp, iDown, iTickSize) {
19019 this.topConstraint = iUp;
19020 this.bottomConstraint = iDown;
19022 this.minY = this.initPageY - iUp;
19023 this.maxY = this.initPageY + iDown;
19024 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19026 this.constrainY = true;
19031 * resetConstraints must be called if you manually reposition a dd element.
19032 * @method resetConstraints
19033 * @param {boolean} maintainOffset
19035 resetConstraints: function() {
19038 // Maintain offsets if necessary
19039 if (this.initPageX || this.initPageX === 0) {
19040 // figure out how much this thing has moved
19041 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19042 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19044 this.setInitPosition(dx, dy);
19046 // This is the first time we have detected the element's position
19048 this.setInitPosition();
19051 if (this.constrainX) {
19052 this.setXConstraint( this.leftConstraint,
19053 this.rightConstraint,
19057 if (this.constrainY) {
19058 this.setYConstraint( this.topConstraint,
19059 this.bottomConstraint,
19065 * Normally the drag element is moved pixel by pixel, but we can specify
19066 * that it move a number of pixels at a time. This method resolves the
19067 * location when we have it set up like this.
19069 * @param {int} val where we want to place the object
19070 * @param {int[]} tickArray sorted array of valid points
19071 * @return {int} the closest tick
19074 getTick: function(val, tickArray) {
19077 // If tick interval is not defined, it is effectively 1 pixel,
19078 // so we return the value passed to us.
19080 } else if (tickArray[0] >= val) {
19081 // The value is lower than the first tick, so we return the first
19083 return tickArray[0];
19085 for (var i=0, len=tickArray.length; i<len; ++i) {
19087 if (tickArray[next] && tickArray[next] >= val) {
19088 var diff1 = val - tickArray[i];
19089 var diff2 = tickArray[next] - val;
19090 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19094 // The value is larger than the last tick, so we return the last
19096 return tickArray[tickArray.length - 1];
19103 * @return {string} string representation of the dd obj
19105 toString: function() {
19106 return ("DragDrop " + this.id);
19114 * Ext JS Library 1.1.1
19115 * Copyright(c) 2006-2007, Ext JS, LLC.
19117 * Originally Released Under LGPL - original licence link has changed is not relivant.
19120 * <script type="text/javascript">
19125 * The drag and drop utility provides a framework for building drag and drop
19126 * applications. In addition to enabling drag and drop for specific elements,
19127 * the drag and drop elements are tracked by the manager class, and the
19128 * interactions between the various elements are tracked during the drag and
19129 * the implementing code is notified about these important moments.
19132 // Only load the library once. Rewriting the manager class would orphan
19133 // existing drag and drop instances.
19134 if (!Roo.dd.DragDropMgr) {
19137 * @class Roo.dd.DragDropMgr
19138 * DragDropMgr is a singleton that tracks the element interaction for
19139 * all DragDrop items in the window. Generally, you will not call
19140 * this class directly, but it does have helper methods that could
19141 * be useful in your DragDrop implementations.
19144 Roo.dd.DragDropMgr = function() {
19146 var Event = Roo.EventManager;
19151 * Two dimensional Array of registered DragDrop objects. The first
19152 * dimension is the DragDrop item group, the second the DragDrop
19155 * @type {string: string}
19162 * Array of element ids defined as drag handles. Used to determine
19163 * if the element that generated the mousedown event is actually the
19164 * handle and not the html element itself.
19165 * @property handleIds
19166 * @type {string: string}
19173 * the DragDrop object that is currently being dragged
19174 * @property dragCurrent
19182 * the DragDrop object(s) that are being hovered over
19183 * @property dragOvers
19191 * the X distance between the cursor and the object being dragged
19200 * the Y distance between the cursor and the object being dragged
19209 * Flag to determine if we should prevent the default behavior of the
19210 * events we define. By default this is true, but this can be set to
19211 * false if you need the default behavior (not recommended)
19212 * @property preventDefault
19216 preventDefault: true,
19219 * Flag to determine if we should stop the propagation of the events
19220 * we generate. This is true by default but you may want to set it to
19221 * false if the html element contains other features that require the
19223 * @property stopPropagation
19227 stopPropagation: true,
19230 * Internal flag that is set to true when drag and drop has been
19232 * @property initialized
19239 * All drag and drop can be disabled.
19247 * Called the first time an element is registered.
19253 this.initialized = true;
19257 * In point mode, drag and drop interaction is defined by the
19258 * location of the cursor during the drag/drop
19266 * In intersect mode, drag and drop interactio nis defined by the
19267 * overlap of two or more drag and drop objects.
19268 * @property INTERSECT
19275 * The current drag and drop mode. Default: POINT
19283 * Runs method on all drag and drop objects
19284 * @method _execOnAll
19288 _execOnAll: function(sMethod, args) {
19289 for (var i in this.ids) {
19290 for (var j in this.ids[i]) {
19291 var oDD = this.ids[i][j];
19292 if (! this.isTypeOfDD(oDD)) {
19295 oDD[sMethod].apply(oDD, args);
19301 * Drag and drop initialization. Sets up the global event handlers
19306 _onLoad: function() {
19310 if (!Roo.isTouch) {
19311 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19312 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19314 Event.on(document, "touchend", this.handleMouseUp, this, true);
19315 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19317 Event.on(window, "unload", this._onUnload, this, true);
19318 Event.on(window, "resize", this._onResize, this, true);
19319 // Event.on(window, "mouseout", this._test);
19324 * Reset constraints on all drag and drop objs
19325 * @method _onResize
19329 _onResize: function(e) {
19330 this._execOnAll("resetConstraints", []);
19334 * Lock all drag and drop functionality
19338 lock: function() { this.locked = true; },
19341 * Unlock all drag and drop functionality
19345 unlock: function() { this.locked = false; },
19348 * Is drag and drop locked?
19350 * @return {boolean} True if drag and drop is locked, false otherwise.
19353 isLocked: function() { return this.locked; },
19356 * Location cache that is set for all drag drop objects when a drag is
19357 * initiated, cleared when the drag is finished.
19358 * @property locationCache
19365 * Set useCache to false if you want to force object the lookup of each
19366 * drag and drop linked element constantly during a drag.
19367 * @property useCache
19374 * The number of pixels that the mouse needs to move after the
19375 * mousedown before the drag is initiated. Default=3;
19376 * @property clickPixelThresh
19380 clickPixelThresh: 3,
19383 * The number of milliseconds after the mousedown event to initiate the
19384 * drag if we don't get a mouseup event. Default=1000
19385 * @property clickTimeThresh
19389 clickTimeThresh: 350,
19392 * Flag that indicates that either the drag pixel threshold or the
19393 * mousdown time threshold has been met
19394 * @property dragThreshMet
19399 dragThreshMet: false,
19402 * Timeout used for the click time threshold
19403 * @property clickTimeout
19408 clickTimeout: null,
19411 * The X position of the mousedown event stored for later use when a
19412 * drag threshold is met.
19421 * The Y position of the mousedown event stored for later use when a
19422 * drag threshold is met.
19431 * Each DragDrop instance must be registered with the DragDropMgr.
19432 * This is executed in DragDrop.init()
19433 * @method regDragDrop
19434 * @param {DragDrop} oDD the DragDrop object to register
19435 * @param {String} sGroup the name of the group this element belongs to
19438 regDragDrop: function(oDD, sGroup) {
19439 if (!this.initialized) { this.init(); }
19441 if (!this.ids[sGroup]) {
19442 this.ids[sGroup] = {};
19444 this.ids[sGroup][oDD.id] = oDD;
19448 * Removes the supplied dd instance from the supplied group. Executed
19449 * by DragDrop.removeFromGroup, so don't call this function directly.
19450 * @method removeDDFromGroup
19454 removeDDFromGroup: function(oDD, sGroup) {
19455 if (!this.ids[sGroup]) {
19456 this.ids[sGroup] = {};
19459 var obj = this.ids[sGroup];
19460 if (obj && obj[oDD.id]) {
19461 delete obj[oDD.id];
19466 * Unregisters a drag and drop item. This is executed in
19467 * DragDrop.unreg, use that method instead of calling this directly.
19472 _remove: function(oDD) {
19473 for (var g in oDD.groups) {
19474 if (g && this.ids[g][oDD.id]) {
19475 delete this.ids[g][oDD.id];
19478 delete this.handleIds[oDD.id];
19482 * Each DragDrop handle element must be registered. This is done
19483 * automatically when executing DragDrop.setHandleElId()
19484 * @method regHandle
19485 * @param {String} sDDId the DragDrop id this element is a handle for
19486 * @param {String} sHandleId the id of the element that is the drag
19490 regHandle: function(sDDId, sHandleId) {
19491 if (!this.handleIds[sDDId]) {
19492 this.handleIds[sDDId] = {};
19494 this.handleIds[sDDId][sHandleId] = sHandleId;
19498 * Utility function to determine if a given element has been
19499 * registered as a drag drop item.
19500 * @method isDragDrop
19501 * @param {String} id the element id to check
19502 * @return {boolean} true if this element is a DragDrop item,
19506 isDragDrop: function(id) {
19507 return ( this.getDDById(id) ) ? true : false;
19511 * Returns the drag and drop instances that are in all groups the
19512 * passed in instance belongs to.
19513 * @method getRelated
19514 * @param {DragDrop} p_oDD the obj to get related data for
19515 * @param {boolean} bTargetsOnly if true, only return targetable objs
19516 * @return {DragDrop[]} the related instances
19519 getRelated: function(p_oDD, bTargetsOnly) {
19521 for (var i in p_oDD.groups) {
19522 for (j in this.ids[i]) {
19523 var dd = this.ids[i][j];
19524 if (! this.isTypeOfDD(dd)) {
19527 if (!bTargetsOnly || dd.isTarget) {
19528 oDDs[oDDs.length] = dd;
19537 * Returns true if the specified dd target is a legal target for
19538 * the specifice drag obj
19539 * @method isLegalTarget
19540 * @param {DragDrop} the drag obj
19541 * @param {DragDrop} the target
19542 * @return {boolean} true if the target is a legal target for the
19546 isLegalTarget: function (oDD, oTargetDD) {
19547 var targets = this.getRelated(oDD, true);
19548 for (var i=0, len=targets.length;i<len;++i) {
19549 if (targets[i].id == oTargetDD.id) {
19558 * My goal is to be able to transparently determine if an object is
19559 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19560 * returns "object", oDD.constructor.toString() always returns
19561 * "DragDrop" and not the name of the subclass. So for now it just
19562 * evaluates a well-known variable in DragDrop.
19563 * @method isTypeOfDD
19564 * @param {Object} the object to evaluate
19565 * @return {boolean} true if typeof oDD = DragDrop
19568 isTypeOfDD: function (oDD) {
19569 return (oDD && oDD.__ygDragDrop);
19573 * Utility function to determine if a given element has been
19574 * registered as a drag drop handle for the given Drag Drop object.
19576 * @param {String} id the element id to check
19577 * @return {boolean} true if this element is a DragDrop handle, false
19581 isHandle: function(sDDId, sHandleId) {
19582 return ( this.handleIds[sDDId] &&
19583 this.handleIds[sDDId][sHandleId] );
19587 * Returns the DragDrop instance for a given id
19588 * @method getDDById
19589 * @param {String} id the id of the DragDrop object
19590 * @return {DragDrop} the drag drop object, null if it is not found
19593 getDDById: function(id) {
19594 for (var i in this.ids) {
19595 if (this.ids[i][id]) {
19596 return this.ids[i][id];
19603 * Fired after a registered DragDrop object gets the mousedown event.
19604 * Sets up the events required to track the object being dragged
19605 * @method handleMouseDown
19606 * @param {Event} e the event
19607 * @param oDD the DragDrop object being dragged
19611 handleMouseDown: function(e, oDD) {
19613 Roo.QuickTips.disable();
19615 this.currentTarget = e.getTarget();
19617 this.dragCurrent = oDD;
19619 var el = oDD.getEl();
19621 // track start position
19622 this.startX = e.getPageX();
19623 this.startY = e.getPageY();
19625 this.deltaX = this.startX - el.offsetLeft;
19626 this.deltaY = this.startY - el.offsetTop;
19628 this.dragThreshMet = false;
19630 this.clickTimeout = setTimeout(
19632 var DDM = Roo.dd.DDM;
19633 DDM.startDrag(DDM.startX, DDM.startY);
19635 this.clickTimeThresh );
19639 * Fired when either the drag pixel threshol or the mousedown hold
19640 * time threshold has been met.
19641 * @method startDrag
19642 * @param x {int} the X position of the original mousedown
19643 * @param y {int} the Y position of the original mousedown
19646 startDrag: function(x, y) {
19647 clearTimeout(this.clickTimeout);
19648 if (this.dragCurrent) {
19649 this.dragCurrent.b4StartDrag(x, y);
19650 this.dragCurrent.startDrag(x, y);
19652 this.dragThreshMet = true;
19656 * Internal function to handle the mouseup event. Will be invoked
19657 * from the context of the document.
19658 * @method handleMouseUp
19659 * @param {Event} e the event
19663 handleMouseUp: function(e) {
19666 Roo.QuickTips.enable();
19668 if (! this.dragCurrent) {
19672 clearTimeout(this.clickTimeout);
19674 if (this.dragThreshMet) {
19675 this.fireEvents(e, true);
19685 * Utility to stop event propagation and event default, if these
19686 * features are turned on.
19687 * @method stopEvent
19688 * @param {Event} e the event as returned by this.getEvent()
19691 stopEvent: function(e){
19692 if(this.stopPropagation) {
19693 e.stopPropagation();
19696 if (this.preventDefault) {
19697 e.preventDefault();
19702 * Internal function to clean up event handlers after the drag
19703 * operation is complete
19705 * @param {Event} e the event
19709 stopDrag: function(e) {
19710 // Fire the drag end event for the item that was dragged
19711 if (this.dragCurrent) {
19712 if (this.dragThreshMet) {
19713 this.dragCurrent.b4EndDrag(e);
19714 this.dragCurrent.endDrag(e);
19717 this.dragCurrent.onMouseUp(e);
19720 this.dragCurrent = null;
19721 this.dragOvers = {};
19725 * Internal function to handle the mousemove event. Will be invoked
19726 * from the context of the html element.
19728 * @TODO figure out what we can do about mouse events lost when the
19729 * user drags objects beyond the window boundary. Currently we can
19730 * detect this in internet explorer by verifying that the mouse is
19731 * down during the mousemove event. Firefox doesn't give us the
19732 * button state on the mousemove event.
19733 * @method handleMouseMove
19734 * @param {Event} e the event
19738 handleMouseMove: function(e) {
19739 if (! this.dragCurrent) {
19743 // var button = e.which || e.button;
19745 // check for IE mouseup outside of page boundary
19746 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19748 return this.handleMouseUp(e);
19751 if (!this.dragThreshMet) {
19752 var diffX = Math.abs(this.startX - e.getPageX());
19753 var diffY = Math.abs(this.startY - e.getPageY());
19754 if (diffX > this.clickPixelThresh ||
19755 diffY > this.clickPixelThresh) {
19756 this.startDrag(this.startX, this.startY);
19760 if (this.dragThreshMet) {
19761 this.dragCurrent.b4Drag(e);
19762 this.dragCurrent.onDrag(e);
19763 if(!this.dragCurrent.moveOnly){
19764 this.fireEvents(e, false);
19774 * Iterates over all of the DragDrop elements to find ones we are
19775 * hovering over or dropping on
19776 * @method fireEvents
19777 * @param {Event} e the event
19778 * @param {boolean} isDrop is this a drop op or a mouseover op?
19782 fireEvents: function(e, isDrop) {
19783 var dc = this.dragCurrent;
19785 // If the user did the mouse up outside of the window, we could
19786 // get here even though we have ended the drag.
19787 if (!dc || dc.isLocked()) {
19791 var pt = e.getPoint();
19793 // cache the previous dragOver array
19799 var enterEvts = [];
19801 // Check to see if the object(s) we were hovering over is no longer
19802 // being hovered over so we can fire the onDragOut event
19803 for (var i in this.dragOvers) {
19805 var ddo = this.dragOvers[i];
19807 if (! this.isTypeOfDD(ddo)) {
19811 if (! this.isOverTarget(pt, ddo, this.mode)) {
19812 outEvts.push( ddo );
19815 oldOvers[i] = true;
19816 delete this.dragOvers[i];
19819 for (var sGroup in dc.groups) {
19821 if ("string" != typeof sGroup) {
19825 for (i in this.ids[sGroup]) {
19826 var oDD = this.ids[sGroup][i];
19827 if (! this.isTypeOfDD(oDD)) {
19831 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19832 if (this.isOverTarget(pt, oDD, this.mode)) {
19833 // look for drop interactions
19835 dropEvts.push( oDD );
19836 // look for drag enter and drag over interactions
19839 // initial drag over: dragEnter fires
19840 if (!oldOvers[oDD.id]) {
19841 enterEvts.push( oDD );
19842 // subsequent drag overs: dragOver fires
19844 overEvts.push( oDD );
19847 this.dragOvers[oDD.id] = oDD;
19855 if (outEvts.length) {
19856 dc.b4DragOut(e, outEvts);
19857 dc.onDragOut(e, outEvts);
19860 if (enterEvts.length) {
19861 dc.onDragEnter(e, enterEvts);
19864 if (overEvts.length) {
19865 dc.b4DragOver(e, overEvts);
19866 dc.onDragOver(e, overEvts);
19869 if (dropEvts.length) {
19870 dc.b4DragDrop(e, dropEvts);
19871 dc.onDragDrop(e, dropEvts);
19875 // fire dragout events
19877 for (i=0, len=outEvts.length; i<len; ++i) {
19878 dc.b4DragOut(e, outEvts[i].id);
19879 dc.onDragOut(e, outEvts[i].id);
19882 // fire enter events
19883 for (i=0,len=enterEvts.length; i<len; ++i) {
19884 // dc.b4DragEnter(e, oDD.id);
19885 dc.onDragEnter(e, enterEvts[i].id);
19888 // fire over events
19889 for (i=0,len=overEvts.length; i<len; ++i) {
19890 dc.b4DragOver(e, overEvts[i].id);
19891 dc.onDragOver(e, overEvts[i].id);
19894 // fire drop events
19895 for (i=0, len=dropEvts.length; i<len; ++i) {
19896 dc.b4DragDrop(e, dropEvts[i].id);
19897 dc.onDragDrop(e, dropEvts[i].id);
19902 // notify about a drop that did not find a target
19903 if (isDrop && !dropEvts.length) {
19904 dc.onInvalidDrop(e);
19910 * Helper function for getting the best match from the list of drag
19911 * and drop objects returned by the drag and drop events when we are
19912 * in INTERSECT mode. It returns either the first object that the
19913 * cursor is over, or the object that has the greatest overlap with
19914 * the dragged element.
19915 * @method getBestMatch
19916 * @param {DragDrop[]} dds The array of drag and drop objects
19918 * @return {DragDrop} The best single match
19921 getBestMatch: function(dds) {
19923 // Return null if the input is not what we expect
19924 //if (!dds || !dds.length || dds.length == 0) {
19926 // If there is only one item, it wins
19927 //} else if (dds.length == 1) {
19929 var len = dds.length;
19934 // Loop through the targeted items
19935 for (var i=0; i<len; ++i) {
19937 // If the cursor is over the object, it wins. If the
19938 // cursor is over multiple matches, the first one we come
19940 if (dd.cursorIsOver) {
19943 // Otherwise the object with the most overlap wins
19946 winner.overlap.getArea() < dd.overlap.getArea()) {
19957 * Refreshes the cache of the top-left and bottom-right points of the
19958 * drag and drop objects in the specified group(s). This is in the
19959 * format that is stored in the drag and drop instance, so typical
19962 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19966 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19968 * @TODO this really should be an indexed array. Alternatively this
19969 * method could accept both.
19970 * @method refreshCache
19971 * @param {Object} groups an associative array of groups to refresh
19974 refreshCache: function(groups) {
19975 for (var sGroup in groups) {
19976 if ("string" != typeof sGroup) {
19979 for (var i in this.ids[sGroup]) {
19980 var oDD = this.ids[sGroup][i];
19982 if (this.isTypeOfDD(oDD)) {
19983 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19984 var loc = this.getLocation(oDD);
19986 this.locationCache[oDD.id] = loc;
19988 delete this.locationCache[oDD.id];
19989 // this will unregister the drag and drop object if
19990 // the element is not in a usable state
19999 * This checks to make sure an element exists and is in the DOM. The
20000 * main purpose is to handle cases where innerHTML is used to remove
20001 * drag and drop objects from the DOM. IE provides an 'unspecified
20002 * error' when trying to access the offsetParent of such an element
20004 * @param {HTMLElement} el the element to check
20005 * @return {boolean} true if the element looks usable
20008 verifyEl: function(el) {
20013 parent = el.offsetParent;
20016 parent = el.offsetParent;
20027 * Returns a Region object containing the drag and drop element's position
20028 * and size, including the padding configured for it
20029 * @method getLocation
20030 * @param {DragDrop} oDD the drag and drop object to get the
20032 * @return {Roo.lib.Region} a Region object representing the total area
20033 * the element occupies, including any padding
20034 * the instance is configured for.
20037 getLocation: function(oDD) {
20038 if (! this.isTypeOfDD(oDD)) {
20042 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20045 pos= Roo.lib.Dom.getXY(el);
20053 x2 = x1 + el.offsetWidth;
20055 y2 = y1 + el.offsetHeight;
20057 t = y1 - oDD.padding[0];
20058 r = x2 + oDD.padding[1];
20059 b = y2 + oDD.padding[2];
20060 l = x1 - oDD.padding[3];
20062 return new Roo.lib.Region( t, r, b, l );
20066 * Checks the cursor location to see if it over the target
20067 * @method isOverTarget
20068 * @param {Roo.lib.Point} pt The point to evaluate
20069 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20070 * @return {boolean} true if the mouse is over the target
20074 isOverTarget: function(pt, oTarget, intersect) {
20075 // use cache if available
20076 var loc = this.locationCache[oTarget.id];
20077 if (!loc || !this.useCache) {
20078 loc = this.getLocation(oTarget);
20079 this.locationCache[oTarget.id] = loc;
20087 oTarget.cursorIsOver = loc.contains( pt );
20089 // DragDrop is using this as a sanity check for the initial mousedown
20090 // in this case we are done. In POINT mode, if the drag obj has no
20091 // contraints, we are also done. Otherwise we need to evaluate the
20092 // location of the target as related to the actual location of the
20093 // dragged element.
20094 var dc = this.dragCurrent;
20095 if (!dc || !dc.getTargetCoord ||
20096 (!intersect && !dc.constrainX && !dc.constrainY)) {
20097 return oTarget.cursorIsOver;
20100 oTarget.overlap = null;
20102 // Get the current location of the drag element, this is the
20103 // location of the mouse event less the delta that represents
20104 // where the original mousedown happened on the element. We
20105 // need to consider constraints and ticks as well.
20106 var pos = dc.getTargetCoord(pt.x, pt.y);
20108 var el = dc.getDragEl();
20109 var curRegion = new Roo.lib.Region( pos.y,
20110 pos.x + el.offsetWidth,
20111 pos.y + el.offsetHeight,
20114 var overlap = curRegion.intersect(loc);
20117 oTarget.overlap = overlap;
20118 return (intersect) ? true : oTarget.cursorIsOver;
20125 * unload event handler
20126 * @method _onUnload
20130 _onUnload: function(e, me) {
20131 Roo.dd.DragDropMgr.unregAll();
20135 * Cleans up the drag and drop events and objects.
20140 unregAll: function() {
20142 if (this.dragCurrent) {
20144 this.dragCurrent = null;
20147 this._execOnAll("unreg", []);
20149 for (i in this.elementCache) {
20150 delete this.elementCache[i];
20153 this.elementCache = {};
20158 * A cache of DOM elements
20159 * @property elementCache
20166 * Get the wrapper for the DOM element specified
20167 * @method getElWrapper
20168 * @param {String} id the id of the element to get
20169 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20171 * @deprecated This wrapper isn't that useful
20174 getElWrapper: function(id) {
20175 var oWrapper = this.elementCache[id];
20176 if (!oWrapper || !oWrapper.el) {
20177 oWrapper = this.elementCache[id] =
20178 new this.ElementWrapper(Roo.getDom(id));
20184 * Returns the actual DOM element
20185 * @method getElement
20186 * @param {String} id the id of the elment to get
20187 * @return {Object} The element
20188 * @deprecated use Roo.getDom instead
20191 getElement: function(id) {
20192 return Roo.getDom(id);
20196 * Returns the style property for the DOM element (i.e.,
20197 * document.getElById(id).style)
20199 * @param {String} id the id of the elment to get
20200 * @return {Object} The style property of the element
20201 * @deprecated use Roo.getDom instead
20204 getCss: function(id) {
20205 var el = Roo.getDom(id);
20206 return (el) ? el.style : null;
20210 * Inner class for cached elements
20211 * @class DragDropMgr.ElementWrapper
20216 ElementWrapper: function(el) {
20221 this.el = el || null;
20226 this.id = this.el && el.id;
20228 * A reference to the style property
20231 this.css = this.el && el.style;
20235 * Returns the X position of an html element
20237 * @param el the element for which to get the position
20238 * @return {int} the X coordinate
20240 * @deprecated use Roo.lib.Dom.getX instead
20243 getPosX: function(el) {
20244 return Roo.lib.Dom.getX(el);
20248 * Returns the Y position of an html element
20250 * @param el the element for which to get the position
20251 * @return {int} the Y coordinate
20252 * @deprecated use Roo.lib.Dom.getY instead
20255 getPosY: function(el) {
20256 return Roo.lib.Dom.getY(el);
20260 * Swap two nodes. In IE, we use the native method, for others we
20261 * emulate the IE behavior
20263 * @param n1 the first node to swap
20264 * @param n2 the other node to swap
20267 swapNode: function(n1, n2) {
20271 var p = n2.parentNode;
20272 var s = n2.nextSibling;
20275 p.insertBefore(n1, n2);
20276 } else if (n2 == n1.nextSibling) {
20277 p.insertBefore(n2, n1);
20279 n1.parentNode.replaceChild(n2, n1);
20280 p.insertBefore(n1, s);
20286 * Returns the current scroll position
20287 * @method getScroll
20291 getScroll: function () {
20292 var t, l, dde=document.documentElement, db=document.body;
20293 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20295 l = dde.scrollLeft;
20302 return { top: t, left: l };
20306 * Returns the specified element style property
20308 * @param {HTMLElement} el the element
20309 * @param {string} styleProp the style property
20310 * @return {string} The value of the style property
20311 * @deprecated use Roo.lib.Dom.getStyle
20314 getStyle: function(el, styleProp) {
20315 return Roo.fly(el).getStyle(styleProp);
20319 * Gets the scrollTop
20320 * @method getScrollTop
20321 * @return {int} the document's scrollTop
20324 getScrollTop: function () { return this.getScroll().top; },
20327 * Gets the scrollLeft
20328 * @method getScrollLeft
20329 * @return {int} the document's scrollTop
20332 getScrollLeft: function () { return this.getScroll().left; },
20335 * Sets the x/y position of an element to the location of the
20338 * @param {HTMLElement} moveEl The element to move
20339 * @param {HTMLElement} targetEl The position reference element
20342 moveToEl: function (moveEl, targetEl) {
20343 var aCoord = Roo.lib.Dom.getXY(targetEl);
20344 Roo.lib.Dom.setXY(moveEl, aCoord);
20348 * Numeric array sort function
20349 * @method numericSort
20352 numericSort: function(a, b) { return (a - b); },
20356 * @property _timeoutCount
20363 * Trying to make the load order less important. Without this we get
20364 * an error if this file is loaded before the Event Utility.
20365 * @method _addListeners
20369 _addListeners: function() {
20370 var DDM = Roo.dd.DDM;
20371 if ( Roo.lib.Event && document ) {
20374 if (DDM._timeoutCount > 2000) {
20376 setTimeout(DDM._addListeners, 10);
20377 if (document && document.body) {
20378 DDM._timeoutCount += 1;
20385 * Recursively searches the immediate parent and all child nodes for
20386 * the handle element in order to determine wheter or not it was
20388 * @method handleWasClicked
20389 * @param node the html element to inspect
20392 handleWasClicked: function(node, id) {
20393 if (this.isHandle(id, node.id)) {
20396 // check to see if this is a text node child of the one we want
20397 var p = node.parentNode;
20400 if (this.isHandle(id, p.id)) {
20415 // shorter alias, save a few bytes
20416 Roo.dd.DDM = Roo.dd.DragDropMgr;
20417 Roo.dd.DDM._addListeners();
20421 * Ext JS Library 1.1.1
20422 * Copyright(c) 2006-2007, Ext JS, LLC.
20424 * Originally Released Under LGPL - original licence link has changed is not relivant.
20427 * <script type="text/javascript">
20432 * A DragDrop implementation where the linked element follows the
20433 * mouse cursor during a drag.
20434 * @extends Roo.dd.DragDrop
20436 * @param {String} id the id of the linked element
20437 * @param {String} sGroup the group of related DragDrop items
20438 * @param {object} config an object containing configurable attributes
20439 * Valid properties for DD:
20442 Roo.dd.DD = function(id, sGroup, config) {
20444 this.init(id, sGroup, config);
20448 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20451 * When set to true, the utility automatically tries to scroll the browser
20452 * window wehn a drag and drop element is dragged near the viewport boundary.
20453 * Defaults to true.
20460 * Sets the pointer offset to the distance between the linked element's top
20461 * left corner and the location the element was clicked
20462 * @method autoOffset
20463 * @param {int} iPageX the X coordinate of the click
20464 * @param {int} iPageY the Y coordinate of the click
20466 autoOffset: function(iPageX, iPageY) {
20467 var x = iPageX - this.startPageX;
20468 var y = iPageY - this.startPageY;
20469 this.setDelta(x, y);
20473 * Sets the pointer offset. You can call this directly to force the
20474 * offset to be in a particular location (e.g., pass in 0,0 to set it
20475 * to the center of the object)
20477 * @param {int} iDeltaX the distance from the left
20478 * @param {int} iDeltaY the distance from the top
20480 setDelta: function(iDeltaX, iDeltaY) {
20481 this.deltaX = iDeltaX;
20482 this.deltaY = iDeltaY;
20486 * Sets the drag element to the location of the mousedown or click event,
20487 * maintaining the cursor location relative to the location on the element
20488 * that was clicked. Override this if you want to place the element in a
20489 * location other than where the cursor is.
20490 * @method setDragElPos
20491 * @param {int} iPageX the X coordinate of the mousedown or drag event
20492 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20494 setDragElPos: function(iPageX, iPageY) {
20495 // the first time we do this, we are going to check to make sure
20496 // the element has css positioning
20498 var el = this.getDragEl();
20499 this.alignElWithMouse(el, iPageX, iPageY);
20503 * Sets the element to the location of the mousedown or click event,
20504 * maintaining the cursor location relative to the location on the element
20505 * that was clicked. Override this if you want to place the element in a
20506 * location other than where the cursor is.
20507 * @method alignElWithMouse
20508 * @param {HTMLElement} el the element to move
20509 * @param {int} iPageX the X coordinate of the mousedown or drag event
20510 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20512 alignElWithMouse: function(el, iPageX, iPageY) {
20513 var oCoord = this.getTargetCoord(iPageX, iPageY);
20514 var fly = el.dom ? el : Roo.fly(el);
20515 if (!this.deltaSetXY) {
20516 var aCoord = [oCoord.x, oCoord.y];
20518 var newLeft = fly.getLeft(true);
20519 var newTop = fly.getTop(true);
20520 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20522 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20525 this.cachePosition(oCoord.x, oCoord.y);
20526 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20531 * Saves the most recent position so that we can reset the constraints and
20532 * tick marks on-demand. We need to know this so that we can calculate the
20533 * number of pixels the element is offset from its original position.
20534 * @method cachePosition
20535 * @param iPageX the current x position (optional, this just makes it so we
20536 * don't have to look it up again)
20537 * @param iPageY the current y position (optional, this just makes it so we
20538 * don't have to look it up again)
20540 cachePosition: function(iPageX, iPageY) {
20542 this.lastPageX = iPageX;
20543 this.lastPageY = iPageY;
20545 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20546 this.lastPageX = aCoord[0];
20547 this.lastPageY = aCoord[1];
20552 * Auto-scroll the window if the dragged object has been moved beyond the
20553 * visible window boundary.
20554 * @method autoScroll
20555 * @param {int} x the drag element's x position
20556 * @param {int} y the drag element's y position
20557 * @param {int} h the height of the drag element
20558 * @param {int} w the width of the drag element
20561 autoScroll: function(x, y, h, w) {
20564 // The client height
20565 var clientH = Roo.lib.Dom.getViewWidth();
20567 // The client width
20568 var clientW = Roo.lib.Dom.getViewHeight();
20570 // The amt scrolled down
20571 var st = this.DDM.getScrollTop();
20573 // The amt scrolled right
20574 var sl = this.DDM.getScrollLeft();
20576 // Location of the bottom of the element
20579 // Location of the right of the element
20582 // The distance from the cursor to the bottom of the visible area,
20583 // adjusted so that we don't scroll if the cursor is beyond the
20584 // element drag constraints
20585 var toBot = (clientH + st - y - this.deltaY);
20587 // The distance from the cursor to the right of the visible area
20588 var toRight = (clientW + sl - x - this.deltaX);
20591 // How close to the edge the cursor must be before we scroll
20592 // var thresh = (document.all) ? 100 : 40;
20595 // How many pixels to scroll per autoscroll op. This helps to reduce
20596 // clunky scrolling. IE is more sensitive about this ... it needs this
20597 // value to be higher.
20598 var scrAmt = (document.all) ? 80 : 30;
20600 // Scroll down if we are near the bottom of the visible page and the
20601 // obj extends below the crease
20602 if ( bot > clientH && toBot < thresh ) {
20603 window.scrollTo(sl, st + scrAmt);
20606 // Scroll up if the window is scrolled down and the top of the object
20607 // goes above the top border
20608 if ( y < st && st > 0 && y - st < thresh ) {
20609 window.scrollTo(sl, st - scrAmt);
20612 // Scroll right if the obj is beyond the right border and the cursor is
20613 // near the border.
20614 if ( right > clientW && toRight < thresh ) {
20615 window.scrollTo(sl + scrAmt, st);
20618 // Scroll left if the window has been scrolled to the right and the obj
20619 // extends past the left border
20620 if ( x < sl && sl > 0 && x - sl < thresh ) {
20621 window.scrollTo(sl - scrAmt, st);
20627 * Finds the location the element should be placed if we want to move
20628 * it to where the mouse location less the click offset would place us.
20629 * @method getTargetCoord
20630 * @param {int} iPageX the X coordinate of the click
20631 * @param {int} iPageY the Y coordinate of the click
20632 * @return an object that contains the coordinates (Object.x and Object.y)
20635 getTargetCoord: function(iPageX, iPageY) {
20638 var x = iPageX - this.deltaX;
20639 var y = iPageY - this.deltaY;
20641 if (this.constrainX) {
20642 if (x < this.minX) { x = this.minX; }
20643 if (x > this.maxX) { x = this.maxX; }
20646 if (this.constrainY) {
20647 if (y < this.minY) { y = this.minY; }
20648 if (y > this.maxY) { y = this.maxY; }
20651 x = this.getTick(x, this.xTicks);
20652 y = this.getTick(y, this.yTicks);
20659 * Sets up config options specific to this class. Overrides
20660 * Roo.dd.DragDrop, but all versions of this method through the
20661 * inheritance chain are called
20663 applyConfig: function() {
20664 Roo.dd.DD.superclass.applyConfig.call(this);
20665 this.scroll = (this.config.scroll !== false);
20669 * Event that fires prior to the onMouseDown event. Overrides
20672 b4MouseDown: function(e) {
20673 // this.resetConstraints();
20674 this.autoOffset(e.getPageX(),
20679 * Event that fires prior to the onDrag event. Overrides
20682 b4Drag: function(e) {
20683 this.setDragElPos(e.getPageX(),
20687 toString: function() {
20688 return ("DD " + this.id);
20691 //////////////////////////////////////////////////////////////////////////
20692 // Debugging ygDragDrop events that can be overridden
20693 //////////////////////////////////////////////////////////////////////////
20695 startDrag: function(x, y) {
20698 onDrag: function(e) {
20701 onDragEnter: function(e, id) {
20704 onDragOver: function(e, id) {
20707 onDragOut: function(e, id) {
20710 onDragDrop: function(e, id) {
20713 endDrag: function(e) {
20720 * Ext JS Library 1.1.1
20721 * Copyright(c) 2006-2007, Ext JS, LLC.
20723 * Originally Released Under LGPL - original licence link has changed is not relivant.
20726 * <script type="text/javascript">
20730 * @class Roo.dd.DDProxy
20731 * A DragDrop implementation that inserts an empty, bordered div into
20732 * the document that follows the cursor during drag operations. At the time of
20733 * the click, the frame div is resized to the dimensions of the linked html
20734 * element, and moved to the exact location of the linked element.
20736 * References to the "frame" element refer to the single proxy element that
20737 * was created to be dragged in place of all DDProxy elements on the
20740 * @extends Roo.dd.DD
20742 * @param {String} id the id of the linked html element
20743 * @param {String} sGroup the group of related DragDrop objects
20744 * @param {object} config an object containing configurable attributes
20745 * Valid properties for DDProxy in addition to those in DragDrop:
20746 * resizeFrame, centerFrame, dragElId
20748 Roo.dd.DDProxy = function(id, sGroup, config) {
20750 this.init(id, sGroup, config);
20756 * The default drag frame div id
20757 * @property Roo.dd.DDProxy.dragElId
20761 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20763 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20766 * By default we resize the drag frame to be the same size as the element
20767 * we want to drag (this is to get the frame effect). We can turn it off
20768 * if we want a different behavior.
20769 * @property resizeFrame
20775 * By default the frame is positioned exactly where the drag element is, so
20776 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20777 * you do not have constraints on the obj is to have the drag frame centered
20778 * around the cursor. Set centerFrame to true for this effect.
20779 * @property centerFrame
20782 centerFrame: false,
20785 * Creates the proxy element if it does not yet exist
20786 * @method createFrame
20788 createFrame: function() {
20790 var body = document.body;
20792 if (!body || !body.firstChild) {
20793 setTimeout( function() { self.createFrame(); }, 50 );
20797 var div = this.getDragEl();
20800 div = document.createElement("div");
20801 div.id = this.dragElId;
20804 s.position = "absolute";
20805 s.visibility = "hidden";
20807 s.border = "2px solid #aaa";
20810 // appendChild can blow up IE if invoked prior to the window load event
20811 // while rendering a table. It is possible there are other scenarios
20812 // that would cause this to happen as well.
20813 body.insertBefore(div, body.firstChild);
20818 * Initialization for the drag frame element. Must be called in the
20819 * constructor of all subclasses
20820 * @method initFrame
20822 initFrame: function() {
20823 this.createFrame();
20826 applyConfig: function() {
20827 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20829 this.resizeFrame = (this.config.resizeFrame !== false);
20830 this.centerFrame = (this.config.centerFrame);
20831 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20835 * Resizes the drag frame to the dimensions of the clicked object, positions
20836 * it over the object, and finally displays it
20837 * @method showFrame
20838 * @param {int} iPageX X click position
20839 * @param {int} iPageY Y click position
20842 showFrame: function(iPageX, iPageY) {
20843 var el = this.getEl();
20844 var dragEl = this.getDragEl();
20845 var s = dragEl.style;
20847 this._resizeProxy();
20849 if (this.centerFrame) {
20850 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20851 Math.round(parseInt(s.height, 10)/2) );
20854 this.setDragElPos(iPageX, iPageY);
20856 Roo.fly(dragEl).show();
20860 * The proxy is automatically resized to the dimensions of the linked
20861 * element when a drag is initiated, unless resizeFrame is set to false
20862 * @method _resizeProxy
20865 _resizeProxy: function() {
20866 if (this.resizeFrame) {
20867 var el = this.getEl();
20868 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20872 // overrides Roo.dd.DragDrop
20873 b4MouseDown: function(e) {
20874 var x = e.getPageX();
20875 var y = e.getPageY();
20876 this.autoOffset(x, y);
20877 this.setDragElPos(x, y);
20880 // overrides Roo.dd.DragDrop
20881 b4StartDrag: function(x, y) {
20882 // show the drag frame
20883 this.showFrame(x, y);
20886 // overrides Roo.dd.DragDrop
20887 b4EndDrag: function(e) {
20888 Roo.fly(this.getDragEl()).hide();
20891 // overrides Roo.dd.DragDrop
20892 // By default we try to move the element to the last location of the frame.
20893 // This is so that the default behavior mirrors that of Roo.dd.DD.
20894 endDrag: function(e) {
20896 var lel = this.getEl();
20897 var del = this.getDragEl();
20899 // Show the drag frame briefly so we can get its position
20900 del.style.visibility = "";
20903 // Hide the linked element before the move to get around a Safari
20905 lel.style.visibility = "hidden";
20906 Roo.dd.DDM.moveToEl(lel, del);
20907 del.style.visibility = "hidden";
20908 lel.style.visibility = "";
20913 beforeMove : function(){
20917 afterDrag : function(){
20921 toString: function() {
20922 return ("DDProxy " + this.id);
20928 * Ext JS Library 1.1.1
20929 * Copyright(c) 2006-2007, Ext JS, LLC.
20931 * Originally Released Under LGPL - original licence link has changed is not relivant.
20934 * <script type="text/javascript">
20938 * @class Roo.dd.DDTarget
20939 * A DragDrop implementation that does not move, but can be a drop
20940 * target. You would get the same result by simply omitting implementation
20941 * for the event callbacks, but this way we reduce the processing cost of the
20942 * event listener and the callbacks.
20943 * @extends Roo.dd.DragDrop
20945 * @param {String} id the id of the element that is a drop target
20946 * @param {String} sGroup the group of related DragDrop objects
20947 * @param {object} config an object containing configurable attributes
20948 * Valid properties for DDTarget in addition to those in
20952 Roo.dd.DDTarget = function(id, sGroup, config) {
20954 this.initTarget(id, sGroup, config);
20956 if (config.listeners || config.events) {
20957 Roo.dd.DragDrop.superclass.constructor.call(this, {
20958 listeners : config.listeners || {},
20959 events : config.events || {}
20964 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20965 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20966 toString: function() {
20967 return ("DDTarget " + this.id);
20972 * Ext JS Library 1.1.1
20973 * Copyright(c) 2006-2007, Ext JS, LLC.
20975 * Originally Released Under LGPL - original licence link has changed is not relivant.
20978 * <script type="text/javascript">
20983 * @class Roo.dd.ScrollManager
20984 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20985 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
20988 Roo.dd.ScrollManager = function(){
20989 var ddm = Roo.dd.DragDropMgr;
20996 var onStop = function(e){
21001 var triggerRefresh = function(){
21002 if(ddm.dragCurrent){
21003 ddm.refreshCache(ddm.dragCurrent.groups);
21007 var doScroll = function(){
21008 if(ddm.dragCurrent){
21009 var dds = Roo.dd.ScrollManager;
21011 if(proc.el.scroll(proc.dir, dds.increment)){
21015 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21020 var clearProc = function(){
21022 clearInterval(proc.id);
21029 var startProc = function(el, dir){
21030 Roo.log('scroll startproc');
21034 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21037 var onFire = function(e, isDrop){
21039 if(isDrop || !ddm.dragCurrent){ return; }
21040 var dds = Roo.dd.ScrollManager;
21041 if(!dragEl || dragEl != ddm.dragCurrent){
21042 dragEl = ddm.dragCurrent;
21043 // refresh regions on drag start
21044 dds.refreshCache();
21047 var xy = Roo.lib.Event.getXY(e);
21048 var pt = new Roo.lib.Point(xy[0], xy[1]);
21049 for(var id in els){
21050 var el = els[id], r = el._region;
21051 if(r && r.contains(pt) && el.isScrollable()){
21052 if(r.bottom - pt.y <= dds.thresh){
21054 startProc(el, "down");
21057 }else if(r.right - pt.x <= dds.thresh){
21059 startProc(el, "left");
21062 }else if(pt.y - r.top <= dds.thresh){
21064 startProc(el, "up");
21067 }else if(pt.x - r.left <= dds.thresh){
21069 startProc(el, "right");
21078 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21079 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21083 * Registers new overflow element(s) to auto scroll
21084 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21086 register : function(el){
21087 if(el instanceof Array){
21088 for(var i = 0, len = el.length; i < len; i++) {
21089 this.register(el[i]);
21095 Roo.dd.ScrollManager.els = els;
21099 * Unregisters overflow element(s) so they are no longer scrolled
21100 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21102 unregister : function(el){
21103 if(el instanceof Array){
21104 for(var i = 0, len = el.length; i < len; i++) {
21105 this.unregister(el[i]);
21114 * The number of pixels from the edge of a container the pointer needs to be to
21115 * trigger scrolling (defaults to 25)
21121 * The number of pixels to scroll in each scroll increment (defaults to 50)
21127 * The frequency of scrolls in milliseconds (defaults to 500)
21133 * True to animate the scroll (defaults to true)
21139 * The animation duration in seconds -
21140 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21146 * Manually trigger a cache refresh.
21148 refreshCache : function(){
21149 for(var id in els){
21150 if(typeof els[id] == 'object'){ // for people extending the object prototype
21151 els[id]._region = els[id].getRegion();
21158 * Ext JS Library 1.1.1
21159 * Copyright(c) 2006-2007, Ext JS, LLC.
21161 * Originally Released Under LGPL - original licence link has changed is not relivant.
21164 * <script type="text/javascript">
21169 * @class Roo.dd.Registry
21170 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21171 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21174 Roo.dd.Registry = function(){
21177 var autoIdSeed = 0;
21179 var getId = function(el, autogen){
21180 if(typeof el == "string"){
21184 if(!id && autogen !== false){
21185 id = "roodd-" + (++autoIdSeed);
21193 * Register a drag drop element
21194 * @param {String|HTMLElement} element The id or DOM node to register
21195 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21196 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21197 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21198 * populated in the data object (if applicable):
21200 Value Description<br />
21201 --------- ------------------------------------------<br />
21202 handles Array of DOM nodes that trigger dragging<br />
21203 for the element being registered<br />
21204 isHandle True if the element passed in triggers<br />
21205 dragging itself, else false
21208 register : function(el, data){
21210 if(typeof el == "string"){
21211 el = document.getElementById(el);
21214 elements[getId(el)] = data;
21215 if(data.isHandle !== false){
21216 handles[data.ddel.id] = data;
21219 var hs = data.handles;
21220 for(var i = 0, len = hs.length; i < len; i++){
21221 handles[getId(hs[i])] = data;
21227 * Unregister a drag drop element
21228 * @param {String|HTMLElement} element The id or DOM node to unregister
21230 unregister : function(el){
21231 var id = getId(el, false);
21232 var data = elements[id];
21234 delete elements[id];
21236 var hs = data.handles;
21237 for(var i = 0, len = hs.length; i < len; i++){
21238 delete handles[getId(hs[i], false)];
21245 * Returns the handle registered for a DOM Node by id
21246 * @param {String|HTMLElement} id The DOM node or id to look up
21247 * @return {Object} handle The custom handle data
21249 getHandle : function(id){
21250 if(typeof id != "string"){ // must be element?
21253 return handles[id];
21257 * Returns the handle that is registered for the DOM node that is the target of the event
21258 * @param {Event} e The event
21259 * @return {Object} handle The custom handle data
21261 getHandleFromEvent : function(e){
21262 var t = Roo.lib.Event.getTarget(e);
21263 return t ? handles[t.id] : null;
21267 * Returns a custom data object that is registered for a DOM node by id
21268 * @param {String|HTMLElement} id The DOM node or id to look up
21269 * @return {Object} data The custom data
21271 getTarget : function(id){
21272 if(typeof id != "string"){ // must be element?
21275 return elements[id];
21279 * Returns a custom data object that is registered for the DOM node that is the target of the event
21280 * @param {Event} e The event
21281 * @return {Object} data The custom data
21283 getTargetFromEvent : function(e){
21284 var t = Roo.lib.Event.getTarget(e);
21285 return t ? elements[t.id] || handles[t.id] : null;
21290 * Ext JS Library 1.1.1
21291 * Copyright(c) 2006-2007, Ext JS, LLC.
21293 * Originally Released Under LGPL - original licence link has changed is not relivant.
21296 * <script type="text/javascript">
21301 * @class Roo.dd.StatusProxy
21302 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21303 * default drag proxy used by all Roo.dd components.
21305 * @param {Object} config
21307 Roo.dd.StatusProxy = function(config){
21308 Roo.apply(this, config);
21309 this.id = this.id || Roo.id();
21310 this.el = new Roo.Layer({
21312 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21313 {tag: "div", cls: "x-dd-drop-icon"},
21314 {tag: "div", cls: "x-dd-drag-ghost"}
21317 shadow: !config || config.shadow !== false
21319 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21320 this.dropStatus = this.dropNotAllowed;
21323 Roo.dd.StatusProxy.prototype = {
21325 * @cfg {String} dropAllowed
21326 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21328 dropAllowed : "x-dd-drop-ok",
21330 * @cfg {String} dropNotAllowed
21331 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21333 dropNotAllowed : "x-dd-drop-nodrop",
21336 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21337 * over the current target element.
21338 * @param {String} cssClass The css class for the new drop status indicator image
21340 setStatus : function(cssClass){
21341 cssClass = cssClass || this.dropNotAllowed;
21342 if(this.dropStatus != cssClass){
21343 this.el.replaceClass(this.dropStatus, cssClass);
21344 this.dropStatus = cssClass;
21349 * Resets the status indicator to the default dropNotAllowed value
21350 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21352 reset : function(clearGhost){
21353 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21354 this.dropStatus = this.dropNotAllowed;
21356 this.ghost.update("");
21361 * Updates the contents of the ghost element
21362 * @param {String} html The html that will replace the current innerHTML of the ghost element
21364 update : function(html){
21365 if(typeof html == "string"){
21366 this.ghost.update(html);
21368 this.ghost.update("");
21369 html.style.margin = "0";
21370 this.ghost.dom.appendChild(html);
21372 // ensure float = none set?? cant remember why though.
21373 var el = this.ghost.dom.firstChild;
21375 Roo.fly(el).setStyle('float', 'none');
21380 * Returns the underlying proxy {@link Roo.Layer}
21381 * @return {Roo.Layer} el
21383 getEl : function(){
21388 * Returns the ghost element
21389 * @return {Roo.Element} el
21391 getGhost : function(){
21397 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21399 hide : function(clear){
21407 * Stops the repair animation if it's currently running
21410 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21416 * Displays this proxy
21423 * Force the Layer to sync its shadow and shim positions to the element
21430 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21431 * invalid drop operation by the item being dragged.
21432 * @param {Array} xy The XY position of the element ([x, y])
21433 * @param {Function} callback The function to call after the repair is complete
21434 * @param {Object} scope The scope in which to execute the callback
21436 repair : function(xy, callback, scope){
21437 this.callback = callback;
21438 this.scope = scope;
21439 if(xy && this.animRepair !== false){
21440 this.el.addClass("x-dd-drag-repair");
21441 this.el.hideUnders(true);
21442 this.anim = this.el.shift({
21443 duration: this.repairDuration || .5,
21447 callback: this.afterRepair,
21451 this.afterRepair();
21456 afterRepair : function(){
21458 if(typeof this.callback == "function"){
21459 this.callback.call(this.scope || this);
21461 this.callback = null;
21466 * Ext JS Library 1.1.1
21467 * Copyright(c) 2006-2007, Ext JS, LLC.
21469 * Originally Released Under LGPL - original licence link has changed is not relivant.
21472 * <script type="text/javascript">
21476 * @class Roo.dd.DragSource
21477 * @extends Roo.dd.DDProxy
21478 * A simple class that provides the basic implementation needed to make any element draggable.
21480 * @param {String/HTMLElement/Element} el The container element
21481 * @param {Object} config
21483 Roo.dd.DragSource = function(el, config){
21484 this.el = Roo.get(el);
21485 this.dragData = {};
21487 Roo.apply(this, config);
21490 this.proxy = new Roo.dd.StatusProxy();
21493 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21494 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21496 this.dragging = false;
21499 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21501 * @cfg {String} dropAllowed
21502 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21504 dropAllowed : "x-dd-drop-ok",
21506 * @cfg {String} dropNotAllowed
21507 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21509 dropNotAllowed : "x-dd-drop-nodrop",
21512 * Returns the data object associated with this drag source
21513 * @return {Object} data An object containing arbitrary data
21515 getDragData : function(e){
21516 return this.dragData;
21520 onDragEnter : function(e, id){
21521 var target = Roo.dd.DragDropMgr.getDDById(id);
21522 this.cachedTarget = target;
21523 if(this.beforeDragEnter(target, e, id) !== false){
21524 if(target.isNotifyTarget){
21525 var status = target.notifyEnter(this, e, this.dragData);
21526 this.proxy.setStatus(status);
21528 this.proxy.setStatus(this.dropAllowed);
21531 if(this.afterDragEnter){
21533 * An empty function by default, but provided so that you can perform a custom action
21534 * when the dragged item enters the drop target by providing an implementation.
21535 * @param {Roo.dd.DragDrop} target The drop target
21536 * @param {Event} e The event object
21537 * @param {String} id The id of the dragged element
21538 * @method afterDragEnter
21540 this.afterDragEnter(target, e, id);
21546 * An empty function by default, but provided so that you can perform a custom action
21547 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21548 * @param {Roo.dd.DragDrop} target The drop target
21549 * @param {Event} e The event object
21550 * @param {String} id The id of the dragged element
21551 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21553 beforeDragEnter : function(target, e, id){
21558 alignElWithMouse: function() {
21559 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21564 onDragOver : function(e, id){
21565 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21566 if(this.beforeDragOver(target, e, id) !== false){
21567 if(target.isNotifyTarget){
21568 var status = target.notifyOver(this, e, this.dragData);
21569 this.proxy.setStatus(status);
21572 if(this.afterDragOver){
21574 * An empty function by default, but provided so that you can perform a custom action
21575 * while the dragged item is over the drop target by providing an implementation.
21576 * @param {Roo.dd.DragDrop} target The drop target
21577 * @param {Event} e The event object
21578 * @param {String} id The id of the dragged element
21579 * @method afterDragOver
21581 this.afterDragOver(target, e, id);
21587 * An empty function by default, but provided so that you can perform a custom action
21588 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21589 * @param {Roo.dd.DragDrop} target The drop target
21590 * @param {Event} e The event object
21591 * @param {String} id The id of the dragged element
21592 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21594 beforeDragOver : function(target, e, id){
21599 onDragOut : function(e, id){
21600 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21601 if(this.beforeDragOut(target, e, id) !== false){
21602 if(target.isNotifyTarget){
21603 target.notifyOut(this, e, this.dragData);
21605 this.proxy.reset();
21606 if(this.afterDragOut){
21608 * An empty function by default, but provided so that you can perform a custom action
21609 * after the dragged item is dragged out of the target without dropping.
21610 * @param {Roo.dd.DragDrop} target The drop target
21611 * @param {Event} e The event object
21612 * @param {String} id The id of the dragged element
21613 * @method afterDragOut
21615 this.afterDragOut(target, e, id);
21618 this.cachedTarget = null;
21622 * An empty function by default, but provided so that you can perform a custom action before the dragged
21623 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21624 * @param {Roo.dd.DragDrop} target The drop target
21625 * @param {Event} e The event object
21626 * @param {String} id The id of the dragged element
21627 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21629 beforeDragOut : function(target, e, id){
21634 onDragDrop : function(e, id){
21635 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21636 if(this.beforeDragDrop(target, e, id) !== false){
21637 if(target.isNotifyTarget){
21638 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21639 this.onValidDrop(target, e, id);
21641 this.onInvalidDrop(target, e, id);
21644 this.onValidDrop(target, e, id);
21647 if(this.afterDragDrop){
21649 * An empty function by default, but provided so that you can perform a custom action
21650 * after a valid drag drop has occurred by providing an implementation.
21651 * @param {Roo.dd.DragDrop} target The drop target
21652 * @param {Event} e The event object
21653 * @param {String} id The id of the dropped element
21654 * @method afterDragDrop
21656 this.afterDragDrop(target, e, id);
21659 delete this.cachedTarget;
21663 * An empty function by default, but provided so that you can perform a custom action before the dragged
21664 * item is dropped onto the target and optionally cancel the onDragDrop.
21665 * @param {Roo.dd.DragDrop} target The drop target
21666 * @param {Event} e The event object
21667 * @param {String} id The id of the dragged element
21668 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21670 beforeDragDrop : function(target, e, id){
21675 onValidDrop : function(target, e, id){
21677 if(this.afterValidDrop){
21679 * An empty function by default, but provided so that you can perform a custom action
21680 * after a valid drop has occurred by providing an implementation.
21681 * @param {Object} target The target DD
21682 * @param {Event} e The event object
21683 * @param {String} id The id of the dropped element
21684 * @method afterInvalidDrop
21686 this.afterValidDrop(target, e, id);
21691 getRepairXY : function(e, data){
21692 return this.el.getXY();
21696 onInvalidDrop : function(target, e, id){
21697 this.beforeInvalidDrop(target, e, id);
21698 if(this.cachedTarget){
21699 if(this.cachedTarget.isNotifyTarget){
21700 this.cachedTarget.notifyOut(this, e, this.dragData);
21702 this.cacheTarget = null;
21704 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21706 if(this.afterInvalidDrop){
21708 * An empty function by default, but provided so that you can perform a custom action
21709 * after an invalid drop has occurred by providing an implementation.
21710 * @param {Event} e The event object
21711 * @param {String} id The id of the dropped element
21712 * @method afterInvalidDrop
21714 this.afterInvalidDrop(e, id);
21719 afterRepair : function(){
21721 this.el.highlight(this.hlColor || "c3daf9");
21723 this.dragging = false;
21727 * An empty function by default, but provided so that you can perform a custom action after an invalid
21728 * drop has occurred.
21729 * @param {Roo.dd.DragDrop} target The drop target
21730 * @param {Event} e The event object
21731 * @param {String} id The id of the dragged element
21732 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21734 beforeInvalidDrop : function(target, e, id){
21739 handleMouseDown : function(e){
21740 if(this.dragging) {
21743 var data = this.getDragData(e);
21744 if(data && this.onBeforeDrag(data, e) !== false){
21745 this.dragData = data;
21747 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21752 * An empty function by default, but provided so that you can perform a custom action before the initial
21753 * drag event begins and optionally cancel it.
21754 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21755 * @param {Event} e The event object
21756 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21758 onBeforeDrag : function(data, e){
21763 * An empty function by default, but provided so that you can perform a custom action once the initial
21764 * drag event has begun. The drag cannot be canceled from this function.
21765 * @param {Number} x The x position of the click on the dragged object
21766 * @param {Number} y The y position of the click on the dragged object
21768 onStartDrag : Roo.emptyFn,
21770 // private - YUI override
21771 startDrag : function(x, y){
21772 this.proxy.reset();
21773 this.dragging = true;
21774 this.proxy.update("");
21775 this.onInitDrag(x, y);
21780 onInitDrag : function(x, y){
21781 var clone = this.el.dom.cloneNode(true);
21782 clone.id = Roo.id(); // prevent duplicate ids
21783 this.proxy.update(clone);
21784 this.onStartDrag(x, y);
21789 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21790 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21792 getProxy : function(){
21797 * Hides the drag source's {@link Roo.dd.StatusProxy}
21799 hideProxy : function(){
21801 this.proxy.reset(true);
21802 this.dragging = false;
21806 triggerCacheRefresh : function(){
21807 Roo.dd.DDM.refreshCache(this.groups);
21810 // private - override to prevent hiding
21811 b4EndDrag: function(e) {
21814 // private - override to prevent moving
21815 endDrag : function(e){
21816 this.onEndDrag(this.dragData, e);
21820 onEndDrag : function(data, e){
21823 // private - pin to cursor
21824 autoOffset : function(x, y) {
21825 this.setDelta(-12, -20);
21829 * Ext JS Library 1.1.1
21830 * Copyright(c) 2006-2007, Ext JS, LLC.
21832 * Originally Released Under LGPL - original licence link has changed is not relivant.
21835 * <script type="text/javascript">
21840 * @class Roo.dd.DropTarget
21841 * @extends Roo.dd.DDTarget
21842 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21843 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21845 * @param {String/HTMLElement/Element} el The container element
21846 * @param {Object} config
21848 Roo.dd.DropTarget = function(el, config){
21849 this.el = Roo.get(el);
21851 var listeners = false; ;
21852 if (config && config.listeners) {
21853 listeners= config.listeners;
21854 delete config.listeners;
21856 Roo.apply(this, config);
21858 if(this.containerScroll){
21859 Roo.dd.ScrollManager.register(this.el);
21863 * @scope Roo.dd.DropTarget
21868 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21869 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21870 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21872 * IMPORTANT : it should set this.overClass and this.dropAllowed
21874 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21875 * @param {Event} e The event
21876 * @param {Object} data An object containing arbitrary data supplied by the drag source
21882 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21883 * This method will be called on every mouse movement while the drag source is over the drop target.
21884 * This default implementation simply returns the dropAllowed config value.
21886 * IMPORTANT : it should set this.dropAllowed
21888 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21889 * @param {Event} e The event
21890 * @param {Object} data An object containing arbitrary data supplied by the drag source
21896 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21897 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21898 * overClass (if any) from the drop element.
21900 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21901 * @param {Event} e The event
21902 * @param {Object} data An object containing arbitrary data supplied by the drag source
21908 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21909 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21910 * implementation that does something to process the drop event and returns true so that the drag source's
21911 * repair action does not run.
21913 * IMPORTANT : it should set this.success
21915 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21916 * @param {Event} e The event
21917 * @param {Object} data An object containing arbitrary data supplied by the drag source
21923 Roo.dd.DropTarget.superclass.constructor.call( this,
21925 this.ddGroup || this.group,
21928 listeners : listeners || {}
21936 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21938 * @cfg {String} overClass
21939 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21942 * @cfg {String} ddGroup
21943 * The drag drop group to handle drop events for
21947 * @cfg {String} dropAllowed
21948 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21950 dropAllowed : "x-dd-drop-ok",
21952 * @cfg {String} dropNotAllowed
21953 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21955 dropNotAllowed : "x-dd-drop-nodrop",
21957 * @cfg {boolean} success
21958 * set this after drop listener..
21962 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21963 * if the drop point is valid for over/enter..
21970 isNotifyTarget : true,
21975 notifyEnter : function(dd, e, data)
21978 this.fireEvent('enter', dd, e, data);
21979 if(this.overClass){
21980 this.el.addClass(this.overClass);
21982 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21983 this.valid ? this.dropAllowed : this.dropNotAllowed
21990 notifyOver : function(dd, e, data)
21993 this.fireEvent('over', dd, e, data);
21994 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21995 this.valid ? this.dropAllowed : this.dropNotAllowed
22002 notifyOut : function(dd, e, data)
22004 this.fireEvent('out', dd, e, data);
22005 if(this.overClass){
22006 this.el.removeClass(this.overClass);
22013 notifyDrop : function(dd, e, data)
22015 this.success = false;
22016 this.fireEvent('drop', dd, e, data);
22017 return this.success;
22021 * Ext JS Library 1.1.1
22022 * Copyright(c) 2006-2007, Ext JS, LLC.
22024 * Originally Released Under LGPL - original licence link has changed is not relivant.
22027 * <script type="text/javascript">
22032 * @class Roo.dd.DragZone
22033 * @extends Roo.dd.DragSource
22034 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22035 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22037 * @param {String/HTMLElement/Element} el The container element
22038 * @param {Object} config
22040 Roo.dd.DragZone = function(el, config){
22041 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22042 if(this.containerScroll){
22043 Roo.dd.ScrollManager.register(this.el);
22047 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22049 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22050 * for auto scrolling during drag operations.
22053 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22054 * method after a failed drop (defaults to "c3daf9" - light blue)
22058 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22059 * for a valid target to drag based on the mouse down. Override this method
22060 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22061 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22062 * @param {EventObject} e The mouse down event
22063 * @return {Object} The dragData
22065 getDragData : function(e){
22066 return Roo.dd.Registry.getHandleFromEvent(e);
22070 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22071 * this.dragData.ddel
22072 * @param {Number} x The x position of the click on the dragged object
22073 * @param {Number} y The y position of the click on the dragged object
22074 * @return {Boolean} true to continue the drag, false to cancel
22076 onInitDrag : function(x, y){
22077 this.proxy.update(this.dragData.ddel.cloneNode(true));
22078 this.onStartDrag(x, y);
22083 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22085 afterRepair : function(){
22087 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22089 this.dragging = false;
22093 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22094 * the XY of this.dragData.ddel
22095 * @param {EventObject} e The mouse up event
22096 * @return {Array} The xy location (e.g. [100, 200])
22098 getRepairXY : function(e){
22099 return Roo.Element.fly(this.dragData.ddel).getXY();
22103 * Ext JS Library 1.1.1
22104 * Copyright(c) 2006-2007, Ext JS, LLC.
22106 * Originally Released Under LGPL - original licence link has changed is not relivant.
22109 * <script type="text/javascript">
22112 * @class Roo.dd.DropZone
22113 * @extends Roo.dd.DropTarget
22114 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22115 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22117 * @param {String/HTMLElement/Element} el The container element
22118 * @param {Object} config
22120 Roo.dd.DropZone = function(el, config){
22121 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22124 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22126 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22127 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22128 * provide your own custom lookup.
22129 * @param {Event} e The event
22130 * @return {Object} data The custom data
22132 getTargetFromEvent : function(e){
22133 return Roo.dd.Registry.getTargetFromEvent(e);
22137 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22138 * that it has registered. This method has no default implementation and should be overridden to provide
22139 * node-specific processing if necessary.
22140 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22141 * {@link #getTargetFromEvent} for this node)
22142 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22143 * @param {Event} e The event
22144 * @param {Object} data An object containing arbitrary data supplied by the drag source
22146 onNodeEnter : function(n, dd, e, data){
22151 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22152 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22153 * overridden to provide the proper feedback.
22154 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22155 * {@link #getTargetFromEvent} for this node)
22156 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22157 * @param {Event} e The event
22158 * @param {Object} data An object containing arbitrary data supplied by the drag source
22159 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22160 * underlying {@link Roo.dd.StatusProxy} can be updated
22162 onNodeOver : function(n, dd, e, data){
22163 return this.dropAllowed;
22167 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22168 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22169 * node-specific processing if necessary.
22170 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22171 * {@link #getTargetFromEvent} for this node)
22172 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22173 * @param {Event} e The event
22174 * @param {Object} data An object containing arbitrary data supplied by the drag source
22176 onNodeOut : function(n, dd, e, data){
22181 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22182 * the drop node. The default implementation returns false, so it should be overridden to provide the
22183 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22184 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22185 * {@link #getTargetFromEvent} for this node)
22186 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22187 * @param {Event} e The event
22188 * @param {Object} data An object containing arbitrary data supplied by the drag source
22189 * @return {Boolean} True if the drop was valid, else false
22191 onNodeDrop : function(n, dd, e, data){
22196 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22197 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22198 * it should be overridden to provide the proper feedback if necessary.
22199 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22200 * @param {Event} e The event
22201 * @param {Object} data An object containing arbitrary data supplied by the drag source
22202 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22203 * underlying {@link Roo.dd.StatusProxy} can be updated
22205 onContainerOver : function(dd, e, data){
22206 return this.dropNotAllowed;
22210 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22211 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22212 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22213 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22214 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22215 * @param {Event} e The event
22216 * @param {Object} data An object containing arbitrary data supplied by the drag source
22217 * @return {Boolean} True if the drop was valid, else false
22219 onContainerDrop : function(dd, e, data){
22224 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22225 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22226 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22227 * you should override this method and provide a custom implementation.
22228 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22229 * @param {Event} e The event
22230 * @param {Object} data An object containing arbitrary data supplied by the drag source
22231 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22232 * underlying {@link Roo.dd.StatusProxy} can be updated
22234 notifyEnter : function(dd, e, data){
22235 return this.dropNotAllowed;
22239 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22240 * This method will be called on every mouse movement while the drag source is over the drop zone.
22241 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22242 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22243 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22244 * registered node, it will call {@link #onContainerOver}.
22245 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22246 * @param {Event} e The event
22247 * @param {Object} data An object containing arbitrary data supplied by the drag source
22248 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22249 * underlying {@link Roo.dd.StatusProxy} can be updated
22251 notifyOver : function(dd, e, data){
22252 var n = this.getTargetFromEvent(e);
22253 if(!n){ // not over valid drop target
22254 if(this.lastOverNode){
22255 this.onNodeOut(this.lastOverNode, dd, e, data);
22256 this.lastOverNode = null;
22258 return this.onContainerOver(dd, e, data);
22260 if(this.lastOverNode != n){
22261 if(this.lastOverNode){
22262 this.onNodeOut(this.lastOverNode, dd, e, data);
22264 this.onNodeEnter(n, dd, e, data);
22265 this.lastOverNode = n;
22267 return this.onNodeOver(n, dd, e, data);
22271 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22272 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22273 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22274 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22275 * @param {Event} e The event
22276 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22278 notifyOut : function(dd, e, data){
22279 if(this.lastOverNode){
22280 this.onNodeOut(this.lastOverNode, dd, e, data);
22281 this.lastOverNode = null;
22286 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22287 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22288 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22289 * otherwise it will call {@link #onContainerDrop}.
22290 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22291 * @param {Event} e The event
22292 * @param {Object} data An object containing arbitrary data supplied by the drag source
22293 * @return {Boolean} True if the drop was valid, else false
22295 notifyDrop : function(dd, e, data){
22296 if(this.lastOverNode){
22297 this.onNodeOut(this.lastOverNode, dd, e, data);
22298 this.lastOverNode = null;
22300 var n = this.getTargetFromEvent(e);
22302 this.onNodeDrop(n, dd, e, data) :
22303 this.onContainerDrop(dd, e, data);
22307 triggerCacheRefresh : function(){
22308 Roo.dd.DDM.refreshCache(this.groups);
22312 * Ext JS Library 1.1.1
22313 * Copyright(c) 2006-2007, Ext JS, LLC.
22315 * Originally Released Under LGPL - original licence link has changed is not relivant.
22318 * <script type="text/javascript">
22323 * @class Roo.data.SortTypes
22325 * Defines the default sorting (casting?) comparison functions used when sorting data.
22327 Roo.data.SortTypes = {
22329 * Default sort that does nothing
22330 * @param {Mixed} s The value being converted
22331 * @return {Mixed} The comparison value
22333 none : function(s){
22338 * The regular expression used to strip tags
22342 stripTagsRE : /<\/?[^>]+>/gi,
22345 * Strips all HTML tags to sort on text only
22346 * @param {Mixed} s The value being converted
22347 * @return {String} The comparison value
22349 asText : function(s){
22350 return String(s).replace(this.stripTagsRE, "");
22354 * Strips all HTML tags to sort on text only - Case insensitive
22355 * @param {Mixed} s The value being converted
22356 * @return {String} The comparison value
22358 asUCText : function(s){
22359 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22363 * Case insensitive string
22364 * @param {Mixed} s The value being converted
22365 * @return {String} The comparison value
22367 asUCString : function(s) {
22368 return String(s).toUpperCase();
22373 * @param {Mixed} s The value being converted
22374 * @return {Number} The comparison value
22376 asDate : function(s) {
22380 if(s instanceof Date){
22381 return s.getTime();
22383 return Date.parse(String(s));
22388 * @param {Mixed} s The value being converted
22389 * @return {Float} The comparison value
22391 asFloat : function(s) {
22392 var val = parseFloat(String(s).replace(/,/g, ""));
22401 * @param {Mixed} s The value being converted
22402 * @return {Number} The comparison value
22404 asInt : function(s) {
22405 var val = parseInt(String(s).replace(/,/g, ""));
22413 * Ext JS Library 1.1.1
22414 * Copyright(c) 2006-2007, Ext JS, LLC.
22416 * Originally Released Under LGPL - original licence link has changed is not relivant.
22419 * <script type="text/javascript">
22423 * @class Roo.data.Record
22424 * Instances of this class encapsulate both record <em>definition</em> information, and record
22425 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22426 * to access Records cached in an {@link Roo.data.Store} object.<br>
22428 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22429 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22432 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22434 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22435 * {@link #create}. The parameters are the same.
22436 * @param {Array} data An associative Array of data values keyed by the field name.
22437 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22438 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22439 * not specified an integer id is generated.
22441 Roo.data.Record = function(data, id){
22442 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22447 * Generate a constructor for a specific record layout.
22448 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22449 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22450 * Each field definition object may contain the following properties: <ul>
22451 * <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,
22452 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22453 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22454 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22455 * is being used, then this is a string containing the javascript expression to reference the data relative to
22456 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22457 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22458 * this may be omitted.</p></li>
22459 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22460 * <ul><li>auto (Default, implies no conversion)</li>
22465 * <li>date</li></ul></p></li>
22466 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22467 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22468 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22469 * by the Reader into an object that will be stored in the Record. It is passed the
22470 * following parameters:<ul>
22471 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22473 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22475 * <br>usage:<br><pre><code>
22476 var TopicRecord = Roo.data.Record.create(
22477 {name: 'title', mapping: 'topic_title'},
22478 {name: 'author', mapping: 'username'},
22479 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22480 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22481 {name: 'lastPoster', mapping: 'user2'},
22482 {name: 'excerpt', mapping: 'post_text'}
22485 var myNewRecord = new TopicRecord({
22486 title: 'Do my job please',
22489 lastPost: new Date(),
22490 lastPoster: 'Animal',
22491 excerpt: 'No way dude!'
22493 myStore.add(myNewRecord);
22498 Roo.data.Record.create = function(o){
22499 var f = function(){
22500 f.superclass.constructor.apply(this, arguments);
22502 Roo.extend(f, Roo.data.Record);
22503 var p = f.prototype;
22504 p.fields = new Roo.util.MixedCollection(false, function(field){
22507 for(var i = 0, len = o.length; i < len; i++){
22508 p.fields.add(new Roo.data.Field(o[i]));
22510 f.getField = function(name){
22511 return p.fields.get(name);
22516 Roo.data.Record.AUTO_ID = 1000;
22517 Roo.data.Record.EDIT = 'edit';
22518 Roo.data.Record.REJECT = 'reject';
22519 Roo.data.Record.COMMIT = 'commit';
22521 Roo.data.Record.prototype = {
22523 * Readonly flag - true if this record has been modified.
22532 join : function(store){
22533 this.store = store;
22537 * Set the named field to the specified value.
22538 * @param {String} name The name of the field to set.
22539 * @param {Object} value The value to set the field to.
22541 set : function(name, value){
22542 if(this.data[name] == value){
22546 if(!this.modified){
22547 this.modified = {};
22549 if(typeof this.modified[name] == 'undefined'){
22550 this.modified[name] = this.data[name];
22552 this.data[name] = value;
22553 if(!this.editing && this.store){
22554 this.store.afterEdit(this);
22559 * Get the value of the named field.
22560 * @param {String} name The name of the field to get the value of.
22561 * @return {Object} The value of the field.
22563 get : function(name){
22564 return this.data[name];
22568 beginEdit : function(){
22569 this.editing = true;
22570 this.modified = {};
22574 cancelEdit : function(){
22575 this.editing = false;
22576 delete this.modified;
22580 endEdit : function(){
22581 this.editing = false;
22582 if(this.dirty && this.store){
22583 this.store.afterEdit(this);
22588 * Usually called by the {@link Roo.data.Store} which owns the Record.
22589 * Rejects all changes made to the Record since either creation, or the last commit operation.
22590 * Modified fields are reverted to their original values.
22592 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22593 * of reject operations.
22595 reject : function(){
22596 var m = this.modified;
22598 if(typeof m[n] != "function"){
22599 this.data[n] = m[n];
22602 this.dirty = false;
22603 delete this.modified;
22604 this.editing = false;
22606 this.store.afterReject(this);
22611 * Usually called by the {@link Roo.data.Store} which owns the Record.
22612 * Commits all changes made to the Record since either creation, or the last commit operation.
22614 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22615 * of commit operations.
22617 commit : function(){
22618 this.dirty = false;
22619 delete this.modified;
22620 this.editing = false;
22622 this.store.afterCommit(this);
22627 hasError : function(){
22628 return this.error != null;
22632 clearError : function(){
22637 * Creates a copy of this record.
22638 * @param {String} id (optional) A new record id if you don't want to use this record's id
22641 copy : function(newId) {
22642 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22646 * Ext JS Library 1.1.1
22647 * Copyright(c) 2006-2007, Ext JS, LLC.
22649 * Originally Released Under LGPL - original licence link has changed is not relivant.
22652 * <script type="text/javascript">
22658 * @class Roo.data.Store
22659 * @extends Roo.util.Observable
22660 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22661 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22663 * 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
22664 * has no knowledge of the format of the data returned by the Proxy.<br>
22666 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22667 * instances from the data object. These records are cached and made available through accessor functions.
22669 * Creates a new Store.
22670 * @param {Object} config A config object containing the objects needed for the Store to access data,
22671 * and read the data into Records.
22673 Roo.data.Store = function(config){
22674 this.data = new Roo.util.MixedCollection(false);
22675 this.data.getKey = function(o){
22678 this.baseParams = {};
22680 this.paramNames = {
22685 "multisort" : "_multisort"
22688 if(config && config.data){
22689 this.inlineData = config.data;
22690 delete config.data;
22693 Roo.apply(this, config);
22695 if(this.reader){ // reader passed
22696 this.reader = Roo.factory(this.reader, Roo.data);
22697 this.reader.xmodule = this.xmodule || false;
22698 if(!this.recordType){
22699 this.recordType = this.reader.recordType;
22701 if(this.reader.onMetaChange){
22702 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22706 if(this.recordType){
22707 this.fields = this.recordType.prototype.fields;
22709 this.modified = [];
22713 * @event datachanged
22714 * Fires when the data cache has changed, and a widget which is using this Store
22715 * as a Record cache should refresh its view.
22716 * @param {Store} this
22718 datachanged : true,
22720 * @event metachange
22721 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22722 * @param {Store} this
22723 * @param {Object} meta The JSON metadata
22728 * Fires when Records have been added to the Store
22729 * @param {Store} this
22730 * @param {Roo.data.Record[]} records The array of Records added
22731 * @param {Number} index The index at which the record(s) were added
22736 * Fires when a Record has been removed from the Store
22737 * @param {Store} this
22738 * @param {Roo.data.Record} record The Record that was removed
22739 * @param {Number} index The index at which the record was removed
22744 * Fires when a Record has been updated
22745 * @param {Store} this
22746 * @param {Roo.data.Record} record The Record that was updated
22747 * @param {String} operation The update operation being performed. Value may be one of:
22749 Roo.data.Record.EDIT
22750 Roo.data.Record.REJECT
22751 Roo.data.Record.COMMIT
22757 * Fires when the data cache has been cleared.
22758 * @param {Store} this
22762 * @event beforeload
22763 * Fires before a request is made for a new data object. If the beforeload handler returns false
22764 * the load action will be canceled.
22765 * @param {Store} this
22766 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22770 * @event beforeloadadd
22771 * Fires after a new set of Records has been loaded.
22772 * @param {Store} this
22773 * @param {Roo.data.Record[]} records The Records that were loaded
22774 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22776 beforeloadadd : true,
22779 * Fires after a new set of Records has been loaded, before they are added to the store.
22780 * @param {Store} this
22781 * @param {Roo.data.Record[]} records The Records that were loaded
22782 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22783 * @params {Object} return from reader
22787 * @event loadexception
22788 * Fires if an exception occurs in the Proxy during loading.
22789 * Called with the signature of the Proxy's "loadexception" event.
22790 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22793 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22794 * @param {Object} load options
22795 * @param {Object} jsonData from your request (normally this contains the Exception)
22797 loadexception : true
22801 this.proxy = Roo.factory(this.proxy, Roo.data);
22802 this.proxy.xmodule = this.xmodule || false;
22803 this.relayEvents(this.proxy, ["loadexception"]);
22805 this.sortToggle = {};
22806 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22808 Roo.data.Store.superclass.constructor.call(this);
22810 if(this.inlineData){
22811 this.loadData(this.inlineData);
22812 delete this.inlineData;
22816 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22818 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22819 * without a remote query - used by combo/forms at present.
22823 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22826 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22829 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22830 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22833 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22834 * on any HTTP request
22837 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22840 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22844 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22845 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22847 remoteSort : false,
22850 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22851 * loaded or when a record is removed. (defaults to false).
22853 pruneModifiedRecords : false,
22856 lastOptions : null,
22859 * Add Records to the Store and fires the add event.
22860 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22862 add : function(records){
22863 records = [].concat(records);
22864 for(var i = 0, len = records.length; i < len; i++){
22865 records[i].join(this);
22867 var index = this.data.length;
22868 this.data.addAll(records);
22869 this.fireEvent("add", this, records, index);
22873 * Remove a Record from the Store and fires the remove event.
22874 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
22876 remove : function(record){
22877 var index = this.data.indexOf(record);
22878 this.data.removeAt(index);
22879 if(this.pruneModifiedRecords){
22880 this.modified.remove(record);
22882 this.fireEvent("remove", this, record, index);
22886 * Remove all Records from the Store and fires the clear event.
22888 removeAll : function(){
22890 if(this.pruneModifiedRecords){
22891 this.modified = [];
22893 this.fireEvent("clear", this);
22897 * Inserts Records to the Store at the given index and fires the add event.
22898 * @param {Number} index The start index at which to insert the passed Records.
22899 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22901 insert : function(index, records){
22902 records = [].concat(records);
22903 for(var i = 0, len = records.length; i < len; i++){
22904 this.data.insert(index, records[i]);
22905 records[i].join(this);
22907 this.fireEvent("add", this, records, index);
22911 * Get the index within the cache of the passed Record.
22912 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
22913 * @return {Number} The index of the passed Record. Returns -1 if not found.
22915 indexOf : function(record){
22916 return this.data.indexOf(record);
22920 * Get the index within the cache of the Record with the passed id.
22921 * @param {String} id The id of the Record to find.
22922 * @return {Number} The index of the Record. Returns -1 if not found.
22924 indexOfId : function(id){
22925 return this.data.indexOfKey(id);
22929 * Get the Record with the specified id.
22930 * @param {String} id The id of the Record to find.
22931 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
22933 getById : function(id){
22934 return this.data.key(id);
22938 * Get the Record at the specified index.
22939 * @param {Number} index The index of the Record to find.
22940 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
22942 getAt : function(index){
22943 return this.data.itemAt(index);
22947 * Returns a range of Records between specified indices.
22948 * @param {Number} startIndex (optional) The starting index (defaults to 0)
22949 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
22950 * @return {Roo.data.Record[]} An array of Records
22952 getRange : function(start, end){
22953 return this.data.getRange(start, end);
22957 storeOptions : function(o){
22958 o = Roo.apply({}, o);
22961 this.lastOptions = o;
22965 * Loads the Record cache from the configured Proxy using the configured Reader.
22967 * If using remote paging, then the first load call must specify the <em>start</em>
22968 * and <em>limit</em> properties in the options.params property to establish the initial
22969 * position within the dataset, and the number of Records to cache on each read from the Proxy.
22971 * <strong>It is important to note that for remote data sources, loading is asynchronous,
22972 * and this call will return before the new data has been loaded. Perform any post-processing
22973 * in a callback function, or in a "load" event handler.</strong>
22975 * @param {Object} options An object containing properties which control loading options:<ul>
22976 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
22977 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
22978 * passed the following arguments:<ul>
22979 * <li>r : Roo.data.Record[]</li>
22980 * <li>options: Options object from the load call</li>
22981 * <li>success: Boolean success indicator</li></ul></li>
22982 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
22983 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
22986 load : function(options){
22987 options = options || {};
22988 if(this.fireEvent("beforeload", this, options) !== false){
22989 this.storeOptions(options);
22990 var p = Roo.apply(options.params || {}, this.baseParams);
22991 // if meta was not loaded from remote source.. try requesting it.
22992 if (!this.reader.metaFromRemote) {
22993 p._requestMeta = 1;
22995 if(this.sortInfo && this.remoteSort){
22996 var pn = this.paramNames;
22997 p[pn["sort"]] = this.sortInfo.field;
22998 p[pn["dir"]] = this.sortInfo.direction;
23000 if (this.multiSort) {
23001 var pn = this.paramNames;
23002 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23005 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23010 * Reloads the Record cache from the configured Proxy using the configured Reader and
23011 * the options from the last load operation performed.
23012 * @param {Object} options (optional) An object containing properties which may override the options
23013 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23014 * the most recently used options are reused).
23016 reload : function(options){
23017 this.load(Roo.applyIf(options||{}, this.lastOptions));
23021 // Called as a callback by the Reader during a load operation.
23022 loadRecords : function(o, options, success){
23023 if(!o || success === false){
23024 if(success !== false){
23025 this.fireEvent("load", this, [], options, o);
23027 if(options.callback){
23028 options.callback.call(options.scope || this, [], options, false);
23032 // if data returned failure - throw an exception.
23033 if (o.success === false) {
23034 // show a message if no listener is registered.
23035 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23036 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23038 // loadmask wil be hooked into this..
23039 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23042 var r = o.records, t = o.totalRecords || r.length;
23044 this.fireEvent("beforeloadadd", this, r, options, o);
23046 if(!options || options.add !== true){
23047 if(this.pruneModifiedRecords){
23048 this.modified = [];
23050 for(var i = 0, len = r.length; i < len; i++){
23054 this.data = this.snapshot;
23055 delete this.snapshot;
23058 this.data.addAll(r);
23059 this.totalLength = t;
23061 this.fireEvent("datachanged", this);
23063 this.totalLength = Math.max(t, this.data.length+r.length);
23066 this.fireEvent("load", this, r, options, o);
23067 if(options.callback){
23068 options.callback.call(options.scope || this, r, options, true);
23074 * Loads data from a passed data block. A Reader which understands the format of the data
23075 * must have been configured in the constructor.
23076 * @param {Object} data The data block from which to read the Records. The format of the data expected
23077 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23078 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23080 loadData : function(o, append){
23081 var r = this.reader.readRecords(o);
23082 this.loadRecords(r, {add: append}, true);
23086 * Gets the number of cached records.
23088 * <em>If using paging, this may not be the total size of the dataset. If the data object
23089 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23090 * the data set size</em>
23092 getCount : function(){
23093 return this.data.length || 0;
23097 * Gets the total number of records in the dataset as returned by the server.
23099 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23100 * the dataset size</em>
23102 getTotalCount : function(){
23103 return this.totalLength || 0;
23107 * Returns the sort state of the Store as an object with two properties:
23109 field {String} The name of the field by which the Records are sorted
23110 direction {String} The sort order, "ASC" or "DESC"
23113 getSortState : function(){
23114 return this.sortInfo;
23118 applySort : function(){
23119 if(this.sortInfo && !this.remoteSort){
23120 var s = this.sortInfo, f = s.field;
23121 var st = this.fields.get(f).sortType;
23122 var fn = function(r1, r2){
23123 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23124 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23126 this.data.sort(s.direction, fn);
23127 if(this.snapshot && this.snapshot != this.data){
23128 this.snapshot.sort(s.direction, fn);
23134 * Sets the default sort column and order to be used by the next load operation.
23135 * @param {String} fieldName The name of the field to sort by.
23136 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23138 setDefaultSort : function(field, dir){
23139 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23143 * Sort the Records.
23144 * If remote sorting is used, the sort is performed on the server, and the cache is
23145 * reloaded. If local sorting is used, the cache is sorted internally.
23146 * @param {String} fieldName The name of the field to sort by.
23147 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23149 sort : function(fieldName, dir){
23150 var f = this.fields.get(fieldName);
23152 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23154 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23155 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23160 this.sortToggle[f.name] = dir;
23161 this.sortInfo = {field: f.name, direction: dir};
23162 if(!this.remoteSort){
23164 this.fireEvent("datachanged", this);
23166 this.load(this.lastOptions);
23171 * Calls the specified function for each of the Records in the cache.
23172 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23173 * Returning <em>false</em> aborts and exits the iteration.
23174 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23176 each : function(fn, scope){
23177 this.data.each(fn, scope);
23181 * Gets all records modified since the last commit. Modified records are persisted across load operations
23182 * (e.g., during paging).
23183 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23185 getModifiedRecords : function(){
23186 return this.modified;
23190 createFilterFn : function(property, value, anyMatch){
23191 if(!value.exec){ // not a regex
23192 value = String(value);
23193 if(value.length == 0){
23196 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23198 return function(r){
23199 return value.test(r.data[property]);
23204 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23205 * @param {String} property A field on your records
23206 * @param {Number} start The record index to start at (defaults to 0)
23207 * @param {Number} end The last record index to include (defaults to length - 1)
23208 * @return {Number} The sum
23210 sum : function(property, start, end){
23211 var rs = this.data.items, v = 0;
23212 start = start || 0;
23213 end = (end || end === 0) ? end : rs.length-1;
23215 for(var i = start; i <= end; i++){
23216 v += (rs[i].data[property] || 0);
23222 * Filter the records by a specified property.
23223 * @param {String} field A field on your records
23224 * @param {String/RegExp} value Either a string that the field
23225 * should start with or a RegExp to test against the field
23226 * @param {Boolean} anyMatch True to match any part not just the beginning
23228 filter : function(property, value, anyMatch){
23229 var fn = this.createFilterFn(property, value, anyMatch);
23230 return fn ? this.filterBy(fn) : this.clearFilter();
23234 * Filter by a function. The specified function will be called with each
23235 * record in this data source. If the function returns true the record is included,
23236 * otherwise it is filtered.
23237 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23238 * @param {Object} scope (optional) The scope of the function (defaults to this)
23240 filterBy : function(fn, scope){
23241 this.snapshot = this.snapshot || this.data;
23242 this.data = this.queryBy(fn, scope||this);
23243 this.fireEvent("datachanged", this);
23247 * Query the records by a specified property.
23248 * @param {String} field A field on your records
23249 * @param {String/RegExp} value Either a string that the field
23250 * should start with or a RegExp to test against the field
23251 * @param {Boolean} anyMatch True to match any part not just the beginning
23252 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23254 query : function(property, value, anyMatch){
23255 var fn = this.createFilterFn(property, value, anyMatch);
23256 return fn ? this.queryBy(fn) : this.data.clone();
23260 * Query by a function. The specified function will be called with each
23261 * record in this data source. If the function returns true the record is included
23263 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23264 * @param {Object} scope (optional) The scope of the function (defaults to this)
23265 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23267 queryBy : function(fn, scope){
23268 var data = this.snapshot || this.data;
23269 return data.filterBy(fn, scope||this);
23273 * Collects unique values for a particular dataIndex from this store.
23274 * @param {String} dataIndex The property to collect
23275 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23276 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23277 * @return {Array} An array of the unique values
23279 collect : function(dataIndex, allowNull, bypassFilter){
23280 var d = (bypassFilter === true && this.snapshot) ?
23281 this.snapshot.items : this.data.items;
23282 var v, sv, r = [], l = {};
23283 for(var i = 0, len = d.length; i < len; i++){
23284 v = d[i].data[dataIndex];
23286 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23295 * Revert to a view of the Record cache with no filtering applied.
23296 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23298 clearFilter : function(suppressEvent){
23299 if(this.snapshot && this.snapshot != this.data){
23300 this.data = this.snapshot;
23301 delete this.snapshot;
23302 if(suppressEvent !== true){
23303 this.fireEvent("datachanged", this);
23309 afterEdit : function(record){
23310 if(this.modified.indexOf(record) == -1){
23311 this.modified.push(record);
23313 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23317 afterReject : function(record){
23318 this.modified.remove(record);
23319 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23323 afterCommit : function(record){
23324 this.modified.remove(record);
23325 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23329 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23330 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23332 commitChanges : function(){
23333 var m = this.modified.slice(0);
23334 this.modified = [];
23335 for(var i = 0, len = m.length; i < len; i++){
23341 * Cancel outstanding changes on all changed records.
23343 rejectChanges : function(){
23344 var m = this.modified.slice(0);
23345 this.modified = [];
23346 for(var i = 0, len = m.length; i < len; i++){
23351 onMetaChange : function(meta, rtype, o){
23352 this.recordType = rtype;
23353 this.fields = rtype.prototype.fields;
23354 delete this.snapshot;
23355 this.sortInfo = meta.sortInfo || this.sortInfo;
23356 this.modified = [];
23357 this.fireEvent('metachange', this, this.reader.meta);
23360 moveIndex : function(data, type)
23362 var index = this.indexOf(data);
23364 var newIndex = index + type;
23368 this.insert(newIndex, data);
23373 * Ext JS Library 1.1.1
23374 * Copyright(c) 2006-2007, Ext JS, LLC.
23376 * Originally Released Under LGPL - original licence link has changed is not relivant.
23379 * <script type="text/javascript">
23383 * @class Roo.data.SimpleStore
23384 * @extends Roo.data.Store
23385 * Small helper class to make creating Stores from Array data easier.
23386 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23387 * @cfg {Array} fields An array of field definition objects, or field name strings.
23388 * @cfg {Array} data The multi-dimensional array of data
23390 * @param {Object} config
23392 Roo.data.SimpleStore = function(config){
23393 Roo.data.SimpleStore.superclass.constructor.call(this, {
23395 reader: new Roo.data.ArrayReader({
23398 Roo.data.Record.create(config.fields)
23400 proxy : new Roo.data.MemoryProxy(config.data)
23404 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23406 * Ext JS Library 1.1.1
23407 * Copyright(c) 2006-2007, Ext JS, LLC.
23409 * Originally Released Under LGPL - original licence link has changed is not relivant.
23412 * <script type="text/javascript">
23417 * @extends Roo.data.Store
23418 * @class Roo.data.JsonStore
23419 * Small helper class to make creating Stores for JSON data easier. <br/>
23421 var store = new Roo.data.JsonStore({
23422 url: 'get-images.php',
23424 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23427 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23428 * JsonReader and HttpProxy (unless inline data is provided).</b>
23429 * @cfg {Array} fields An array of field definition objects, or field name strings.
23431 * @param {Object} config
23433 Roo.data.JsonStore = function(c){
23434 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23435 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23436 reader: new Roo.data.JsonReader(c, c.fields)
23439 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23441 * Ext JS Library 1.1.1
23442 * Copyright(c) 2006-2007, Ext JS, LLC.
23444 * Originally Released Under LGPL - original licence link has changed is not relivant.
23447 * <script type="text/javascript">
23451 Roo.data.Field = function(config){
23452 if(typeof config == "string"){
23453 config = {name: config};
23455 Roo.apply(this, config);
23458 this.type = "auto";
23461 var st = Roo.data.SortTypes;
23462 // named sortTypes are supported, here we look them up
23463 if(typeof this.sortType == "string"){
23464 this.sortType = st[this.sortType];
23467 // set default sortType for strings and dates
23468 if(!this.sortType){
23471 this.sortType = st.asUCString;
23474 this.sortType = st.asDate;
23477 this.sortType = st.none;
23482 var stripRe = /[\$,%]/g;
23484 // prebuilt conversion function for this field, instead of
23485 // switching every time we're reading a value
23487 var cv, dateFormat = this.dateFormat;
23492 cv = function(v){ return v; };
23495 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23499 return v !== undefined && v !== null && v !== '' ?
23500 parseInt(String(v).replace(stripRe, ""), 10) : '';
23505 return v !== undefined && v !== null && v !== '' ?
23506 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23511 cv = function(v){ return v === true || v === "true" || v == 1; };
23518 if(v instanceof Date){
23522 if(dateFormat == "timestamp"){
23523 return new Date(v*1000);
23525 return Date.parseDate(v, dateFormat);
23527 var parsed = Date.parse(v);
23528 return parsed ? new Date(parsed) : null;
23537 Roo.data.Field.prototype = {
23545 * Ext JS Library 1.1.1
23546 * Copyright(c) 2006-2007, Ext JS, LLC.
23548 * Originally Released Under LGPL - original licence link has changed is not relivant.
23551 * <script type="text/javascript">
23554 // Base class for reading structured data from a data source. This class is intended to be
23555 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23558 * @class Roo.data.DataReader
23559 * Base class for reading structured data from a data source. This class is intended to be
23560 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23563 Roo.data.DataReader = function(meta, recordType){
23567 this.recordType = recordType instanceof Array ?
23568 Roo.data.Record.create(recordType) : recordType;
23571 Roo.data.DataReader.prototype = {
23573 * Create an empty record
23574 * @param {Object} data (optional) - overlay some values
23575 * @return {Roo.data.Record} record created.
23577 newRow : function(d) {
23579 this.recordType.prototype.fields.each(function(c) {
23581 case 'int' : da[c.name] = 0; break;
23582 case 'date' : da[c.name] = new Date(); break;
23583 case 'float' : da[c.name] = 0.0; break;
23584 case 'boolean' : da[c.name] = false; break;
23585 default : da[c.name] = ""; break;
23589 return new this.recordType(Roo.apply(da, d));
23594 * Ext JS Library 1.1.1
23595 * Copyright(c) 2006-2007, Ext JS, LLC.
23597 * Originally Released Under LGPL - original licence link has changed is not relivant.
23600 * <script type="text/javascript">
23604 * @class Roo.data.DataProxy
23605 * @extends Roo.data.Observable
23606 * This class is an abstract base class for implementations which provide retrieval of
23607 * unformatted data objects.<br>
23609 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23610 * (of the appropriate type which knows how to parse the data object) to provide a block of
23611 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23613 * Custom implementations must implement the load method as described in
23614 * {@link Roo.data.HttpProxy#load}.
23616 Roo.data.DataProxy = function(){
23619 * @event beforeload
23620 * Fires before a network request is made to retrieve a data object.
23621 * @param {Object} This DataProxy object.
23622 * @param {Object} params The params parameter to the load function.
23627 * Fires before the load method's callback is called.
23628 * @param {Object} This DataProxy object.
23629 * @param {Object} o The data object.
23630 * @param {Object} arg The callback argument object passed to the load function.
23634 * @event loadexception
23635 * Fires if an Exception occurs during data retrieval.
23636 * @param {Object} This DataProxy object.
23637 * @param {Object} o The data object.
23638 * @param {Object} arg The callback argument object passed to the load function.
23639 * @param {Object} e The Exception.
23641 loadexception : true
23643 Roo.data.DataProxy.superclass.constructor.call(this);
23646 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23649 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23653 * Ext JS Library 1.1.1
23654 * Copyright(c) 2006-2007, Ext JS, LLC.
23656 * Originally Released Under LGPL - original licence link has changed is not relivant.
23659 * <script type="text/javascript">
23662 * @class Roo.data.MemoryProxy
23663 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23664 * to the Reader when its load method is called.
23666 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23668 Roo.data.MemoryProxy = function(data){
23672 Roo.data.MemoryProxy.superclass.constructor.call(this);
23676 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23679 * Load data from the requested source (in this case an in-memory
23680 * data object passed to the constructor), read the data object into
23681 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23682 * process that block using the passed callback.
23683 * @param {Object} params This parameter is not used by the MemoryProxy class.
23684 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23685 * object into a block of Roo.data.Records.
23686 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23687 * The function must be passed <ul>
23688 * <li>The Record block object</li>
23689 * <li>The "arg" argument from the load function</li>
23690 * <li>A boolean success indicator</li>
23692 * @param {Object} scope The scope in which to call the callback
23693 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23695 load : function(params, reader, callback, scope, arg){
23696 params = params || {};
23699 result = reader.readRecords(this.data);
23701 this.fireEvent("loadexception", this, arg, null, e);
23702 callback.call(scope, null, arg, false);
23705 callback.call(scope, result, arg, true);
23709 update : function(params, records){
23714 * Ext JS Library 1.1.1
23715 * Copyright(c) 2006-2007, Ext JS, LLC.
23717 * Originally Released Under LGPL - original licence link has changed is not relivant.
23720 * <script type="text/javascript">
23723 * @class Roo.data.HttpProxy
23724 * @extends Roo.data.DataProxy
23725 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23726 * configured to reference a certain URL.<br><br>
23728 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23729 * from which the running page was served.<br><br>
23731 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23733 * Be aware that to enable the browser to parse an XML document, the server must set
23734 * the Content-Type header in the HTTP response to "text/xml".
23736 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23737 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23738 * will be used to make the request.
23740 Roo.data.HttpProxy = function(conn){
23741 Roo.data.HttpProxy.superclass.constructor.call(this);
23742 // is conn a conn config or a real conn?
23744 this.useAjax = !conn || !conn.events;
23748 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23749 // thse are take from connection...
23752 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23755 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23756 * extra parameters to each request made by this object. (defaults to undefined)
23759 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23760 * to each request made by this object. (defaults to undefined)
23763 * @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)
23766 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23769 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23775 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23779 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23780 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23781 * a finer-grained basis than the DataProxy events.
23783 getConnection : function(){
23784 return this.useAjax ? Roo.Ajax : this.conn;
23788 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23789 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23790 * process that block using the passed callback.
23791 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23792 * for the request to the remote server.
23793 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23794 * object into a block of Roo.data.Records.
23795 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23796 * The function must be passed <ul>
23797 * <li>The Record block object</li>
23798 * <li>The "arg" argument from the load function</li>
23799 * <li>A boolean success indicator</li>
23801 * @param {Object} scope The scope in which to call the callback
23802 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23804 load : function(params, reader, callback, scope, arg){
23805 if(this.fireEvent("beforeload", this, params) !== false){
23807 params : params || {},
23809 callback : callback,
23814 callback : this.loadResponse,
23818 Roo.applyIf(o, this.conn);
23819 if(this.activeRequest){
23820 Roo.Ajax.abort(this.activeRequest);
23822 this.activeRequest = Roo.Ajax.request(o);
23824 this.conn.request(o);
23827 callback.call(scope||this, null, arg, false);
23832 loadResponse : function(o, success, response){
23833 delete this.activeRequest;
23835 this.fireEvent("loadexception", this, o, response);
23836 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23841 result = o.reader.read(response);
23843 this.fireEvent("loadexception", this, o, response, e);
23844 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23848 this.fireEvent("load", this, o, o.request.arg);
23849 o.request.callback.call(o.request.scope, result, o.request.arg, true);
23853 update : function(dataSet){
23858 updateResponse : function(dataSet){
23863 * Ext JS Library 1.1.1
23864 * Copyright(c) 2006-2007, Ext JS, LLC.
23866 * Originally Released Under LGPL - original licence link has changed is not relivant.
23869 * <script type="text/javascript">
23873 * @class Roo.data.ScriptTagProxy
23874 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
23875 * other than the originating domain of the running page.<br><br>
23877 * <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
23878 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
23880 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
23881 * source code that is used as the source inside a <script> tag.<br><br>
23883 * In order for the browser to process the returned data, the server must wrap the data object
23884 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
23885 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
23886 * depending on whether the callback name was passed:
23889 boolean scriptTag = false;
23890 String cb = request.getParameter("callback");
23893 response.setContentType("text/javascript");
23895 response.setContentType("application/x-json");
23897 Writer out = response.getWriter();
23899 out.write(cb + "(");
23901 out.print(dataBlock.toJsonString());
23908 * @param {Object} config A configuration object.
23910 Roo.data.ScriptTagProxy = function(config){
23911 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
23912 Roo.apply(this, config);
23913 this.head = document.getElementsByTagName("head")[0];
23916 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
23918 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
23920 * @cfg {String} url The URL from which to request the data object.
23923 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
23927 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
23928 * the server the name of the callback function set up by the load call to process the returned data object.
23929 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
23930 * javascript output which calls this named function passing the data object as its only parameter.
23932 callbackParam : "callback",
23934 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
23935 * name to the request.
23940 * Load data from the configured URL, read the data object into
23941 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23942 * process that block using the passed callback.
23943 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23944 * for the request to the remote server.
23945 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23946 * object into a block of Roo.data.Records.
23947 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23948 * The function must be passed <ul>
23949 * <li>The Record block object</li>
23950 * <li>The "arg" argument from the load function</li>
23951 * <li>A boolean success indicator</li>
23953 * @param {Object} scope The scope in which to call the callback
23954 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23956 load : function(params, reader, callback, scope, arg){
23957 if(this.fireEvent("beforeload", this, params) !== false){
23959 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
23961 var url = this.url;
23962 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
23964 url += "&_dc=" + (new Date().getTime());
23966 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
23969 cb : "stcCallback"+transId,
23970 scriptId : "stcScript"+transId,
23974 callback : callback,
23980 window[trans.cb] = function(o){
23981 conn.handleResponse(o, trans);
23984 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
23986 if(this.autoAbort !== false){
23990 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
23992 var script = document.createElement("script");
23993 script.setAttribute("src", url);
23994 script.setAttribute("type", "text/javascript");
23995 script.setAttribute("id", trans.scriptId);
23996 this.head.appendChild(script);
23998 this.trans = trans;
24000 callback.call(scope||this, null, arg, false);
24005 isLoading : function(){
24006 return this.trans ? true : false;
24010 * Abort the current server request.
24012 abort : function(){
24013 if(this.isLoading()){
24014 this.destroyTrans(this.trans);
24019 destroyTrans : function(trans, isLoaded){
24020 this.head.removeChild(document.getElementById(trans.scriptId));
24021 clearTimeout(trans.timeoutId);
24023 window[trans.cb] = undefined;
24025 delete window[trans.cb];
24028 // if hasn't been loaded, wait for load to remove it to prevent script error
24029 window[trans.cb] = function(){
24030 window[trans.cb] = undefined;
24032 delete window[trans.cb];
24039 handleResponse : function(o, trans){
24040 this.trans = false;
24041 this.destroyTrans(trans, true);
24044 result = trans.reader.readRecords(o);
24046 this.fireEvent("loadexception", this, o, trans.arg, e);
24047 trans.callback.call(trans.scope||window, null, trans.arg, false);
24050 this.fireEvent("load", this, o, trans.arg);
24051 trans.callback.call(trans.scope||window, result, trans.arg, true);
24055 handleFailure : function(trans){
24056 this.trans = false;
24057 this.destroyTrans(trans, false);
24058 this.fireEvent("loadexception", this, null, trans.arg);
24059 trans.callback.call(trans.scope||window, null, trans.arg, false);
24063 * Ext JS Library 1.1.1
24064 * Copyright(c) 2006-2007, Ext JS, LLC.
24066 * Originally Released Under LGPL - original licence link has changed is not relivant.
24069 * <script type="text/javascript">
24073 * @class Roo.data.JsonReader
24074 * @extends Roo.data.DataReader
24075 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24076 * based on mappings in a provided Roo.data.Record constructor.
24078 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24079 * in the reply previously.
24084 var RecordDef = Roo.data.Record.create([
24085 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24086 {name: 'occupation'} // This field will use "occupation" as the mapping.
24088 var myReader = new Roo.data.JsonReader({
24089 totalProperty: "results", // The property which contains the total dataset size (optional)
24090 root: "rows", // The property which contains an Array of row objects
24091 id: "id" // The property within each row object that provides an ID for the record (optional)
24095 * This would consume a JSON file like this:
24097 { 'results': 2, 'rows': [
24098 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24099 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24102 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24103 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24104 * paged from the remote server.
24105 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24106 * @cfg {String} root name of the property which contains the Array of row objects.
24107 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24108 * @cfg {Array} fields Array of field definition objects
24110 * Create a new JsonReader
24111 * @param {Object} meta Metadata configuration options
24112 * @param {Object} recordType Either an Array of field definition objects,
24113 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24115 Roo.data.JsonReader = function(meta, recordType){
24118 // set some defaults:
24119 Roo.applyIf(meta, {
24120 totalProperty: 'total',
24121 successProperty : 'success',
24126 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24128 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24131 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24132 * Used by Store query builder to append _requestMeta to params.
24135 metaFromRemote : false,
24137 * This method is only used by a DataProxy which has retrieved data from a remote server.
24138 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24139 * @return {Object} data A data block which is used by an Roo.data.Store object as
24140 * a cache of Roo.data.Records.
24142 read : function(response){
24143 var json = response.responseText;
24145 var o = /* eval:var:o */ eval("("+json+")");
24147 throw {message: "JsonReader.read: Json object not found"};
24153 this.metaFromRemote = true;
24154 this.meta = o.metaData;
24155 this.recordType = Roo.data.Record.create(o.metaData.fields);
24156 this.onMetaChange(this.meta, this.recordType, o);
24158 return this.readRecords(o);
24161 // private function a store will implement
24162 onMetaChange : function(meta, recordType, o){
24169 simpleAccess: function(obj, subsc) {
24176 getJsonAccessor: function(){
24178 return function(expr) {
24180 return(re.test(expr))
24181 ? new Function("obj", "return obj." + expr)
24186 return Roo.emptyFn;
24191 * Create a data block containing Roo.data.Records from an XML document.
24192 * @param {Object} o An object which contains an Array of row objects in the property specified
24193 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24194 * which contains the total size of the dataset.
24195 * @return {Object} data A data block which is used by an Roo.data.Store object as
24196 * a cache of Roo.data.Records.
24198 readRecords : function(o){
24200 * After any data loads, the raw JSON data is available for further custom processing.
24204 var s = this.meta, Record = this.recordType,
24205 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24207 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24209 if(s.totalProperty) {
24210 this.getTotal = this.getJsonAccessor(s.totalProperty);
24212 if(s.successProperty) {
24213 this.getSuccess = this.getJsonAccessor(s.successProperty);
24215 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24217 var g = this.getJsonAccessor(s.id);
24218 this.getId = function(rec) {
24220 return (r === undefined || r === "") ? null : r;
24223 this.getId = function(){return null;};
24226 for(var jj = 0; jj < fl; jj++){
24228 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24229 this.ef[jj] = this.getJsonAccessor(map);
24233 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24234 if(s.totalProperty){
24235 var vt = parseInt(this.getTotal(o), 10);
24240 if(s.successProperty){
24241 var vs = this.getSuccess(o);
24242 if(vs === false || vs === 'false'){
24247 for(var i = 0; i < c; i++){
24250 var id = this.getId(n);
24251 for(var j = 0; j < fl; j++){
24253 var v = this.ef[j](n);
24255 Roo.log('missing convert for ' + f.name);
24259 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24261 var record = new Record(values, id);
24263 records[i] = record;
24269 totalRecords : totalRecords
24274 * Ext JS Library 1.1.1
24275 * Copyright(c) 2006-2007, Ext JS, LLC.
24277 * Originally Released Under LGPL - original licence link has changed is not relivant.
24280 * <script type="text/javascript">
24284 * @class Roo.data.XmlReader
24285 * @extends Roo.data.DataReader
24286 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24287 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24289 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24290 * header in the HTTP response must be set to "text/xml".</em>
24294 var RecordDef = Roo.data.Record.create([
24295 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24296 {name: 'occupation'} // This field will use "occupation" as the mapping.
24298 var myReader = new Roo.data.XmlReader({
24299 totalRecords: "results", // The element which contains the total dataset size (optional)
24300 record: "row", // The repeated element which contains row information
24301 id: "id" // The element within the row that provides an ID for the record (optional)
24305 * This would consume an XML file like this:
24309 <results>2</results>
24312 <name>Bill</name>
24313 <occupation>Gardener</occupation>
24317 <name>Ben</name>
24318 <occupation>Horticulturalist</occupation>
24322 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24323 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24324 * paged from the remote server.
24325 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24326 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24327 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24328 * a record identifier value.
24330 * Create a new XmlReader
24331 * @param {Object} meta Metadata configuration options
24332 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24333 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24334 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24336 Roo.data.XmlReader = function(meta, recordType){
24338 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24340 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24342 * This method is only used by a DataProxy which has retrieved data from a remote server.
24343 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24344 * to contain a method called 'responseXML' that returns an XML document object.
24345 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24346 * a cache of Roo.data.Records.
24348 read : function(response){
24349 var doc = response.responseXML;
24351 throw {message: "XmlReader.read: XML Document not available"};
24353 return this.readRecords(doc);
24357 * Create a data block containing Roo.data.Records from an XML document.
24358 * @param {Object} doc A parsed XML document.
24359 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24360 * a cache of Roo.data.Records.
24362 readRecords : function(doc){
24364 * After any data loads/reads, the raw XML Document is available for further custom processing.
24365 * @type XMLDocument
24367 this.xmlData = doc;
24368 var root = doc.documentElement || doc;
24369 var q = Roo.DomQuery;
24370 var recordType = this.recordType, fields = recordType.prototype.fields;
24371 var sid = this.meta.id;
24372 var totalRecords = 0, success = true;
24373 if(this.meta.totalRecords){
24374 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24377 if(this.meta.success){
24378 var sv = q.selectValue(this.meta.success, root, true);
24379 success = sv !== false && sv !== 'false';
24382 var ns = q.select(this.meta.record, root);
24383 for(var i = 0, len = ns.length; i < len; i++) {
24386 var id = sid ? q.selectValue(sid, n) : undefined;
24387 for(var j = 0, jlen = fields.length; j < jlen; j++){
24388 var f = fields.items[j];
24389 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24391 values[f.name] = v;
24393 var record = new recordType(values, id);
24395 records[records.length] = record;
24401 totalRecords : totalRecords || records.length
24406 * Ext JS Library 1.1.1
24407 * Copyright(c) 2006-2007, Ext JS, LLC.
24409 * Originally Released Under LGPL - original licence link has changed is not relivant.
24412 * <script type="text/javascript">
24416 * @class Roo.data.ArrayReader
24417 * @extends Roo.data.DataReader
24418 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24419 * Each element of that Array represents a row of data fields. The
24420 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24421 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24425 var RecordDef = Roo.data.Record.create([
24426 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24427 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24429 var myReader = new Roo.data.ArrayReader({
24430 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24434 * This would consume an Array like this:
24436 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24438 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24440 * Create a new JsonReader
24441 * @param {Object} meta Metadata configuration options.
24442 * @param {Object} recordType Either an Array of field definition objects
24443 * as specified to {@link Roo.data.Record#create},
24444 * or an {@link Roo.data.Record} object
24445 * created using {@link Roo.data.Record#create}.
24447 Roo.data.ArrayReader = function(meta, recordType){
24448 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24451 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24453 * Create a data block containing Roo.data.Records from an XML document.
24454 * @param {Object} o An Array of row objects which represents the dataset.
24455 * @return {Object} data A data block which is used by an Roo.data.Store object as
24456 * a cache of Roo.data.Records.
24458 readRecords : function(o){
24459 var sid = this.meta ? this.meta.id : null;
24460 var recordType = this.recordType, fields = recordType.prototype.fields;
24463 for(var i = 0; i < root.length; i++){
24466 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24467 for(var j = 0, jlen = fields.length; j < jlen; j++){
24468 var f = fields.items[j];
24469 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24470 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24472 values[f.name] = v;
24474 var record = new recordType(values, id);
24476 records[records.length] = record;
24480 totalRecords : records.length
24485 * Ext JS Library 1.1.1
24486 * Copyright(c) 2006-2007, Ext JS, LLC.
24488 * Originally Released Under LGPL - original licence link has changed is not relivant.
24491 * <script type="text/javascript">
24496 * @class Roo.data.Tree
24497 * @extends Roo.util.Observable
24498 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24499 * in the tree have most standard DOM functionality.
24501 * @param {Node} root (optional) The root node
24503 Roo.data.Tree = function(root){
24504 this.nodeHash = {};
24506 * The root node for this tree
24511 this.setRootNode(root);
24516 * Fires when a new child node is appended to a node in this tree.
24517 * @param {Tree} tree The owner tree
24518 * @param {Node} parent The parent node
24519 * @param {Node} node The newly appended node
24520 * @param {Number} index The index of the newly appended node
24525 * Fires when a child node is removed from a node in this tree.
24526 * @param {Tree} tree The owner tree
24527 * @param {Node} parent The parent node
24528 * @param {Node} node The child node removed
24533 * Fires when a node is moved to a new location in the tree
24534 * @param {Tree} tree The owner tree
24535 * @param {Node} node The node moved
24536 * @param {Node} oldParent The old parent of this node
24537 * @param {Node} newParent The new parent of this node
24538 * @param {Number} index The index it was moved to
24543 * Fires when a new child node is inserted in a node in this tree.
24544 * @param {Tree} tree The owner tree
24545 * @param {Node} parent The parent node
24546 * @param {Node} node The child node inserted
24547 * @param {Node} refNode The child node the node was inserted before
24551 * @event beforeappend
24552 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24553 * @param {Tree} tree The owner tree
24554 * @param {Node} parent The parent node
24555 * @param {Node} node The child node to be appended
24557 "beforeappend" : true,
24559 * @event beforeremove
24560 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24561 * @param {Tree} tree The owner tree
24562 * @param {Node} parent The parent node
24563 * @param {Node} node The child node to be removed
24565 "beforeremove" : true,
24567 * @event beforemove
24568 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24569 * @param {Tree} tree The owner tree
24570 * @param {Node} node The node being moved
24571 * @param {Node} oldParent The parent of the node
24572 * @param {Node} newParent The new parent the node is moving to
24573 * @param {Number} index The index it is being moved to
24575 "beforemove" : true,
24577 * @event beforeinsert
24578 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24579 * @param {Tree} tree The owner tree
24580 * @param {Node} parent The parent node
24581 * @param {Node} node The child node to be inserted
24582 * @param {Node} refNode The child node the node is being inserted before
24584 "beforeinsert" : true
24587 Roo.data.Tree.superclass.constructor.call(this);
24590 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24591 pathSeparator: "/",
24593 proxyNodeEvent : function(){
24594 return this.fireEvent.apply(this, arguments);
24598 * Returns the root node for this tree.
24601 getRootNode : function(){
24606 * Sets the root node for this tree.
24607 * @param {Node} node
24610 setRootNode : function(node){
24612 node.ownerTree = this;
24613 node.isRoot = true;
24614 this.registerNode(node);
24619 * Gets a node in this tree by its id.
24620 * @param {String} id
24623 getNodeById : function(id){
24624 return this.nodeHash[id];
24627 registerNode : function(node){
24628 this.nodeHash[node.id] = node;
24631 unregisterNode : function(node){
24632 delete this.nodeHash[node.id];
24635 toString : function(){
24636 return "[Tree"+(this.id?" "+this.id:"")+"]";
24641 * @class Roo.data.Node
24642 * @extends Roo.util.Observable
24643 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24644 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24646 * @param {Object} attributes The attributes/config for the node
24648 Roo.data.Node = function(attributes){
24650 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24653 this.attributes = attributes || {};
24654 this.leaf = this.attributes.leaf;
24656 * The node id. @type String
24658 this.id = this.attributes.id;
24660 this.id = Roo.id(null, "ynode-");
24661 this.attributes.id = this.id;
24666 * All child nodes of this node. @type Array
24668 this.childNodes = [];
24669 if(!this.childNodes.indexOf){ // indexOf is a must
24670 this.childNodes.indexOf = function(o){
24671 for(var i = 0, len = this.length; i < len; i++){
24680 * The parent node for this node. @type Node
24682 this.parentNode = null;
24684 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24686 this.firstChild = null;
24688 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24690 this.lastChild = null;
24692 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24694 this.previousSibling = null;
24696 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24698 this.nextSibling = null;
24703 * Fires when a new child node is appended
24704 * @param {Tree} tree The owner tree
24705 * @param {Node} this This node
24706 * @param {Node} node The newly appended node
24707 * @param {Number} index The index of the newly appended node
24712 * Fires when a child node is removed
24713 * @param {Tree} tree The owner tree
24714 * @param {Node} this This node
24715 * @param {Node} node The removed node
24720 * Fires when this node is moved to a new location in the tree
24721 * @param {Tree} tree The owner tree
24722 * @param {Node} this This node
24723 * @param {Node} oldParent The old parent of this node
24724 * @param {Node} newParent The new parent of this node
24725 * @param {Number} index The index it was moved to
24730 * Fires when a new child node is inserted.
24731 * @param {Tree} tree The owner tree
24732 * @param {Node} this This node
24733 * @param {Node} node The child node inserted
24734 * @param {Node} refNode The child node the node was inserted before
24738 * @event beforeappend
24739 * Fires before a new child is appended, return false to cancel the append.
24740 * @param {Tree} tree The owner tree
24741 * @param {Node} this This node
24742 * @param {Node} node The child node to be appended
24744 "beforeappend" : true,
24746 * @event beforeremove
24747 * Fires before a child is removed, return false to cancel the remove.
24748 * @param {Tree} tree The owner tree
24749 * @param {Node} this This node
24750 * @param {Node} node The child node to be removed
24752 "beforeremove" : true,
24754 * @event beforemove
24755 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24756 * @param {Tree} tree The owner tree
24757 * @param {Node} this This node
24758 * @param {Node} oldParent The parent of this node
24759 * @param {Node} newParent The new parent this node is moving to
24760 * @param {Number} index The index it is being moved to
24762 "beforemove" : true,
24764 * @event beforeinsert
24765 * Fires before a new child is inserted, return false to cancel the insert.
24766 * @param {Tree} tree The owner tree
24767 * @param {Node} this This node
24768 * @param {Node} node The child node to be inserted
24769 * @param {Node} refNode The child node the node is being inserted before
24771 "beforeinsert" : true
24773 this.listeners = this.attributes.listeners;
24774 Roo.data.Node.superclass.constructor.call(this);
24777 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24778 fireEvent : function(evtName){
24779 // first do standard event for this node
24780 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24783 // then bubble it up to the tree if the event wasn't cancelled
24784 var ot = this.getOwnerTree();
24786 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24794 * Returns true if this node is a leaf
24795 * @return {Boolean}
24797 isLeaf : function(){
24798 return this.leaf === true;
24802 setFirstChild : function(node){
24803 this.firstChild = node;
24807 setLastChild : function(node){
24808 this.lastChild = node;
24813 * Returns true if this node is the last child of its parent
24814 * @return {Boolean}
24816 isLast : function(){
24817 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24821 * Returns true if this node is the first child of its parent
24822 * @return {Boolean}
24824 isFirst : function(){
24825 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24828 hasChildNodes : function(){
24829 return !this.isLeaf() && this.childNodes.length > 0;
24833 * Insert node(s) as the last child node of this node.
24834 * @param {Node/Array} node The node or Array of nodes to append
24835 * @return {Node} The appended node if single append, or null if an array was passed
24837 appendChild : function(node){
24839 if(node instanceof Array){
24841 }else if(arguments.length > 1){
24844 // if passed an array or multiple args do them one by one
24846 for(var i = 0, len = multi.length; i < len; i++) {
24847 this.appendChild(multi[i]);
24850 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
24853 var index = this.childNodes.length;
24854 var oldParent = node.parentNode;
24855 // it's a move, make sure we move it cleanly
24857 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
24860 oldParent.removeChild(node);
24862 index = this.childNodes.length;
24864 this.setFirstChild(node);
24866 this.childNodes.push(node);
24867 node.parentNode = this;
24868 var ps = this.childNodes[index-1];
24870 node.previousSibling = ps;
24871 ps.nextSibling = node;
24873 node.previousSibling = null;
24875 node.nextSibling = null;
24876 this.setLastChild(node);
24877 node.setOwnerTree(this.getOwnerTree());
24878 this.fireEvent("append", this.ownerTree, this, node, index);
24880 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
24887 * Removes a child node from this node.
24888 * @param {Node} node The node to remove
24889 * @return {Node} The removed node
24891 removeChild : function(node){
24892 var index = this.childNodes.indexOf(node);
24896 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
24900 // remove it from childNodes collection
24901 this.childNodes.splice(index, 1);
24904 if(node.previousSibling){
24905 node.previousSibling.nextSibling = node.nextSibling;
24907 if(node.nextSibling){
24908 node.nextSibling.previousSibling = node.previousSibling;
24911 // update child refs
24912 if(this.firstChild == node){
24913 this.setFirstChild(node.nextSibling);
24915 if(this.lastChild == node){
24916 this.setLastChild(node.previousSibling);
24919 node.setOwnerTree(null);
24920 // clear any references from the node
24921 node.parentNode = null;
24922 node.previousSibling = null;
24923 node.nextSibling = null;
24924 this.fireEvent("remove", this.ownerTree, this, node);
24929 * Inserts the first node before the second node in this nodes childNodes collection.
24930 * @param {Node} node The node to insert
24931 * @param {Node} refNode The node to insert before (if null the node is appended)
24932 * @return {Node} The inserted node
24934 insertBefore : function(node, refNode){
24935 if(!refNode){ // like standard Dom, refNode can be null for append
24936 return this.appendChild(node);
24939 if(node == refNode){
24943 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
24946 var index = this.childNodes.indexOf(refNode);
24947 var oldParent = node.parentNode;
24948 var refIndex = index;
24950 // when moving internally, indexes will change after remove
24951 if(oldParent == this && this.childNodes.indexOf(node) < index){
24955 // it's a move, make sure we move it cleanly
24957 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
24960 oldParent.removeChild(node);
24963 this.setFirstChild(node);
24965 this.childNodes.splice(refIndex, 0, node);
24966 node.parentNode = this;
24967 var ps = this.childNodes[refIndex-1];
24969 node.previousSibling = ps;
24970 ps.nextSibling = node;
24972 node.previousSibling = null;
24974 node.nextSibling = refNode;
24975 refNode.previousSibling = node;
24976 node.setOwnerTree(this.getOwnerTree());
24977 this.fireEvent("insert", this.ownerTree, this, node, refNode);
24979 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
24985 * Returns the child node at the specified index.
24986 * @param {Number} index
24989 item : function(index){
24990 return this.childNodes[index];
24994 * Replaces one child node in this node with another.
24995 * @param {Node} newChild The replacement node
24996 * @param {Node} oldChild The node to replace
24997 * @return {Node} The replaced node
24999 replaceChild : function(newChild, oldChild){
25000 this.insertBefore(newChild, oldChild);
25001 this.removeChild(oldChild);
25006 * Returns the index of a child node
25007 * @param {Node} node
25008 * @return {Number} The index of the node or -1 if it was not found
25010 indexOf : function(child){
25011 return this.childNodes.indexOf(child);
25015 * Returns the tree this node is in.
25018 getOwnerTree : function(){
25019 // if it doesn't have one, look for one
25020 if(!this.ownerTree){
25024 this.ownerTree = p.ownerTree;
25030 return this.ownerTree;
25034 * Returns depth of this node (the root node has a depth of 0)
25037 getDepth : function(){
25040 while(p.parentNode){
25048 setOwnerTree : function(tree){
25049 // if it's move, we need to update everyone
25050 if(tree != this.ownerTree){
25051 if(this.ownerTree){
25052 this.ownerTree.unregisterNode(this);
25054 this.ownerTree = tree;
25055 var cs = this.childNodes;
25056 for(var i = 0, len = cs.length; i < len; i++) {
25057 cs[i].setOwnerTree(tree);
25060 tree.registerNode(this);
25066 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25067 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25068 * @return {String} The path
25070 getPath : function(attr){
25071 attr = attr || "id";
25072 var p = this.parentNode;
25073 var b = [this.attributes[attr]];
25075 b.unshift(p.attributes[attr]);
25078 var sep = this.getOwnerTree().pathSeparator;
25079 return sep + b.join(sep);
25083 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25084 * function call will be the scope provided or the current node. The arguments to the function
25085 * will be the args provided or the current node. If the function returns false at any point,
25086 * the bubble is stopped.
25087 * @param {Function} fn The function to call
25088 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25089 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25091 bubble : function(fn, scope, args){
25094 if(fn.call(scope || p, args || p) === false){
25102 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25103 * function call will be the scope provided or the current node. The arguments to the function
25104 * will be the args provided or the current node. If the function returns false at any point,
25105 * the cascade is stopped on that branch.
25106 * @param {Function} fn The function to call
25107 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25108 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25110 cascade : function(fn, scope, args){
25111 if(fn.call(scope || this, args || this) !== false){
25112 var cs = this.childNodes;
25113 for(var i = 0, len = cs.length; i < len; i++) {
25114 cs[i].cascade(fn, scope, args);
25120 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25121 * function call will be the scope provided or the current node. The arguments to the function
25122 * will be the args provided or the current node. If the function returns false at any point,
25123 * the iteration stops.
25124 * @param {Function} fn The function to call
25125 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25126 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25128 eachChild : function(fn, scope, args){
25129 var cs = this.childNodes;
25130 for(var i = 0, len = cs.length; i < len; i++) {
25131 if(fn.call(scope || this, args || cs[i]) === false){
25138 * Finds the first child that has the attribute with the specified value.
25139 * @param {String} attribute The attribute name
25140 * @param {Mixed} value The value to search for
25141 * @return {Node} The found child or null if none was found
25143 findChild : function(attribute, value){
25144 var cs = this.childNodes;
25145 for(var i = 0, len = cs.length; i < len; i++) {
25146 if(cs[i].attributes[attribute] == value){
25154 * Finds the first child by a custom function. The child matches if the function passed
25156 * @param {Function} fn
25157 * @param {Object} scope (optional)
25158 * @return {Node} The found child or null if none was found
25160 findChildBy : function(fn, scope){
25161 var cs = this.childNodes;
25162 for(var i = 0, len = cs.length; i < len; i++) {
25163 if(fn.call(scope||cs[i], cs[i]) === true){
25171 * Sorts this nodes children using the supplied sort function
25172 * @param {Function} fn
25173 * @param {Object} scope (optional)
25175 sort : function(fn, scope){
25176 var cs = this.childNodes;
25177 var len = cs.length;
25179 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25181 for(var i = 0; i < len; i++){
25183 n.previousSibling = cs[i-1];
25184 n.nextSibling = cs[i+1];
25186 this.setFirstChild(n);
25189 this.setLastChild(n);
25196 * Returns true if this node is an ancestor (at any point) of the passed node.
25197 * @param {Node} node
25198 * @return {Boolean}
25200 contains : function(node){
25201 return node.isAncestor(this);
25205 * Returns true if the passed node is an ancestor (at any point) of this node.
25206 * @param {Node} node
25207 * @return {Boolean}
25209 isAncestor : function(node){
25210 var p = this.parentNode;
25220 toString : function(){
25221 return "[Node"+(this.id?" "+this.id:"")+"]";
25225 * Ext JS Library 1.1.1
25226 * Copyright(c) 2006-2007, Ext JS, LLC.
25228 * Originally Released Under LGPL - original licence link has changed is not relivant.
25231 * <script type="text/javascript">
25236 * @extends Roo.Element
25237 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25238 * automatic maintaining of shadow/shim positions.
25239 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25240 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25241 * you can pass a string with a CSS class name. False turns off the shadow.
25242 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25243 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25244 * @cfg {String} cls CSS class to add to the element
25245 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25246 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25248 * @param {Object} config An object with config options.
25249 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25252 Roo.Layer = function(config, existingEl){
25253 config = config || {};
25254 var dh = Roo.DomHelper;
25255 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25257 this.dom = Roo.getDom(existingEl);
25260 var o = config.dh || {tag: "div", cls: "x-layer"};
25261 this.dom = dh.append(pel, o);
25264 this.addClass(config.cls);
25266 this.constrain = config.constrain !== false;
25267 this.visibilityMode = Roo.Element.VISIBILITY;
25269 this.id = this.dom.id = config.id;
25271 this.id = Roo.id(this.dom);
25273 this.zindex = config.zindex || this.getZIndex();
25274 this.position("absolute", this.zindex);
25276 this.shadowOffset = config.shadowOffset || 4;
25277 this.shadow = new Roo.Shadow({
25278 offset : this.shadowOffset,
25279 mode : config.shadow
25282 this.shadowOffset = 0;
25284 this.useShim = config.shim !== false && Roo.useShims;
25285 this.useDisplay = config.useDisplay;
25289 var supr = Roo.Element.prototype;
25291 // shims are shared among layer to keep from having 100 iframes
25294 Roo.extend(Roo.Layer, Roo.Element, {
25296 getZIndex : function(){
25297 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25300 getShim : function(){
25307 var shim = shims.shift();
25309 shim = this.createShim();
25310 shim.enableDisplayMode('block');
25311 shim.dom.style.display = 'none';
25312 shim.dom.style.visibility = 'visible';
25314 var pn = this.dom.parentNode;
25315 if(shim.dom.parentNode != pn){
25316 pn.insertBefore(shim.dom, this.dom);
25318 shim.setStyle('z-index', this.getZIndex()-2);
25323 hideShim : function(){
25325 this.shim.setDisplayed(false);
25326 shims.push(this.shim);
25331 disableShadow : function(){
25333 this.shadowDisabled = true;
25334 this.shadow.hide();
25335 this.lastShadowOffset = this.shadowOffset;
25336 this.shadowOffset = 0;
25340 enableShadow : function(show){
25342 this.shadowDisabled = false;
25343 this.shadowOffset = this.lastShadowOffset;
25344 delete this.lastShadowOffset;
25352 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25353 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25354 sync : function(doShow){
25355 var sw = this.shadow;
25356 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25357 var sh = this.getShim();
25359 var w = this.getWidth(),
25360 h = this.getHeight();
25362 var l = this.getLeft(true),
25363 t = this.getTop(true);
25365 if(sw && !this.shadowDisabled){
25366 if(doShow && !sw.isVisible()){
25369 sw.realign(l, t, w, h);
25375 // fit the shim behind the shadow, so it is shimmed too
25376 var a = sw.adjusts, s = sh.dom.style;
25377 s.left = (Math.min(l, l+a.l))+"px";
25378 s.top = (Math.min(t, t+a.t))+"px";
25379 s.width = (w+a.w)+"px";
25380 s.height = (h+a.h)+"px";
25387 sh.setLeftTop(l, t);
25394 destroy : function(){
25397 this.shadow.hide();
25399 this.removeAllListeners();
25400 var pn = this.dom.parentNode;
25402 pn.removeChild(this.dom);
25404 Roo.Element.uncache(this.id);
25407 remove : function(){
25412 beginUpdate : function(){
25413 this.updating = true;
25417 endUpdate : function(){
25418 this.updating = false;
25423 hideUnders : function(negOffset){
25425 this.shadow.hide();
25431 constrainXY : function(){
25432 if(this.constrain){
25433 var vw = Roo.lib.Dom.getViewWidth(),
25434 vh = Roo.lib.Dom.getViewHeight();
25435 var s = Roo.get(document).getScroll();
25437 var xy = this.getXY();
25438 var x = xy[0], y = xy[1];
25439 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25440 // only move it if it needs it
25442 // first validate right/bottom
25443 if((x + w) > vw+s.left){
25444 x = vw - w - this.shadowOffset;
25447 if((y + h) > vh+s.top){
25448 y = vh - h - this.shadowOffset;
25451 // then make sure top/left isn't negative
25462 var ay = this.avoidY;
25463 if(y <= ay && (y+h) >= ay){
25469 supr.setXY.call(this, xy);
25475 isVisible : function(){
25476 return this.visible;
25480 showAction : function(){
25481 this.visible = true; // track visibility to prevent getStyle calls
25482 if(this.useDisplay === true){
25483 this.setDisplayed("");
25484 }else if(this.lastXY){
25485 supr.setXY.call(this, this.lastXY);
25486 }else if(this.lastLT){
25487 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25492 hideAction : function(){
25493 this.visible = false;
25494 if(this.useDisplay === true){
25495 this.setDisplayed(false);
25497 this.setLeftTop(-10000,-10000);
25501 // overridden Element method
25502 setVisible : function(v, a, d, c, e){
25507 var cb = function(){
25512 }.createDelegate(this);
25513 supr.setVisible.call(this, true, true, d, cb, e);
25516 this.hideUnders(true);
25525 }.createDelegate(this);
25527 supr.setVisible.call(this, v, a, d, cb, e);
25536 storeXY : function(xy){
25537 delete this.lastLT;
25541 storeLeftTop : function(left, top){
25542 delete this.lastXY;
25543 this.lastLT = [left, top];
25547 beforeFx : function(){
25548 this.beforeAction();
25549 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25553 afterFx : function(){
25554 Roo.Layer.superclass.afterFx.apply(this, arguments);
25555 this.sync(this.isVisible());
25559 beforeAction : function(){
25560 if(!this.updating && this.shadow){
25561 this.shadow.hide();
25565 // overridden Element method
25566 setLeft : function(left){
25567 this.storeLeftTop(left, this.getTop(true));
25568 supr.setLeft.apply(this, arguments);
25572 setTop : function(top){
25573 this.storeLeftTop(this.getLeft(true), top);
25574 supr.setTop.apply(this, arguments);
25578 setLeftTop : function(left, top){
25579 this.storeLeftTop(left, top);
25580 supr.setLeftTop.apply(this, arguments);
25584 setXY : function(xy, a, d, c, e){
25586 this.beforeAction();
25588 var cb = this.createCB(c);
25589 supr.setXY.call(this, xy, a, d, cb, e);
25596 createCB : function(c){
25607 // overridden Element method
25608 setX : function(x, a, d, c, e){
25609 this.setXY([x, this.getY()], a, d, c, e);
25612 // overridden Element method
25613 setY : function(y, a, d, c, e){
25614 this.setXY([this.getX(), y], a, d, c, e);
25617 // overridden Element method
25618 setSize : function(w, h, a, d, c, e){
25619 this.beforeAction();
25620 var cb = this.createCB(c);
25621 supr.setSize.call(this, w, h, a, d, cb, e);
25627 // overridden Element method
25628 setWidth : function(w, a, d, c, e){
25629 this.beforeAction();
25630 var cb = this.createCB(c);
25631 supr.setWidth.call(this, w, a, d, cb, e);
25637 // overridden Element method
25638 setHeight : function(h, a, d, c, e){
25639 this.beforeAction();
25640 var cb = this.createCB(c);
25641 supr.setHeight.call(this, h, a, d, cb, e);
25647 // overridden Element method
25648 setBounds : function(x, y, w, h, a, d, c, e){
25649 this.beforeAction();
25650 var cb = this.createCB(c);
25652 this.storeXY([x, y]);
25653 supr.setXY.call(this, [x, y]);
25654 supr.setSize.call(this, w, h, a, d, cb, e);
25657 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25663 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25664 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25665 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25666 * @param {Number} zindex The new z-index to set
25667 * @return {this} The Layer
25669 setZIndex : function(zindex){
25670 this.zindex = zindex;
25671 this.setStyle("z-index", zindex + 2);
25673 this.shadow.setZIndex(zindex + 1);
25676 this.shim.setStyle("z-index", zindex);
25682 * Ext JS Library 1.1.1
25683 * Copyright(c) 2006-2007, Ext JS, LLC.
25685 * Originally Released Under LGPL - original licence link has changed is not relivant.
25688 * <script type="text/javascript">
25693 * @class Roo.Shadow
25694 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25695 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25696 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25698 * Create a new Shadow
25699 * @param {Object} config The config object
25701 Roo.Shadow = function(config){
25702 Roo.apply(this, config);
25703 if(typeof this.mode != "string"){
25704 this.mode = this.defaultMode;
25706 var o = this.offset, a = {h: 0};
25707 var rad = Math.floor(this.offset/2);
25708 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25714 a.l -= this.offset + rad;
25715 a.t -= this.offset + rad;
25726 a.l -= (this.offset - rad);
25727 a.t -= this.offset + rad;
25729 a.w -= (this.offset - rad)*2;
25740 a.l -= (this.offset - rad);
25741 a.t -= (this.offset - rad);
25743 a.w -= (this.offset + rad + 1);
25744 a.h -= (this.offset + rad);
25753 Roo.Shadow.prototype = {
25755 * @cfg {String} mode
25756 * The shadow display mode. Supports the following options:<br />
25757 * sides: Shadow displays on both sides and bottom only<br />
25758 * frame: Shadow displays equally on all four sides<br />
25759 * drop: Traditional bottom-right drop shadow (default)
25762 * @cfg {String} offset
25763 * The number of pixels to offset the shadow from the element (defaults to 4)
25768 defaultMode: "drop",
25771 * Displays the shadow under the target element
25772 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25774 show : function(target){
25775 target = Roo.get(target);
25777 this.el = Roo.Shadow.Pool.pull();
25778 if(this.el.dom.nextSibling != target.dom){
25779 this.el.insertBefore(target);
25782 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25784 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25787 target.getLeft(true),
25788 target.getTop(true),
25792 this.el.dom.style.display = "block";
25796 * Returns true if the shadow is visible, else false
25798 isVisible : function(){
25799 return this.el ? true : false;
25803 * Direct alignment when values are already available. Show must be called at least once before
25804 * calling this method to ensure it is initialized.
25805 * @param {Number} left The target element left position
25806 * @param {Number} top The target element top position
25807 * @param {Number} width The target element width
25808 * @param {Number} height The target element height
25810 realign : function(l, t, w, h){
25814 var a = this.adjusts, d = this.el.dom, s = d.style;
25816 s.left = (l+a.l)+"px";
25817 s.top = (t+a.t)+"px";
25818 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25820 if(s.width != sws || s.height != shs){
25824 var cn = d.childNodes;
25825 var sww = Math.max(0, (sw-12))+"px";
25826 cn[0].childNodes[1].style.width = sww;
25827 cn[1].childNodes[1].style.width = sww;
25828 cn[2].childNodes[1].style.width = sww;
25829 cn[1].style.height = Math.max(0, (sh-12))+"px";
25835 * Hides this shadow
25839 this.el.dom.style.display = "none";
25840 Roo.Shadow.Pool.push(this.el);
25846 * Adjust the z-index of this shadow
25847 * @param {Number} zindex The new z-index
25849 setZIndex : function(z){
25852 this.el.setStyle("z-index", z);
25857 // Private utility class that manages the internal Shadow cache
25858 Roo.Shadow.Pool = function(){
25860 var markup = Roo.isIE ?
25861 '<div class="x-ie-shadow"></div>' :
25862 '<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>';
25865 var sh = p.shift();
25867 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
25868 sh.autoBoxAdjust = false;
25873 push : function(sh){
25879 * Ext JS Library 1.1.1
25880 * Copyright(c) 2006-2007, Ext JS, LLC.
25882 * Originally Released Under LGPL - original licence link has changed is not relivant.
25885 * <script type="text/javascript">
25890 * @class Roo.SplitBar
25891 * @extends Roo.util.Observable
25892 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
25896 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
25897 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
25898 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
25899 split.minSize = 100;
25900 split.maxSize = 600;
25901 split.animate = true;
25902 split.on('moved', splitterMoved);
25905 * Create a new SplitBar
25906 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
25907 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
25908 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25909 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
25910 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
25911 position of the SplitBar).
25913 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
25916 this.el = Roo.get(dragElement, true);
25917 this.el.dom.unselectable = "on";
25919 this.resizingEl = Roo.get(resizingElement, true);
25923 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25924 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
25927 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
25930 * The minimum size of the resizing element. (Defaults to 0)
25936 * The maximum size of the resizing element. (Defaults to 2000)
25939 this.maxSize = 2000;
25942 * Whether to animate the transition to the new size
25945 this.animate = false;
25948 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
25951 this.useShim = false;
25956 if(!existingProxy){
25958 this.proxy = Roo.SplitBar.createProxy(this.orientation);
25960 this.proxy = Roo.get(existingProxy).dom;
25963 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
25966 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
25969 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
25972 this.dragSpecs = {};
25975 * @private The adapter to use to positon and resize elements
25977 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
25978 this.adapter.init(this);
25980 if(this.orientation == Roo.SplitBar.HORIZONTAL){
25982 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
25983 this.el.addClass("x-splitbar-h");
25986 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
25987 this.el.addClass("x-splitbar-v");
25993 * Fires when the splitter is moved (alias for {@link #event-moved})
25994 * @param {Roo.SplitBar} this
25995 * @param {Number} newSize the new width or height
26000 * Fires when the splitter is moved
26001 * @param {Roo.SplitBar} this
26002 * @param {Number} newSize the new width or height
26006 * @event beforeresize
26007 * Fires before the splitter is dragged
26008 * @param {Roo.SplitBar} this
26010 "beforeresize" : true,
26012 "beforeapply" : true
26015 Roo.util.Observable.call(this);
26018 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26019 onStartProxyDrag : function(x, y){
26020 this.fireEvent("beforeresize", this);
26022 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26024 o.enableDisplayMode("block");
26025 // all splitbars share the same overlay
26026 Roo.SplitBar.prototype.overlay = o;
26028 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26029 this.overlay.show();
26030 Roo.get(this.proxy).setDisplayed("block");
26031 var size = this.adapter.getElementSize(this);
26032 this.activeMinSize = this.getMinimumSize();;
26033 this.activeMaxSize = this.getMaximumSize();;
26034 var c1 = size - this.activeMinSize;
26035 var c2 = Math.max(this.activeMaxSize - size, 0);
26036 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26037 this.dd.resetConstraints();
26038 this.dd.setXConstraint(
26039 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26040 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26042 this.dd.setYConstraint(0, 0);
26044 this.dd.resetConstraints();
26045 this.dd.setXConstraint(0, 0);
26046 this.dd.setYConstraint(
26047 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26048 this.placement == Roo.SplitBar.TOP ? c2 : c1
26051 this.dragSpecs.startSize = size;
26052 this.dragSpecs.startPoint = [x, y];
26053 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26057 * @private Called after the drag operation by the DDProxy
26059 onEndProxyDrag : function(e){
26060 Roo.get(this.proxy).setDisplayed(false);
26061 var endPoint = Roo.lib.Event.getXY(e);
26063 this.overlay.hide();
26066 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26067 newSize = this.dragSpecs.startSize +
26068 (this.placement == Roo.SplitBar.LEFT ?
26069 endPoint[0] - this.dragSpecs.startPoint[0] :
26070 this.dragSpecs.startPoint[0] - endPoint[0]
26073 newSize = this.dragSpecs.startSize +
26074 (this.placement == Roo.SplitBar.TOP ?
26075 endPoint[1] - this.dragSpecs.startPoint[1] :
26076 this.dragSpecs.startPoint[1] - endPoint[1]
26079 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26080 if(newSize != this.dragSpecs.startSize){
26081 if(this.fireEvent('beforeapply', this, newSize) !== false){
26082 this.adapter.setElementSize(this, newSize);
26083 this.fireEvent("moved", this, newSize);
26084 this.fireEvent("resize", this, newSize);
26090 * Get the adapter this SplitBar uses
26091 * @return The adapter object
26093 getAdapter : function(){
26094 return this.adapter;
26098 * Set the adapter this SplitBar uses
26099 * @param {Object} adapter A SplitBar adapter object
26101 setAdapter : function(adapter){
26102 this.adapter = adapter;
26103 this.adapter.init(this);
26107 * Gets the minimum size for the resizing element
26108 * @return {Number} The minimum size
26110 getMinimumSize : function(){
26111 return this.minSize;
26115 * Sets the minimum size for the resizing element
26116 * @param {Number} minSize The minimum size
26118 setMinimumSize : function(minSize){
26119 this.minSize = minSize;
26123 * Gets the maximum size for the resizing element
26124 * @return {Number} The maximum size
26126 getMaximumSize : function(){
26127 return this.maxSize;
26131 * Sets the maximum size for the resizing element
26132 * @param {Number} maxSize The maximum size
26134 setMaximumSize : function(maxSize){
26135 this.maxSize = maxSize;
26139 * Sets the initialize size for the resizing element
26140 * @param {Number} size The initial size
26142 setCurrentSize : function(size){
26143 var oldAnimate = this.animate;
26144 this.animate = false;
26145 this.adapter.setElementSize(this, size);
26146 this.animate = oldAnimate;
26150 * Destroy this splitbar.
26151 * @param {Boolean} removeEl True to remove the element
26153 destroy : function(removeEl){
26155 this.shim.remove();
26158 this.proxy.parentNode.removeChild(this.proxy);
26166 * @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.
26168 Roo.SplitBar.createProxy = function(dir){
26169 var proxy = new Roo.Element(document.createElement("div"));
26170 proxy.unselectable();
26171 var cls = 'x-splitbar-proxy';
26172 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26173 document.body.appendChild(proxy.dom);
26178 * @class Roo.SplitBar.BasicLayoutAdapter
26179 * Default Adapter. It assumes the splitter and resizing element are not positioned
26180 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26182 Roo.SplitBar.BasicLayoutAdapter = function(){
26185 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26186 // do nothing for now
26187 init : function(s){
26191 * Called before drag operations to get the current size of the resizing element.
26192 * @param {Roo.SplitBar} s The SplitBar using this adapter
26194 getElementSize : function(s){
26195 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26196 return s.resizingEl.getWidth();
26198 return s.resizingEl.getHeight();
26203 * Called after drag operations to set the size of the resizing element.
26204 * @param {Roo.SplitBar} s The SplitBar using this adapter
26205 * @param {Number} newSize The new size to set
26206 * @param {Function} onComplete A function to be invoked when resizing is complete
26208 setElementSize : function(s, newSize, onComplete){
26209 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26211 s.resizingEl.setWidth(newSize);
26213 onComplete(s, newSize);
26216 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26221 s.resizingEl.setHeight(newSize);
26223 onComplete(s, newSize);
26226 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26233 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26234 * @extends Roo.SplitBar.BasicLayoutAdapter
26235 * Adapter that moves the splitter element to align with the resized sizing element.
26236 * Used with an absolute positioned SplitBar.
26237 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26238 * document.body, make sure you assign an id to the body element.
26240 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26241 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26242 this.container = Roo.get(container);
26245 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26246 init : function(s){
26247 this.basic.init(s);
26250 getElementSize : function(s){
26251 return this.basic.getElementSize(s);
26254 setElementSize : function(s, newSize, onComplete){
26255 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26258 moveSplitter : function(s){
26259 var yes = Roo.SplitBar;
26260 switch(s.placement){
26262 s.el.setX(s.resizingEl.getRight());
26265 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26268 s.el.setY(s.resizingEl.getBottom());
26271 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26278 * Orientation constant - Create a vertical SplitBar
26282 Roo.SplitBar.VERTICAL = 1;
26285 * Orientation constant - Create a horizontal SplitBar
26289 Roo.SplitBar.HORIZONTAL = 2;
26292 * Placement constant - The resizing element is to the left of the splitter element
26296 Roo.SplitBar.LEFT = 1;
26299 * Placement constant - The resizing element is to the right of the splitter element
26303 Roo.SplitBar.RIGHT = 2;
26306 * Placement constant - The resizing element is positioned above the splitter element
26310 Roo.SplitBar.TOP = 3;
26313 * Placement constant - The resizing element is positioned under splitter element
26317 Roo.SplitBar.BOTTOM = 4;
26320 * Ext JS Library 1.1.1
26321 * Copyright(c) 2006-2007, Ext JS, LLC.
26323 * Originally Released Under LGPL - original licence link has changed is not relivant.
26326 * <script type="text/javascript">
26331 * @extends Roo.util.Observable
26332 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26333 * This class also supports single and multi selection modes. <br>
26334 * Create a data model bound view:
26336 var store = new Roo.data.Store(...);
26338 var view = new Roo.View({
26340 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26342 singleSelect: true,
26343 selectedClass: "ydataview-selected",
26347 // listen for node click?
26348 view.on("click", function(vw, index, node, e){
26349 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26353 dataModel.load("foobar.xml");
26355 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26357 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26358 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26360 * Note: old style constructor is still suported (container, template, config)
26363 * Create a new View
26364 * @param {Object} config The config object
26367 Roo.View = function(config, depreciated_tpl, depreciated_config){
26369 this.parent = false;
26371 if (typeof(depreciated_tpl) == 'undefined') {
26372 // new way.. - universal constructor.
26373 Roo.apply(this, config);
26374 this.el = Roo.get(this.el);
26377 this.el = Roo.get(config);
26378 this.tpl = depreciated_tpl;
26379 Roo.apply(this, depreciated_config);
26381 this.wrapEl = this.el.wrap().wrap();
26382 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26385 if(typeof(this.tpl) == "string"){
26386 this.tpl = new Roo.Template(this.tpl);
26388 // support xtype ctors..
26389 this.tpl = new Roo.factory(this.tpl, Roo);
26393 this.tpl.compile();
26398 * @event beforeclick
26399 * Fires before a click is processed. Returns false to cancel the default action.
26400 * @param {Roo.View} this
26401 * @param {Number} index The index of the target node
26402 * @param {HTMLElement} node The target node
26403 * @param {Roo.EventObject} e The raw event object
26405 "beforeclick" : true,
26408 * Fires when a template node is clicked.
26409 * @param {Roo.View} this
26410 * @param {Number} index The index of the target node
26411 * @param {HTMLElement} node The target node
26412 * @param {Roo.EventObject} e The raw event object
26417 * Fires when a template node is double clicked.
26418 * @param {Roo.View} this
26419 * @param {Number} index The index of the target node
26420 * @param {HTMLElement} node The target node
26421 * @param {Roo.EventObject} e The raw event object
26425 * @event contextmenu
26426 * Fires when a template node is right clicked.
26427 * @param {Roo.View} this
26428 * @param {Number} index The index of the target node
26429 * @param {HTMLElement} node The target node
26430 * @param {Roo.EventObject} e The raw event object
26432 "contextmenu" : true,
26434 * @event selectionchange
26435 * Fires when the selected nodes change.
26436 * @param {Roo.View} this
26437 * @param {Array} selections Array of the selected nodes
26439 "selectionchange" : true,
26442 * @event beforeselect
26443 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26444 * @param {Roo.View} this
26445 * @param {HTMLElement} node The node to be selected
26446 * @param {Array} selections Array of currently selected nodes
26448 "beforeselect" : true,
26450 * @event preparedata
26451 * Fires on every row to render, to allow you to change the data.
26452 * @param {Roo.View} this
26453 * @param {Object} data to be rendered (change this)
26455 "preparedata" : true
26463 "click": this.onClick,
26464 "dblclick": this.onDblClick,
26465 "contextmenu": this.onContextMenu,
26469 this.selections = [];
26471 this.cmp = new Roo.CompositeElementLite([]);
26473 this.store = Roo.factory(this.store, Roo.data);
26474 this.setStore(this.store, true);
26477 if ( this.footer && this.footer.xtype) {
26479 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26481 this.footer.dataSource = this.store;
26482 this.footer.container = fctr;
26483 this.footer = Roo.factory(this.footer, Roo);
26484 fctr.insertFirst(this.el);
26486 // this is a bit insane - as the paging toolbar seems to detach the el..
26487 // dom.parentNode.parentNode.parentNode
26488 // they get detached?
26492 Roo.View.superclass.constructor.call(this);
26497 Roo.extend(Roo.View, Roo.util.Observable, {
26500 * @cfg {Roo.data.Store} store Data store to load data from.
26505 * @cfg {String|Roo.Element} el The container element.
26510 * @cfg {String|Roo.Template} tpl The template used by this View
26514 * @cfg {String} dataName the named area of the template to use as the data area
26515 * Works with domtemplates roo-name="name"
26519 * @cfg {String} selectedClass The css class to add to selected nodes
26521 selectedClass : "x-view-selected",
26523 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26528 * @cfg {String} text to display on mask (default Loading)
26532 * @cfg {Boolean} multiSelect Allow multiple selection
26534 multiSelect : false,
26536 * @cfg {Boolean} singleSelect Allow single selection
26538 singleSelect: false,
26541 * @cfg {Boolean} toggleSelect - selecting
26543 toggleSelect : false,
26546 * @cfg {Boolean} tickable - selecting
26551 * Returns the element this view is bound to.
26552 * @return {Roo.Element}
26554 getEl : function(){
26555 return this.wrapEl;
26561 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26563 refresh : function(){
26564 //Roo.log('refresh');
26567 // if we are using something like 'domtemplate', then
26568 // the what gets used is:
26569 // t.applySubtemplate(NAME, data, wrapping data..)
26570 // the outer template then get' applied with
26571 // the store 'extra data'
26572 // and the body get's added to the
26573 // roo-name="data" node?
26574 // <span class='roo-tpl-{name}'></span> ?????
26578 this.clearSelections();
26579 this.el.update("");
26581 var records = this.store.getRange();
26582 if(records.length < 1) {
26584 // is this valid?? = should it render a template??
26586 this.el.update(this.emptyText);
26590 if (this.dataName) {
26591 this.el.update(t.apply(this.store.meta)); //????
26592 el = this.el.child('.roo-tpl-' + this.dataName);
26595 for(var i = 0, len = records.length; i < len; i++){
26596 var data = this.prepareData(records[i].data, i, records[i]);
26597 this.fireEvent("preparedata", this, data, i, records[i]);
26599 var d = Roo.apply({}, data);
26602 Roo.apply(d, {'roo-id' : Roo.id()});
26606 Roo.each(this.parent.item, function(item){
26607 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26610 Roo.apply(d, {'roo-data-checked' : 'checked'});
26614 html[html.length] = Roo.util.Format.trim(
26616 t.applySubtemplate(this.dataName, d, this.store.meta) :
26623 el.update(html.join(""));
26624 this.nodes = el.dom.childNodes;
26625 this.updateIndexes(0);
26630 * Function to override to reformat the data that is sent to
26631 * the template for each node.
26632 * DEPRICATED - use the preparedata event handler.
26633 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26634 * a JSON object for an UpdateManager bound view).
26636 prepareData : function(data, index, record)
26638 this.fireEvent("preparedata", this, data, index, record);
26642 onUpdate : function(ds, record){
26643 // Roo.log('on update');
26644 this.clearSelections();
26645 var index = this.store.indexOf(record);
26646 var n = this.nodes[index];
26647 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26648 n.parentNode.removeChild(n);
26649 this.updateIndexes(index, index);
26655 onAdd : function(ds, records, index)
26657 //Roo.log(['on Add', ds, records, index] );
26658 this.clearSelections();
26659 if(this.nodes.length == 0){
26663 var n = this.nodes[index];
26664 for(var i = 0, len = records.length; i < len; i++){
26665 var d = this.prepareData(records[i].data, i, records[i]);
26667 this.tpl.insertBefore(n, d);
26670 this.tpl.append(this.el, d);
26673 this.updateIndexes(index);
26676 onRemove : function(ds, record, index){
26677 // Roo.log('onRemove');
26678 this.clearSelections();
26679 var el = this.dataName ?
26680 this.el.child('.roo-tpl-' + this.dataName) :
26683 el.dom.removeChild(this.nodes[index]);
26684 this.updateIndexes(index);
26688 * Refresh an individual node.
26689 * @param {Number} index
26691 refreshNode : function(index){
26692 this.onUpdate(this.store, this.store.getAt(index));
26695 updateIndexes : function(startIndex, endIndex){
26696 var ns = this.nodes;
26697 startIndex = startIndex || 0;
26698 endIndex = endIndex || ns.length - 1;
26699 for(var i = startIndex; i <= endIndex; i++){
26700 ns[i].nodeIndex = i;
26705 * Changes the data store this view uses and refresh the view.
26706 * @param {Store} store
26708 setStore : function(store, initial){
26709 if(!initial && this.store){
26710 this.store.un("datachanged", this.refresh);
26711 this.store.un("add", this.onAdd);
26712 this.store.un("remove", this.onRemove);
26713 this.store.un("update", this.onUpdate);
26714 this.store.un("clear", this.refresh);
26715 this.store.un("beforeload", this.onBeforeLoad);
26716 this.store.un("load", this.onLoad);
26717 this.store.un("loadexception", this.onLoad);
26721 store.on("datachanged", this.refresh, this);
26722 store.on("add", this.onAdd, this);
26723 store.on("remove", this.onRemove, this);
26724 store.on("update", this.onUpdate, this);
26725 store.on("clear", this.refresh, this);
26726 store.on("beforeload", this.onBeforeLoad, this);
26727 store.on("load", this.onLoad, this);
26728 store.on("loadexception", this.onLoad, this);
26736 * onbeforeLoad - masks the loading area.
26739 onBeforeLoad : function(store,opts)
26741 //Roo.log('onBeforeLoad');
26743 this.el.update("");
26745 this.el.mask(this.mask ? this.mask : "Loading" );
26747 onLoad : function ()
26754 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26755 * @param {HTMLElement} node
26756 * @return {HTMLElement} The template node
26758 findItemFromChild : function(node){
26759 var el = this.dataName ?
26760 this.el.child('.roo-tpl-' + this.dataName,true) :
26763 if(!node || node.parentNode == el){
26766 var p = node.parentNode;
26767 while(p && p != el){
26768 if(p.parentNode == el){
26777 onClick : function(e){
26778 var item = this.findItemFromChild(e.getTarget());
26780 var index = this.indexOf(item);
26781 if(this.onItemClick(item, index, e) !== false){
26782 this.fireEvent("click", this, index, item, e);
26785 this.clearSelections();
26790 onContextMenu : function(e){
26791 var item = this.findItemFromChild(e.getTarget());
26793 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26798 onDblClick : function(e){
26799 var item = this.findItemFromChild(e.getTarget());
26801 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26805 onItemClick : function(item, index, e)
26807 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26810 if (this.toggleSelect) {
26811 var m = this.isSelected(item) ? 'unselect' : 'select';
26814 _t[m](item, true, false);
26817 if(this.multiSelect || this.singleSelect){
26818 if(this.multiSelect && e.shiftKey && this.lastSelection){
26819 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26821 this.select(item, this.multiSelect && e.ctrlKey);
26822 this.lastSelection = item;
26825 if(!this.tickable){
26826 e.preventDefault();
26834 * Get the number of selected nodes.
26837 getSelectionCount : function(){
26838 return this.selections.length;
26842 * Get the currently selected nodes.
26843 * @return {Array} An array of HTMLElements
26845 getSelectedNodes : function(){
26846 return this.selections;
26850 * Get the indexes of the selected nodes.
26853 getSelectedIndexes : function(){
26854 var indexes = [], s = this.selections;
26855 for(var i = 0, len = s.length; i < len; i++){
26856 indexes.push(s[i].nodeIndex);
26862 * Clear all selections
26863 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
26865 clearSelections : function(suppressEvent){
26866 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
26867 this.cmp.elements = this.selections;
26868 this.cmp.removeClass(this.selectedClass);
26869 this.selections = [];
26870 if(!suppressEvent){
26871 this.fireEvent("selectionchange", this, this.selections);
26877 * Returns true if the passed node is selected
26878 * @param {HTMLElement/Number} node The node or node index
26879 * @return {Boolean}
26881 isSelected : function(node){
26882 var s = this.selections;
26886 node = this.getNode(node);
26887 return s.indexOf(node) !== -1;
26892 * @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
26893 * @param {Boolean} keepExisting (optional) true to keep existing selections
26894 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26896 select : function(nodeInfo, keepExisting, suppressEvent){
26897 if(nodeInfo instanceof Array){
26899 this.clearSelections(true);
26901 for(var i = 0, len = nodeInfo.length; i < len; i++){
26902 this.select(nodeInfo[i], true, true);
26906 var node = this.getNode(nodeInfo);
26907 if(!node || this.isSelected(node)){
26908 return; // already selected.
26911 this.clearSelections(true);
26914 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
26915 Roo.fly(node).addClass(this.selectedClass);
26916 this.selections.push(node);
26917 if(!suppressEvent){
26918 this.fireEvent("selectionchange", this, this.selections);
26926 * @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
26927 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
26928 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26930 unselect : function(nodeInfo, keepExisting, suppressEvent)
26932 if(nodeInfo instanceof Array){
26933 Roo.each(this.selections, function(s) {
26934 this.unselect(s, nodeInfo);
26938 var node = this.getNode(nodeInfo);
26939 if(!node || !this.isSelected(node)){
26940 //Roo.log("not selected");
26941 return; // not selected.
26945 Roo.each(this.selections, function(s) {
26947 Roo.fly(node).removeClass(this.selectedClass);
26954 this.selections= ns;
26955 this.fireEvent("selectionchange", this, this.selections);
26959 * Gets a template node.
26960 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26961 * @return {HTMLElement} The node or null if it wasn't found
26963 getNode : function(nodeInfo){
26964 if(typeof nodeInfo == "string"){
26965 return document.getElementById(nodeInfo);
26966 }else if(typeof nodeInfo == "number"){
26967 return this.nodes[nodeInfo];
26973 * Gets a range template nodes.
26974 * @param {Number} startIndex
26975 * @param {Number} endIndex
26976 * @return {Array} An array of nodes
26978 getNodes : function(start, end){
26979 var ns = this.nodes;
26980 start = start || 0;
26981 end = typeof end == "undefined" ? ns.length - 1 : end;
26984 for(var i = start; i <= end; i++){
26988 for(var i = start; i >= end; i--){
26996 * Finds the index of the passed node
26997 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26998 * @return {Number} The index of the node or -1
27000 indexOf : function(node){
27001 node = this.getNode(node);
27002 if(typeof node.nodeIndex == "number"){
27003 return node.nodeIndex;
27005 var ns = this.nodes;
27006 for(var i = 0, len = ns.length; i < len; i++){
27016 * Ext JS Library 1.1.1
27017 * Copyright(c) 2006-2007, Ext JS, LLC.
27019 * Originally Released Under LGPL - original licence link has changed is not relivant.
27022 * <script type="text/javascript">
27026 * @class Roo.JsonView
27027 * @extends Roo.View
27028 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27030 var view = new Roo.JsonView({
27031 container: "my-element",
27032 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27037 // listen for node click?
27038 view.on("click", function(vw, index, node, e){
27039 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27042 // direct load of JSON data
27043 view.load("foobar.php");
27045 // Example from my blog list
27046 var tpl = new Roo.Template(
27047 '<div class="entry">' +
27048 '<a class="entry-title" href="{link}">{title}</a>' +
27049 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27050 "</div><hr />"
27053 var moreView = new Roo.JsonView({
27054 container : "entry-list",
27058 moreView.on("beforerender", this.sortEntries, this);
27060 url: "/blog/get-posts.php",
27061 params: "allposts=true",
27062 text: "Loading Blog Entries..."
27066 * Note: old code is supported with arguments : (container, template, config)
27070 * Create a new JsonView
27072 * @param {Object} config The config object
27075 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27078 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27080 var um = this.el.getUpdateManager();
27081 um.setRenderer(this);
27082 um.on("update", this.onLoad, this);
27083 um.on("failure", this.onLoadException, this);
27086 * @event beforerender
27087 * Fires before rendering of the downloaded JSON data.
27088 * @param {Roo.JsonView} this
27089 * @param {Object} data The JSON data loaded
27093 * Fires when data is loaded.
27094 * @param {Roo.JsonView} this
27095 * @param {Object} data The JSON data loaded
27096 * @param {Object} response The raw Connect response object
27099 * @event loadexception
27100 * Fires when loading fails.
27101 * @param {Roo.JsonView} this
27102 * @param {Object} response The raw Connect response object
27105 'beforerender' : true,
27107 'loadexception' : true
27110 Roo.extend(Roo.JsonView, Roo.View, {
27112 * @type {String} The root property in the loaded JSON object that contains the data
27117 * Refreshes the view.
27119 refresh : function(){
27120 this.clearSelections();
27121 this.el.update("");
27123 var o = this.jsonData;
27124 if(o && o.length > 0){
27125 for(var i = 0, len = o.length; i < len; i++){
27126 var data = this.prepareData(o[i], i, o);
27127 html[html.length] = this.tpl.apply(data);
27130 html.push(this.emptyText);
27132 this.el.update(html.join(""));
27133 this.nodes = this.el.dom.childNodes;
27134 this.updateIndexes(0);
27138 * 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.
27139 * @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:
27142 url: "your-url.php",
27143 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27144 callback: yourFunction,
27145 scope: yourObject, //(optional scope)
27148 text: "Loading...",
27153 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27154 * 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.
27155 * @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}
27156 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27157 * @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.
27160 var um = this.el.getUpdateManager();
27161 um.update.apply(um, arguments);
27164 // note - render is a standard framework call...
27165 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27166 render : function(el, response){
27168 this.clearSelections();
27169 this.el.update("");
27172 if (response != '') {
27173 o = Roo.util.JSON.decode(response.responseText);
27176 o = o[this.jsonRoot];
27182 * The current JSON data or null
27185 this.beforeRender();
27190 * Get the number of records in the current JSON dataset
27193 getCount : function(){
27194 return this.jsonData ? this.jsonData.length : 0;
27198 * Returns the JSON object for the specified node(s)
27199 * @param {HTMLElement/Array} node The node or an array of nodes
27200 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27201 * you get the JSON object for the node
27203 getNodeData : function(node){
27204 if(node instanceof Array){
27206 for(var i = 0, len = node.length; i < len; i++){
27207 data.push(this.getNodeData(node[i]));
27211 return this.jsonData[this.indexOf(node)] || null;
27214 beforeRender : function(){
27215 this.snapshot = this.jsonData;
27217 this.sort.apply(this, this.sortInfo);
27219 this.fireEvent("beforerender", this, this.jsonData);
27222 onLoad : function(el, o){
27223 this.fireEvent("load", this, this.jsonData, o);
27226 onLoadException : function(el, o){
27227 this.fireEvent("loadexception", this, o);
27231 * Filter the data by a specific property.
27232 * @param {String} property A property on your JSON objects
27233 * @param {String/RegExp} value Either string that the property values
27234 * should start with, or a RegExp to test against the property
27236 filter : function(property, value){
27239 var ss = this.snapshot;
27240 if(typeof value == "string"){
27241 var vlen = value.length;
27243 this.clearFilter();
27246 value = value.toLowerCase();
27247 for(var i = 0, len = ss.length; i < len; i++){
27249 if(o[property].substr(0, vlen).toLowerCase() == value){
27253 } else if(value.exec){ // regex?
27254 for(var i = 0, len = ss.length; i < len; i++){
27256 if(value.test(o[property])){
27263 this.jsonData = data;
27269 * Filter by a function. The passed function will be called with each
27270 * object in the current dataset. If the function returns true the value is kept,
27271 * otherwise it is filtered.
27272 * @param {Function} fn
27273 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27275 filterBy : function(fn, scope){
27278 var ss = this.snapshot;
27279 for(var i = 0, len = ss.length; i < len; i++){
27281 if(fn.call(scope || this, o)){
27285 this.jsonData = data;
27291 * Clears the current filter.
27293 clearFilter : function(){
27294 if(this.snapshot && this.jsonData != this.snapshot){
27295 this.jsonData = this.snapshot;
27302 * Sorts the data for this view and refreshes it.
27303 * @param {String} property A property on your JSON objects to sort on
27304 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27305 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27307 sort : function(property, dir, sortType){
27308 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27311 var dsc = dir && dir.toLowerCase() == "desc";
27312 var f = function(o1, o2){
27313 var v1 = sortType ? sortType(o1[p]) : o1[p];
27314 var v2 = sortType ? sortType(o2[p]) : o2[p];
27317 return dsc ? +1 : -1;
27318 } else if(v1 > v2){
27319 return dsc ? -1 : +1;
27324 this.jsonData.sort(f);
27326 if(this.jsonData != this.snapshot){
27327 this.snapshot.sort(f);
27333 * Ext JS Library 1.1.1
27334 * Copyright(c) 2006-2007, Ext JS, LLC.
27336 * Originally Released Under LGPL - original licence link has changed is not relivant.
27339 * <script type="text/javascript">
27344 * @class Roo.ColorPalette
27345 * @extends Roo.Component
27346 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27347 * Here's an example of typical usage:
27349 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27350 cp.render('my-div');
27352 cp.on('select', function(palette, selColor){
27353 // do something with selColor
27357 * Create a new ColorPalette
27358 * @param {Object} config The config object
27360 Roo.ColorPalette = function(config){
27361 Roo.ColorPalette.superclass.constructor.call(this, config);
27365 * Fires when a color is selected
27366 * @param {ColorPalette} this
27367 * @param {String} color The 6-digit color hex code (without the # symbol)
27373 this.on("select", this.handler, this.scope, true);
27376 Roo.extend(Roo.ColorPalette, Roo.Component, {
27378 * @cfg {String} itemCls
27379 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27381 itemCls : "x-color-palette",
27383 * @cfg {String} value
27384 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27385 * the hex codes are case-sensitive.
27388 clickEvent:'click',
27390 ctype: "Roo.ColorPalette",
27393 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27395 allowReselect : false,
27398 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27399 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27400 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27401 * of colors with the width setting until the box is symmetrical.</p>
27402 * <p>You can override individual colors if needed:</p>
27404 var cp = new Roo.ColorPalette();
27405 cp.colors[0] = "FF0000"; // change the first box to red
27408 Or you can provide a custom array of your own for complete control:
27410 var cp = new Roo.ColorPalette();
27411 cp.colors = ["000000", "993300", "333300"];
27416 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27417 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27418 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27419 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27420 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27424 onRender : function(container, position){
27425 var t = new Roo.MasterTemplate(
27426 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27428 var c = this.colors;
27429 for(var i = 0, len = c.length; i < len; i++){
27432 var el = document.createElement("div");
27433 el.className = this.itemCls;
27435 container.dom.insertBefore(el, position);
27436 this.el = Roo.get(el);
27437 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27438 if(this.clickEvent != 'click'){
27439 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27444 afterRender : function(){
27445 Roo.ColorPalette.superclass.afterRender.call(this);
27447 var s = this.value;
27454 handleClick : function(e, t){
27455 e.preventDefault();
27456 if(!this.disabled){
27457 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27458 this.select(c.toUpperCase());
27463 * Selects the specified color in the palette (fires the select event)
27464 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27466 select : function(color){
27467 color = color.replace("#", "");
27468 if(color != this.value || this.allowReselect){
27471 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27473 el.child("a.color-"+color).addClass("x-color-palette-sel");
27474 this.value = color;
27475 this.fireEvent("select", this, color);
27480 * Ext JS Library 1.1.1
27481 * Copyright(c) 2006-2007, Ext JS, LLC.
27483 * Originally Released Under LGPL - original licence link has changed is not relivant.
27486 * <script type="text/javascript">
27490 * @class Roo.DatePicker
27491 * @extends Roo.Component
27492 * Simple date picker class.
27494 * Create a new DatePicker
27495 * @param {Object} config The config object
27497 Roo.DatePicker = function(config){
27498 Roo.DatePicker.superclass.constructor.call(this, config);
27500 this.value = config && config.value ?
27501 config.value.clearTime() : new Date().clearTime();
27506 * Fires when a date is selected
27507 * @param {DatePicker} this
27508 * @param {Date} date The selected date
27512 * @event monthchange
27513 * Fires when the displayed month changes
27514 * @param {DatePicker} this
27515 * @param {Date} date The selected month
27517 'monthchange': true
27521 this.on("select", this.handler, this.scope || this);
27523 // build the disabledDatesRE
27524 if(!this.disabledDatesRE && this.disabledDates){
27525 var dd = this.disabledDates;
27527 for(var i = 0; i < dd.length; i++){
27529 if(i != dd.length-1) {
27533 this.disabledDatesRE = new RegExp(re + ")");
27537 Roo.extend(Roo.DatePicker, Roo.Component, {
27539 * @cfg {String} todayText
27540 * The text to display on the button that selects the current date (defaults to "Today")
27542 todayText : "Today",
27544 * @cfg {String} okText
27545 * The text to display on the ok button
27547 okText : " OK ", //   to give the user extra clicking room
27549 * @cfg {String} cancelText
27550 * The text to display on the cancel button
27552 cancelText : "Cancel",
27554 * @cfg {String} todayTip
27555 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27557 todayTip : "{0} (Spacebar)",
27559 * @cfg {Date} minDate
27560 * Minimum allowable date (JavaScript date object, defaults to null)
27564 * @cfg {Date} maxDate
27565 * Maximum allowable date (JavaScript date object, defaults to null)
27569 * @cfg {String} minText
27570 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27572 minText : "This date is before the minimum date",
27574 * @cfg {String} maxText
27575 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27577 maxText : "This date is after the maximum date",
27579 * @cfg {String} format
27580 * The default date format string which can be overriden for localization support. The format must be
27581 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27585 * @cfg {Array} disabledDays
27586 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27588 disabledDays : null,
27590 * @cfg {String} disabledDaysText
27591 * The tooltip to display when the date falls on a disabled day (defaults to "")
27593 disabledDaysText : "",
27595 * @cfg {RegExp} disabledDatesRE
27596 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27598 disabledDatesRE : null,
27600 * @cfg {String} disabledDatesText
27601 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27603 disabledDatesText : "",
27605 * @cfg {Boolean} constrainToViewport
27606 * True to constrain the date picker to the viewport (defaults to true)
27608 constrainToViewport : true,
27610 * @cfg {Array} monthNames
27611 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27613 monthNames : Date.monthNames,
27615 * @cfg {Array} dayNames
27616 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27618 dayNames : Date.dayNames,
27620 * @cfg {String} nextText
27621 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27623 nextText: 'Next Month (Control+Right)',
27625 * @cfg {String} prevText
27626 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27628 prevText: 'Previous Month (Control+Left)',
27630 * @cfg {String} monthYearText
27631 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27633 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27635 * @cfg {Number} startDay
27636 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27640 * @cfg {Bool} showClear
27641 * Show a clear button (usefull for date form elements that can be blank.)
27647 * Sets the value of the date field
27648 * @param {Date} value The date to set
27650 setValue : function(value){
27651 var old = this.value;
27653 if (typeof(value) == 'string') {
27655 value = Date.parseDate(value, this.format);
27658 value = new Date();
27661 this.value = value.clearTime(true);
27663 this.update(this.value);
27668 * Gets the current selected value of the date field
27669 * @return {Date} The selected date
27671 getValue : function(){
27676 focus : function(){
27678 this.update(this.activeDate);
27683 onRender : function(container, position){
27686 '<table cellspacing="0">',
27687 '<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>',
27688 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27689 var dn = this.dayNames;
27690 for(var i = 0; i < 7; i++){
27691 var d = this.startDay+i;
27695 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27697 m[m.length] = "</tr></thead><tbody><tr>";
27698 for(var i = 0; i < 42; i++) {
27699 if(i % 7 == 0 && i != 0){
27700 m[m.length] = "</tr><tr>";
27702 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27704 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27705 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27707 var el = document.createElement("div");
27708 el.className = "x-date-picker";
27709 el.innerHTML = m.join("");
27711 container.dom.insertBefore(el, position);
27713 this.el = Roo.get(el);
27714 this.eventEl = Roo.get(el.firstChild);
27716 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27717 handler: this.showPrevMonth,
27719 preventDefault:true,
27723 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27724 handler: this.showNextMonth,
27726 preventDefault:true,
27730 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27732 this.monthPicker = this.el.down('div.x-date-mp');
27733 this.monthPicker.enableDisplayMode('block');
27735 var kn = new Roo.KeyNav(this.eventEl, {
27736 "left" : function(e){
27738 this.showPrevMonth() :
27739 this.update(this.activeDate.add("d", -1));
27742 "right" : function(e){
27744 this.showNextMonth() :
27745 this.update(this.activeDate.add("d", 1));
27748 "up" : function(e){
27750 this.showNextYear() :
27751 this.update(this.activeDate.add("d", -7));
27754 "down" : function(e){
27756 this.showPrevYear() :
27757 this.update(this.activeDate.add("d", 7));
27760 "pageUp" : function(e){
27761 this.showNextMonth();
27764 "pageDown" : function(e){
27765 this.showPrevMonth();
27768 "enter" : function(e){
27769 e.stopPropagation();
27776 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27778 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27780 this.el.unselectable();
27782 this.cells = this.el.select("table.x-date-inner tbody td");
27783 this.textNodes = this.el.query("table.x-date-inner tbody span");
27785 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27787 tooltip: this.monthYearText
27790 this.mbtn.on('click', this.showMonthPicker, this);
27791 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27794 var today = (new Date()).dateFormat(this.format);
27796 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27797 if (this.showClear) {
27798 baseTb.add( new Roo.Toolbar.Fill());
27801 text: String.format(this.todayText, today),
27802 tooltip: String.format(this.todayTip, today),
27803 handler: this.selectToday,
27807 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27810 if (this.showClear) {
27812 baseTb.add( new Roo.Toolbar.Fill());
27815 cls: 'x-btn-icon x-btn-clear',
27816 handler: function() {
27818 this.fireEvent("select", this, '');
27828 this.update(this.value);
27831 createMonthPicker : function(){
27832 if(!this.monthPicker.dom.firstChild){
27833 var buf = ['<table border="0" cellspacing="0">'];
27834 for(var i = 0; i < 6; i++){
27836 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27837 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27839 '<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>' :
27840 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27844 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27846 '</button><button type="button" class="x-date-mp-cancel">',
27848 '</button></td></tr>',
27851 this.monthPicker.update(buf.join(''));
27852 this.monthPicker.on('click', this.onMonthClick, this);
27853 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
27855 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
27856 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
27858 this.mpMonths.each(function(m, a, i){
27861 m.dom.xmonth = 5 + Math.round(i * .5);
27863 m.dom.xmonth = Math.round((i-1) * .5);
27869 showMonthPicker : function(){
27870 this.createMonthPicker();
27871 var size = this.el.getSize();
27872 this.monthPicker.setSize(size);
27873 this.monthPicker.child('table').setSize(size);
27875 this.mpSelMonth = (this.activeDate || this.value).getMonth();
27876 this.updateMPMonth(this.mpSelMonth);
27877 this.mpSelYear = (this.activeDate || this.value).getFullYear();
27878 this.updateMPYear(this.mpSelYear);
27880 this.monthPicker.slideIn('t', {duration:.2});
27883 updateMPYear : function(y){
27885 var ys = this.mpYears.elements;
27886 for(var i = 1; i <= 10; i++){
27887 var td = ys[i-1], y2;
27889 y2 = y + Math.round(i * .5);
27890 td.firstChild.innerHTML = y2;
27893 y2 = y - (5-Math.round(i * .5));
27894 td.firstChild.innerHTML = y2;
27897 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
27901 updateMPMonth : function(sm){
27902 this.mpMonths.each(function(m, a, i){
27903 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
27907 selectMPMonth: function(m){
27911 onMonthClick : function(e, t){
27913 var el = new Roo.Element(t), pn;
27914 if(el.is('button.x-date-mp-cancel')){
27915 this.hideMonthPicker();
27917 else if(el.is('button.x-date-mp-ok')){
27918 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27919 this.hideMonthPicker();
27921 else if(pn = el.up('td.x-date-mp-month', 2)){
27922 this.mpMonths.removeClass('x-date-mp-sel');
27923 pn.addClass('x-date-mp-sel');
27924 this.mpSelMonth = pn.dom.xmonth;
27926 else if(pn = el.up('td.x-date-mp-year', 2)){
27927 this.mpYears.removeClass('x-date-mp-sel');
27928 pn.addClass('x-date-mp-sel');
27929 this.mpSelYear = pn.dom.xyear;
27931 else if(el.is('a.x-date-mp-prev')){
27932 this.updateMPYear(this.mpyear-10);
27934 else if(el.is('a.x-date-mp-next')){
27935 this.updateMPYear(this.mpyear+10);
27939 onMonthDblClick : function(e, t){
27941 var el = new Roo.Element(t), pn;
27942 if(pn = el.up('td.x-date-mp-month', 2)){
27943 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
27944 this.hideMonthPicker();
27946 else if(pn = el.up('td.x-date-mp-year', 2)){
27947 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27948 this.hideMonthPicker();
27952 hideMonthPicker : function(disableAnim){
27953 if(this.monthPicker){
27954 if(disableAnim === true){
27955 this.monthPicker.hide();
27957 this.monthPicker.slideOut('t', {duration:.2});
27963 showPrevMonth : function(e){
27964 this.update(this.activeDate.add("mo", -1));
27968 showNextMonth : function(e){
27969 this.update(this.activeDate.add("mo", 1));
27973 showPrevYear : function(){
27974 this.update(this.activeDate.add("y", -1));
27978 showNextYear : function(){
27979 this.update(this.activeDate.add("y", 1));
27983 handleMouseWheel : function(e){
27984 var delta = e.getWheelDelta();
27986 this.showPrevMonth();
27988 } else if(delta < 0){
27989 this.showNextMonth();
27995 handleDateClick : function(e, t){
27997 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
27998 this.setValue(new Date(t.dateValue));
27999 this.fireEvent("select", this, this.value);
28004 selectToday : function(){
28005 this.setValue(new Date().clearTime());
28006 this.fireEvent("select", this, this.value);
28010 update : function(date)
28012 var vd = this.activeDate;
28013 this.activeDate = date;
28015 var t = date.getTime();
28016 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28017 this.cells.removeClass("x-date-selected");
28018 this.cells.each(function(c){
28019 if(c.dom.firstChild.dateValue == t){
28020 c.addClass("x-date-selected");
28021 setTimeout(function(){
28022 try{c.dom.firstChild.focus();}catch(e){}
28031 var days = date.getDaysInMonth();
28032 var firstOfMonth = date.getFirstDateOfMonth();
28033 var startingPos = firstOfMonth.getDay()-this.startDay;
28035 if(startingPos <= this.startDay){
28039 var pm = date.add("mo", -1);
28040 var prevStart = pm.getDaysInMonth()-startingPos;
28042 var cells = this.cells.elements;
28043 var textEls = this.textNodes;
28044 days += startingPos;
28046 // convert everything to numbers so it's fast
28047 var day = 86400000;
28048 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28049 var today = new Date().clearTime().getTime();
28050 var sel = date.clearTime().getTime();
28051 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28052 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28053 var ddMatch = this.disabledDatesRE;
28054 var ddText = this.disabledDatesText;
28055 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28056 var ddaysText = this.disabledDaysText;
28057 var format = this.format;
28059 var setCellClass = function(cal, cell){
28061 var t = d.getTime();
28062 cell.firstChild.dateValue = t;
28064 cell.className += " x-date-today";
28065 cell.title = cal.todayText;
28068 cell.className += " x-date-selected";
28069 setTimeout(function(){
28070 try{cell.firstChild.focus();}catch(e){}
28075 cell.className = " x-date-disabled";
28076 cell.title = cal.minText;
28080 cell.className = " x-date-disabled";
28081 cell.title = cal.maxText;
28085 if(ddays.indexOf(d.getDay()) != -1){
28086 cell.title = ddaysText;
28087 cell.className = " x-date-disabled";
28090 if(ddMatch && format){
28091 var fvalue = d.dateFormat(format);
28092 if(ddMatch.test(fvalue)){
28093 cell.title = ddText.replace("%0", fvalue);
28094 cell.className = " x-date-disabled";
28100 for(; i < startingPos; i++) {
28101 textEls[i].innerHTML = (++prevStart);
28102 d.setDate(d.getDate()+1);
28103 cells[i].className = "x-date-prevday";
28104 setCellClass(this, cells[i]);
28106 for(; i < days; i++){
28107 intDay = i - startingPos + 1;
28108 textEls[i].innerHTML = (intDay);
28109 d.setDate(d.getDate()+1);
28110 cells[i].className = "x-date-active";
28111 setCellClass(this, cells[i]);
28114 for(; i < 42; i++) {
28115 textEls[i].innerHTML = (++extraDays);
28116 d.setDate(d.getDate()+1);
28117 cells[i].className = "x-date-nextday";
28118 setCellClass(this, cells[i]);
28121 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28122 this.fireEvent('monthchange', this, date);
28124 if(!this.internalRender){
28125 var main = this.el.dom.firstChild;
28126 var w = main.offsetWidth;
28127 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28128 Roo.fly(main).setWidth(w);
28129 this.internalRender = true;
28130 // opera does not respect the auto grow header center column
28131 // then, after it gets a width opera refuses to recalculate
28132 // without a second pass
28133 if(Roo.isOpera && !this.secondPass){
28134 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28135 this.secondPass = true;
28136 this.update.defer(10, this, [date]);
28144 * Ext JS Library 1.1.1
28145 * Copyright(c) 2006-2007, Ext JS, LLC.
28147 * Originally Released Under LGPL - original licence link has changed is not relivant.
28150 * <script type="text/javascript">
28153 * @class Roo.TabPanel
28154 * @extends Roo.util.Observable
28155 * A lightweight tab container.
28159 // basic tabs 1, built from existing content
28160 var tabs = new Roo.TabPanel("tabs1");
28161 tabs.addTab("script", "View Script");
28162 tabs.addTab("markup", "View Markup");
28163 tabs.activate("script");
28165 // more advanced tabs, built from javascript
28166 var jtabs = new Roo.TabPanel("jtabs");
28167 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28169 // set up the UpdateManager
28170 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28171 var updater = tab2.getUpdateManager();
28172 updater.setDefaultUrl("ajax1.htm");
28173 tab2.on('activate', updater.refresh, updater, true);
28175 // Use setUrl for Ajax loading
28176 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28177 tab3.setUrl("ajax2.htm", null, true);
28180 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28183 jtabs.activate("jtabs-1");
28186 * Create a new TabPanel.
28187 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28188 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28190 Roo.TabPanel = function(container, config){
28192 * The container element for this TabPanel.
28193 * @type Roo.Element
28195 this.el = Roo.get(container, true);
28197 if(typeof config == "boolean"){
28198 this.tabPosition = config ? "bottom" : "top";
28200 Roo.apply(this, config);
28203 if(this.tabPosition == "bottom"){
28204 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28205 this.el.addClass("x-tabs-bottom");
28207 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28208 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28209 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28211 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28213 if(this.tabPosition != "bottom"){
28214 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28215 * @type Roo.Element
28217 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28218 this.el.addClass("x-tabs-top");
28222 this.bodyEl.setStyle("position", "relative");
28224 this.active = null;
28225 this.activateDelegate = this.activate.createDelegate(this);
28230 * Fires when the active tab changes
28231 * @param {Roo.TabPanel} this
28232 * @param {Roo.TabPanelItem} activePanel The new active tab
28236 * @event beforetabchange
28237 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28238 * @param {Roo.TabPanel} this
28239 * @param {Object} e Set cancel to true on this object to cancel the tab change
28240 * @param {Roo.TabPanelItem} tab The tab being changed to
28242 "beforetabchange" : true
28245 Roo.EventManager.onWindowResize(this.onResize, this);
28246 this.cpad = this.el.getPadding("lr");
28247 this.hiddenCount = 0;
28250 // toolbar on the tabbar support...
28251 if (this.toolbar) {
28252 var tcfg = this.toolbar;
28253 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28254 this.toolbar = new Roo.Toolbar(tcfg);
28255 if (Roo.isSafari) {
28256 var tbl = tcfg.container.child('table', true);
28257 tbl.setAttribute('width', '100%');
28264 Roo.TabPanel.superclass.constructor.call(this);
28267 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28269 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28271 tabPosition : "top",
28273 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28275 currentTabWidth : 0,
28277 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28281 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28285 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28287 preferredTabWidth : 175,
28289 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28291 resizeTabs : false,
28293 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28295 monitorResize : true,
28297 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28302 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28303 * @param {String} id The id of the div to use <b>or create</b>
28304 * @param {String} text The text for the tab
28305 * @param {String} content (optional) Content to put in the TabPanelItem body
28306 * @param {Boolean} closable (optional) True to create a close icon on the tab
28307 * @return {Roo.TabPanelItem} The created TabPanelItem
28309 addTab : function(id, text, content, closable){
28310 var item = new Roo.TabPanelItem(this, id, text, closable);
28311 this.addTabItem(item);
28313 item.setContent(content);
28319 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28320 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28321 * @return {Roo.TabPanelItem}
28323 getTab : function(id){
28324 return this.items[id];
28328 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28329 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28331 hideTab : function(id){
28332 var t = this.items[id];
28335 this.hiddenCount++;
28336 this.autoSizeTabs();
28341 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28342 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28344 unhideTab : function(id){
28345 var t = this.items[id];
28347 t.setHidden(false);
28348 this.hiddenCount--;
28349 this.autoSizeTabs();
28354 * Adds an existing {@link Roo.TabPanelItem}.
28355 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28357 addTabItem : function(item){
28358 this.items[item.id] = item;
28359 this.items.push(item);
28360 if(this.resizeTabs){
28361 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28362 this.autoSizeTabs();
28369 * Removes a {@link Roo.TabPanelItem}.
28370 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28372 removeTab : function(id){
28373 var items = this.items;
28374 var tab = items[id];
28375 if(!tab) { return; }
28376 var index = items.indexOf(tab);
28377 if(this.active == tab && items.length > 1){
28378 var newTab = this.getNextAvailable(index);
28383 this.stripEl.dom.removeChild(tab.pnode.dom);
28384 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28385 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28387 items.splice(index, 1);
28388 delete this.items[tab.id];
28389 tab.fireEvent("close", tab);
28390 tab.purgeListeners();
28391 this.autoSizeTabs();
28394 getNextAvailable : function(start){
28395 var items = this.items;
28397 // look for a next tab that will slide over to
28398 // replace the one being removed
28399 while(index < items.length){
28400 var item = items[++index];
28401 if(item && !item.isHidden()){
28405 // if one isn't found select the previous tab (on the left)
28408 var item = items[--index];
28409 if(item && !item.isHidden()){
28417 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28418 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28420 disableTab : function(id){
28421 var tab = this.items[id];
28422 if(tab && this.active != tab){
28428 * Enables a {@link Roo.TabPanelItem} that is disabled.
28429 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28431 enableTab : function(id){
28432 var tab = this.items[id];
28437 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28438 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28439 * @return {Roo.TabPanelItem} The TabPanelItem.
28441 activate : function(id){
28442 var tab = this.items[id];
28446 if(tab == this.active || tab.disabled){
28450 this.fireEvent("beforetabchange", this, e, tab);
28451 if(e.cancel !== true && !tab.disabled){
28453 this.active.hide();
28455 this.active = this.items[id];
28456 this.active.show();
28457 this.fireEvent("tabchange", this, this.active);
28463 * Gets the active {@link Roo.TabPanelItem}.
28464 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28466 getActiveTab : function(){
28467 return this.active;
28471 * Updates the tab body element to fit the height of the container element
28472 * for overflow scrolling
28473 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28475 syncHeight : function(targetHeight){
28476 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28477 var bm = this.bodyEl.getMargins();
28478 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28479 this.bodyEl.setHeight(newHeight);
28483 onResize : function(){
28484 if(this.monitorResize){
28485 this.autoSizeTabs();
28490 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28492 beginUpdate : function(){
28493 this.updating = true;
28497 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28499 endUpdate : function(){
28500 this.updating = false;
28501 this.autoSizeTabs();
28505 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28507 autoSizeTabs : function(){
28508 var count = this.items.length;
28509 var vcount = count - this.hiddenCount;
28510 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28513 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28514 var availWidth = Math.floor(w / vcount);
28515 var b = this.stripBody;
28516 if(b.getWidth() > w){
28517 var tabs = this.items;
28518 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28519 if(availWidth < this.minTabWidth){
28520 /*if(!this.sleft){ // incomplete scrolling code
28521 this.createScrollButtons();
28524 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28527 if(this.currentTabWidth < this.preferredTabWidth){
28528 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28534 * Returns the number of tabs in this TabPanel.
28537 getCount : function(){
28538 return this.items.length;
28542 * Resizes all the tabs to the passed width
28543 * @param {Number} The new width
28545 setTabWidth : function(width){
28546 this.currentTabWidth = width;
28547 for(var i = 0, len = this.items.length; i < len; i++) {
28548 if(!this.items[i].isHidden()) {
28549 this.items[i].setWidth(width);
28555 * Destroys this TabPanel
28556 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28558 destroy : function(removeEl){
28559 Roo.EventManager.removeResizeListener(this.onResize, this);
28560 for(var i = 0, len = this.items.length; i < len; i++){
28561 this.items[i].purgeListeners();
28563 if(removeEl === true){
28564 this.el.update("");
28571 * @class Roo.TabPanelItem
28572 * @extends Roo.util.Observable
28573 * Represents an individual item (tab plus body) in a TabPanel.
28574 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28575 * @param {String} id The id of this TabPanelItem
28576 * @param {String} text The text for the tab of this TabPanelItem
28577 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28579 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28581 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28582 * @type Roo.TabPanel
28584 this.tabPanel = tabPanel;
28586 * The id for this TabPanelItem
28591 this.disabled = false;
28595 this.loaded = false;
28596 this.closable = closable;
28599 * The body element for this TabPanelItem.
28600 * @type Roo.Element
28602 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28603 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28604 this.bodyEl.setStyle("display", "block");
28605 this.bodyEl.setStyle("zoom", "1");
28608 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28610 this.el = Roo.get(els.el, true);
28611 this.inner = Roo.get(els.inner, true);
28612 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28613 this.pnode = Roo.get(els.el.parentNode, true);
28614 this.el.on("mousedown", this.onTabMouseDown, this);
28615 this.el.on("click", this.onTabClick, this);
28618 var c = Roo.get(els.close, true);
28619 c.dom.title = this.closeText;
28620 c.addClassOnOver("close-over");
28621 c.on("click", this.closeClick, this);
28627 * Fires when this tab becomes the active tab.
28628 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28629 * @param {Roo.TabPanelItem} this
28633 * @event beforeclose
28634 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28635 * @param {Roo.TabPanelItem} this
28636 * @param {Object} e Set cancel to true on this object to cancel the close.
28638 "beforeclose": true,
28641 * Fires when this tab is closed.
28642 * @param {Roo.TabPanelItem} this
28646 * @event deactivate
28647 * Fires when this tab is no longer the active tab.
28648 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28649 * @param {Roo.TabPanelItem} this
28651 "deactivate" : true
28653 this.hidden = false;
28655 Roo.TabPanelItem.superclass.constructor.call(this);
28658 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28659 purgeListeners : function(){
28660 Roo.util.Observable.prototype.purgeListeners.call(this);
28661 this.el.removeAllListeners();
28664 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28667 this.pnode.addClass("on");
28670 this.tabPanel.stripWrap.repaint();
28672 this.fireEvent("activate", this.tabPanel, this);
28676 * Returns true if this tab is the active tab.
28677 * @return {Boolean}
28679 isActive : function(){
28680 return this.tabPanel.getActiveTab() == this;
28684 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28687 this.pnode.removeClass("on");
28689 this.fireEvent("deactivate", this.tabPanel, this);
28692 hideAction : function(){
28693 this.bodyEl.hide();
28694 this.bodyEl.setStyle("position", "absolute");
28695 this.bodyEl.setLeft("-20000px");
28696 this.bodyEl.setTop("-20000px");
28699 showAction : function(){
28700 this.bodyEl.setStyle("position", "relative");
28701 this.bodyEl.setTop("");
28702 this.bodyEl.setLeft("");
28703 this.bodyEl.show();
28707 * Set the tooltip for the tab.
28708 * @param {String} tooltip The tab's tooltip
28710 setTooltip : function(text){
28711 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28712 this.textEl.dom.qtip = text;
28713 this.textEl.dom.removeAttribute('title');
28715 this.textEl.dom.title = text;
28719 onTabClick : function(e){
28720 e.preventDefault();
28721 this.tabPanel.activate(this.id);
28724 onTabMouseDown : function(e){
28725 e.preventDefault();
28726 this.tabPanel.activate(this.id);
28729 getWidth : function(){
28730 return this.inner.getWidth();
28733 setWidth : function(width){
28734 var iwidth = width - this.pnode.getPadding("lr");
28735 this.inner.setWidth(iwidth);
28736 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28737 this.pnode.setWidth(width);
28741 * Show or hide the tab
28742 * @param {Boolean} hidden True to hide or false to show.
28744 setHidden : function(hidden){
28745 this.hidden = hidden;
28746 this.pnode.setStyle("display", hidden ? "none" : "");
28750 * Returns true if this tab is "hidden"
28751 * @return {Boolean}
28753 isHidden : function(){
28754 return this.hidden;
28758 * Returns the text for this tab
28761 getText : function(){
28765 autoSize : function(){
28766 //this.el.beginMeasure();
28767 this.textEl.setWidth(1);
28769 * #2804 [new] Tabs in Roojs
28770 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28772 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28773 //this.el.endMeasure();
28777 * Sets the text for the tab (Note: this also sets the tooltip text)
28778 * @param {String} text The tab's text and tooltip
28780 setText : function(text){
28782 this.textEl.update(text);
28783 this.setTooltip(text);
28784 if(!this.tabPanel.resizeTabs){
28789 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28791 activate : function(){
28792 this.tabPanel.activate(this.id);
28796 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28798 disable : function(){
28799 if(this.tabPanel.active != this){
28800 this.disabled = true;
28801 this.pnode.addClass("disabled");
28806 * Enables this TabPanelItem if it was previously disabled.
28808 enable : function(){
28809 this.disabled = false;
28810 this.pnode.removeClass("disabled");
28814 * Sets the content for this TabPanelItem.
28815 * @param {String} content The content
28816 * @param {Boolean} loadScripts true to look for and load scripts
28818 setContent : function(content, loadScripts){
28819 this.bodyEl.update(content, loadScripts);
28823 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28824 * @return {Roo.UpdateManager} The UpdateManager
28826 getUpdateManager : function(){
28827 return this.bodyEl.getUpdateManager();
28831 * Set a URL to be used to load the content for this TabPanelItem.
28832 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28833 * @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)
28834 * @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)
28835 * @return {Roo.UpdateManager} The UpdateManager
28837 setUrl : function(url, params, loadOnce){
28838 if(this.refreshDelegate){
28839 this.un('activate', this.refreshDelegate);
28841 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28842 this.on("activate", this.refreshDelegate);
28843 return this.bodyEl.getUpdateManager();
28847 _handleRefresh : function(url, params, loadOnce){
28848 if(!loadOnce || !this.loaded){
28849 var updater = this.bodyEl.getUpdateManager();
28850 updater.update(url, params, this._setLoaded.createDelegate(this));
28855 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
28856 * Will fail silently if the setUrl method has not been called.
28857 * This does not activate the panel, just updates its content.
28859 refresh : function(){
28860 if(this.refreshDelegate){
28861 this.loaded = false;
28862 this.refreshDelegate();
28867 _setLoaded : function(){
28868 this.loaded = true;
28872 closeClick : function(e){
28875 this.fireEvent("beforeclose", this, o);
28876 if(o.cancel !== true){
28877 this.tabPanel.removeTab(this.id);
28881 * The text displayed in the tooltip for the close icon.
28884 closeText : "Close this tab"
28888 Roo.TabPanel.prototype.createStrip = function(container){
28889 var strip = document.createElement("div");
28890 strip.className = "x-tabs-wrap";
28891 container.appendChild(strip);
28895 Roo.TabPanel.prototype.createStripList = function(strip){
28896 // div wrapper for retard IE
28897 // returns the "tr" element.
28898 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
28899 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
28900 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
28901 return strip.firstChild.firstChild.firstChild.firstChild;
28904 Roo.TabPanel.prototype.createBody = function(container){
28905 var body = document.createElement("div");
28906 Roo.id(body, "tab-body");
28907 Roo.fly(body).addClass("x-tabs-body");
28908 container.appendChild(body);
28912 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
28913 var body = Roo.getDom(id);
28915 body = document.createElement("div");
28918 Roo.fly(body).addClass("x-tabs-item-body");
28919 bodyEl.insertBefore(body, bodyEl.firstChild);
28923 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
28924 var td = document.createElement("td");
28925 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
28926 //stripEl.appendChild(td);
28928 td.className = "x-tabs-closable";
28929 if(!this.closeTpl){
28930 this.closeTpl = new Roo.Template(
28931 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28932 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
28933 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
28936 var el = this.closeTpl.overwrite(td, {"text": text});
28937 var close = el.getElementsByTagName("div")[0];
28938 var inner = el.getElementsByTagName("em")[0];
28939 return {"el": el, "close": close, "inner": inner};
28942 this.tabTpl = new Roo.Template(
28943 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28944 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
28947 var el = this.tabTpl.overwrite(td, {"text": text});
28948 var inner = el.getElementsByTagName("em")[0];
28949 return {"el": el, "inner": inner};
28953 * Ext JS Library 1.1.1
28954 * Copyright(c) 2006-2007, Ext JS, LLC.
28956 * Originally Released Under LGPL - original licence link has changed is not relivant.
28959 * <script type="text/javascript">
28963 * @class Roo.Button
28964 * @extends Roo.util.Observable
28965 * Simple Button class
28966 * @cfg {String} text The button text
28967 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
28968 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
28969 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
28970 * @cfg {Object} scope The scope of the handler
28971 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
28972 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
28973 * @cfg {Boolean} hidden True to start hidden (defaults to false)
28974 * @cfg {Boolean} disabled True to start disabled (defaults to false)
28975 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
28976 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
28977 applies if enableToggle = true)
28978 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
28979 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
28980 an {@link Roo.util.ClickRepeater} config object (defaults to false).
28982 * Create a new button
28983 * @param {Object} config The config object
28985 Roo.Button = function(renderTo, config)
28989 renderTo = config.renderTo || false;
28992 Roo.apply(this, config);
28996 * Fires when this button is clicked
28997 * @param {Button} this
28998 * @param {EventObject} e The click event
29003 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29004 * @param {Button} this
29005 * @param {Boolean} pressed
29010 * Fires when the mouse hovers over the button
29011 * @param {Button} this
29012 * @param {Event} e The event object
29014 'mouseover' : true,
29017 * Fires when the mouse exits the button
29018 * @param {Button} this
29019 * @param {Event} e The event object
29024 * Fires when the button is rendered
29025 * @param {Button} this
29030 this.menu = Roo.menu.MenuMgr.get(this.menu);
29032 // register listeners first!! - so render can be captured..
29033 Roo.util.Observable.call(this);
29035 this.render(renderTo);
29041 Roo.extend(Roo.Button, Roo.util.Observable, {
29047 * Read-only. True if this button is hidden
29052 * Read-only. True if this button is disabled
29057 * Read-only. True if this button is pressed (only if enableToggle = true)
29063 * @cfg {Number} tabIndex
29064 * The DOM tabIndex for this button (defaults to undefined)
29066 tabIndex : undefined,
29069 * @cfg {Boolean} enableToggle
29070 * True to enable pressed/not pressed toggling (defaults to false)
29072 enableToggle: false,
29074 * @cfg {Mixed} menu
29075 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29079 * @cfg {String} menuAlign
29080 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29082 menuAlign : "tl-bl?",
29085 * @cfg {String} iconCls
29086 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29088 iconCls : undefined,
29090 * @cfg {String} type
29091 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29096 menuClassTarget: 'tr',
29099 * @cfg {String} clickEvent
29100 * The type of event to map to the button's event handler (defaults to 'click')
29102 clickEvent : 'click',
29105 * @cfg {Boolean} handleMouseEvents
29106 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29108 handleMouseEvents : true,
29111 * @cfg {String} tooltipType
29112 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29114 tooltipType : 'qtip',
29117 * @cfg {String} cls
29118 * A CSS class to apply to the button's main element.
29122 * @cfg {Roo.Template} template (Optional)
29123 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29124 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29125 * require code modifications if required elements (e.g. a button) aren't present.
29129 render : function(renderTo){
29131 if(this.hideParent){
29132 this.parentEl = Roo.get(renderTo);
29134 if(!this.dhconfig){
29135 if(!this.template){
29136 if(!Roo.Button.buttonTemplate){
29137 // hideous table template
29138 Roo.Button.buttonTemplate = new Roo.Template(
29139 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29140 '<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>',
29141 "</tr></tbody></table>");
29143 this.template = Roo.Button.buttonTemplate;
29145 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29146 var btnEl = btn.child("button:first");
29147 btnEl.on('focus', this.onFocus, this);
29148 btnEl.on('blur', this.onBlur, this);
29150 btn.addClass(this.cls);
29153 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29156 btnEl.addClass(this.iconCls);
29158 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29161 if(this.tabIndex !== undefined){
29162 btnEl.dom.tabIndex = this.tabIndex;
29165 if(typeof this.tooltip == 'object'){
29166 Roo.QuickTips.tips(Roo.apply({
29170 btnEl.dom[this.tooltipType] = this.tooltip;
29174 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29178 this.el.dom.id = this.el.id = this.id;
29181 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29182 this.menu.on("show", this.onMenuShow, this);
29183 this.menu.on("hide", this.onMenuHide, this);
29185 btn.addClass("x-btn");
29186 if(Roo.isIE && !Roo.isIE7){
29187 this.autoWidth.defer(1, this);
29191 if(this.handleMouseEvents){
29192 btn.on("mouseover", this.onMouseOver, this);
29193 btn.on("mouseout", this.onMouseOut, this);
29194 btn.on("mousedown", this.onMouseDown, this);
29196 btn.on(this.clickEvent, this.onClick, this);
29197 //btn.on("mouseup", this.onMouseUp, this);
29204 Roo.ButtonToggleMgr.register(this);
29206 this.el.addClass("x-btn-pressed");
29209 var repeater = new Roo.util.ClickRepeater(btn,
29210 typeof this.repeat == "object" ? this.repeat : {}
29212 repeater.on("click", this.onClick, this);
29215 this.fireEvent('render', this);
29219 * Returns the button's underlying element
29220 * @return {Roo.Element} The element
29222 getEl : function(){
29227 * Destroys this Button and removes any listeners.
29229 destroy : function(){
29230 Roo.ButtonToggleMgr.unregister(this);
29231 this.el.removeAllListeners();
29232 this.purgeListeners();
29237 autoWidth : function(){
29239 this.el.setWidth("auto");
29240 if(Roo.isIE7 && Roo.isStrict){
29241 var ib = this.el.child('button');
29242 if(ib && ib.getWidth() > 20){
29244 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29249 this.el.beginMeasure();
29251 if(this.el.getWidth() < this.minWidth){
29252 this.el.setWidth(this.minWidth);
29255 this.el.endMeasure();
29262 * Assigns this button's click handler
29263 * @param {Function} handler The function to call when the button is clicked
29264 * @param {Object} scope (optional) Scope for the function passed in
29266 setHandler : function(handler, scope){
29267 this.handler = handler;
29268 this.scope = scope;
29272 * Sets this button's text
29273 * @param {String} text The button text
29275 setText : function(text){
29278 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29284 * Gets the text for this button
29285 * @return {String} The button text
29287 getText : function(){
29295 this.hidden = false;
29297 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29305 this.hidden = true;
29307 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29312 * Convenience function for boolean show/hide
29313 * @param {Boolean} visible True to show, false to hide
29315 setVisible: function(visible){
29324 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29325 * @param {Boolean} state (optional) Force a particular state
29327 toggle : function(state){
29328 state = state === undefined ? !this.pressed : state;
29329 if(state != this.pressed){
29331 this.el.addClass("x-btn-pressed");
29332 this.pressed = true;
29333 this.fireEvent("toggle", this, true);
29335 this.el.removeClass("x-btn-pressed");
29336 this.pressed = false;
29337 this.fireEvent("toggle", this, false);
29339 if(this.toggleHandler){
29340 this.toggleHandler.call(this.scope || this, this, state);
29348 focus : function(){
29349 this.el.child('button:first').focus();
29353 * Disable this button
29355 disable : function(){
29357 this.el.addClass("x-btn-disabled");
29359 this.disabled = true;
29363 * Enable this button
29365 enable : function(){
29367 this.el.removeClass("x-btn-disabled");
29369 this.disabled = false;
29373 * Convenience function for boolean enable/disable
29374 * @param {Boolean} enabled True to enable, false to disable
29376 setDisabled : function(v){
29377 this[v !== true ? "enable" : "disable"]();
29381 onClick : function(e)
29384 e.preventDefault();
29389 if(!this.disabled){
29390 if(this.enableToggle){
29393 if(this.menu && !this.menu.isVisible()){
29394 this.menu.show(this.el, this.menuAlign);
29396 this.fireEvent("click", this, e);
29398 this.el.removeClass("x-btn-over");
29399 this.handler.call(this.scope || this, this, e);
29404 onMouseOver : function(e){
29405 if(!this.disabled){
29406 this.el.addClass("x-btn-over");
29407 this.fireEvent('mouseover', this, e);
29411 onMouseOut : function(e){
29412 if(!e.within(this.el, true)){
29413 this.el.removeClass("x-btn-over");
29414 this.fireEvent('mouseout', this, e);
29418 onFocus : function(e){
29419 if(!this.disabled){
29420 this.el.addClass("x-btn-focus");
29424 onBlur : function(e){
29425 this.el.removeClass("x-btn-focus");
29428 onMouseDown : function(e){
29429 if(!this.disabled && e.button == 0){
29430 this.el.addClass("x-btn-click");
29431 Roo.get(document).on('mouseup', this.onMouseUp, this);
29435 onMouseUp : function(e){
29437 this.el.removeClass("x-btn-click");
29438 Roo.get(document).un('mouseup', this.onMouseUp, this);
29442 onMenuShow : function(e){
29443 this.el.addClass("x-btn-menu-active");
29446 onMenuHide : function(e){
29447 this.el.removeClass("x-btn-menu-active");
29451 // Private utility class used by Button
29452 Roo.ButtonToggleMgr = function(){
29455 function toggleGroup(btn, state){
29457 var g = groups[btn.toggleGroup];
29458 for(var i = 0, l = g.length; i < l; i++){
29460 g[i].toggle(false);
29467 register : function(btn){
29468 if(!btn.toggleGroup){
29471 var g = groups[btn.toggleGroup];
29473 g = groups[btn.toggleGroup] = [];
29476 btn.on("toggle", toggleGroup);
29479 unregister : function(btn){
29480 if(!btn.toggleGroup){
29483 var g = groups[btn.toggleGroup];
29486 btn.un("toggle", toggleGroup);
29492 * Ext JS Library 1.1.1
29493 * Copyright(c) 2006-2007, Ext JS, LLC.
29495 * Originally Released Under LGPL - original licence link has changed is not relivant.
29498 * <script type="text/javascript">
29502 * @class Roo.SplitButton
29503 * @extends Roo.Button
29504 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29505 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29506 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29507 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29508 * @cfg {String} arrowTooltip The title attribute of the arrow
29510 * Create a new menu button
29511 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29512 * @param {Object} config The config object
29514 Roo.SplitButton = function(renderTo, config){
29515 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29517 * @event arrowclick
29518 * Fires when this button's arrow is clicked
29519 * @param {SplitButton} this
29520 * @param {EventObject} e The click event
29522 this.addEvents({"arrowclick":true});
29525 Roo.extend(Roo.SplitButton, Roo.Button, {
29526 render : function(renderTo){
29527 // this is one sweet looking template!
29528 var tpl = new Roo.Template(
29529 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29530 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29531 '<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>',
29532 "</tbody></table></td><td>",
29533 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29534 '<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>',
29535 "</tbody></table></td></tr></table>"
29537 var btn = tpl.append(renderTo, [this.text, this.type], true);
29538 var btnEl = btn.child("button");
29540 btn.addClass(this.cls);
29543 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29546 btnEl.addClass(this.iconCls);
29548 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29552 if(this.handleMouseEvents){
29553 btn.on("mouseover", this.onMouseOver, this);
29554 btn.on("mouseout", this.onMouseOut, this);
29555 btn.on("mousedown", this.onMouseDown, this);
29556 btn.on("mouseup", this.onMouseUp, this);
29558 btn.on(this.clickEvent, this.onClick, this);
29560 if(typeof this.tooltip == 'object'){
29561 Roo.QuickTips.tips(Roo.apply({
29565 btnEl.dom[this.tooltipType] = this.tooltip;
29568 if(this.arrowTooltip){
29569 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29578 this.el.addClass("x-btn-pressed");
29580 if(Roo.isIE && !Roo.isIE7){
29581 this.autoWidth.defer(1, this);
29586 this.menu.on("show", this.onMenuShow, this);
29587 this.menu.on("hide", this.onMenuHide, this);
29589 this.fireEvent('render', this);
29593 autoWidth : function(){
29595 var tbl = this.el.child("table:first");
29596 var tbl2 = this.el.child("table:last");
29597 this.el.setWidth("auto");
29598 tbl.setWidth("auto");
29599 if(Roo.isIE7 && Roo.isStrict){
29600 var ib = this.el.child('button:first');
29601 if(ib && ib.getWidth() > 20){
29603 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29608 this.el.beginMeasure();
29610 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29611 tbl.setWidth(this.minWidth-tbl2.getWidth());
29614 this.el.endMeasure();
29617 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29621 * Sets this button's click handler
29622 * @param {Function} handler The function to call when the button is clicked
29623 * @param {Object} scope (optional) Scope for the function passed above
29625 setHandler : function(handler, scope){
29626 this.handler = handler;
29627 this.scope = scope;
29631 * Sets this button's arrow click handler
29632 * @param {Function} handler The function to call when the arrow is clicked
29633 * @param {Object} scope (optional) Scope for the function passed above
29635 setArrowHandler : function(handler, scope){
29636 this.arrowHandler = handler;
29637 this.scope = scope;
29643 focus : function(){
29645 this.el.child("button:first").focus();
29650 onClick : function(e){
29651 e.preventDefault();
29652 if(!this.disabled){
29653 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29654 if(this.menu && !this.menu.isVisible()){
29655 this.menu.show(this.el, this.menuAlign);
29657 this.fireEvent("arrowclick", this, e);
29658 if(this.arrowHandler){
29659 this.arrowHandler.call(this.scope || this, this, e);
29662 this.fireEvent("click", this, e);
29664 this.handler.call(this.scope || this, this, e);
29670 onMouseDown : function(e){
29671 if(!this.disabled){
29672 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29676 onMouseUp : function(e){
29677 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29682 // backwards compat
29683 Roo.MenuButton = Roo.SplitButton;/*
29685 * Ext JS Library 1.1.1
29686 * Copyright(c) 2006-2007, Ext JS, LLC.
29688 * Originally Released Under LGPL - original licence link has changed is not relivant.
29691 * <script type="text/javascript">
29695 * @class Roo.Toolbar
29696 * Basic Toolbar class.
29698 * Creates a new Toolbar
29699 * @param {Object} container The config object
29701 Roo.Toolbar = function(container, buttons, config)
29703 /// old consturctor format still supported..
29704 if(container instanceof Array){ // omit the container for later rendering
29705 buttons = container;
29709 if (typeof(container) == 'object' && container.xtype) {
29710 config = container;
29711 container = config.container;
29712 buttons = config.buttons || []; // not really - use items!!
29715 if (config && config.items) {
29716 xitems = config.items;
29717 delete config.items;
29719 Roo.apply(this, config);
29720 this.buttons = buttons;
29723 this.render(container);
29725 this.xitems = xitems;
29726 Roo.each(xitems, function(b) {
29732 Roo.Toolbar.prototype = {
29734 * @cfg {Array} items
29735 * array of button configs or elements to add (will be converted to a MixedCollection)
29739 * @cfg {String/HTMLElement/Element} container
29740 * The id or element that will contain the toolbar
29743 render : function(ct){
29744 this.el = Roo.get(ct);
29746 this.el.addClass(this.cls);
29748 // using a table allows for vertical alignment
29749 // 100% width is needed by Safari...
29750 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29751 this.tr = this.el.child("tr", true);
29753 this.items = new Roo.util.MixedCollection(false, function(o){
29754 return o.id || ("item" + (++autoId));
29757 this.add.apply(this, this.buttons);
29758 delete this.buttons;
29763 * Adds element(s) to the toolbar -- this function takes a variable number of
29764 * arguments of mixed type and adds them to the toolbar.
29765 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29767 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29768 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29769 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29770 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29771 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29772 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29773 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29774 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29775 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29777 * @param {Mixed} arg2
29778 * @param {Mixed} etc.
29781 var a = arguments, l = a.length;
29782 for(var i = 0; i < l; i++){
29787 _add : function(el) {
29790 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29793 if (el.applyTo){ // some kind of form field
29794 return this.addField(el);
29796 if (el.render){ // some kind of Toolbar.Item
29797 return this.addItem(el);
29799 if (typeof el == "string"){ // string
29800 if(el == "separator" || el == "-"){
29801 return this.addSeparator();
29804 return this.addSpacer();
29807 return this.addFill();
29809 return this.addText(el);
29812 if(el.tagName){ // element
29813 return this.addElement(el);
29815 if(typeof el == "object"){ // must be button config?
29816 return this.addButton(el);
29818 // and now what?!?!
29824 * Add an Xtype element
29825 * @param {Object} xtype Xtype Object
29826 * @return {Object} created Object
29828 addxtype : function(e){
29829 return this.add(e);
29833 * Returns the Element for this toolbar.
29834 * @return {Roo.Element}
29836 getEl : function(){
29842 * @return {Roo.Toolbar.Item} The separator item
29844 addSeparator : function(){
29845 return this.addItem(new Roo.Toolbar.Separator());
29849 * Adds a spacer element
29850 * @return {Roo.Toolbar.Spacer} The spacer item
29852 addSpacer : function(){
29853 return this.addItem(new Roo.Toolbar.Spacer());
29857 * Adds a fill element that forces subsequent additions to the right side of the toolbar
29858 * @return {Roo.Toolbar.Fill} The fill item
29860 addFill : function(){
29861 return this.addItem(new Roo.Toolbar.Fill());
29865 * Adds any standard HTML element to the toolbar
29866 * @param {String/HTMLElement/Element} el The element or id of the element to add
29867 * @return {Roo.Toolbar.Item} The element's item
29869 addElement : function(el){
29870 return this.addItem(new Roo.Toolbar.Item(el));
29873 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
29874 * @type Roo.util.MixedCollection
29879 * Adds any Toolbar.Item or subclass
29880 * @param {Roo.Toolbar.Item} item
29881 * @return {Roo.Toolbar.Item} The item
29883 addItem : function(item){
29884 var td = this.nextBlock();
29886 this.items.add(item);
29891 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
29892 * @param {Object/Array} config A button config or array of configs
29893 * @return {Roo.Toolbar.Button/Array}
29895 addButton : function(config){
29896 if(config instanceof Array){
29898 for(var i = 0, len = config.length; i < len; i++) {
29899 buttons.push(this.addButton(config[i]));
29904 if(!(config instanceof Roo.Toolbar.Button)){
29906 new Roo.Toolbar.SplitButton(config) :
29907 new Roo.Toolbar.Button(config);
29909 var td = this.nextBlock();
29916 * Adds text to the toolbar
29917 * @param {String} text The text to add
29918 * @return {Roo.Toolbar.Item} The element's item
29920 addText : function(text){
29921 return this.addItem(new Roo.Toolbar.TextItem(text));
29925 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
29926 * @param {Number} index The index where the item is to be inserted
29927 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
29928 * @return {Roo.Toolbar.Button/Item}
29930 insertButton : function(index, item){
29931 if(item instanceof Array){
29933 for(var i = 0, len = item.length; i < len; i++) {
29934 buttons.push(this.insertButton(index + i, item[i]));
29938 if (!(item instanceof Roo.Toolbar.Button)){
29939 item = new Roo.Toolbar.Button(item);
29941 var td = document.createElement("td");
29942 this.tr.insertBefore(td, this.tr.childNodes[index]);
29944 this.items.insert(index, item);
29949 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
29950 * @param {Object} config
29951 * @return {Roo.Toolbar.Item} The element's item
29953 addDom : function(config, returnEl){
29954 var td = this.nextBlock();
29955 Roo.DomHelper.overwrite(td, config);
29956 var ti = new Roo.Toolbar.Item(td.firstChild);
29958 this.items.add(ti);
29963 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
29964 * @type Roo.util.MixedCollection
29969 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
29970 * Note: the field should not have been rendered yet. For a field that has already been
29971 * rendered, use {@link #addElement}.
29972 * @param {Roo.form.Field} field
29973 * @return {Roo.ToolbarItem}
29977 addField : function(field) {
29978 if (!this.fields) {
29980 this.fields = new Roo.util.MixedCollection(false, function(o){
29981 return o.id || ("item" + (++autoId));
29986 var td = this.nextBlock();
29988 var ti = new Roo.Toolbar.Item(td.firstChild);
29990 this.items.add(ti);
29991 this.fields.add(field);
30002 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30003 this.el.child('div').hide();
30011 this.el.child('div').show();
30015 nextBlock : function(){
30016 var td = document.createElement("td");
30017 this.tr.appendChild(td);
30022 destroy : function(){
30023 if(this.items){ // rendered?
30024 Roo.destroy.apply(Roo, this.items.items);
30026 if(this.fields){ // rendered?
30027 Roo.destroy.apply(Roo, this.fields.items);
30029 Roo.Element.uncache(this.el, this.tr);
30034 * @class Roo.Toolbar.Item
30035 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30037 * Creates a new Item
30038 * @param {HTMLElement} el
30040 Roo.Toolbar.Item = function(el){
30042 if (typeof (el.xtype) != 'undefined') {
30047 this.el = Roo.getDom(el);
30048 this.id = Roo.id(this.el);
30049 this.hidden = false;
30054 * Fires when the button is rendered
30055 * @param {Button} this
30059 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30061 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30062 //Roo.Toolbar.Item.prototype = {
30065 * Get this item's HTML Element
30066 * @return {HTMLElement}
30068 getEl : function(){
30073 render : function(td){
30076 td.appendChild(this.el);
30078 this.fireEvent('render', this);
30082 * Removes and destroys this item.
30084 destroy : function(){
30085 this.td.parentNode.removeChild(this.td);
30092 this.hidden = false;
30093 this.td.style.display = "";
30100 this.hidden = true;
30101 this.td.style.display = "none";
30105 * Convenience function for boolean show/hide.
30106 * @param {Boolean} visible true to show/false to hide
30108 setVisible: function(visible){
30117 * Try to focus this item.
30119 focus : function(){
30120 Roo.fly(this.el).focus();
30124 * Disables this item.
30126 disable : function(){
30127 Roo.fly(this.td).addClass("x-item-disabled");
30128 this.disabled = true;
30129 this.el.disabled = true;
30133 * Enables this item.
30135 enable : function(){
30136 Roo.fly(this.td).removeClass("x-item-disabled");
30137 this.disabled = false;
30138 this.el.disabled = false;
30144 * @class Roo.Toolbar.Separator
30145 * @extends Roo.Toolbar.Item
30146 * A simple toolbar separator class
30148 * Creates a new Separator
30150 Roo.Toolbar.Separator = function(cfg){
30152 var s = document.createElement("span");
30153 s.className = "ytb-sep";
30158 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30160 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30161 enable:Roo.emptyFn,
30162 disable:Roo.emptyFn,
30167 * @class Roo.Toolbar.Spacer
30168 * @extends Roo.Toolbar.Item
30169 * A simple element that adds extra horizontal space to a toolbar.
30171 * Creates a new Spacer
30173 Roo.Toolbar.Spacer = function(cfg){
30174 var s = document.createElement("div");
30175 s.className = "ytb-spacer";
30179 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30181 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30182 enable:Roo.emptyFn,
30183 disable:Roo.emptyFn,
30188 * @class Roo.Toolbar.Fill
30189 * @extends Roo.Toolbar.Spacer
30190 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30192 * Creates a new Spacer
30194 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30196 render : function(td){
30197 td.style.width = '100%';
30198 Roo.Toolbar.Fill.superclass.render.call(this, td);
30203 * @class Roo.Toolbar.TextItem
30204 * @extends Roo.Toolbar.Item
30205 * A simple class that renders text directly into a toolbar.
30207 * Creates a new TextItem
30208 * @param {String} text
30210 Roo.Toolbar.TextItem = function(cfg){
30211 var text = cfg || "";
30212 if (typeof(cfg) == 'object') {
30213 text = cfg.text || "";
30217 var s = document.createElement("span");
30218 s.className = "ytb-text";
30219 s.innerHTML = text;
30224 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30226 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30229 enable:Roo.emptyFn,
30230 disable:Roo.emptyFn,
30235 * @class Roo.Toolbar.Button
30236 * @extends Roo.Button
30237 * A button that renders into a toolbar.
30239 * Creates a new Button
30240 * @param {Object} config A standard {@link Roo.Button} config object
30242 Roo.Toolbar.Button = function(config){
30243 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30245 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30246 render : function(td){
30248 Roo.Toolbar.Button.superclass.render.call(this, td);
30252 * Removes and destroys this button
30254 destroy : function(){
30255 Roo.Toolbar.Button.superclass.destroy.call(this);
30256 this.td.parentNode.removeChild(this.td);
30260 * Shows this button
30263 this.hidden = false;
30264 this.td.style.display = "";
30268 * Hides this button
30271 this.hidden = true;
30272 this.td.style.display = "none";
30276 * Disables this item
30278 disable : function(){
30279 Roo.fly(this.td).addClass("x-item-disabled");
30280 this.disabled = true;
30284 * Enables this item
30286 enable : function(){
30287 Roo.fly(this.td).removeClass("x-item-disabled");
30288 this.disabled = false;
30291 // backwards compat
30292 Roo.ToolbarButton = Roo.Toolbar.Button;
30295 * @class Roo.Toolbar.SplitButton
30296 * @extends Roo.SplitButton
30297 * A menu button that renders into a toolbar.
30299 * Creates a new SplitButton
30300 * @param {Object} config A standard {@link Roo.SplitButton} config object
30302 Roo.Toolbar.SplitButton = function(config){
30303 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30305 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30306 render : function(td){
30308 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30312 * Removes and destroys this button
30314 destroy : function(){
30315 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30316 this.td.parentNode.removeChild(this.td);
30320 * Shows this button
30323 this.hidden = false;
30324 this.td.style.display = "";
30328 * Hides this button
30331 this.hidden = true;
30332 this.td.style.display = "none";
30336 // backwards compat
30337 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30339 * Ext JS Library 1.1.1
30340 * Copyright(c) 2006-2007, Ext JS, LLC.
30342 * Originally Released Under LGPL - original licence link has changed is not relivant.
30345 * <script type="text/javascript">
30349 * @class Roo.PagingToolbar
30350 * @extends Roo.Toolbar
30351 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30353 * Create a new PagingToolbar
30354 * @param {Object} config The config object
30356 Roo.PagingToolbar = function(el, ds, config)
30358 // old args format still supported... - xtype is prefered..
30359 if (typeof(el) == 'object' && el.xtype) {
30360 // created from xtype...
30362 ds = el.dataSource;
30363 el = config.container;
30366 if (config.items) {
30367 items = config.items;
30371 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30374 this.renderButtons(this.el);
30377 // supprot items array.
30379 Roo.each(items, function(e) {
30380 this.add(Roo.factory(e));
30385 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30387 * @cfg {Roo.data.Store} dataSource
30388 * The underlying data store providing the paged data
30391 * @cfg {String/HTMLElement/Element} container
30392 * container The id or element that will contain the toolbar
30395 * @cfg {Boolean} displayInfo
30396 * True to display the displayMsg (defaults to false)
30399 * @cfg {Number} pageSize
30400 * The number of records to display per page (defaults to 20)
30404 * @cfg {String} displayMsg
30405 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30407 displayMsg : 'Displaying {0} - {1} of {2}',
30409 * @cfg {String} emptyMsg
30410 * The message to display when no records are found (defaults to "No data to display")
30412 emptyMsg : 'No data to display',
30414 * Customizable piece of the default paging text (defaults to "Page")
30417 beforePageText : "Page",
30419 * Customizable piece of the default paging text (defaults to "of %0")
30422 afterPageText : "of {0}",
30424 * Customizable piece of the default paging text (defaults to "First Page")
30427 firstText : "First Page",
30429 * Customizable piece of the default paging text (defaults to "Previous Page")
30432 prevText : "Previous Page",
30434 * Customizable piece of the default paging text (defaults to "Next Page")
30437 nextText : "Next Page",
30439 * Customizable piece of the default paging text (defaults to "Last Page")
30442 lastText : "Last Page",
30444 * Customizable piece of the default paging text (defaults to "Refresh")
30447 refreshText : "Refresh",
30450 renderButtons : function(el){
30451 Roo.PagingToolbar.superclass.render.call(this, el);
30452 this.first = this.addButton({
30453 tooltip: this.firstText,
30454 cls: "x-btn-icon x-grid-page-first",
30456 handler: this.onClick.createDelegate(this, ["first"])
30458 this.prev = this.addButton({
30459 tooltip: this.prevText,
30460 cls: "x-btn-icon x-grid-page-prev",
30462 handler: this.onClick.createDelegate(this, ["prev"])
30464 //this.addSeparator();
30465 this.add(this.beforePageText);
30466 this.field = Roo.get(this.addDom({
30471 cls: "x-grid-page-number"
30473 this.field.on("keydown", this.onPagingKeydown, this);
30474 this.field.on("focus", function(){this.dom.select();});
30475 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30476 this.field.setHeight(18);
30477 //this.addSeparator();
30478 this.next = this.addButton({
30479 tooltip: this.nextText,
30480 cls: "x-btn-icon x-grid-page-next",
30482 handler: this.onClick.createDelegate(this, ["next"])
30484 this.last = this.addButton({
30485 tooltip: this.lastText,
30486 cls: "x-btn-icon x-grid-page-last",
30488 handler: this.onClick.createDelegate(this, ["last"])
30490 //this.addSeparator();
30491 this.loading = this.addButton({
30492 tooltip: this.refreshText,
30493 cls: "x-btn-icon x-grid-loading",
30494 handler: this.onClick.createDelegate(this, ["refresh"])
30497 if(this.displayInfo){
30498 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30503 updateInfo : function(){
30504 if(this.displayEl){
30505 var count = this.ds.getCount();
30506 var msg = count == 0 ?
30510 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30512 this.displayEl.update(msg);
30517 onLoad : function(ds, r, o){
30518 this.cursor = o.params ? o.params.start : 0;
30519 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30521 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30522 this.field.dom.value = ap;
30523 this.first.setDisabled(ap == 1);
30524 this.prev.setDisabled(ap == 1);
30525 this.next.setDisabled(ap == ps);
30526 this.last.setDisabled(ap == ps);
30527 this.loading.enable();
30532 getPageData : function(){
30533 var total = this.ds.getTotalCount();
30536 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30537 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30542 onLoadError : function(){
30543 this.loading.enable();
30547 onPagingKeydown : function(e){
30548 var k = e.getKey();
30549 var d = this.getPageData();
30551 var v = this.field.dom.value, pageNum;
30552 if(!v || isNaN(pageNum = parseInt(v, 10))){
30553 this.field.dom.value = d.activePage;
30556 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30557 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30560 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))
30562 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30563 this.field.dom.value = pageNum;
30564 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30567 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30569 var v = this.field.dom.value, pageNum;
30570 var increment = (e.shiftKey) ? 10 : 1;
30571 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30574 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30575 this.field.dom.value = d.activePage;
30578 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30580 this.field.dom.value = parseInt(v, 10) + increment;
30581 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30582 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30589 beforeLoad : function(){
30591 this.loading.disable();
30596 onClick : function(which){
30600 ds.load({params:{start: 0, limit: this.pageSize}});
30603 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30606 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30609 var total = ds.getTotalCount();
30610 var extra = total % this.pageSize;
30611 var lastStart = extra ? (total - extra) : total-this.pageSize;
30612 ds.load({params:{start: lastStart, limit: this.pageSize}});
30615 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30621 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30622 * @param {Roo.data.Store} store The data store to unbind
30624 unbind : function(ds){
30625 ds.un("beforeload", this.beforeLoad, this);
30626 ds.un("load", this.onLoad, this);
30627 ds.un("loadexception", this.onLoadError, this);
30628 ds.un("remove", this.updateInfo, this);
30629 ds.un("add", this.updateInfo, this);
30630 this.ds = undefined;
30634 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30635 * @param {Roo.data.Store} store The data store to bind
30637 bind : function(ds){
30638 ds.on("beforeload", this.beforeLoad, this);
30639 ds.on("load", this.onLoad, this);
30640 ds.on("loadexception", this.onLoadError, this);
30641 ds.on("remove", this.updateInfo, this);
30642 ds.on("add", this.updateInfo, this);
30647 * Ext JS Library 1.1.1
30648 * Copyright(c) 2006-2007, Ext JS, LLC.
30650 * Originally Released Under LGPL - original licence link has changed is not relivant.
30653 * <script type="text/javascript">
30657 * @class Roo.Resizable
30658 * @extends Roo.util.Observable
30659 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30660 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30661 * 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
30662 * the element will be wrapped for you automatically.</p>
30663 * <p>Here is the list of valid resize handles:</p>
30666 ------ -------------------
30675 'hd' horizontal drag
30678 * <p>Here's an example showing the creation of a typical Resizable:</p>
30680 var resizer = new Roo.Resizable("element-id", {
30688 resizer.on("resize", myHandler);
30690 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30691 * resizer.east.setDisplayed(false);</p>
30692 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30693 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30694 * resize operation's new size (defaults to [0, 0])
30695 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30696 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30697 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30698 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30699 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30700 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30701 * @cfg {Number} width The width of the element in pixels (defaults to null)
30702 * @cfg {Number} height The height of the element in pixels (defaults to null)
30703 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30704 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30705 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30706 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30707 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30708 * in favor of the handles config option (defaults to false)
30709 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30710 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30711 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30712 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30713 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30714 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30715 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30716 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30717 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30718 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30719 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30721 * Create a new resizable component
30722 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30723 * @param {Object} config configuration options
30725 Roo.Resizable = function(el, config)
30727 this.el = Roo.get(el);
30729 if(config && config.wrap){
30730 config.resizeChild = this.el;
30731 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30732 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30733 this.el.setStyle("overflow", "hidden");
30734 this.el.setPositioning(config.resizeChild.getPositioning());
30735 config.resizeChild.clearPositioning();
30736 if(!config.width || !config.height){
30737 var csize = config.resizeChild.getSize();
30738 this.el.setSize(csize.width, csize.height);
30740 if(config.pinned && !config.adjustments){
30741 config.adjustments = "auto";
30745 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30746 this.proxy.unselectable();
30747 this.proxy.enableDisplayMode('block');
30749 Roo.apply(this, config);
30752 this.disableTrackOver = true;
30753 this.el.addClass("x-resizable-pinned");
30755 // if the element isn't positioned, make it relative
30756 var position = this.el.getStyle("position");
30757 if(position != "absolute" && position != "fixed"){
30758 this.el.setStyle("position", "relative");
30760 if(!this.handles){ // no handles passed, must be legacy style
30761 this.handles = 's,e,se';
30762 if(this.multiDirectional){
30763 this.handles += ',n,w';
30766 if(this.handles == "all"){
30767 this.handles = "n s e w ne nw se sw";
30769 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30770 var ps = Roo.Resizable.positions;
30771 for(var i = 0, len = hs.length; i < len; i++){
30772 if(hs[i] && ps[hs[i]]){
30773 var pos = ps[hs[i]];
30774 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30778 this.corner = this.southeast;
30780 // updateBox = the box can move..
30781 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30782 this.updateBox = true;
30785 this.activeHandle = null;
30787 if(this.resizeChild){
30788 if(typeof this.resizeChild == "boolean"){
30789 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30791 this.resizeChild = Roo.get(this.resizeChild, true);
30795 if(this.adjustments == "auto"){
30796 var rc = this.resizeChild;
30797 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30798 if(rc && (hw || hn)){
30799 rc.position("relative");
30800 rc.setLeft(hw ? hw.el.getWidth() : 0);
30801 rc.setTop(hn ? hn.el.getHeight() : 0);
30803 this.adjustments = [
30804 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30805 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30809 if(this.draggable){
30810 this.dd = this.dynamic ?
30811 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30812 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30818 * @event beforeresize
30819 * Fired before resize is allowed. Set enabled to false to cancel resize.
30820 * @param {Roo.Resizable} this
30821 * @param {Roo.EventObject} e The mousedown event
30823 "beforeresize" : true,
30826 * Fired a resizing.
30827 * @param {Roo.Resizable} this
30828 * @param {Number} x The new x position
30829 * @param {Number} y The new y position
30830 * @param {Number} w The new w width
30831 * @param {Number} h The new h hight
30832 * @param {Roo.EventObject} e The mouseup event
30837 * Fired after a resize.
30838 * @param {Roo.Resizable} this
30839 * @param {Number} width The new width
30840 * @param {Number} height The new height
30841 * @param {Roo.EventObject} e The mouseup event
30846 if(this.width !== null && this.height !== null){
30847 this.resizeTo(this.width, this.height);
30849 this.updateChildSize();
30852 this.el.dom.style.zoom = 1;
30854 Roo.Resizable.superclass.constructor.call(this);
30857 Roo.extend(Roo.Resizable, Roo.util.Observable, {
30858 resizeChild : false,
30859 adjustments : [0, 0],
30869 multiDirectional : false,
30870 disableTrackOver : false,
30871 easing : 'easeOutStrong',
30872 widthIncrement : 0,
30873 heightIncrement : 0,
30877 preserveRatio : false,
30878 transparent: false,
30884 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
30886 constrainTo: undefined,
30888 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
30890 resizeRegion: undefined,
30894 * Perform a manual resize
30895 * @param {Number} width
30896 * @param {Number} height
30898 resizeTo : function(width, height){
30899 this.el.setSize(width, height);
30900 this.updateChildSize();
30901 this.fireEvent("resize", this, width, height, null);
30905 startSizing : function(e, handle){
30906 this.fireEvent("beforeresize", this, e);
30907 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
30910 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
30911 this.overlay.unselectable();
30912 this.overlay.enableDisplayMode("block");
30913 this.overlay.on("mousemove", this.onMouseMove, this);
30914 this.overlay.on("mouseup", this.onMouseUp, this);
30916 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
30918 this.resizing = true;
30919 this.startBox = this.el.getBox();
30920 this.startPoint = e.getXY();
30921 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
30922 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
30924 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30925 this.overlay.show();
30927 if(this.constrainTo) {
30928 var ct = Roo.get(this.constrainTo);
30929 this.resizeRegion = ct.getRegion().adjust(
30930 ct.getFrameWidth('t'),
30931 ct.getFrameWidth('l'),
30932 -ct.getFrameWidth('b'),
30933 -ct.getFrameWidth('r')
30937 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
30939 this.proxy.setBox(this.startBox);
30941 this.proxy.setStyle('visibility', 'visible');
30947 onMouseDown : function(handle, e){
30950 this.activeHandle = handle;
30951 this.startSizing(e, handle);
30956 onMouseUp : function(e){
30957 var size = this.resizeElement();
30958 this.resizing = false;
30960 this.overlay.hide();
30962 this.fireEvent("resize", this, size.width, size.height, e);
30966 updateChildSize : function(){
30968 if(this.resizeChild){
30970 var child = this.resizeChild;
30971 var adj = this.adjustments;
30972 if(el.dom.offsetWidth){
30973 var b = el.getSize(true);
30974 child.setSize(b.width+adj[0], b.height+adj[1]);
30976 // Second call here for IE
30977 // The first call enables instant resizing and
30978 // the second call corrects scroll bars if they
30981 setTimeout(function(){
30982 if(el.dom.offsetWidth){
30983 var b = el.getSize(true);
30984 child.setSize(b.width+adj[0], b.height+adj[1]);
30992 snap : function(value, inc, min){
30993 if(!inc || !value) {
30996 var newValue = value;
30997 var m = value % inc;
31000 newValue = value + (inc-m);
31002 newValue = value - m;
31005 return Math.max(min, newValue);
31009 resizeElement : function(){
31010 var box = this.proxy.getBox();
31011 if(this.updateBox){
31012 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31014 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31016 this.updateChildSize();
31024 constrain : function(v, diff, m, mx){
31027 }else if(v - diff > mx){
31034 onMouseMove : function(e){
31037 try{// try catch so if something goes wrong the user doesn't get hung
31039 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31043 //var curXY = this.startPoint;
31044 var curSize = this.curSize || this.startBox;
31045 var x = this.startBox.x, y = this.startBox.y;
31046 var ox = x, oy = y;
31047 var w = curSize.width, h = curSize.height;
31048 var ow = w, oh = h;
31049 var mw = this.minWidth, mh = this.minHeight;
31050 var mxw = this.maxWidth, mxh = this.maxHeight;
31051 var wi = this.widthIncrement;
31052 var hi = this.heightIncrement;
31054 var eventXY = e.getXY();
31055 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31056 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31058 var pos = this.activeHandle.position;
31063 w = Math.min(Math.max(mw, w), mxw);
31068 h = Math.min(Math.max(mh, h), mxh);
31073 w = Math.min(Math.max(mw, w), mxw);
31074 h = Math.min(Math.max(mh, h), mxh);
31077 diffY = this.constrain(h, diffY, mh, mxh);
31084 var adiffX = Math.abs(diffX);
31085 var sub = (adiffX % wi); // how much
31086 if (sub > (wi/2)) { // far enough to snap
31087 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31089 // remove difference..
31090 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31094 x = Math.max(this.minX, x);
31097 diffX = this.constrain(w, diffX, mw, mxw);
31103 w = Math.min(Math.max(mw, w), mxw);
31104 diffY = this.constrain(h, diffY, mh, mxh);
31109 diffX = this.constrain(w, diffX, mw, mxw);
31110 diffY = this.constrain(h, diffY, mh, mxh);
31117 diffX = this.constrain(w, diffX, mw, mxw);
31119 h = Math.min(Math.max(mh, h), mxh);
31125 var sw = this.snap(w, wi, mw);
31126 var sh = this.snap(h, hi, mh);
31127 if(sw != w || sh != h){
31150 if(this.preserveRatio){
31155 h = Math.min(Math.max(mh, h), mxh);
31160 w = Math.min(Math.max(mw, w), mxw);
31165 w = Math.min(Math.max(mw, w), mxw);
31171 w = Math.min(Math.max(mw, w), mxw);
31177 h = Math.min(Math.max(mh, h), mxh);
31185 h = Math.min(Math.max(mh, h), mxh);
31195 h = Math.min(Math.max(mh, h), mxh);
31203 if (pos == 'hdrag') {
31206 this.proxy.setBounds(x, y, w, h);
31208 this.resizeElement();
31212 this.fireEvent("resizing", this, x, y, w, h, e);
31216 handleOver : function(){
31218 this.el.addClass("x-resizable-over");
31223 handleOut : function(){
31224 if(!this.resizing){
31225 this.el.removeClass("x-resizable-over");
31230 * Returns the element this component is bound to.
31231 * @return {Roo.Element}
31233 getEl : function(){
31238 * Returns the resizeChild element (or null).
31239 * @return {Roo.Element}
31241 getResizeChild : function(){
31242 return this.resizeChild;
31244 groupHandler : function()
31249 * Destroys this resizable. If the element was wrapped and
31250 * removeEl is not true then the element remains.
31251 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31253 destroy : function(removeEl){
31254 this.proxy.remove();
31256 this.overlay.removeAllListeners();
31257 this.overlay.remove();
31259 var ps = Roo.Resizable.positions;
31261 if(typeof ps[k] != "function" && this[ps[k]]){
31262 var h = this[ps[k]];
31263 h.el.removeAllListeners();
31268 this.el.update("");
31275 // hash to map config positions to true positions
31276 Roo.Resizable.positions = {
31277 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31282 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31284 // only initialize the template if resizable is used
31285 var tpl = Roo.DomHelper.createTemplate(
31286 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31289 Roo.Resizable.Handle.prototype.tpl = tpl;
31291 this.position = pos;
31293 // show north drag fro topdra
31294 var handlepos = pos == 'hdrag' ? 'north' : pos;
31296 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31297 if (pos == 'hdrag') {
31298 this.el.setStyle('cursor', 'pointer');
31300 this.el.unselectable();
31302 this.el.setOpacity(0);
31304 this.el.on("mousedown", this.onMouseDown, this);
31305 if(!disableTrackOver){
31306 this.el.on("mouseover", this.onMouseOver, this);
31307 this.el.on("mouseout", this.onMouseOut, this);
31312 Roo.Resizable.Handle.prototype = {
31313 afterResize : function(rz){
31318 onMouseDown : function(e){
31319 this.rz.onMouseDown(this, e);
31322 onMouseOver : function(e){
31323 this.rz.handleOver(this, e);
31326 onMouseOut : function(e){
31327 this.rz.handleOut(this, e);
31331 * Ext JS Library 1.1.1
31332 * Copyright(c) 2006-2007, Ext JS, LLC.
31334 * Originally Released Under LGPL - original licence link has changed is not relivant.
31337 * <script type="text/javascript">
31341 * @class Roo.Editor
31342 * @extends Roo.Component
31343 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31345 * Create a new Editor
31346 * @param {Roo.form.Field} field The Field object (or descendant)
31347 * @param {Object} config The config object
31349 Roo.Editor = function(field, config){
31350 Roo.Editor.superclass.constructor.call(this, config);
31351 this.field = field;
31354 * @event beforestartedit
31355 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31356 * false from the handler of this event.
31357 * @param {Editor} this
31358 * @param {Roo.Element} boundEl The underlying element bound to this editor
31359 * @param {Mixed} value The field value being set
31361 "beforestartedit" : true,
31364 * Fires when this editor is displayed
31365 * @param {Roo.Element} boundEl The underlying element bound to this editor
31366 * @param {Mixed} value The starting field value
31368 "startedit" : true,
31370 * @event beforecomplete
31371 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31372 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31373 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31374 * event will not fire since no edit actually occurred.
31375 * @param {Editor} this
31376 * @param {Mixed} value The current field value
31377 * @param {Mixed} startValue The original field value
31379 "beforecomplete" : true,
31382 * Fires after editing is complete and any changed value has been written to the underlying field.
31383 * @param {Editor} this
31384 * @param {Mixed} value The current field value
31385 * @param {Mixed} startValue The original field value
31389 * @event specialkey
31390 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31391 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31392 * @param {Roo.form.Field} this
31393 * @param {Roo.EventObject} e The event object
31395 "specialkey" : true
31399 Roo.extend(Roo.Editor, Roo.Component, {
31401 * @cfg {Boolean/String} autosize
31402 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31403 * or "height" to adopt the height only (defaults to false)
31406 * @cfg {Boolean} revertInvalid
31407 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31408 * validation fails (defaults to true)
31411 * @cfg {Boolean} ignoreNoChange
31412 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31413 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31414 * will never be ignored.
31417 * @cfg {Boolean} hideEl
31418 * False to keep the bound element visible while the editor is displayed (defaults to true)
31421 * @cfg {Mixed} value
31422 * The data value of the underlying field (defaults to "")
31426 * @cfg {String} alignment
31427 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31431 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31432 * for bottom-right shadow (defaults to "frame")
31436 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31440 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31442 completeOnEnter : false,
31444 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31446 cancelOnEsc : false,
31448 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31453 onRender : function(ct, position){
31454 this.el = new Roo.Layer({
31455 shadow: this.shadow,
31461 constrain: this.constrain
31463 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31464 if(this.field.msgTarget != 'title'){
31465 this.field.msgTarget = 'qtip';
31467 this.field.render(this.el);
31469 this.field.el.dom.setAttribute('autocomplete', 'off');
31471 this.field.on("specialkey", this.onSpecialKey, this);
31472 if(this.swallowKeys){
31473 this.field.el.swallowEvent(['keydown','keypress']);
31476 this.field.on("blur", this.onBlur, this);
31477 if(this.field.grow){
31478 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31482 onSpecialKey : function(field, e)
31484 //Roo.log('editor onSpecialKey');
31485 if(this.completeOnEnter && e.getKey() == e.ENTER){
31487 this.completeEdit();
31490 // do not fire special key otherwise it might hide close the editor...
31491 if(e.getKey() == e.ENTER){
31494 if(this.cancelOnEsc && e.getKey() == e.ESC){
31498 this.fireEvent('specialkey', field, e);
31503 * Starts the editing process and shows the editor.
31504 * @param {String/HTMLElement/Element} el The element to edit
31505 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31506 * to the innerHTML of el.
31508 startEdit : function(el, value){
31510 this.completeEdit();
31512 this.boundEl = Roo.get(el);
31513 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31514 if(!this.rendered){
31515 this.render(this.parentEl || document.body);
31517 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31520 this.startValue = v;
31521 this.field.setValue(v);
31523 var sz = this.boundEl.getSize();
31524 switch(this.autoSize){
31526 this.setSize(sz.width, "");
31529 this.setSize("", sz.height);
31532 this.setSize(sz.width, sz.height);
31535 this.el.alignTo(this.boundEl, this.alignment);
31536 this.editing = true;
31538 Roo.QuickTips.disable();
31544 * Sets the height and width of this editor.
31545 * @param {Number} width The new width
31546 * @param {Number} height The new height
31548 setSize : function(w, h){
31549 this.field.setSize(w, h);
31556 * Realigns the editor to the bound field based on the current alignment config value.
31558 realign : function(){
31559 this.el.alignTo(this.boundEl, this.alignment);
31563 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31564 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31566 completeEdit : function(remainVisible){
31570 var v = this.getValue();
31571 if(this.revertInvalid !== false && !this.field.isValid()){
31572 v = this.startValue;
31573 this.cancelEdit(true);
31575 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31576 this.editing = false;
31580 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31581 this.editing = false;
31582 if(this.updateEl && this.boundEl){
31583 this.boundEl.update(v);
31585 if(remainVisible !== true){
31588 this.fireEvent("complete", this, v, this.startValue);
31593 onShow : function(){
31595 if(this.hideEl !== false){
31596 this.boundEl.hide();
31599 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31600 this.fixIEFocus = true;
31601 this.deferredFocus.defer(50, this);
31603 this.field.focus();
31605 this.fireEvent("startedit", this.boundEl, this.startValue);
31608 deferredFocus : function(){
31610 this.field.focus();
31615 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31616 * reverted to the original starting value.
31617 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31618 * cancel (defaults to false)
31620 cancelEdit : function(remainVisible){
31622 this.setValue(this.startValue);
31623 if(remainVisible !== true){
31630 onBlur : function(){
31631 if(this.allowBlur !== true && this.editing){
31632 this.completeEdit();
31637 onHide : function(){
31639 this.completeEdit();
31643 if(this.field.collapse){
31644 this.field.collapse();
31647 if(this.hideEl !== false){
31648 this.boundEl.show();
31651 Roo.QuickTips.enable();
31656 * Sets the data value of the editor
31657 * @param {Mixed} value Any valid value supported by the underlying field
31659 setValue : function(v){
31660 this.field.setValue(v);
31664 * Gets the data value of the editor
31665 * @return {Mixed} The data value
31667 getValue : function(){
31668 return this.field.getValue();
31672 * Ext JS Library 1.1.1
31673 * Copyright(c) 2006-2007, Ext JS, LLC.
31675 * Originally Released Under LGPL - original licence link has changed is not relivant.
31678 * <script type="text/javascript">
31682 * @class Roo.BasicDialog
31683 * @extends Roo.util.Observable
31684 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31686 var dlg = new Roo.BasicDialog("my-dlg", {
31695 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31696 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31697 dlg.addButton('Cancel', dlg.hide, dlg);
31700 <b>A Dialog should always be a direct child of the body element.</b>
31701 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31702 * @cfg {String} title Default text to display in the title bar (defaults to null)
31703 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31704 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31705 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31706 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31707 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31708 * (defaults to null with no animation)
31709 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31710 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31711 * property for valid values (defaults to 'all')
31712 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31713 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31714 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31715 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31716 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31717 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31718 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31719 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31720 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31721 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31722 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31723 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31724 * draggable = true (defaults to false)
31725 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31726 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31727 * shadow (defaults to false)
31728 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31729 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31730 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31731 * @cfg {Array} buttons Array of buttons
31732 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31734 * Create a new BasicDialog.
31735 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31736 * @param {Object} config Configuration options
31738 Roo.BasicDialog = function(el, config){
31739 this.el = Roo.get(el);
31740 var dh = Roo.DomHelper;
31741 if(!this.el && config && config.autoCreate){
31742 if(typeof config.autoCreate == "object"){
31743 if(!config.autoCreate.id){
31744 config.autoCreate.id = el;
31746 this.el = dh.append(document.body,
31747 config.autoCreate, true);
31749 this.el = dh.append(document.body,
31750 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31754 el.setDisplayed(true);
31755 el.hide = this.hideAction;
31757 el.addClass("x-dlg");
31759 Roo.apply(this, config);
31761 this.proxy = el.createProxy("x-dlg-proxy");
31762 this.proxy.hide = this.hideAction;
31763 this.proxy.setOpacity(.5);
31767 el.setWidth(config.width);
31770 el.setHeight(config.height);
31772 this.size = el.getSize();
31773 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31774 this.xy = [config.x,config.y];
31776 this.xy = el.getCenterXY(true);
31778 /** The header element @type Roo.Element */
31779 this.header = el.child("> .x-dlg-hd");
31780 /** The body element @type Roo.Element */
31781 this.body = el.child("> .x-dlg-bd");
31782 /** The footer element @type Roo.Element */
31783 this.footer = el.child("> .x-dlg-ft");
31786 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31789 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31792 this.header.unselectable();
31794 this.header.update(this.title);
31796 // this element allows the dialog to be focused for keyboard event
31797 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31798 this.focusEl.swallowEvent("click", true);
31800 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31802 // wrap the body and footer for special rendering
31803 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31805 this.bwrap.dom.appendChild(this.footer.dom);
31808 this.bg = this.el.createChild({
31809 tag: "div", cls:"x-dlg-bg",
31810 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31812 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31815 if(this.autoScroll !== false && !this.autoTabs){
31816 this.body.setStyle("overflow", "auto");
31819 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31821 if(this.closable !== false){
31822 this.el.addClass("x-dlg-closable");
31823 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31824 this.close.on("click", this.closeClick, this);
31825 this.close.addClassOnOver("x-dlg-close-over");
31827 if(this.collapsible !== false){
31828 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31829 this.collapseBtn.on("click", this.collapseClick, this);
31830 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31831 this.header.on("dblclick", this.collapseClick, this);
31833 if(this.resizable !== false){
31834 this.el.addClass("x-dlg-resizable");
31835 this.resizer = new Roo.Resizable(el, {
31836 minWidth: this.minWidth || 80,
31837 minHeight:this.minHeight || 80,
31838 handles: this.resizeHandles || "all",
31841 this.resizer.on("beforeresize", this.beforeResize, this);
31842 this.resizer.on("resize", this.onResize, this);
31844 if(this.draggable !== false){
31845 el.addClass("x-dlg-draggable");
31846 if (!this.proxyDrag) {
31847 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
31850 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
31852 dd.setHandleElId(this.header.id);
31853 dd.endDrag = this.endMove.createDelegate(this);
31854 dd.startDrag = this.startMove.createDelegate(this);
31855 dd.onDrag = this.onDrag.createDelegate(this);
31860 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
31861 this.mask.enableDisplayMode("block");
31863 this.el.addClass("x-dlg-modal");
31866 this.shadow = new Roo.Shadow({
31867 mode : typeof this.shadow == "string" ? this.shadow : "sides",
31868 offset : this.shadowOffset
31871 this.shadowOffset = 0;
31873 if(Roo.useShims && this.shim !== false){
31874 this.shim = this.el.createShim();
31875 this.shim.hide = this.hideAction;
31883 if (this.buttons) {
31884 var bts= this.buttons;
31886 Roo.each(bts, function(b) {
31895 * Fires when a key is pressed
31896 * @param {Roo.BasicDialog} this
31897 * @param {Roo.EventObject} e
31902 * Fires when this dialog is moved by the user.
31903 * @param {Roo.BasicDialog} this
31904 * @param {Number} x The new page X
31905 * @param {Number} y The new page Y
31910 * Fires when this dialog is resized by the user.
31911 * @param {Roo.BasicDialog} this
31912 * @param {Number} width The new width
31913 * @param {Number} height The new height
31917 * @event beforehide
31918 * Fires before this dialog is hidden.
31919 * @param {Roo.BasicDialog} this
31921 "beforehide" : true,
31924 * Fires when this dialog is hidden.
31925 * @param {Roo.BasicDialog} this
31929 * @event beforeshow
31930 * Fires before this dialog is shown.
31931 * @param {Roo.BasicDialog} this
31933 "beforeshow" : true,
31936 * Fires when this dialog is shown.
31937 * @param {Roo.BasicDialog} this
31941 el.on("keydown", this.onKeyDown, this);
31942 el.on("mousedown", this.toFront, this);
31943 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
31945 Roo.DialogManager.register(this);
31946 Roo.BasicDialog.superclass.constructor.call(this);
31949 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
31950 shadowOffset: Roo.isIE ? 6 : 5,
31953 minButtonWidth: 75,
31954 defaultButton: null,
31955 buttonAlign: "right",
31960 * Sets the dialog title text
31961 * @param {String} text The title text to display
31962 * @return {Roo.BasicDialog} this
31964 setTitle : function(text){
31965 this.header.update(text);
31970 closeClick : function(){
31975 collapseClick : function(){
31976 this[this.collapsed ? "expand" : "collapse"]();
31980 * Collapses the dialog to its minimized state (only the title bar is visible).
31981 * Equivalent to the user clicking the collapse dialog button.
31983 collapse : function(){
31984 if(!this.collapsed){
31985 this.collapsed = true;
31986 this.el.addClass("x-dlg-collapsed");
31987 this.restoreHeight = this.el.getHeight();
31988 this.resizeTo(this.el.getWidth(), this.header.getHeight());
31993 * Expands a collapsed dialog back to its normal state. Equivalent to the user
31994 * clicking the expand dialog button.
31996 expand : function(){
31997 if(this.collapsed){
31998 this.collapsed = false;
31999 this.el.removeClass("x-dlg-collapsed");
32000 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32005 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32006 * @return {Roo.TabPanel} The tabs component
32008 initTabs : function(){
32009 var tabs = this.getTabs();
32010 while(tabs.getTab(0)){
32013 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32015 tabs.addTab(Roo.id(dom), dom.title);
32023 beforeResize : function(){
32024 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32028 onResize : function(){
32029 this.refreshSize();
32030 this.syncBodyHeight();
32031 this.adjustAssets();
32033 this.fireEvent("resize", this, this.size.width, this.size.height);
32037 onKeyDown : function(e){
32038 if(this.isVisible()){
32039 this.fireEvent("keydown", this, e);
32044 * Resizes the dialog.
32045 * @param {Number} width
32046 * @param {Number} height
32047 * @return {Roo.BasicDialog} this
32049 resizeTo : function(width, height){
32050 this.el.setSize(width, height);
32051 this.size = {width: width, height: height};
32052 this.syncBodyHeight();
32053 if(this.fixedcenter){
32056 if(this.isVisible()){
32057 this.constrainXY();
32058 this.adjustAssets();
32060 this.fireEvent("resize", this, width, height);
32066 * Resizes the dialog to fit the specified content size.
32067 * @param {Number} width
32068 * @param {Number} height
32069 * @return {Roo.BasicDialog} this
32071 setContentSize : function(w, h){
32072 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32073 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32074 //if(!this.el.isBorderBox()){
32075 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32076 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32079 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32080 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32082 this.resizeTo(w, h);
32087 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32088 * executed in response to a particular key being pressed while the dialog is active.
32089 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32090 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32091 * @param {Function} fn The function to call
32092 * @param {Object} scope (optional) The scope of the function
32093 * @return {Roo.BasicDialog} this
32095 addKeyListener : function(key, fn, scope){
32096 var keyCode, shift, ctrl, alt;
32097 if(typeof key == "object" && !(key instanceof Array)){
32098 keyCode = key["key"];
32099 shift = key["shift"];
32100 ctrl = key["ctrl"];
32105 var handler = function(dlg, e){
32106 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32107 var k = e.getKey();
32108 if(keyCode instanceof Array){
32109 for(var i = 0, len = keyCode.length; i < len; i++){
32110 if(keyCode[i] == k){
32111 fn.call(scope || window, dlg, k, e);
32117 fn.call(scope || window, dlg, k, e);
32122 this.on("keydown", handler);
32127 * Returns the TabPanel component (creates it if it doesn't exist).
32128 * Note: If you wish to simply check for the existence of tabs without creating them,
32129 * check for a null 'tabs' property.
32130 * @return {Roo.TabPanel} The tabs component
32132 getTabs : function(){
32134 this.el.addClass("x-dlg-auto-tabs");
32135 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32136 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32142 * Adds a button to the footer section of the dialog.
32143 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32144 * object or a valid Roo.DomHelper element config
32145 * @param {Function} handler The function called when the button is clicked
32146 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32147 * @return {Roo.Button} The new button
32149 addButton : function(config, handler, scope){
32150 var dh = Roo.DomHelper;
32152 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32154 if(!this.btnContainer){
32155 var tb = this.footer.createChild({
32157 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32158 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32160 this.btnContainer = tb.firstChild.firstChild.firstChild;
32165 minWidth: this.minButtonWidth,
32168 if(typeof config == "string"){
32169 bconfig.text = config;
32172 bconfig.dhconfig = config;
32174 Roo.apply(bconfig, config);
32178 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32179 bconfig.position = Math.max(0, bconfig.position);
32180 fc = this.btnContainer.childNodes[bconfig.position];
32183 var btn = new Roo.Button(
32185 this.btnContainer.insertBefore(document.createElement("td"),fc)
32186 : this.btnContainer.appendChild(document.createElement("td")),
32187 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32190 this.syncBodyHeight();
32193 * Array of all the buttons that have been added to this dialog via addButton
32198 this.buttons.push(btn);
32203 * Sets the default button to be focused when the dialog is displayed.
32204 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32205 * @return {Roo.BasicDialog} this
32207 setDefaultButton : function(btn){
32208 this.defaultButton = btn;
32213 getHeaderFooterHeight : function(safe){
32216 height += this.header.getHeight();
32219 var fm = this.footer.getMargins();
32220 height += (this.footer.getHeight()+fm.top+fm.bottom);
32222 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32223 height += this.centerBg.getPadding("tb");
32228 syncBodyHeight : function()
32230 var bd = this.body, // the text
32231 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32233 var height = this.size.height - this.getHeaderFooterHeight(false);
32234 bd.setHeight(height-bd.getMargins("tb"));
32235 var hh = this.header.getHeight();
32236 var h = this.size.height-hh;
32239 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32240 bw.setHeight(h-cb.getPadding("tb"));
32242 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32243 bd.setWidth(bw.getWidth(true));
32245 this.tabs.syncHeight();
32247 this.tabs.el.repaint();
32253 * Restores the previous state of the dialog if Roo.state is configured.
32254 * @return {Roo.BasicDialog} this
32256 restoreState : function(){
32257 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32258 if(box && box.width){
32259 this.xy = [box.x, box.y];
32260 this.resizeTo(box.width, box.height);
32266 beforeShow : function(){
32268 if(this.fixedcenter){
32269 this.xy = this.el.getCenterXY(true);
32272 Roo.get(document.body).addClass("x-body-masked");
32273 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32276 this.constrainXY();
32280 animShow : function(){
32281 var b = Roo.get(this.animateTarget).getBox();
32282 this.proxy.setSize(b.width, b.height);
32283 this.proxy.setLocation(b.x, b.y);
32285 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32286 true, .35, this.showEl.createDelegate(this));
32290 * Shows the dialog.
32291 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32292 * @return {Roo.BasicDialog} this
32294 show : function(animateTarget){
32295 if (this.fireEvent("beforeshow", this) === false){
32298 if(this.syncHeightBeforeShow){
32299 this.syncBodyHeight();
32300 }else if(this.firstShow){
32301 this.firstShow = false;
32302 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32304 this.animateTarget = animateTarget || this.animateTarget;
32305 if(!this.el.isVisible()){
32307 if(this.animateTarget && Roo.get(this.animateTarget)){
32317 showEl : function(){
32319 this.el.setXY(this.xy);
32321 this.adjustAssets(true);
32324 // IE peekaboo bug - fix found by Dave Fenwick
32328 this.fireEvent("show", this);
32332 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32333 * dialog itself will receive focus.
32335 focus : function(){
32336 if(this.defaultButton){
32337 this.defaultButton.focus();
32339 this.focusEl.focus();
32344 constrainXY : function(){
32345 if(this.constraintoviewport !== false){
32346 if(!this.viewSize){
32347 if(this.container){
32348 var s = this.container.getSize();
32349 this.viewSize = [s.width, s.height];
32351 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32354 var s = Roo.get(this.container||document).getScroll();
32356 var x = this.xy[0], y = this.xy[1];
32357 var w = this.size.width, h = this.size.height;
32358 var vw = this.viewSize[0], vh = this.viewSize[1];
32359 // only move it if it needs it
32361 // first validate right/bottom
32362 if(x + w > vw+s.left){
32366 if(y + h > vh+s.top){
32370 // then make sure top/left isn't negative
32382 if(this.isVisible()){
32383 this.el.setLocation(x, y);
32384 this.adjustAssets();
32391 onDrag : function(){
32392 if(!this.proxyDrag){
32393 this.xy = this.el.getXY();
32394 this.adjustAssets();
32399 adjustAssets : function(doShow){
32400 var x = this.xy[0], y = this.xy[1];
32401 var w = this.size.width, h = this.size.height;
32402 if(doShow === true){
32404 this.shadow.show(this.el);
32410 if(this.shadow && this.shadow.isVisible()){
32411 this.shadow.show(this.el);
32413 if(this.shim && this.shim.isVisible()){
32414 this.shim.setBounds(x, y, w, h);
32419 adjustViewport : function(w, h){
32421 w = Roo.lib.Dom.getViewWidth();
32422 h = Roo.lib.Dom.getViewHeight();
32425 this.viewSize = [w, h];
32426 if(this.modal && this.mask.isVisible()){
32427 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32428 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32430 if(this.isVisible()){
32431 this.constrainXY();
32436 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32437 * shadow, proxy, mask, etc.) Also removes all event listeners.
32438 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32440 destroy : function(removeEl){
32441 if(this.isVisible()){
32442 this.animateTarget = null;
32445 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32447 this.tabs.destroy(removeEl);
32460 for(var i = 0, len = this.buttons.length; i < len; i++){
32461 this.buttons[i].destroy();
32464 this.el.removeAllListeners();
32465 if(removeEl === true){
32466 this.el.update("");
32469 Roo.DialogManager.unregister(this);
32473 startMove : function(){
32474 if(this.proxyDrag){
32477 if(this.constraintoviewport !== false){
32478 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32483 endMove : function(){
32484 if(!this.proxyDrag){
32485 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32487 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32490 this.refreshSize();
32491 this.adjustAssets();
32493 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32497 * Brings this dialog to the front of any other visible dialogs
32498 * @return {Roo.BasicDialog} this
32500 toFront : function(){
32501 Roo.DialogManager.bringToFront(this);
32506 * Sends this dialog to the back (under) of any other visible dialogs
32507 * @return {Roo.BasicDialog} this
32509 toBack : function(){
32510 Roo.DialogManager.sendToBack(this);
32515 * Centers this dialog in the viewport
32516 * @return {Roo.BasicDialog} this
32518 center : function(){
32519 var xy = this.el.getCenterXY(true);
32520 this.moveTo(xy[0], xy[1]);
32525 * Moves the dialog's top-left corner to the specified point
32526 * @param {Number} x
32527 * @param {Number} y
32528 * @return {Roo.BasicDialog} this
32530 moveTo : function(x, y){
32532 if(this.isVisible()){
32533 this.el.setXY(this.xy);
32534 this.adjustAssets();
32540 * Aligns the dialog to the specified element
32541 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32542 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32543 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32544 * @return {Roo.BasicDialog} this
32546 alignTo : function(element, position, offsets){
32547 this.xy = this.el.getAlignToXY(element, position, offsets);
32548 if(this.isVisible()){
32549 this.el.setXY(this.xy);
32550 this.adjustAssets();
32556 * Anchors an element to another element and realigns it when the window is resized.
32557 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32558 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32559 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32560 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32561 * is a number, it is used as the buffer delay (defaults to 50ms).
32562 * @return {Roo.BasicDialog} this
32564 anchorTo : function(el, alignment, offsets, monitorScroll){
32565 var action = function(){
32566 this.alignTo(el, alignment, offsets);
32568 Roo.EventManager.onWindowResize(action, this);
32569 var tm = typeof monitorScroll;
32570 if(tm != 'undefined'){
32571 Roo.EventManager.on(window, 'scroll', action, this,
32572 {buffer: tm == 'number' ? monitorScroll : 50});
32579 * Returns true if the dialog is visible
32580 * @return {Boolean}
32582 isVisible : function(){
32583 return this.el.isVisible();
32587 animHide : function(callback){
32588 var b = Roo.get(this.animateTarget).getBox();
32590 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32592 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32593 this.hideEl.createDelegate(this, [callback]));
32597 * Hides the dialog.
32598 * @param {Function} callback (optional) Function to call when the dialog is hidden
32599 * @return {Roo.BasicDialog} this
32601 hide : function(callback){
32602 if (this.fireEvent("beforehide", this) === false){
32606 this.shadow.hide();
32611 // sometimes animateTarget seems to get set.. causing problems...
32612 // this just double checks..
32613 if(this.animateTarget && Roo.get(this.animateTarget)) {
32614 this.animHide(callback);
32617 this.hideEl(callback);
32623 hideEl : function(callback){
32627 Roo.get(document.body).removeClass("x-body-masked");
32629 this.fireEvent("hide", this);
32630 if(typeof callback == "function"){
32636 hideAction : function(){
32637 this.setLeft("-10000px");
32638 this.setTop("-10000px");
32639 this.setStyle("visibility", "hidden");
32643 refreshSize : function(){
32644 this.size = this.el.getSize();
32645 this.xy = this.el.getXY();
32646 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32650 // z-index is managed by the DialogManager and may be overwritten at any time
32651 setZIndex : function(index){
32653 this.mask.setStyle("z-index", index);
32656 this.shim.setStyle("z-index", ++index);
32659 this.shadow.setZIndex(++index);
32661 this.el.setStyle("z-index", ++index);
32663 this.proxy.setStyle("z-index", ++index);
32666 this.resizer.proxy.setStyle("z-index", ++index);
32669 this.lastZIndex = index;
32673 * Returns the element for this dialog
32674 * @return {Roo.Element} The underlying dialog Element
32676 getEl : function(){
32682 * @class Roo.DialogManager
32683 * Provides global access to BasicDialogs that have been created and
32684 * support for z-indexing (layering) multiple open dialogs.
32686 Roo.DialogManager = function(){
32688 var accessList = [];
32692 var sortDialogs = function(d1, d2){
32693 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32697 var orderDialogs = function(){
32698 accessList.sort(sortDialogs);
32699 var seed = Roo.DialogManager.zseed;
32700 for(var i = 0, len = accessList.length; i < len; i++){
32701 var dlg = accessList[i];
32703 dlg.setZIndex(seed + (i*10));
32710 * The starting z-index for BasicDialogs (defaults to 9000)
32711 * @type Number The z-index value
32716 register : function(dlg){
32717 list[dlg.id] = dlg;
32718 accessList.push(dlg);
32722 unregister : function(dlg){
32723 delete list[dlg.id];
32726 if(!accessList.indexOf){
32727 for( i = 0, len = accessList.length; i < len; i++){
32728 if(accessList[i] == dlg){
32729 accessList.splice(i, 1);
32734 i = accessList.indexOf(dlg);
32736 accessList.splice(i, 1);
32742 * Gets a registered dialog by id
32743 * @param {String/Object} id The id of the dialog or a dialog
32744 * @return {Roo.BasicDialog} this
32746 get : function(id){
32747 return typeof id == "object" ? id : list[id];
32751 * Brings the specified dialog to the front
32752 * @param {String/Object} dlg The id of the dialog or a dialog
32753 * @return {Roo.BasicDialog} this
32755 bringToFront : function(dlg){
32756 dlg = this.get(dlg);
32759 dlg._lastAccess = new Date().getTime();
32766 * Sends the specified dialog to the back
32767 * @param {String/Object} dlg The id of the dialog or a dialog
32768 * @return {Roo.BasicDialog} this
32770 sendToBack : function(dlg){
32771 dlg = this.get(dlg);
32772 dlg._lastAccess = -(new Date().getTime());
32778 * Hides all dialogs
32780 hideAll : function(){
32781 for(var id in list){
32782 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32791 * @class Roo.LayoutDialog
32792 * @extends Roo.BasicDialog
32793 * Dialog which provides adjustments for working with a layout in a Dialog.
32794 * Add your necessary layout config options to the dialog's config.<br>
32795 * Example usage (including a nested layout):
32798 dialog = new Roo.LayoutDialog("download-dlg", {
32807 // layout config merges with the dialog config
32809 tabPosition: "top",
32810 alwaysShowTabs: true
32813 dialog.addKeyListener(27, dialog.hide, dialog);
32814 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32815 dialog.addButton("Build It!", this.getDownload, this);
32817 // we can even add nested layouts
32818 var innerLayout = new Roo.BorderLayout("dl-inner", {
32828 innerLayout.beginUpdate();
32829 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32830 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32831 innerLayout.endUpdate(true);
32833 var layout = dialog.getLayout();
32834 layout.beginUpdate();
32835 layout.add("center", new Roo.ContentPanel("standard-panel",
32836 {title: "Download the Source", fitToFrame:true}));
32837 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32838 {title: "Build your own roo.js"}));
32839 layout.getRegion("center").showPanel(sp);
32840 layout.endUpdate();
32844 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32845 * @param {Object} config configuration options
32847 Roo.LayoutDialog = function(el, cfg){
32850 if (typeof(cfg) == 'undefined') {
32851 config = Roo.apply({}, el);
32852 // not sure why we use documentElement here.. - it should always be body.
32853 // IE7 borks horribly if we use documentElement.
32854 // webkit also does not like documentElement - it creates a body element...
32855 el = Roo.get( document.body || document.documentElement ).createChild();
32856 //config.autoCreate = true;
32860 config.autoTabs = false;
32861 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
32862 this.body.setStyle({overflow:"hidden", position:"relative"});
32863 this.layout = new Roo.BorderLayout(this.body.dom, config);
32864 this.layout.monitorWindowResize = false;
32865 this.el.addClass("x-dlg-auto-layout");
32866 // fix case when center region overwrites center function
32867 this.center = Roo.BasicDialog.prototype.center;
32868 this.on("show", this.layout.layout, this.layout, true);
32869 if (config.items) {
32870 var xitems = config.items;
32871 delete config.items;
32872 Roo.each(xitems, this.addxtype, this);
32877 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
32879 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
32882 endUpdate : function(){
32883 this.layout.endUpdate();
32887 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
32890 beginUpdate : function(){
32891 this.layout.beginUpdate();
32895 * Get the BorderLayout for this dialog
32896 * @return {Roo.BorderLayout}
32898 getLayout : function(){
32899 return this.layout;
32902 showEl : function(){
32903 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
32905 this.layout.layout();
32910 // Use the syncHeightBeforeShow config option to control this automatically
32911 syncBodyHeight : function(){
32912 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
32913 if(this.layout){this.layout.layout();}
32917 * Add an xtype element (actually adds to the layout.)
32918 * @return {Object} xdata xtype object data.
32921 addxtype : function(c) {
32922 return this.layout.addxtype(c);
32926 * Ext JS Library 1.1.1
32927 * Copyright(c) 2006-2007, Ext JS, LLC.
32929 * Originally Released Under LGPL - original licence link has changed is not relivant.
32932 * <script type="text/javascript">
32936 * @class Roo.MessageBox
32937 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
32941 Roo.Msg.alert('Status', 'Changes saved successfully.');
32943 // Prompt for user data:
32944 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
32946 // process text value...
32950 // Show a dialog using config options:
32952 title:'Save Changes?',
32953 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
32954 buttons: Roo.Msg.YESNOCANCEL,
32961 Roo.MessageBox = function(){
32962 var dlg, opt, mask, waitTimer;
32963 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
32964 var buttons, activeTextEl, bwidth;
32967 var handleButton = function(button){
32969 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
32973 var handleHide = function(){
32974 if(opt && opt.cls){
32975 dlg.el.removeClass(opt.cls);
32978 Roo.TaskMgr.stop(waitTimer);
32984 var updateButtons = function(b){
32987 buttons["ok"].hide();
32988 buttons["cancel"].hide();
32989 buttons["yes"].hide();
32990 buttons["no"].hide();
32991 dlg.footer.dom.style.display = 'none';
32994 dlg.footer.dom.style.display = '';
32995 for(var k in buttons){
32996 if(typeof buttons[k] != "function"){
32999 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33000 width += buttons[k].el.getWidth()+15;
33010 var handleEsc = function(d, k, e){
33011 if(opt && opt.closable !== false){
33021 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33022 * @return {Roo.BasicDialog} The BasicDialog element
33024 getDialog : function(){
33026 dlg = new Roo.BasicDialog("x-msg-box", {
33031 constraintoviewport:false,
33033 collapsible : false,
33036 width:400, height:100,
33037 buttonAlign:"center",
33038 closeClick : function(){
33039 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33040 handleButton("no");
33042 handleButton("cancel");
33046 dlg.on("hide", handleHide);
33048 dlg.addKeyListener(27, handleEsc);
33050 var bt = this.buttonText;
33051 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33052 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33053 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33054 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33055 bodyEl = dlg.body.createChild({
33057 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>'
33059 msgEl = bodyEl.dom.firstChild;
33060 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33061 textboxEl.enableDisplayMode();
33062 textboxEl.addKeyListener([10,13], function(){
33063 if(dlg.isVisible() && opt && opt.buttons){
33064 if(opt.buttons.ok){
33065 handleButton("ok");
33066 }else if(opt.buttons.yes){
33067 handleButton("yes");
33071 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33072 textareaEl.enableDisplayMode();
33073 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33074 progressEl.enableDisplayMode();
33075 var pf = progressEl.dom.firstChild;
33077 pp = Roo.get(pf.firstChild);
33078 pp.setHeight(pf.offsetHeight);
33086 * Updates the message box body text
33087 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33088 * the XHTML-compliant non-breaking space character '&#160;')
33089 * @return {Roo.MessageBox} This message box
33091 updateText : function(text){
33092 if(!dlg.isVisible() && !opt.width){
33093 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33095 msgEl.innerHTML = text || ' ';
33097 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33098 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33100 Math.min(opt.width || cw , this.maxWidth),
33101 Math.max(opt.minWidth || this.minWidth, bwidth)
33104 activeTextEl.setWidth(w);
33106 if(dlg.isVisible()){
33107 dlg.fixedcenter = false;
33109 // to big, make it scroll. = But as usual stupid IE does not support
33112 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33113 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33114 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33116 bodyEl.dom.style.height = '';
33117 bodyEl.dom.style.overflowY = '';
33120 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33122 bodyEl.dom.style.overflowX = '';
33125 dlg.setContentSize(w, bodyEl.getHeight());
33126 if(dlg.isVisible()){
33127 dlg.fixedcenter = true;
33133 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33134 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33135 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33136 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33137 * @return {Roo.MessageBox} This message box
33139 updateProgress : function(value, text){
33141 this.updateText(text);
33143 if (pp) { // weird bug on my firefox - for some reason this is not defined
33144 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33150 * Returns true if the message box is currently displayed
33151 * @return {Boolean} True if the message box is visible, else false
33153 isVisible : function(){
33154 return dlg && dlg.isVisible();
33158 * Hides the message box if it is displayed
33161 if(this.isVisible()){
33167 * Displays a new message box, or reinitializes an existing message box, based on the config options
33168 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33169 * The following config object properties are supported:
33171 Property Type Description
33172 ---------- --------------- ------------------------------------------------------------------------------------
33173 animEl String/Element An id or Element from which the message box should animate as it opens and
33174 closes (defaults to undefined)
33175 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33176 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33177 closable Boolean False to hide the top-right close button (defaults to true). Note that
33178 progress and wait dialogs will ignore this property and always hide the
33179 close button as they can only be closed programmatically.
33180 cls String A custom CSS class to apply to the message box element
33181 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33182 displayed (defaults to 75)
33183 fn Function A callback function to execute after closing the dialog. The arguments to the
33184 function will be btn (the name of the button that was clicked, if applicable,
33185 e.g. "ok"), and text (the value of the active text field, if applicable).
33186 Progress and wait dialogs will ignore this option since they do not respond to
33187 user actions and can only be closed programmatically, so any required function
33188 should be called by the same code after it closes the dialog.
33189 icon String A CSS class that provides a background image to be used as an icon for
33190 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33191 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33192 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33193 modal Boolean False to allow user interaction with the page while the message box is
33194 displayed (defaults to true)
33195 msg String A string that will replace the existing message box body text (defaults
33196 to the XHTML-compliant non-breaking space character ' ')
33197 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33198 progress Boolean True to display a progress bar (defaults to false)
33199 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33200 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33201 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33202 title String The title text
33203 value String The string value to set into the active textbox element if displayed
33204 wait Boolean True to display a progress bar (defaults to false)
33205 width Number The width of the dialog in pixels
33212 msg: 'Please enter your address:',
33214 buttons: Roo.MessageBox.OKCANCEL,
33217 animEl: 'addAddressBtn'
33220 * @param {Object} config Configuration options
33221 * @return {Roo.MessageBox} This message box
33223 show : function(options)
33226 // this causes nightmares if you show one dialog after another
33227 // especially on callbacks..
33229 if(this.isVisible()){
33232 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33233 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33234 Roo.log("New Dialog Message:" + options.msg )
33235 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33236 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33239 var d = this.getDialog();
33241 d.setTitle(opt.title || " ");
33242 d.close.setDisplayed(opt.closable !== false);
33243 activeTextEl = textboxEl;
33244 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33249 textareaEl.setHeight(typeof opt.multiline == "number" ?
33250 opt.multiline : this.defaultTextHeight);
33251 activeTextEl = textareaEl;
33260 progressEl.setDisplayed(opt.progress === true);
33261 this.updateProgress(0);
33262 activeTextEl.dom.value = opt.value || "";
33264 dlg.setDefaultButton(activeTextEl);
33266 var bs = opt.buttons;
33269 db = buttons["ok"];
33270 }else if(bs && bs.yes){
33271 db = buttons["yes"];
33273 dlg.setDefaultButton(db);
33275 bwidth = updateButtons(opt.buttons);
33276 this.updateText(opt.msg);
33278 d.el.addClass(opt.cls);
33280 d.proxyDrag = opt.proxyDrag === true;
33281 d.modal = opt.modal !== false;
33282 d.mask = opt.modal !== false ? mask : false;
33283 if(!d.isVisible()){
33284 // force it to the end of the z-index stack so it gets a cursor in FF
33285 document.body.appendChild(dlg.el.dom);
33286 d.animateTarget = null;
33287 d.show(options.animEl);
33293 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33294 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33295 * and closing the message box when the process is complete.
33296 * @param {String} title The title bar text
33297 * @param {String} msg The message box body text
33298 * @return {Roo.MessageBox} This message box
33300 progress : function(title, msg){
33307 minWidth: this.minProgressWidth,
33314 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33315 * If a callback function is passed it will be called after the user clicks the button, and the
33316 * id of the button that was clicked will be passed as the only parameter to the callback
33317 * (could also be the top-right close button).
33318 * @param {String} title The title bar text
33319 * @param {String} msg The message box body text
33320 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33321 * @param {Object} scope (optional) The scope of the callback function
33322 * @return {Roo.MessageBox} This message box
33324 alert : function(title, msg, fn, scope){
33337 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33338 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33339 * You are responsible for closing the message box when the process is complete.
33340 * @param {String} msg The message box body text
33341 * @param {String} title (optional) The title bar text
33342 * @return {Roo.MessageBox} This message box
33344 wait : function(msg, title){
33355 waitTimer = Roo.TaskMgr.start({
33357 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33365 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33366 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33367 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33368 * @param {String} title The title bar text
33369 * @param {String} msg The message box body text
33370 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33371 * @param {Object} scope (optional) The scope of the callback function
33372 * @return {Roo.MessageBox} This message box
33374 confirm : function(title, msg, fn, scope){
33378 buttons: this.YESNO,
33387 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33388 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33389 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33390 * (could also be the top-right close button) and the text that was entered will be passed as the two
33391 * parameters to the callback.
33392 * @param {String} title The title bar text
33393 * @param {String} msg The message box body text
33394 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33395 * @param {Object} scope (optional) The scope of the callback function
33396 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33397 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33398 * @return {Roo.MessageBox} This message box
33400 prompt : function(title, msg, fn, scope, multiline){
33404 buttons: this.OKCANCEL,
33409 multiline: multiline,
33416 * Button config that displays a single OK button
33421 * Button config that displays Yes and No buttons
33424 YESNO : {yes:true, no:true},
33426 * Button config that displays OK and Cancel buttons
33429 OKCANCEL : {ok:true, cancel:true},
33431 * Button config that displays Yes, No and Cancel buttons
33434 YESNOCANCEL : {yes:true, no:true, cancel:true},
33437 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33440 defaultTextHeight : 75,
33442 * The maximum width in pixels of the message box (defaults to 600)
33447 * The minimum width in pixels of the message box (defaults to 100)
33452 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33453 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33456 minProgressWidth : 250,
33458 * An object containing the default button text strings that can be overriden for localized language support.
33459 * Supported properties are: ok, cancel, yes and no.
33460 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33473 * Shorthand for {@link Roo.MessageBox}
33475 Roo.Msg = Roo.MessageBox;/*
33477 * Ext JS Library 1.1.1
33478 * Copyright(c) 2006-2007, Ext JS, LLC.
33480 * Originally Released Under LGPL - original licence link has changed is not relivant.
33483 * <script type="text/javascript">
33486 * @class Roo.QuickTips
33487 * Provides attractive and customizable tooltips for any element.
33490 Roo.QuickTips = function(){
33491 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33492 var ce, bd, xy, dd;
33493 var visible = false, disabled = true, inited = false;
33494 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33496 var onOver = function(e){
33500 var t = e.getTarget();
33501 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33504 if(ce && t == ce.el){
33505 clearTimeout(hideProc);
33508 if(t && tagEls[t.id]){
33509 tagEls[t.id].el = t;
33510 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33513 var ttp, et = Roo.fly(t);
33514 var ns = cfg.namespace;
33515 if(tm.interceptTitles && t.title){
33518 t.removeAttribute("title");
33519 e.preventDefault();
33521 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33524 showProc = show.defer(tm.showDelay, tm, [{
33527 width: et.getAttributeNS(ns, cfg.width),
33528 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33529 title: et.getAttributeNS(ns, cfg.title),
33530 cls: et.getAttributeNS(ns, cfg.cls)
33535 var onOut = function(e){
33536 clearTimeout(showProc);
33537 var t = e.getTarget();
33538 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33539 hideProc = setTimeout(hide, tm.hideDelay);
33543 var onMove = function(e){
33549 if(tm.trackMouse && ce){
33554 var onDown = function(e){
33555 clearTimeout(showProc);
33556 clearTimeout(hideProc);
33558 if(tm.hideOnClick){
33561 tm.enable.defer(100, tm);
33566 var getPad = function(){
33567 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33570 var show = function(o){
33574 clearTimeout(dismissProc);
33576 if(removeCls){ // in case manually hidden
33577 el.removeClass(removeCls);
33581 el.addClass(ce.cls);
33582 removeCls = ce.cls;
33585 tipTitle.update(ce.title);
33588 tipTitle.update('');
33591 el.dom.style.width = tm.maxWidth+'px';
33592 //tipBody.dom.style.width = '';
33593 tipBodyText.update(o.text);
33594 var p = getPad(), w = ce.width;
33596 var td = tipBodyText.dom;
33597 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33598 if(aw > tm.maxWidth){
33600 }else if(aw < tm.minWidth){
33606 //tipBody.setWidth(w);
33607 el.setWidth(parseInt(w, 10) + p);
33608 if(ce.autoHide === false){
33609 close.setDisplayed(true);
33614 close.setDisplayed(false);
33620 el.avoidY = xy[1]-18;
33625 el.setStyle("visibility", "visible");
33626 el.fadeIn({callback: afterShow});
33632 var afterShow = function(){
33636 if(tm.autoDismiss && ce.autoHide !== false){
33637 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33642 var hide = function(noanim){
33643 clearTimeout(dismissProc);
33644 clearTimeout(hideProc);
33646 if(el.isVisible()){
33648 if(noanim !== true && tm.animate){
33649 el.fadeOut({callback: afterHide});
33656 var afterHide = function(){
33659 el.removeClass(removeCls);
33666 * @cfg {Number} minWidth
33667 * The minimum width of the quick tip (defaults to 40)
33671 * @cfg {Number} maxWidth
33672 * The maximum width of the quick tip (defaults to 300)
33676 * @cfg {Boolean} interceptTitles
33677 * True to automatically use the element's DOM title value if available (defaults to false)
33679 interceptTitles : false,
33681 * @cfg {Boolean} trackMouse
33682 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33684 trackMouse : false,
33686 * @cfg {Boolean} hideOnClick
33687 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33689 hideOnClick : true,
33691 * @cfg {Number} showDelay
33692 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33696 * @cfg {Number} hideDelay
33697 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33701 * @cfg {Boolean} autoHide
33702 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33703 * Used in conjunction with hideDelay.
33708 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33709 * (defaults to true). Used in conjunction with autoDismissDelay.
33711 autoDismiss : true,
33714 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33716 autoDismissDelay : 5000,
33718 * @cfg {Boolean} animate
33719 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33724 * @cfg {String} title
33725 * Title text to display (defaults to ''). This can be any valid HTML markup.
33729 * @cfg {String} text
33730 * Body text to display (defaults to ''). This can be any valid HTML markup.
33734 * @cfg {String} cls
33735 * A CSS class to apply to the base quick tip element (defaults to '').
33739 * @cfg {Number} width
33740 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33741 * minWidth or maxWidth.
33746 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33747 * or display QuickTips in a page.
33750 tm = Roo.QuickTips;
33751 cfg = tm.tagConfig;
33753 if(!Roo.isReady){ // allow calling of init() before onReady
33754 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33757 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33758 el.fxDefaults = {stopFx: true};
33759 // maximum custom styling
33760 //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>');
33761 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>');
33762 tipTitle = el.child('h3');
33763 tipTitle.enableDisplayMode("block");
33764 tipBody = el.child('div.x-tip-bd');
33765 tipBodyText = el.child('div.x-tip-bd-inner');
33766 //bdLeft = el.child('div.x-tip-bd-left');
33767 //bdRight = el.child('div.x-tip-bd-right');
33768 close = el.child('div.x-tip-close');
33769 close.enableDisplayMode("block");
33770 close.on("click", hide);
33771 var d = Roo.get(document);
33772 d.on("mousedown", onDown);
33773 d.on("mouseover", onOver);
33774 d.on("mouseout", onOut);
33775 d.on("mousemove", onMove);
33776 esc = d.addKeyListener(27, hide);
33779 dd = el.initDD("default", null, {
33780 onDrag : function(){
33784 dd.setHandleElId(tipTitle.id);
33793 * Configures a new quick tip instance and assigns it to a target element. The following config options
33796 Property Type Description
33797 ---------- --------------------- ------------------------------------------------------------------------
33798 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33800 * @param {Object} config The config object
33802 register : function(config){
33803 var cs = config instanceof Array ? config : arguments;
33804 for(var i = 0, len = cs.length; i < len; i++) {
33806 var target = c.target;
33808 if(target instanceof Array){
33809 for(var j = 0, jlen = target.length; j < jlen; j++){
33810 tagEls[target[j]] = c;
33813 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33820 * Removes this quick tip from its element and destroys it.
33821 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33823 unregister : function(el){
33824 delete tagEls[Roo.id(el)];
33828 * Enable this quick tip.
33830 enable : function(){
33831 if(inited && disabled){
33833 if(locks.length < 1){
33840 * Disable this quick tip.
33842 disable : function(){
33844 clearTimeout(showProc);
33845 clearTimeout(hideProc);
33846 clearTimeout(dismissProc);
33854 * Returns true if the quick tip is enabled, else false.
33856 isEnabled : function(){
33862 namespace : "roo", // was ext?? this may break..
33863 alt_namespace : "ext",
33864 attribute : "qtip",
33874 // backwards compat
33875 Roo.QuickTips.tips = Roo.QuickTips.register;/*
33877 * Ext JS Library 1.1.1
33878 * Copyright(c) 2006-2007, Ext JS, LLC.
33880 * Originally Released Under LGPL - original licence link has changed is not relivant.
33883 * <script type="text/javascript">
33888 * @class Roo.tree.TreePanel
33889 * @extends Roo.data.Tree
33891 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
33892 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
33893 * @cfg {Boolean} enableDD true to enable drag and drop
33894 * @cfg {Boolean} enableDrag true to enable just drag
33895 * @cfg {Boolean} enableDrop true to enable just drop
33896 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
33897 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
33898 * @cfg {String} ddGroup The DD group this TreePanel belongs to
33899 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
33900 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
33901 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
33902 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
33903 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
33904 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
33905 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
33906 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
33907 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
33908 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
33909 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
33910 * @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>
33911 * @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>
33914 * @param {String/HTMLElement/Element} el The container element
33915 * @param {Object} config
33917 Roo.tree.TreePanel = function(el, config){
33919 var loader = false;
33921 root = config.root;
33922 delete config.root;
33924 if (config.loader) {
33925 loader = config.loader;
33926 delete config.loader;
33929 Roo.apply(this, config);
33930 Roo.tree.TreePanel.superclass.constructor.call(this);
33931 this.el = Roo.get(el);
33932 this.el.addClass('x-tree');
33933 //console.log(root);
33935 this.setRootNode( Roo.factory(root, Roo.tree));
33938 this.loader = Roo.factory(loader, Roo.tree);
33941 * Read-only. The id of the container element becomes this TreePanel's id.
33943 this.id = this.el.id;
33946 * @event beforeload
33947 * Fires before a node is loaded, return false to cancel
33948 * @param {Node} node The node being loaded
33950 "beforeload" : true,
33953 * Fires when a node is loaded
33954 * @param {Node} node The node that was loaded
33958 * @event textchange
33959 * Fires when the text for a node is changed
33960 * @param {Node} node The node
33961 * @param {String} text The new text
33962 * @param {String} oldText The old text
33964 "textchange" : true,
33966 * @event beforeexpand
33967 * Fires before a node is expanded, return false to cancel.
33968 * @param {Node} node The node
33969 * @param {Boolean} deep
33970 * @param {Boolean} anim
33972 "beforeexpand" : true,
33974 * @event beforecollapse
33975 * Fires before a node is collapsed, return false to cancel.
33976 * @param {Node} node The node
33977 * @param {Boolean} deep
33978 * @param {Boolean} anim
33980 "beforecollapse" : true,
33983 * Fires when a node is expanded
33984 * @param {Node} node The node
33988 * @event disabledchange
33989 * Fires when the disabled status of a node changes
33990 * @param {Node} node The node
33991 * @param {Boolean} disabled
33993 "disabledchange" : true,
33996 * Fires when a node is collapsed
33997 * @param {Node} node The node
34001 * @event beforeclick
34002 * Fires before click processing on a node. Return false to cancel the default action.
34003 * @param {Node} node The node
34004 * @param {Roo.EventObject} e The event object
34006 "beforeclick":true,
34008 * @event checkchange
34009 * Fires when a node with a checkbox's checked property changes
34010 * @param {Node} this This node
34011 * @param {Boolean} checked
34013 "checkchange":true,
34016 * Fires when a node is clicked
34017 * @param {Node} node The node
34018 * @param {Roo.EventObject} e The event object
34023 * Fires when a node is double clicked
34024 * @param {Node} node The node
34025 * @param {Roo.EventObject} e The event object
34029 * @event contextmenu
34030 * Fires when a node is right clicked
34031 * @param {Node} node The node
34032 * @param {Roo.EventObject} e The event object
34034 "contextmenu":true,
34036 * @event beforechildrenrendered
34037 * Fires right before the child nodes for a node are rendered
34038 * @param {Node} node The node
34040 "beforechildrenrendered":true,
34043 * Fires when a node starts being dragged
34044 * @param {Roo.tree.TreePanel} this
34045 * @param {Roo.tree.TreeNode} node
34046 * @param {event} e The raw browser event
34048 "startdrag" : true,
34051 * Fires when a drag operation is complete
34052 * @param {Roo.tree.TreePanel} this
34053 * @param {Roo.tree.TreeNode} node
34054 * @param {event} e The raw browser event
34059 * Fires when a dragged node is dropped on a valid DD target
34060 * @param {Roo.tree.TreePanel} this
34061 * @param {Roo.tree.TreeNode} node
34062 * @param {DD} dd The dd it was dropped on
34063 * @param {event} e The raw browser event
34067 * @event beforenodedrop
34068 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34069 * passed to handlers has the following properties:<br />
34070 * <ul style="padding:5px;padding-left:16px;">
34071 * <li>tree - The TreePanel</li>
34072 * <li>target - The node being targeted for the drop</li>
34073 * <li>data - The drag data from the drag source</li>
34074 * <li>point - The point of the drop - append, above or below</li>
34075 * <li>source - The drag source</li>
34076 * <li>rawEvent - Raw mouse event</li>
34077 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34078 * to be inserted by setting them on this object.</li>
34079 * <li>cancel - Set this to true to cancel the drop.</li>
34081 * @param {Object} dropEvent
34083 "beforenodedrop" : true,
34086 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34087 * passed to handlers has the following properties:<br />
34088 * <ul style="padding:5px;padding-left:16px;">
34089 * <li>tree - The TreePanel</li>
34090 * <li>target - The node being targeted for the drop</li>
34091 * <li>data - The drag data from the drag source</li>
34092 * <li>point - The point of the drop - append, above or below</li>
34093 * <li>source - The drag source</li>
34094 * <li>rawEvent - Raw mouse event</li>
34095 * <li>dropNode - Dropped node(s).</li>
34097 * @param {Object} dropEvent
34101 * @event nodedragover
34102 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34103 * passed to handlers has the following properties:<br />
34104 * <ul style="padding:5px;padding-left:16px;">
34105 * <li>tree - The TreePanel</li>
34106 * <li>target - The node being targeted for the drop</li>
34107 * <li>data - The drag data from the drag source</li>
34108 * <li>point - The point of the drop - append, above or below</li>
34109 * <li>source - The drag source</li>
34110 * <li>rawEvent - Raw mouse event</li>
34111 * <li>dropNode - Drop node(s) provided by the source.</li>
34112 * <li>cancel - Set this to true to signal drop not allowed.</li>
34114 * @param {Object} dragOverEvent
34116 "nodedragover" : true
34119 if(this.singleExpand){
34120 this.on("beforeexpand", this.restrictExpand, this);
34123 this.editor.tree = this;
34124 this.editor = Roo.factory(this.editor, Roo.tree);
34127 if (this.selModel) {
34128 this.selModel = Roo.factory(this.selModel, Roo.tree);
34132 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34133 rootVisible : true,
34134 animate: Roo.enableFx,
34137 hlDrop : Roo.enableFx,
34141 rendererTip: false,
34143 restrictExpand : function(node){
34144 var p = node.parentNode;
34146 if(p.expandedChild && p.expandedChild.parentNode == p){
34147 p.expandedChild.collapse();
34149 p.expandedChild = node;
34153 // private override
34154 setRootNode : function(node){
34155 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34156 if(!this.rootVisible){
34157 node.ui = new Roo.tree.RootTreeNodeUI(node);
34163 * Returns the container element for this TreePanel
34165 getEl : function(){
34170 * Returns the default TreeLoader for this TreePanel
34172 getLoader : function(){
34173 return this.loader;
34179 expandAll : function(){
34180 this.root.expand(true);
34184 * Collapse all nodes
34186 collapseAll : function(){
34187 this.root.collapse(true);
34191 * Returns the selection model used by this TreePanel
34193 getSelectionModel : function(){
34194 if(!this.selModel){
34195 this.selModel = new Roo.tree.DefaultSelectionModel();
34197 return this.selModel;
34201 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34202 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34203 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34206 getChecked : function(a, startNode){
34207 startNode = startNode || this.root;
34209 var f = function(){
34210 if(this.attributes.checked){
34211 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34214 startNode.cascade(f);
34219 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34220 * @param {String} path
34221 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34222 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34223 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34225 expandPath : function(path, attr, callback){
34226 attr = attr || "id";
34227 var keys = path.split(this.pathSeparator);
34228 var curNode = this.root;
34229 if(curNode.attributes[attr] != keys[1]){ // invalid root
34231 callback(false, null);
34236 var f = function(){
34237 if(++index == keys.length){
34239 callback(true, curNode);
34243 var c = curNode.findChild(attr, keys[index]);
34246 callback(false, curNode);
34251 c.expand(false, false, f);
34253 curNode.expand(false, false, f);
34257 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34258 * @param {String} path
34259 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34260 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34261 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34263 selectPath : function(path, attr, callback){
34264 attr = attr || "id";
34265 var keys = path.split(this.pathSeparator);
34266 var v = keys.pop();
34267 if(keys.length > 0){
34268 var f = function(success, node){
34269 if(success && node){
34270 var n = node.findChild(attr, v);
34276 }else if(callback){
34277 callback(false, n);
34281 callback(false, n);
34285 this.expandPath(keys.join(this.pathSeparator), attr, f);
34287 this.root.select();
34289 callback(true, this.root);
34294 getTreeEl : function(){
34299 * Trigger rendering of this TreePanel
34301 render : function(){
34302 if (this.innerCt) {
34303 return this; // stop it rendering more than once!!
34306 this.innerCt = this.el.createChild({tag:"ul",
34307 cls:"x-tree-root-ct " +
34308 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34310 if(this.containerScroll){
34311 Roo.dd.ScrollManager.register(this.el);
34313 if((this.enableDD || this.enableDrop) && !this.dropZone){
34315 * The dropZone used by this tree if drop is enabled
34316 * @type Roo.tree.TreeDropZone
34318 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34319 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34322 if((this.enableDD || this.enableDrag) && !this.dragZone){
34324 * The dragZone used by this tree if drag is enabled
34325 * @type Roo.tree.TreeDragZone
34327 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34328 ddGroup: this.ddGroup || "TreeDD",
34329 scroll: this.ddScroll
34332 this.getSelectionModel().init(this);
34334 Roo.log("ROOT not set in tree");
34337 this.root.render();
34338 if(!this.rootVisible){
34339 this.root.renderChildren();
34345 * Ext JS Library 1.1.1
34346 * Copyright(c) 2006-2007, Ext JS, LLC.
34348 * Originally Released Under LGPL - original licence link has changed is not relivant.
34351 * <script type="text/javascript">
34356 * @class Roo.tree.DefaultSelectionModel
34357 * @extends Roo.util.Observable
34358 * The default single selection for a TreePanel.
34359 * @param {Object} cfg Configuration
34361 Roo.tree.DefaultSelectionModel = function(cfg){
34362 this.selNode = null;
34368 * @event selectionchange
34369 * Fires when the selected node changes
34370 * @param {DefaultSelectionModel} this
34371 * @param {TreeNode} node the new selection
34373 "selectionchange" : true,
34376 * @event beforeselect
34377 * Fires before the selected node changes, return false to cancel the change
34378 * @param {DefaultSelectionModel} this
34379 * @param {TreeNode} node the new selection
34380 * @param {TreeNode} node the old selection
34382 "beforeselect" : true
34385 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34388 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34389 init : function(tree){
34391 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34392 tree.on("click", this.onNodeClick, this);
34395 onNodeClick : function(node, e){
34396 if (e.ctrlKey && this.selNode == node) {
34397 this.unselect(node);
34405 * @param {TreeNode} node The node to select
34406 * @return {TreeNode} The selected node
34408 select : function(node){
34409 var last = this.selNode;
34410 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34412 last.ui.onSelectedChange(false);
34414 this.selNode = node;
34415 node.ui.onSelectedChange(true);
34416 this.fireEvent("selectionchange", this, node, last);
34423 * @param {TreeNode} node The node to unselect
34425 unselect : function(node){
34426 if(this.selNode == node){
34427 this.clearSelections();
34432 * Clear all selections
34434 clearSelections : function(){
34435 var n = this.selNode;
34437 n.ui.onSelectedChange(false);
34438 this.selNode = null;
34439 this.fireEvent("selectionchange", this, null);
34445 * Get the selected node
34446 * @return {TreeNode} The selected node
34448 getSelectedNode : function(){
34449 return this.selNode;
34453 * Returns true if the node is selected
34454 * @param {TreeNode} node The node to check
34455 * @return {Boolean}
34457 isSelected : function(node){
34458 return this.selNode == node;
34462 * Selects the node above the selected node in the tree, intelligently walking the nodes
34463 * @return TreeNode The new selection
34465 selectPrevious : function(){
34466 var s = this.selNode || this.lastSelNode;
34470 var ps = s.previousSibling;
34472 if(!ps.isExpanded() || ps.childNodes.length < 1){
34473 return this.select(ps);
34475 var lc = ps.lastChild;
34476 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34479 return this.select(lc);
34481 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34482 return this.select(s.parentNode);
34488 * Selects the node above the selected node in the tree, intelligently walking the nodes
34489 * @return TreeNode The new selection
34491 selectNext : function(){
34492 var s = this.selNode || this.lastSelNode;
34496 if(s.firstChild && s.isExpanded()){
34497 return this.select(s.firstChild);
34498 }else if(s.nextSibling){
34499 return this.select(s.nextSibling);
34500 }else if(s.parentNode){
34502 s.parentNode.bubble(function(){
34503 if(this.nextSibling){
34504 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34513 onKeyDown : function(e){
34514 var s = this.selNode || this.lastSelNode;
34515 // undesirable, but required
34520 var k = e.getKey();
34528 this.selectPrevious();
34531 e.preventDefault();
34532 if(s.hasChildNodes()){
34533 if(!s.isExpanded()){
34535 }else if(s.firstChild){
34536 this.select(s.firstChild, e);
34541 e.preventDefault();
34542 if(s.hasChildNodes() && s.isExpanded()){
34544 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34545 this.select(s.parentNode, e);
34553 * @class Roo.tree.MultiSelectionModel
34554 * @extends Roo.util.Observable
34555 * Multi selection for a TreePanel.
34556 * @param {Object} cfg Configuration
34558 Roo.tree.MultiSelectionModel = function(){
34559 this.selNodes = [];
34563 * @event selectionchange
34564 * Fires when the selected nodes change
34565 * @param {MultiSelectionModel} this
34566 * @param {Array} nodes Array of the selected nodes
34568 "selectionchange" : true
34570 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34574 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34575 init : function(tree){
34577 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34578 tree.on("click", this.onNodeClick, this);
34581 onNodeClick : function(node, e){
34582 this.select(node, e, e.ctrlKey);
34587 * @param {TreeNode} node The node to select
34588 * @param {EventObject} e (optional) An event associated with the selection
34589 * @param {Boolean} keepExisting True to retain existing selections
34590 * @return {TreeNode} The selected node
34592 select : function(node, e, keepExisting){
34593 if(keepExisting !== true){
34594 this.clearSelections(true);
34596 if(this.isSelected(node)){
34597 this.lastSelNode = node;
34600 this.selNodes.push(node);
34601 this.selMap[node.id] = node;
34602 this.lastSelNode = node;
34603 node.ui.onSelectedChange(true);
34604 this.fireEvent("selectionchange", this, this.selNodes);
34610 * @param {TreeNode} node The node to unselect
34612 unselect : function(node){
34613 if(this.selMap[node.id]){
34614 node.ui.onSelectedChange(false);
34615 var sn = this.selNodes;
34618 index = sn.indexOf(node);
34620 for(var i = 0, len = sn.length; i < len; i++){
34628 this.selNodes.splice(index, 1);
34630 delete this.selMap[node.id];
34631 this.fireEvent("selectionchange", this, this.selNodes);
34636 * Clear all selections
34638 clearSelections : function(suppressEvent){
34639 var sn = this.selNodes;
34641 for(var i = 0, len = sn.length; i < len; i++){
34642 sn[i].ui.onSelectedChange(false);
34644 this.selNodes = [];
34646 if(suppressEvent !== true){
34647 this.fireEvent("selectionchange", this, this.selNodes);
34653 * Returns true if the node is selected
34654 * @param {TreeNode} node The node to check
34655 * @return {Boolean}
34657 isSelected : function(node){
34658 return this.selMap[node.id] ? true : false;
34662 * Returns an array of the selected nodes
34665 getSelectedNodes : function(){
34666 return this.selNodes;
34669 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34671 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34673 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34676 * Ext JS Library 1.1.1
34677 * Copyright(c) 2006-2007, Ext JS, LLC.
34679 * Originally Released Under LGPL - original licence link has changed is not relivant.
34682 * <script type="text/javascript">
34686 * @class Roo.tree.TreeNode
34687 * @extends Roo.data.Node
34688 * @cfg {String} text The text for this node
34689 * @cfg {Boolean} expanded true to start the node expanded
34690 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34691 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34692 * @cfg {Boolean} disabled true to start the node disabled
34693 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34694 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34695 * @cfg {String} cls A css class to be added to the node
34696 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34697 * @cfg {String} href URL of the link used for the node (defaults to #)
34698 * @cfg {String} hrefTarget target frame for the link
34699 * @cfg {String} qtip An Ext QuickTip for the node
34700 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34701 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34702 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34703 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34704 * (defaults to undefined with no checkbox rendered)
34706 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34708 Roo.tree.TreeNode = function(attributes){
34709 attributes = attributes || {};
34710 if(typeof attributes == "string"){
34711 attributes = {text: attributes};
34713 this.childrenRendered = false;
34714 this.rendered = false;
34715 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34716 this.expanded = attributes.expanded === true;
34717 this.isTarget = attributes.isTarget !== false;
34718 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34719 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34722 * Read-only. The text for this node. To change it use setText().
34725 this.text = attributes.text;
34727 * True if this node is disabled.
34730 this.disabled = attributes.disabled === true;
34734 * @event textchange
34735 * Fires when the text for this node is changed
34736 * @param {Node} this This node
34737 * @param {String} text The new text
34738 * @param {String} oldText The old text
34740 "textchange" : true,
34742 * @event beforeexpand
34743 * Fires before this node is expanded, return false to cancel.
34744 * @param {Node} this This node
34745 * @param {Boolean} deep
34746 * @param {Boolean} anim
34748 "beforeexpand" : true,
34750 * @event beforecollapse
34751 * Fires before this node is collapsed, return false to cancel.
34752 * @param {Node} this This node
34753 * @param {Boolean} deep
34754 * @param {Boolean} anim
34756 "beforecollapse" : true,
34759 * Fires when this node is expanded
34760 * @param {Node} this This node
34764 * @event disabledchange
34765 * Fires when the disabled status of this node changes
34766 * @param {Node} this This node
34767 * @param {Boolean} disabled
34769 "disabledchange" : true,
34772 * Fires when this node is collapsed
34773 * @param {Node} this This node
34777 * @event beforeclick
34778 * Fires before click processing. Return false to cancel the default action.
34779 * @param {Node} this This node
34780 * @param {Roo.EventObject} e The event object
34782 "beforeclick":true,
34784 * @event checkchange
34785 * Fires when a node with a checkbox's checked property changes
34786 * @param {Node} this This node
34787 * @param {Boolean} checked
34789 "checkchange":true,
34792 * Fires when this node is clicked
34793 * @param {Node} this This node
34794 * @param {Roo.EventObject} e The event object
34799 * Fires when this node is double clicked
34800 * @param {Node} this This node
34801 * @param {Roo.EventObject} e The event object
34805 * @event contextmenu
34806 * Fires when this node is right clicked
34807 * @param {Node} this This node
34808 * @param {Roo.EventObject} e The event object
34810 "contextmenu":true,
34812 * @event beforechildrenrendered
34813 * Fires right before the child nodes for this node are rendered
34814 * @param {Node} this This node
34816 "beforechildrenrendered":true
34819 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34822 * Read-only. The UI for this node
34825 this.ui = new uiClass(this);
34827 // finally support items[]
34828 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34833 Roo.each(this.attributes.items, function(c) {
34834 this.appendChild(Roo.factory(c,Roo.Tree));
34836 delete this.attributes.items;
34841 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34842 preventHScroll: true,
34844 * Returns true if this node is expanded
34845 * @return {Boolean}
34847 isExpanded : function(){
34848 return this.expanded;
34852 * Returns the UI object for this node
34853 * @return {TreeNodeUI}
34855 getUI : function(){
34859 // private override
34860 setFirstChild : function(node){
34861 var of = this.firstChild;
34862 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
34863 if(this.childrenRendered && of && node != of){
34864 of.renderIndent(true, true);
34867 this.renderIndent(true, true);
34871 // private override
34872 setLastChild : function(node){
34873 var ol = this.lastChild;
34874 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
34875 if(this.childrenRendered && ol && node != ol){
34876 ol.renderIndent(true, true);
34879 this.renderIndent(true, true);
34883 // these methods are overridden to provide lazy rendering support
34884 // private override
34885 appendChild : function()
34887 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
34888 if(node && this.childrenRendered){
34891 this.ui.updateExpandIcon();
34895 // private override
34896 removeChild : function(node){
34897 this.ownerTree.getSelectionModel().unselect(node);
34898 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
34899 // if it's been rendered remove dom node
34900 if(this.childrenRendered){
34903 if(this.childNodes.length < 1){
34904 this.collapse(false, false);
34906 this.ui.updateExpandIcon();
34908 if(!this.firstChild) {
34909 this.childrenRendered = false;
34914 // private override
34915 insertBefore : function(node, refNode){
34916 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
34917 if(newNode && refNode && this.childrenRendered){
34920 this.ui.updateExpandIcon();
34925 * Sets the text for this node
34926 * @param {String} text
34928 setText : function(text){
34929 var oldText = this.text;
34931 this.attributes.text = text;
34932 if(this.rendered){ // event without subscribing
34933 this.ui.onTextChange(this, text, oldText);
34935 this.fireEvent("textchange", this, text, oldText);
34939 * Triggers selection of this node
34941 select : function(){
34942 this.getOwnerTree().getSelectionModel().select(this);
34946 * Triggers deselection of this node
34948 unselect : function(){
34949 this.getOwnerTree().getSelectionModel().unselect(this);
34953 * Returns true if this node is selected
34954 * @return {Boolean}
34956 isSelected : function(){
34957 return this.getOwnerTree().getSelectionModel().isSelected(this);
34961 * Expand this node.
34962 * @param {Boolean} deep (optional) True to expand all children as well
34963 * @param {Boolean} anim (optional) false to cancel the default animation
34964 * @param {Function} callback (optional) A callback to be called when
34965 * expanding this node completes (does not wait for deep expand to complete).
34966 * Called with 1 parameter, this node.
34968 expand : function(deep, anim, callback){
34969 if(!this.expanded){
34970 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
34973 if(!this.childrenRendered){
34974 this.renderChildren();
34976 this.expanded = true;
34977 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
34978 this.ui.animExpand(function(){
34979 this.fireEvent("expand", this);
34980 if(typeof callback == "function"){
34984 this.expandChildNodes(true);
34986 }.createDelegate(this));
34990 this.fireEvent("expand", this);
34991 if(typeof callback == "function"){
34996 if(typeof callback == "function"){
35001 this.expandChildNodes(true);
35005 isHiddenRoot : function(){
35006 return this.isRoot && !this.getOwnerTree().rootVisible;
35010 * Collapse this node.
35011 * @param {Boolean} deep (optional) True to collapse all children as well
35012 * @param {Boolean} anim (optional) false to cancel the default animation
35014 collapse : function(deep, anim){
35015 if(this.expanded && !this.isHiddenRoot()){
35016 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35019 this.expanded = false;
35020 if((this.getOwnerTree().animate && anim !== false) || anim){
35021 this.ui.animCollapse(function(){
35022 this.fireEvent("collapse", this);
35024 this.collapseChildNodes(true);
35026 }.createDelegate(this));
35029 this.ui.collapse();
35030 this.fireEvent("collapse", this);
35034 var cs = this.childNodes;
35035 for(var i = 0, len = cs.length; i < len; i++) {
35036 cs[i].collapse(true, false);
35042 delayedExpand : function(delay){
35043 if(!this.expandProcId){
35044 this.expandProcId = this.expand.defer(delay, this);
35049 cancelExpand : function(){
35050 if(this.expandProcId){
35051 clearTimeout(this.expandProcId);
35053 this.expandProcId = false;
35057 * Toggles expanded/collapsed state of the node
35059 toggle : function(){
35068 * Ensures all parent nodes are expanded
35070 ensureVisible : function(callback){
35071 var tree = this.getOwnerTree();
35072 tree.expandPath(this.parentNode.getPath(), false, function(){
35073 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35074 Roo.callback(callback);
35075 }.createDelegate(this));
35079 * Expand all child nodes
35080 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35082 expandChildNodes : function(deep){
35083 var cs = this.childNodes;
35084 for(var i = 0, len = cs.length; i < len; i++) {
35085 cs[i].expand(deep);
35090 * Collapse all child nodes
35091 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35093 collapseChildNodes : function(deep){
35094 var cs = this.childNodes;
35095 for(var i = 0, len = cs.length; i < len; i++) {
35096 cs[i].collapse(deep);
35101 * Disables this node
35103 disable : function(){
35104 this.disabled = true;
35106 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35107 this.ui.onDisableChange(this, true);
35109 this.fireEvent("disabledchange", this, true);
35113 * Enables this node
35115 enable : function(){
35116 this.disabled = false;
35117 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35118 this.ui.onDisableChange(this, false);
35120 this.fireEvent("disabledchange", this, false);
35124 renderChildren : function(suppressEvent){
35125 if(suppressEvent !== false){
35126 this.fireEvent("beforechildrenrendered", this);
35128 var cs = this.childNodes;
35129 for(var i = 0, len = cs.length; i < len; i++){
35130 cs[i].render(true);
35132 this.childrenRendered = true;
35136 sort : function(fn, scope){
35137 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35138 if(this.childrenRendered){
35139 var cs = this.childNodes;
35140 for(var i = 0, len = cs.length; i < len; i++){
35141 cs[i].render(true);
35147 render : function(bulkRender){
35148 this.ui.render(bulkRender);
35149 if(!this.rendered){
35150 this.rendered = true;
35152 this.expanded = false;
35153 this.expand(false, false);
35159 renderIndent : function(deep, refresh){
35161 this.ui.childIndent = null;
35163 this.ui.renderIndent();
35164 if(deep === true && this.childrenRendered){
35165 var cs = this.childNodes;
35166 for(var i = 0, len = cs.length; i < len; i++){
35167 cs[i].renderIndent(true, refresh);
35173 * Ext JS Library 1.1.1
35174 * Copyright(c) 2006-2007, Ext JS, LLC.
35176 * Originally Released Under LGPL - original licence link has changed is not relivant.
35179 * <script type="text/javascript">
35183 * @class Roo.tree.AsyncTreeNode
35184 * @extends Roo.tree.TreeNode
35185 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35187 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35189 Roo.tree.AsyncTreeNode = function(config){
35190 this.loaded = false;
35191 this.loading = false;
35192 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35194 * @event beforeload
35195 * Fires before this node is loaded, return false to cancel
35196 * @param {Node} this This node
35198 this.addEvents({'beforeload':true, 'load': true});
35201 * Fires when this node is loaded
35202 * @param {Node} this This node
35205 * The loader used by this node (defaults to using the tree's defined loader)
35210 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35211 expand : function(deep, anim, callback){
35212 if(this.loading){ // if an async load is already running, waiting til it's done
35214 var f = function(){
35215 if(!this.loading){ // done loading
35216 clearInterval(timer);
35217 this.expand(deep, anim, callback);
35219 }.createDelegate(this);
35220 timer = setInterval(f, 200);
35224 if(this.fireEvent("beforeload", this) === false){
35227 this.loading = true;
35228 this.ui.beforeLoad(this);
35229 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35231 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35235 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35239 * Returns true if this node is currently loading
35240 * @return {Boolean}
35242 isLoading : function(){
35243 return this.loading;
35246 loadComplete : function(deep, anim, callback){
35247 this.loading = false;
35248 this.loaded = true;
35249 this.ui.afterLoad(this);
35250 this.fireEvent("load", this);
35251 this.expand(deep, anim, callback);
35255 * Returns true if this node has been loaded
35256 * @return {Boolean}
35258 isLoaded : function(){
35259 return this.loaded;
35262 hasChildNodes : function(){
35263 if(!this.isLeaf() && !this.loaded){
35266 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35271 * Trigger a reload for this node
35272 * @param {Function} callback
35274 reload : function(callback){
35275 this.collapse(false, false);
35276 while(this.firstChild){
35277 this.removeChild(this.firstChild);
35279 this.childrenRendered = false;
35280 this.loaded = false;
35281 if(this.isHiddenRoot()){
35282 this.expanded = false;
35284 this.expand(false, false, callback);
35288 * Ext JS Library 1.1.1
35289 * Copyright(c) 2006-2007, Ext JS, LLC.
35291 * Originally Released Under LGPL - original licence link has changed is not relivant.
35294 * <script type="text/javascript">
35298 * @class Roo.tree.TreeNodeUI
35300 * @param {Object} node The node to render
35301 * The TreeNode UI implementation is separate from the
35302 * tree implementation. Unless you are customizing the tree UI,
35303 * you should never have to use this directly.
35305 Roo.tree.TreeNodeUI = function(node){
35307 this.rendered = false;
35308 this.animating = false;
35309 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35312 Roo.tree.TreeNodeUI.prototype = {
35313 removeChild : function(node){
35315 this.ctNode.removeChild(node.ui.getEl());
35319 beforeLoad : function(){
35320 this.addClass("x-tree-node-loading");
35323 afterLoad : function(){
35324 this.removeClass("x-tree-node-loading");
35327 onTextChange : function(node, text, oldText){
35329 this.textNode.innerHTML = text;
35333 onDisableChange : function(node, state){
35334 this.disabled = state;
35336 this.addClass("x-tree-node-disabled");
35338 this.removeClass("x-tree-node-disabled");
35342 onSelectedChange : function(state){
35345 this.addClass("x-tree-selected");
35348 this.removeClass("x-tree-selected");
35352 onMove : function(tree, node, oldParent, newParent, index, refNode){
35353 this.childIndent = null;
35355 var targetNode = newParent.ui.getContainer();
35356 if(!targetNode){//target not rendered
35357 this.holder = document.createElement("div");
35358 this.holder.appendChild(this.wrap);
35361 var insertBefore = refNode ? refNode.ui.getEl() : null;
35363 targetNode.insertBefore(this.wrap, insertBefore);
35365 targetNode.appendChild(this.wrap);
35367 this.node.renderIndent(true);
35371 addClass : function(cls){
35373 Roo.fly(this.elNode).addClass(cls);
35377 removeClass : function(cls){
35379 Roo.fly(this.elNode).removeClass(cls);
35383 remove : function(){
35385 this.holder = document.createElement("div");
35386 this.holder.appendChild(this.wrap);
35390 fireEvent : function(){
35391 return this.node.fireEvent.apply(this.node, arguments);
35394 initEvents : function(){
35395 this.node.on("move", this.onMove, this);
35396 var E = Roo.EventManager;
35397 var a = this.anchor;
35399 var el = Roo.fly(a, '_treeui');
35401 if(Roo.isOpera){ // opera render bug ignores the CSS
35402 el.setStyle("text-decoration", "none");
35405 el.on("click", this.onClick, this);
35406 el.on("dblclick", this.onDblClick, this);
35409 Roo.EventManager.on(this.checkbox,
35410 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35413 el.on("contextmenu", this.onContextMenu, this);
35415 var icon = Roo.fly(this.iconNode);
35416 icon.on("click", this.onClick, this);
35417 icon.on("dblclick", this.onDblClick, this);
35418 icon.on("contextmenu", this.onContextMenu, this);
35419 E.on(this.ecNode, "click", this.ecClick, this, true);
35421 if(this.node.disabled){
35422 this.addClass("x-tree-node-disabled");
35424 if(this.node.hidden){
35425 this.addClass("x-tree-node-disabled");
35427 var ot = this.node.getOwnerTree();
35428 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35429 if(dd && (!this.node.isRoot || ot.rootVisible)){
35430 Roo.dd.Registry.register(this.elNode, {
35432 handles: this.getDDHandles(),
35438 getDDHandles : function(){
35439 return [this.iconNode, this.textNode];
35444 this.wrap.style.display = "none";
35450 this.wrap.style.display = "";
35454 onContextMenu : function(e){
35455 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35456 e.preventDefault();
35458 this.fireEvent("contextmenu", this.node, e);
35462 onClick : function(e){
35467 if(this.fireEvent("beforeclick", this.node, e) !== false){
35468 if(!this.disabled && this.node.attributes.href){
35469 this.fireEvent("click", this.node, e);
35472 e.preventDefault();
35477 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35478 this.node.toggle();
35481 this.fireEvent("click", this.node, e);
35487 onDblClick : function(e){
35488 e.preventDefault();
35493 this.toggleCheck();
35495 if(!this.animating && this.node.hasChildNodes()){
35496 this.node.toggle();
35498 this.fireEvent("dblclick", this.node, e);
35501 onCheckChange : function(){
35502 var checked = this.checkbox.checked;
35503 this.node.attributes.checked = checked;
35504 this.fireEvent('checkchange', this.node, checked);
35507 ecClick : function(e){
35508 if(!this.animating && this.node.hasChildNodes()){
35509 this.node.toggle();
35513 startDrop : function(){
35514 this.dropping = true;
35517 // delayed drop so the click event doesn't get fired on a drop
35518 endDrop : function(){
35519 setTimeout(function(){
35520 this.dropping = false;
35521 }.createDelegate(this), 50);
35524 expand : function(){
35525 this.updateExpandIcon();
35526 this.ctNode.style.display = "";
35529 focus : function(){
35530 if(!this.node.preventHScroll){
35531 try{this.anchor.focus();
35533 }else if(!Roo.isIE){
35535 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35536 var l = noscroll.scrollLeft;
35537 this.anchor.focus();
35538 noscroll.scrollLeft = l;
35543 toggleCheck : function(value){
35544 var cb = this.checkbox;
35546 cb.checked = (value === undefined ? !cb.checked : value);
35552 this.anchor.blur();
35556 animExpand : function(callback){
35557 var ct = Roo.get(this.ctNode);
35559 if(!this.node.hasChildNodes()){
35560 this.updateExpandIcon();
35561 this.ctNode.style.display = "";
35562 Roo.callback(callback);
35565 this.animating = true;
35566 this.updateExpandIcon();
35569 callback : function(){
35570 this.animating = false;
35571 Roo.callback(callback);
35574 duration: this.node.ownerTree.duration || .25
35578 highlight : function(){
35579 var tree = this.node.getOwnerTree();
35580 Roo.fly(this.wrap).highlight(
35581 tree.hlColor || "C3DAF9",
35582 {endColor: tree.hlBaseColor}
35586 collapse : function(){
35587 this.updateExpandIcon();
35588 this.ctNode.style.display = "none";
35591 animCollapse : function(callback){
35592 var ct = Roo.get(this.ctNode);
35593 ct.enableDisplayMode('block');
35596 this.animating = true;
35597 this.updateExpandIcon();
35600 callback : function(){
35601 this.animating = false;
35602 Roo.callback(callback);
35605 duration: this.node.ownerTree.duration || .25
35609 getContainer : function(){
35610 return this.ctNode;
35613 getEl : function(){
35617 appendDDGhost : function(ghostNode){
35618 ghostNode.appendChild(this.elNode.cloneNode(true));
35621 getDDRepairXY : function(){
35622 return Roo.lib.Dom.getXY(this.iconNode);
35625 onRender : function(){
35629 render : function(bulkRender){
35630 var n = this.node, a = n.attributes;
35631 var targetNode = n.parentNode ?
35632 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35634 if(!this.rendered){
35635 this.rendered = true;
35637 this.renderElements(n, a, targetNode, bulkRender);
35640 if(this.textNode.setAttributeNS){
35641 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35643 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35646 this.textNode.setAttribute("ext:qtip", a.qtip);
35648 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35651 }else if(a.qtipCfg){
35652 a.qtipCfg.target = Roo.id(this.textNode);
35653 Roo.QuickTips.register(a.qtipCfg);
35656 if(!this.node.expanded){
35657 this.updateExpandIcon();
35660 if(bulkRender === true) {
35661 targetNode.appendChild(this.wrap);
35666 renderElements : function(n, a, targetNode, bulkRender)
35668 // add some indent caching, this helps performance when rendering a large tree
35669 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35670 var t = n.getOwnerTree();
35671 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35672 if (typeof(n.attributes.html) != 'undefined') {
35673 txt = n.attributes.html;
35675 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35676 var cb = typeof a.checked == 'boolean';
35677 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35678 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35679 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35680 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35681 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35682 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35683 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35684 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35685 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35686 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35689 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35690 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35691 n.nextSibling.ui.getEl(), buf.join(""));
35693 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35696 this.elNode = this.wrap.childNodes[0];
35697 this.ctNode = this.wrap.childNodes[1];
35698 var cs = this.elNode.childNodes;
35699 this.indentNode = cs[0];
35700 this.ecNode = cs[1];
35701 this.iconNode = cs[2];
35704 this.checkbox = cs[3];
35707 this.anchor = cs[index];
35708 this.textNode = cs[index].firstChild;
35711 getAnchor : function(){
35712 return this.anchor;
35715 getTextEl : function(){
35716 return this.textNode;
35719 getIconEl : function(){
35720 return this.iconNode;
35723 isChecked : function(){
35724 return this.checkbox ? this.checkbox.checked : false;
35727 updateExpandIcon : function(){
35729 var n = this.node, c1, c2;
35730 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35731 var hasChild = n.hasChildNodes();
35735 c1 = "x-tree-node-collapsed";
35736 c2 = "x-tree-node-expanded";
35739 c1 = "x-tree-node-expanded";
35740 c2 = "x-tree-node-collapsed";
35743 this.removeClass("x-tree-node-leaf");
35744 this.wasLeaf = false;
35746 if(this.c1 != c1 || this.c2 != c2){
35747 Roo.fly(this.elNode).replaceClass(c1, c2);
35748 this.c1 = c1; this.c2 = c2;
35751 // this changes non-leafs into leafs if they have no children.
35752 // it's not very rational behaviour..
35754 if(!this.wasLeaf && this.node.leaf){
35755 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35758 this.wasLeaf = true;
35761 var ecc = "x-tree-ec-icon "+cls;
35762 if(this.ecc != ecc){
35763 this.ecNode.className = ecc;
35769 getChildIndent : function(){
35770 if(!this.childIndent){
35774 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35776 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35778 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35783 this.childIndent = buf.join("");
35785 return this.childIndent;
35788 renderIndent : function(){
35791 var p = this.node.parentNode;
35793 indent = p.ui.getChildIndent();
35795 if(this.indentMarkup != indent){ // don't rerender if not required
35796 this.indentNode.innerHTML = indent;
35797 this.indentMarkup = indent;
35799 this.updateExpandIcon();
35804 Roo.tree.RootTreeNodeUI = function(){
35805 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35807 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35808 render : function(){
35809 if(!this.rendered){
35810 var targetNode = this.node.ownerTree.innerCt.dom;
35811 this.node.expanded = true;
35812 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35813 this.wrap = this.ctNode = targetNode.firstChild;
35816 collapse : function(){
35818 expand : function(){
35822 * Ext JS Library 1.1.1
35823 * Copyright(c) 2006-2007, Ext JS, LLC.
35825 * Originally Released Under LGPL - original licence link has changed is not relivant.
35828 * <script type="text/javascript">
35831 * @class Roo.tree.TreeLoader
35832 * @extends Roo.util.Observable
35833 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35834 * nodes from a specified URL. The response must be a javascript Array definition
35835 * who's elements are node definition objects. eg:
35840 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35841 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
35848 * The old style respose with just an array is still supported, but not recommended.
35851 * A server request is sent, and child nodes are loaded only when a node is expanded.
35852 * The loading node's id is passed to the server under the parameter name "node" to
35853 * enable the server to produce the correct child nodes.
35855 * To pass extra parameters, an event handler may be attached to the "beforeload"
35856 * event, and the parameters specified in the TreeLoader's baseParams property:
35858 myTreeLoader.on("beforeload", function(treeLoader, node) {
35859 this.baseParams.category = node.attributes.category;
35862 * This would pass an HTTP parameter called "category" to the server containing
35863 * the value of the Node's "category" attribute.
35865 * Creates a new Treeloader.
35866 * @param {Object} config A config object containing config properties.
35868 Roo.tree.TreeLoader = function(config){
35869 this.baseParams = {};
35870 this.requestMethod = "POST";
35871 Roo.apply(this, config);
35876 * @event beforeload
35877 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
35878 * @param {Object} This TreeLoader object.
35879 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35880 * @param {Object} callback The callback function specified in the {@link #load} call.
35885 * Fires when the node has been successfuly loaded.
35886 * @param {Object} This TreeLoader object.
35887 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35888 * @param {Object} response The response object containing the data from the server.
35892 * @event loadexception
35893 * Fires if the network request failed.
35894 * @param {Object} This TreeLoader object.
35895 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35896 * @param {Object} response The response object containing the data from the server.
35898 loadexception : true,
35901 * Fires before a node is created, enabling you to return custom Node types
35902 * @param {Object} This TreeLoader object.
35903 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
35908 Roo.tree.TreeLoader.superclass.constructor.call(this);
35911 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
35913 * @cfg {String} dataUrl The URL from which to request a Json string which
35914 * specifies an array of node definition object representing the child nodes
35918 * @cfg {String} requestMethod either GET or POST
35919 * defaults to POST (due to BC)
35923 * @cfg {Object} baseParams (optional) An object containing properties which
35924 * specify HTTP parameters to be passed to each request for child nodes.
35927 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
35928 * created by this loader. If the attributes sent by the server have an attribute in this object,
35929 * they take priority.
35932 * @cfg {Object} uiProviders (optional) An object containing properties which
35934 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
35935 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
35936 * <i>uiProvider</i> attribute of a returned child node is a string rather
35937 * than a reference to a TreeNodeUI implementation, this that string value
35938 * is used as a property name in the uiProviders object. You can define the provider named
35939 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
35944 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
35945 * child nodes before loading.
35947 clearOnLoad : true,
35950 * @cfg {String} root (optional) Default to false. Use this to read data from an object
35951 * property on loading, rather than expecting an array. (eg. more compatible to a standard
35952 * Grid query { data : [ .....] }
35957 * @cfg {String} queryParam (optional)
35958 * Name of the query as it will be passed on the querystring (defaults to 'node')
35959 * eg. the request will be ?node=[id]
35966 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
35967 * This is called automatically when a node is expanded, but may be used to reload
35968 * a node (or append new children if the {@link #clearOnLoad} option is false.)
35969 * @param {Roo.tree.TreeNode} node
35970 * @param {Function} callback
35972 load : function(node, callback){
35973 if(this.clearOnLoad){
35974 while(node.firstChild){
35975 node.removeChild(node.firstChild);
35978 if(node.attributes.children){ // preloaded json children
35979 var cs = node.attributes.children;
35980 for(var i = 0, len = cs.length; i < len; i++){
35981 node.appendChild(this.createNode(cs[i]));
35983 if(typeof callback == "function"){
35986 }else if(this.dataUrl){
35987 this.requestData(node, callback);
35991 getParams: function(node){
35992 var buf = [], bp = this.baseParams;
35993 for(var key in bp){
35994 if(typeof bp[key] != "function"){
35995 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
35998 var n = this.queryParam === false ? 'node' : this.queryParam;
35999 buf.push(n + "=", encodeURIComponent(node.id));
36000 return buf.join("");
36003 requestData : function(node, callback){
36004 if(this.fireEvent("beforeload", this, node, callback) !== false){
36005 this.transId = Roo.Ajax.request({
36006 method:this.requestMethod,
36007 url: this.dataUrl||this.url,
36008 success: this.handleResponse,
36009 failure: this.handleFailure,
36011 argument: {callback: callback, node: node},
36012 params: this.getParams(node)
36015 // if the load is cancelled, make sure we notify
36016 // the node that we are done
36017 if(typeof callback == "function"){
36023 isLoading : function(){
36024 return this.transId ? true : false;
36027 abort : function(){
36028 if(this.isLoading()){
36029 Roo.Ajax.abort(this.transId);
36034 createNode : function(attr)
36036 // apply baseAttrs, nice idea Corey!
36037 if(this.baseAttrs){
36038 Roo.applyIf(attr, this.baseAttrs);
36040 if(this.applyLoader !== false){
36041 attr.loader = this;
36043 // uiProvider = depreciated..
36045 if(typeof(attr.uiProvider) == 'string'){
36046 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36047 /** eval:var:attr */ eval(attr.uiProvider);
36049 if(typeof(this.uiProviders['default']) != 'undefined') {
36050 attr.uiProvider = this.uiProviders['default'];
36053 this.fireEvent('create', this, attr);
36055 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36057 new Roo.tree.TreeNode(attr) :
36058 new Roo.tree.AsyncTreeNode(attr));
36061 processResponse : function(response, node, callback)
36063 var json = response.responseText;
36066 var o = Roo.decode(json);
36068 if (this.root === false && typeof(o.success) != undefined) {
36069 this.root = 'data'; // the default behaviour for list like data..
36072 if (this.root !== false && !o.success) {
36073 // it's a failure condition.
36074 var a = response.argument;
36075 this.fireEvent("loadexception", this, a.node, response);
36076 Roo.log("Load failed - should have a handler really");
36082 if (this.root !== false) {
36086 for(var i = 0, len = o.length; i < len; i++){
36087 var n = this.createNode(o[i]);
36089 node.appendChild(n);
36092 if(typeof callback == "function"){
36093 callback(this, node);
36096 this.handleFailure(response);
36100 handleResponse : function(response){
36101 this.transId = false;
36102 var a = response.argument;
36103 this.processResponse(response, a.node, a.callback);
36104 this.fireEvent("load", this, a.node, response);
36107 handleFailure : function(response)
36109 // should handle failure better..
36110 this.transId = false;
36111 var a = response.argument;
36112 this.fireEvent("loadexception", this, a.node, response);
36113 if(typeof a.callback == "function"){
36114 a.callback(this, a.node);
36119 * Ext JS Library 1.1.1
36120 * Copyright(c) 2006-2007, Ext JS, LLC.
36122 * Originally Released Under LGPL - original licence link has changed is not relivant.
36125 * <script type="text/javascript">
36129 * @class Roo.tree.TreeFilter
36130 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36131 * @param {TreePanel} tree
36132 * @param {Object} config (optional)
36134 Roo.tree.TreeFilter = function(tree, config){
36136 this.filtered = {};
36137 Roo.apply(this, config);
36140 Roo.tree.TreeFilter.prototype = {
36147 * Filter the data by a specific attribute.
36148 * @param {String/RegExp} value Either string that the attribute value
36149 * should start with or a RegExp to test against the attribute
36150 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36151 * @param {TreeNode} startNode (optional) The node to start the filter at.
36153 filter : function(value, attr, startNode){
36154 attr = attr || "text";
36156 if(typeof value == "string"){
36157 var vlen = value.length;
36158 // auto clear empty filter
36159 if(vlen == 0 && this.clearBlank){
36163 value = value.toLowerCase();
36165 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36167 }else if(value.exec){ // regex?
36169 return value.test(n.attributes[attr]);
36172 throw 'Illegal filter type, must be string or regex';
36174 this.filterBy(f, null, startNode);
36178 * Filter by a function. The passed function will be called with each
36179 * node in the tree (or from the startNode). If the function returns true, the node is kept
36180 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36181 * @param {Function} fn The filter function
36182 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36184 filterBy : function(fn, scope, startNode){
36185 startNode = startNode || this.tree.root;
36186 if(this.autoClear){
36189 var af = this.filtered, rv = this.reverse;
36190 var f = function(n){
36191 if(n == startNode){
36197 var m = fn.call(scope || n, n);
36205 startNode.cascade(f);
36208 if(typeof id != "function"){
36210 if(n && n.parentNode){
36211 n.parentNode.removeChild(n);
36219 * Clears the current filter. Note: with the "remove" option
36220 * set a filter cannot be cleared.
36222 clear : function(){
36224 var af = this.filtered;
36226 if(typeof id != "function"){
36233 this.filtered = {};
36238 * Ext JS Library 1.1.1
36239 * Copyright(c) 2006-2007, Ext JS, LLC.
36241 * Originally Released Under LGPL - original licence link has changed is not relivant.
36244 * <script type="text/javascript">
36249 * @class Roo.tree.TreeSorter
36250 * Provides sorting of nodes in a TreePanel
36252 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36253 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36254 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36255 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36256 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36257 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36259 * @param {TreePanel} tree
36260 * @param {Object} config
36262 Roo.tree.TreeSorter = function(tree, config){
36263 Roo.apply(this, config);
36264 tree.on("beforechildrenrendered", this.doSort, this);
36265 tree.on("append", this.updateSort, this);
36266 tree.on("insert", this.updateSort, this);
36268 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36269 var p = this.property || "text";
36270 var sortType = this.sortType;
36271 var fs = this.folderSort;
36272 var cs = this.caseSensitive === true;
36273 var leafAttr = this.leafAttr || 'leaf';
36275 this.sortFn = function(n1, n2){
36277 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36280 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36284 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36285 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36287 return dsc ? +1 : -1;
36289 return dsc ? -1 : +1;
36296 Roo.tree.TreeSorter.prototype = {
36297 doSort : function(node){
36298 node.sort(this.sortFn);
36301 compareNodes : function(n1, n2){
36302 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36305 updateSort : function(tree, node){
36306 if(node.childrenRendered){
36307 this.doSort.defer(1, this, [node]);
36312 * Ext JS Library 1.1.1
36313 * Copyright(c) 2006-2007, Ext JS, LLC.
36315 * Originally Released Under LGPL - original licence link has changed is not relivant.
36318 * <script type="text/javascript">
36321 if(Roo.dd.DropZone){
36323 Roo.tree.TreeDropZone = function(tree, config){
36324 this.allowParentInsert = false;
36325 this.allowContainerDrop = false;
36326 this.appendOnly = false;
36327 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36329 this.lastInsertClass = "x-tree-no-status";
36330 this.dragOverData = {};
36333 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36334 ddGroup : "TreeDD",
36337 expandDelay : 1000,
36339 expandNode : function(node){
36340 if(node.hasChildNodes() && !node.isExpanded()){
36341 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36345 queueExpand : function(node){
36346 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36349 cancelExpand : function(){
36350 if(this.expandProcId){
36351 clearTimeout(this.expandProcId);
36352 this.expandProcId = false;
36356 isValidDropPoint : function(n, pt, dd, e, data){
36357 if(!n || !data){ return false; }
36358 var targetNode = n.node;
36359 var dropNode = data.node;
36360 // default drop rules
36361 if(!(targetNode && targetNode.isTarget && pt)){
36364 if(pt == "append" && targetNode.allowChildren === false){
36367 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36370 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36373 // reuse the object
36374 var overEvent = this.dragOverData;
36375 overEvent.tree = this.tree;
36376 overEvent.target = targetNode;
36377 overEvent.data = data;
36378 overEvent.point = pt;
36379 overEvent.source = dd;
36380 overEvent.rawEvent = e;
36381 overEvent.dropNode = dropNode;
36382 overEvent.cancel = false;
36383 var result = this.tree.fireEvent("nodedragover", overEvent);
36384 return overEvent.cancel === false && result !== false;
36387 getDropPoint : function(e, n, dd)
36391 return tn.allowChildren !== false ? "append" : false; // always append for root
36393 var dragEl = n.ddel;
36394 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36395 var y = Roo.lib.Event.getPageY(e);
36396 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36398 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36399 var noAppend = tn.allowChildren === false;
36400 if(this.appendOnly || tn.parentNode.allowChildren === false){
36401 return noAppend ? false : "append";
36403 var noBelow = false;
36404 if(!this.allowParentInsert){
36405 noBelow = tn.hasChildNodes() && tn.isExpanded();
36407 var q = (b - t) / (noAppend ? 2 : 3);
36408 if(y >= t && y < (t + q)){
36410 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36417 onNodeEnter : function(n, dd, e, data)
36419 this.cancelExpand();
36422 onNodeOver : function(n, dd, e, data)
36425 var pt = this.getDropPoint(e, n, dd);
36428 // auto node expand check
36429 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36430 this.queueExpand(node);
36431 }else if(pt != "append"){
36432 this.cancelExpand();
36435 // set the insert point style on the target node
36436 var returnCls = this.dropNotAllowed;
36437 if(this.isValidDropPoint(n, pt, dd, e, data)){
36442 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36443 cls = "x-tree-drag-insert-above";
36444 }else if(pt == "below"){
36445 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36446 cls = "x-tree-drag-insert-below";
36448 returnCls = "x-tree-drop-ok-append";
36449 cls = "x-tree-drag-append";
36451 if(this.lastInsertClass != cls){
36452 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36453 this.lastInsertClass = cls;
36460 onNodeOut : function(n, dd, e, data){
36462 this.cancelExpand();
36463 this.removeDropIndicators(n);
36466 onNodeDrop : function(n, dd, e, data){
36467 var point = this.getDropPoint(e, n, dd);
36468 var targetNode = n.node;
36469 targetNode.ui.startDrop();
36470 if(!this.isValidDropPoint(n, point, dd, e, data)){
36471 targetNode.ui.endDrop();
36474 // first try to find the drop node
36475 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36478 target: targetNode,
36483 dropNode: dropNode,
36486 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36487 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36488 targetNode.ui.endDrop();
36491 // allow target changing
36492 targetNode = dropEvent.target;
36493 if(point == "append" && !targetNode.isExpanded()){
36494 targetNode.expand(false, null, function(){
36495 this.completeDrop(dropEvent);
36496 }.createDelegate(this));
36498 this.completeDrop(dropEvent);
36503 completeDrop : function(de){
36504 var ns = de.dropNode, p = de.point, t = de.target;
36505 if(!(ns instanceof Array)){
36509 for(var i = 0, len = ns.length; i < len; i++){
36512 t.parentNode.insertBefore(n, t);
36513 }else if(p == "below"){
36514 t.parentNode.insertBefore(n, t.nextSibling);
36520 if(this.tree.hlDrop){
36524 this.tree.fireEvent("nodedrop", de);
36527 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36528 if(this.tree.hlDrop){
36529 dropNode.ui.focus();
36530 dropNode.ui.highlight();
36532 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36535 getTree : function(){
36539 removeDropIndicators : function(n){
36542 Roo.fly(el).removeClass([
36543 "x-tree-drag-insert-above",
36544 "x-tree-drag-insert-below",
36545 "x-tree-drag-append"]);
36546 this.lastInsertClass = "_noclass";
36550 beforeDragDrop : function(target, e, id){
36551 this.cancelExpand();
36555 afterRepair : function(data){
36556 if(data && Roo.enableFx){
36557 data.node.ui.highlight();
36567 * Ext JS Library 1.1.1
36568 * Copyright(c) 2006-2007, Ext JS, LLC.
36570 * Originally Released Under LGPL - original licence link has changed is not relivant.
36573 * <script type="text/javascript">
36577 if(Roo.dd.DragZone){
36578 Roo.tree.TreeDragZone = function(tree, config){
36579 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36583 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36584 ddGroup : "TreeDD",
36586 onBeforeDrag : function(data, e){
36588 return n && n.draggable && !n.disabled;
36592 onInitDrag : function(e){
36593 var data = this.dragData;
36594 this.tree.getSelectionModel().select(data.node);
36595 this.proxy.update("");
36596 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36597 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36600 getRepairXY : function(e, data){
36601 return data.node.ui.getDDRepairXY();
36604 onEndDrag : function(data, e){
36605 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36610 onValidDrop : function(dd, e, id){
36611 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36615 beforeInvalidDrop : function(e, id){
36616 // this scrolls the original position back into view
36617 var sm = this.tree.getSelectionModel();
36618 sm.clearSelections();
36619 sm.select(this.dragData.node);
36624 * Ext JS Library 1.1.1
36625 * Copyright(c) 2006-2007, Ext JS, LLC.
36627 * Originally Released Under LGPL - original licence link has changed is not relivant.
36630 * <script type="text/javascript">
36633 * @class Roo.tree.TreeEditor
36634 * @extends Roo.Editor
36635 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36636 * as the editor field.
36638 * @param {Object} config (used to be the tree panel.)
36639 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36641 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36642 * @cfg {Roo.form.TextField|Object} field The field configuration
36646 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36649 if (oldconfig) { // old style..
36650 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36653 tree = config.tree;
36654 config.field = config.field || {};
36655 config.field.xtype = 'TextField';
36656 field = Roo.factory(config.field, Roo.form);
36658 config = config || {};
36663 * @event beforenodeedit
36664 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36665 * false from the handler of this event.
36666 * @param {Editor} this
36667 * @param {Roo.tree.Node} node
36669 "beforenodeedit" : true
36673 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36677 tree.on('beforeclick', this.beforeNodeClick, this);
36678 tree.getTreeEl().on('mousedown', this.hide, this);
36679 this.on('complete', this.updateNode, this);
36680 this.on('beforestartedit', this.fitToTree, this);
36681 this.on('startedit', this.bindScroll, this, {delay:10});
36682 this.on('specialkey', this.onSpecialKey, this);
36685 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36687 * @cfg {String} alignment
36688 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36694 * @cfg {Boolean} hideEl
36695 * True to hide the bound element while the editor is displayed (defaults to false)
36699 * @cfg {String} cls
36700 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36702 cls: "x-small-editor x-tree-editor",
36704 * @cfg {Boolean} shim
36705 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36711 * @cfg {Number} maxWidth
36712 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36713 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36714 * scroll and client offsets into account prior to each edit.
36721 fitToTree : function(ed, el){
36722 var td = this.tree.getTreeEl().dom, nd = el.dom;
36723 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36724 td.scrollLeft = nd.offsetLeft;
36728 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36729 this.setSize(w, '');
36731 return this.fireEvent('beforenodeedit', this, this.editNode);
36736 triggerEdit : function(node){
36737 this.completeEdit();
36738 this.editNode = node;
36739 this.startEdit(node.ui.textNode, node.text);
36743 bindScroll : function(){
36744 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36748 beforeNodeClick : function(node, e){
36749 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36750 this.lastClick = new Date();
36751 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36753 this.triggerEdit(node);
36760 updateNode : function(ed, value){
36761 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36762 this.editNode.setText(value);
36766 onHide : function(){
36767 Roo.tree.TreeEditor.superclass.onHide.call(this);
36769 this.editNode.ui.focus();
36774 onSpecialKey : function(field, e){
36775 var k = e.getKey();
36779 }else if(k == e.ENTER && !e.hasModifier()){
36781 this.completeEdit();
36784 });//<Script type="text/javascript">
36787 * Ext JS Library 1.1.1
36788 * Copyright(c) 2006-2007, Ext JS, LLC.
36790 * Originally Released Under LGPL - original licence link has changed is not relivant.
36793 * <script type="text/javascript">
36797 * Not documented??? - probably should be...
36800 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36801 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36803 renderElements : function(n, a, targetNode, bulkRender){
36804 //consel.log("renderElements?");
36805 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36807 var t = n.getOwnerTree();
36808 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36810 var cols = t.columns;
36811 var bw = t.borderWidth;
36813 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36814 var cb = typeof a.checked == "boolean";
36815 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36816 var colcls = 'x-t-' + tid + '-c0';
36818 '<li class="x-tree-node">',
36821 '<div class="x-tree-node-el ', a.cls,'">',
36823 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36826 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36827 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36828 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36829 (a.icon ? ' x-tree-node-inline-icon' : ''),
36830 (a.iconCls ? ' '+a.iconCls : ''),
36831 '" unselectable="on" />',
36832 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36833 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36835 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36836 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36837 '<span unselectable="on" qtip="' + tx + '">',
36841 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36842 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36844 for(var i = 1, len = cols.length; i < len; i++){
36846 colcls = 'x-t-' + tid + '-c' +i;
36847 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36848 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
36849 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
36855 '<div class="x-clear"></div></div>',
36856 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36859 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36860 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36861 n.nextSibling.ui.getEl(), buf.join(""));
36863 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36865 var el = this.wrap.firstChild;
36867 this.elNode = el.firstChild;
36868 this.ranchor = el.childNodes[1];
36869 this.ctNode = this.wrap.childNodes[1];
36870 var cs = el.firstChild.childNodes;
36871 this.indentNode = cs[0];
36872 this.ecNode = cs[1];
36873 this.iconNode = cs[2];
36876 this.checkbox = cs[3];
36879 this.anchor = cs[index];
36881 this.textNode = cs[index].firstChild;
36883 //el.on("click", this.onClick, this);
36884 //el.on("dblclick", this.onDblClick, this);
36887 // console.log(this);
36889 initEvents : function(){
36890 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
36893 var a = this.ranchor;
36895 var el = Roo.get(a);
36897 if(Roo.isOpera){ // opera render bug ignores the CSS
36898 el.setStyle("text-decoration", "none");
36901 el.on("click", this.onClick, this);
36902 el.on("dblclick", this.onDblClick, this);
36903 el.on("contextmenu", this.onContextMenu, this);
36907 /*onSelectedChange : function(state){
36910 this.addClass("x-tree-selected");
36913 this.removeClass("x-tree-selected");
36916 addClass : function(cls){
36918 Roo.fly(this.elRow).addClass(cls);
36924 removeClass : function(cls){
36926 Roo.fly(this.elRow).removeClass(cls);
36932 });//<Script type="text/javascript">
36936 * Ext JS Library 1.1.1
36937 * Copyright(c) 2006-2007, Ext JS, LLC.
36939 * Originally Released Under LGPL - original licence link has changed is not relivant.
36942 * <script type="text/javascript">
36947 * @class Roo.tree.ColumnTree
36948 * @extends Roo.data.TreePanel
36949 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
36950 * @cfg {int} borderWidth compined right/left border allowance
36952 * @param {String/HTMLElement/Element} el The container element
36953 * @param {Object} config
36955 Roo.tree.ColumnTree = function(el, config)
36957 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
36961 * Fire this event on a container when it resizes
36962 * @param {int} w Width
36963 * @param {int} h Height
36967 this.on('resize', this.onResize, this);
36970 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
36974 borderWidth: Roo.isBorderBox ? 0 : 2,
36977 render : function(){
36978 // add the header.....
36980 Roo.tree.ColumnTree.superclass.render.apply(this);
36982 this.el.addClass('x-column-tree');
36984 this.headers = this.el.createChild(
36985 {cls:'x-tree-headers'},this.innerCt.dom);
36987 var cols = this.columns, c;
36988 var totalWidth = 0;
36990 var len = cols.length;
36991 for(var i = 0; i < len; i++){
36993 totalWidth += c.width;
36994 this.headEls.push(this.headers.createChild({
36995 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
36997 cls:'x-tree-hd-text',
37000 style:'width:'+(c.width-this.borderWidth)+'px;'
37003 this.headers.createChild({cls:'x-clear'});
37004 // prevent floats from wrapping when clipped
37005 this.headers.setWidth(totalWidth);
37006 //this.innerCt.setWidth(totalWidth);
37007 this.innerCt.setStyle({ overflow: 'auto' });
37008 this.onResize(this.width, this.height);
37012 onResize : function(w,h)
37017 this.innerCt.setWidth(this.width);
37018 this.innerCt.setHeight(this.height-20);
37021 var cols = this.columns, c;
37022 var totalWidth = 0;
37024 var len = cols.length;
37025 for(var i = 0; i < len; i++){
37027 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37028 // it's the expander..
37029 expEl = this.headEls[i];
37032 totalWidth += c.width;
37036 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37038 this.headers.setWidth(w-20);
37047 * Ext JS Library 1.1.1
37048 * Copyright(c) 2006-2007, Ext JS, LLC.
37050 * Originally Released Under LGPL - original licence link has changed is not relivant.
37053 * <script type="text/javascript">
37057 * @class Roo.menu.Menu
37058 * @extends Roo.util.Observable
37059 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37060 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37062 * Creates a new Menu
37063 * @param {Object} config Configuration options
37065 Roo.menu.Menu = function(config){
37066 Roo.apply(this, config);
37067 this.id = this.id || Roo.id();
37070 * @event beforeshow
37071 * Fires before this menu is displayed
37072 * @param {Roo.menu.Menu} this
37076 * @event beforehide
37077 * Fires before this menu is hidden
37078 * @param {Roo.menu.Menu} this
37083 * Fires after this menu is displayed
37084 * @param {Roo.menu.Menu} this
37089 * Fires after this menu is hidden
37090 * @param {Roo.menu.Menu} this
37095 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37096 * @param {Roo.menu.Menu} this
37097 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37098 * @param {Roo.EventObject} e
37103 * Fires when the mouse is hovering over this menu
37104 * @param {Roo.menu.Menu} this
37105 * @param {Roo.EventObject} e
37106 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37111 * Fires when the mouse exits this menu
37112 * @param {Roo.menu.Menu} this
37113 * @param {Roo.EventObject} e
37114 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37119 * Fires when a menu item contained in this menu is clicked
37120 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37121 * @param {Roo.EventObject} e
37125 if (this.registerMenu) {
37126 Roo.menu.MenuMgr.register(this);
37129 var mis = this.items;
37130 this.items = new Roo.util.MixedCollection();
37132 this.add.apply(this, mis);
37136 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37138 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37142 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37143 * for bottom-right shadow (defaults to "sides")
37147 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37148 * this menu (defaults to "tl-tr?")
37150 subMenuAlign : "tl-tr?",
37152 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37153 * relative to its element of origin (defaults to "tl-bl?")
37155 defaultAlign : "tl-bl?",
37157 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37159 allowOtherMenus : false,
37161 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37163 registerMenu : true,
37168 render : function(){
37172 var el = this.el = new Roo.Layer({
37174 shadow:this.shadow,
37176 parentEl: this.parentEl || document.body,
37180 this.keyNav = new Roo.menu.MenuNav(this);
37183 el.addClass("x-menu-plain");
37186 el.addClass(this.cls);
37188 // generic focus element
37189 this.focusEl = el.createChild({
37190 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37192 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37193 //disabling touch- as it's causing issues ..
37194 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37195 ul.on('click' , this.onClick, this);
37198 ul.on("mouseover", this.onMouseOver, this);
37199 ul.on("mouseout", this.onMouseOut, this);
37200 this.items.each(function(item){
37205 var li = document.createElement("li");
37206 li.className = "x-menu-list-item";
37207 ul.dom.appendChild(li);
37208 item.render(li, this);
37215 autoWidth : function(){
37216 var el = this.el, ul = this.ul;
37220 var w = this.width;
37223 }else if(Roo.isIE){
37224 el.setWidth(this.minWidth);
37225 var t = el.dom.offsetWidth; // force recalc
37226 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37231 delayAutoWidth : function(){
37234 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37236 this.awTask.delay(20);
37241 findTargetItem : function(e){
37242 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37243 if(t && t.menuItemId){
37244 return this.items.get(t.menuItemId);
37249 onClick : function(e){
37250 Roo.log("menu.onClick");
37251 var t = this.findTargetItem(e);
37256 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37257 if(t == this.activeItem && t.shouldDeactivate(e)){
37258 this.activeItem.deactivate();
37259 delete this.activeItem;
37263 this.setActiveItem(t, true);
37271 this.fireEvent("click", this, t, e);
37275 setActiveItem : function(item, autoExpand){
37276 if(item != this.activeItem){
37277 if(this.activeItem){
37278 this.activeItem.deactivate();
37280 this.activeItem = item;
37281 item.activate(autoExpand);
37282 }else if(autoExpand){
37288 tryActivate : function(start, step){
37289 var items = this.items;
37290 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37291 var item = items.get(i);
37292 if(!item.disabled && item.canActivate){
37293 this.setActiveItem(item, false);
37301 onMouseOver : function(e){
37303 if(t = this.findTargetItem(e)){
37304 if(t.canActivate && !t.disabled){
37305 this.setActiveItem(t, true);
37308 this.fireEvent("mouseover", this, e, t);
37312 onMouseOut : function(e){
37314 if(t = this.findTargetItem(e)){
37315 if(t == this.activeItem && t.shouldDeactivate(e)){
37316 this.activeItem.deactivate();
37317 delete this.activeItem;
37320 this.fireEvent("mouseout", this, e, t);
37324 * Read-only. Returns true if the menu is currently displayed, else false.
37327 isVisible : function(){
37328 return this.el && !this.hidden;
37332 * Displays this menu relative to another element
37333 * @param {String/HTMLElement/Roo.Element} element The element to align to
37334 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37335 * the element (defaults to this.defaultAlign)
37336 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37338 show : function(el, pos, parentMenu){
37339 this.parentMenu = parentMenu;
37343 this.fireEvent("beforeshow", this);
37344 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37348 * Displays this menu at a specific xy position
37349 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37350 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37352 showAt : function(xy, parentMenu, /* private: */_e){
37353 this.parentMenu = parentMenu;
37358 this.fireEvent("beforeshow", this);
37359 xy = this.el.adjustForConstraints(xy);
37363 this.hidden = false;
37365 this.fireEvent("show", this);
37368 focus : function(){
37370 this.doFocus.defer(50, this);
37374 doFocus : function(){
37376 this.focusEl.focus();
37381 * Hides this menu and optionally all parent menus
37382 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37384 hide : function(deep){
37385 if(this.el && this.isVisible()){
37386 this.fireEvent("beforehide", this);
37387 if(this.activeItem){
37388 this.activeItem.deactivate();
37389 this.activeItem = null;
37392 this.hidden = true;
37393 this.fireEvent("hide", this);
37395 if(deep === true && this.parentMenu){
37396 this.parentMenu.hide(true);
37401 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37402 * Any of the following are valid:
37404 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37405 * <li>An HTMLElement object which will be converted to a menu item</li>
37406 * <li>A menu item config object that will be created as a new menu item</li>
37407 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37408 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37413 var menu = new Roo.menu.Menu();
37415 // Create a menu item to add by reference
37416 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37418 // Add a bunch of items at once using different methods.
37419 // Only the last item added will be returned.
37420 var item = menu.add(
37421 menuItem, // add existing item by ref
37422 'Dynamic Item', // new TextItem
37423 '-', // new separator
37424 { text: 'Config Item' } // new item by config
37427 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37428 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37431 var a = arguments, l = a.length, item;
37432 for(var i = 0; i < l; i++){
37434 if ((typeof(el) == "object") && el.xtype && el.xns) {
37435 el = Roo.factory(el, Roo.menu);
37438 if(el.render){ // some kind of Item
37439 item = this.addItem(el);
37440 }else if(typeof el == "string"){ // string
37441 if(el == "separator" || el == "-"){
37442 item = this.addSeparator();
37444 item = this.addText(el);
37446 }else if(el.tagName || el.el){ // element
37447 item = this.addElement(el);
37448 }else if(typeof el == "object"){ // must be menu item config?
37449 item = this.addMenuItem(el);
37456 * Returns this menu's underlying {@link Roo.Element} object
37457 * @return {Roo.Element} The element
37459 getEl : function(){
37467 * Adds a separator bar to the menu
37468 * @return {Roo.menu.Item} The menu item that was added
37470 addSeparator : function(){
37471 return this.addItem(new Roo.menu.Separator());
37475 * Adds an {@link Roo.Element} object to the menu
37476 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37477 * @return {Roo.menu.Item} The menu item that was added
37479 addElement : function(el){
37480 return this.addItem(new Roo.menu.BaseItem(el));
37484 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37485 * @param {Roo.menu.Item} item The menu item to add
37486 * @return {Roo.menu.Item} The menu item that was added
37488 addItem : function(item){
37489 this.items.add(item);
37491 var li = document.createElement("li");
37492 li.className = "x-menu-list-item";
37493 this.ul.dom.appendChild(li);
37494 item.render(li, this);
37495 this.delayAutoWidth();
37501 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37502 * @param {Object} config A MenuItem config object
37503 * @return {Roo.menu.Item} The menu item that was added
37505 addMenuItem : function(config){
37506 if(!(config instanceof Roo.menu.Item)){
37507 if(typeof config.checked == "boolean"){ // must be check menu item config?
37508 config = new Roo.menu.CheckItem(config);
37510 config = new Roo.menu.Item(config);
37513 return this.addItem(config);
37517 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37518 * @param {String} text The text to display in the menu item
37519 * @return {Roo.menu.Item} The menu item that was added
37521 addText : function(text){
37522 return this.addItem(new Roo.menu.TextItem({ text : text }));
37526 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37527 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37528 * @param {Roo.menu.Item} item The menu item to add
37529 * @return {Roo.menu.Item} The menu item that was added
37531 insert : function(index, item){
37532 this.items.insert(index, item);
37534 var li = document.createElement("li");
37535 li.className = "x-menu-list-item";
37536 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37537 item.render(li, this);
37538 this.delayAutoWidth();
37544 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37545 * @param {Roo.menu.Item} item The menu item to remove
37547 remove : function(item){
37548 this.items.removeKey(item.id);
37553 * Removes and destroys all items in the menu
37555 removeAll : function(){
37557 while(f = this.items.first()){
37563 // MenuNav is a private utility class used internally by the Menu
37564 Roo.menu.MenuNav = function(menu){
37565 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37566 this.scope = this.menu = menu;
37569 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37570 doRelay : function(e, h){
37571 var k = e.getKey();
37572 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37573 this.menu.tryActivate(0, 1);
37576 return h.call(this.scope || this, e, this.menu);
37579 up : function(e, m){
37580 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37581 m.tryActivate(m.items.length-1, -1);
37585 down : function(e, m){
37586 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37587 m.tryActivate(0, 1);
37591 right : function(e, m){
37593 m.activeItem.expandMenu(true);
37597 left : function(e, m){
37599 if(m.parentMenu && m.parentMenu.activeItem){
37600 m.parentMenu.activeItem.activate();
37604 enter : function(e, m){
37606 e.stopPropagation();
37607 m.activeItem.onClick(e);
37608 m.fireEvent("click", this, m.activeItem);
37614 * Ext JS Library 1.1.1
37615 * Copyright(c) 2006-2007, Ext JS, LLC.
37617 * Originally Released Under LGPL - original licence link has changed is not relivant.
37620 * <script type="text/javascript">
37624 * @class Roo.menu.MenuMgr
37625 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37628 Roo.menu.MenuMgr = function(){
37629 var menus, active, groups = {}, attached = false, lastShow = new Date();
37631 // private - called when first menu is created
37634 active = new Roo.util.MixedCollection();
37635 Roo.get(document).addKeyListener(27, function(){
37636 if(active.length > 0){
37643 function hideAll(){
37644 if(active && active.length > 0){
37645 var c = active.clone();
37646 c.each(function(m){
37653 function onHide(m){
37655 if(active.length < 1){
37656 Roo.get(document).un("mousedown", onMouseDown);
37662 function onShow(m){
37663 var last = active.last();
37664 lastShow = new Date();
37667 Roo.get(document).on("mousedown", onMouseDown);
37671 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37672 m.parentMenu.activeChild = m;
37673 }else if(last && last.isVisible()){
37674 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37679 function onBeforeHide(m){
37681 m.activeChild.hide();
37683 if(m.autoHideTimer){
37684 clearTimeout(m.autoHideTimer);
37685 delete m.autoHideTimer;
37690 function onBeforeShow(m){
37691 var pm = m.parentMenu;
37692 if(!pm && !m.allowOtherMenus){
37694 }else if(pm && pm.activeChild && active != m){
37695 pm.activeChild.hide();
37700 function onMouseDown(e){
37701 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37707 function onBeforeCheck(mi, state){
37709 var g = groups[mi.group];
37710 for(var i = 0, l = g.length; i < l; i++){
37712 g[i].setChecked(false);
37721 * Hides all menus that are currently visible
37723 hideAll : function(){
37728 register : function(menu){
37732 menus[menu.id] = menu;
37733 menu.on("beforehide", onBeforeHide);
37734 menu.on("hide", onHide);
37735 menu.on("beforeshow", onBeforeShow);
37736 menu.on("show", onShow);
37737 var g = menu.group;
37738 if(g && menu.events["checkchange"]){
37742 groups[g].push(menu);
37743 menu.on("checkchange", onCheck);
37748 * Returns a {@link Roo.menu.Menu} object
37749 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37750 * be used to generate and return a new Menu instance.
37752 get : function(menu){
37753 if(typeof menu == "string"){ // menu id
37754 return menus[menu];
37755 }else if(menu.events){ // menu instance
37757 }else if(typeof menu.length == 'number'){ // array of menu items?
37758 return new Roo.menu.Menu({items:menu});
37759 }else{ // otherwise, must be a config
37760 return new Roo.menu.Menu(menu);
37765 unregister : function(menu){
37766 delete menus[menu.id];
37767 menu.un("beforehide", onBeforeHide);
37768 menu.un("hide", onHide);
37769 menu.un("beforeshow", onBeforeShow);
37770 menu.un("show", onShow);
37771 var g = menu.group;
37772 if(g && menu.events["checkchange"]){
37773 groups[g].remove(menu);
37774 menu.un("checkchange", onCheck);
37779 registerCheckable : function(menuItem){
37780 var g = menuItem.group;
37785 groups[g].push(menuItem);
37786 menuItem.on("beforecheckchange", onBeforeCheck);
37791 unregisterCheckable : function(menuItem){
37792 var g = menuItem.group;
37794 groups[g].remove(menuItem);
37795 menuItem.un("beforecheckchange", onBeforeCheck);
37801 * Ext JS Library 1.1.1
37802 * Copyright(c) 2006-2007, Ext JS, LLC.
37804 * Originally Released Under LGPL - original licence link has changed is not relivant.
37807 * <script type="text/javascript">
37812 * @class Roo.menu.BaseItem
37813 * @extends Roo.Component
37814 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37815 * management and base configuration options shared by all menu components.
37817 * Creates a new BaseItem
37818 * @param {Object} config Configuration options
37820 Roo.menu.BaseItem = function(config){
37821 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37826 * Fires when this item is clicked
37827 * @param {Roo.menu.BaseItem} this
37828 * @param {Roo.EventObject} e
37833 * Fires when this item is activated
37834 * @param {Roo.menu.BaseItem} this
37838 * @event deactivate
37839 * Fires when this item is deactivated
37840 * @param {Roo.menu.BaseItem} this
37846 this.on("click", this.handler, this.scope, true);
37850 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
37852 * @cfg {Function} handler
37853 * A function that will handle the click event of this menu item (defaults to undefined)
37856 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
37858 canActivate : false,
37861 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
37866 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
37868 activeClass : "x-menu-item-active",
37870 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
37872 hideOnClick : true,
37874 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
37879 ctype: "Roo.menu.BaseItem",
37882 actionMode : "container",
37885 render : function(container, parentMenu){
37886 this.parentMenu = parentMenu;
37887 Roo.menu.BaseItem.superclass.render.call(this, container);
37888 this.container.menuItemId = this.id;
37892 onRender : function(container, position){
37893 this.el = Roo.get(this.el);
37894 container.dom.appendChild(this.el.dom);
37898 onClick : function(e){
37899 if(!this.disabled && this.fireEvent("click", this, e) !== false
37900 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
37901 this.handleClick(e);
37908 activate : function(){
37912 var li = this.container;
37913 li.addClass(this.activeClass);
37914 this.region = li.getRegion().adjust(2, 2, -2, -2);
37915 this.fireEvent("activate", this);
37920 deactivate : function(){
37921 this.container.removeClass(this.activeClass);
37922 this.fireEvent("deactivate", this);
37926 shouldDeactivate : function(e){
37927 return !this.region || !this.region.contains(e.getPoint());
37931 handleClick : function(e){
37932 if(this.hideOnClick){
37933 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
37938 expandMenu : function(autoActivate){
37943 hideMenu : function(){
37948 * Ext JS Library 1.1.1
37949 * Copyright(c) 2006-2007, Ext JS, LLC.
37951 * Originally Released Under LGPL - original licence link has changed is not relivant.
37954 * <script type="text/javascript">
37958 * @class Roo.menu.Adapter
37959 * @extends Roo.menu.BaseItem
37960 * 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.
37961 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
37963 * Creates a new Adapter
37964 * @param {Object} config Configuration options
37966 Roo.menu.Adapter = function(component, config){
37967 Roo.menu.Adapter.superclass.constructor.call(this, config);
37968 this.component = component;
37970 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
37972 canActivate : true,
37975 onRender : function(container, position){
37976 this.component.render(container);
37977 this.el = this.component.getEl();
37981 activate : function(){
37985 this.component.focus();
37986 this.fireEvent("activate", this);
37991 deactivate : function(){
37992 this.fireEvent("deactivate", this);
37996 disable : function(){
37997 this.component.disable();
37998 Roo.menu.Adapter.superclass.disable.call(this);
38002 enable : function(){
38003 this.component.enable();
38004 Roo.menu.Adapter.superclass.enable.call(this);
38008 * Ext JS Library 1.1.1
38009 * Copyright(c) 2006-2007, Ext JS, LLC.
38011 * Originally Released Under LGPL - original licence link has changed is not relivant.
38014 * <script type="text/javascript">
38018 * @class Roo.menu.TextItem
38019 * @extends Roo.menu.BaseItem
38020 * Adds a static text string to a menu, usually used as either a heading or group separator.
38021 * Note: old style constructor with text is still supported.
38024 * Creates a new TextItem
38025 * @param {Object} cfg Configuration
38027 Roo.menu.TextItem = function(cfg){
38028 if (typeof(cfg) == 'string') {
38031 Roo.apply(this,cfg);
38034 Roo.menu.TextItem.superclass.constructor.call(this);
38037 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38039 * @cfg {Boolean} text Text to show on item.
38044 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38046 hideOnClick : false,
38048 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38050 itemCls : "x-menu-text",
38053 onRender : function(){
38054 var s = document.createElement("span");
38055 s.className = this.itemCls;
38056 s.innerHTML = this.text;
38058 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38062 * Ext JS Library 1.1.1
38063 * Copyright(c) 2006-2007, Ext JS, LLC.
38065 * Originally Released Under LGPL - original licence link has changed is not relivant.
38068 * <script type="text/javascript">
38072 * @class Roo.menu.Separator
38073 * @extends Roo.menu.BaseItem
38074 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38075 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38077 * @param {Object} config Configuration options
38079 Roo.menu.Separator = function(config){
38080 Roo.menu.Separator.superclass.constructor.call(this, config);
38083 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38085 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38087 itemCls : "x-menu-sep",
38089 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38091 hideOnClick : false,
38094 onRender : function(li){
38095 var s = document.createElement("span");
38096 s.className = this.itemCls;
38097 s.innerHTML = " ";
38099 li.addClass("x-menu-sep-li");
38100 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38104 * Ext JS Library 1.1.1
38105 * Copyright(c) 2006-2007, Ext JS, LLC.
38107 * Originally Released Under LGPL - original licence link has changed is not relivant.
38110 * <script type="text/javascript">
38113 * @class Roo.menu.Item
38114 * @extends Roo.menu.BaseItem
38115 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38116 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38117 * activation and click handling.
38119 * Creates a new Item
38120 * @param {Object} config Configuration options
38122 Roo.menu.Item = function(config){
38123 Roo.menu.Item.superclass.constructor.call(this, config);
38125 this.menu = Roo.menu.MenuMgr.get(this.menu);
38128 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38131 * @cfg {String} text
38132 * The text to show on the menu item.
38136 * @cfg {String} HTML to render in menu
38137 * The text to show on the menu item (HTML version).
38141 * @cfg {String} icon
38142 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38146 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38148 itemCls : "x-menu-item",
38150 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38152 canActivate : true,
38154 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38157 // doc'd in BaseItem
38161 ctype: "Roo.menu.Item",
38164 onRender : function(container, position){
38165 var el = document.createElement("a");
38166 el.hideFocus = true;
38167 el.unselectable = "on";
38168 el.href = this.href || "#";
38169 if(this.hrefTarget){
38170 el.target = this.hrefTarget;
38172 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38174 var html = this.html.length ? this.html : String.format('{0}',this.text);
38176 el.innerHTML = String.format(
38177 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38178 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38180 Roo.menu.Item.superclass.onRender.call(this, container, position);
38184 * Sets the text to display in this menu item
38185 * @param {String} text The text to display
38186 * @param {Boolean} isHTML true to indicate text is pure html.
38188 setText : function(text, isHTML){
38196 var html = this.html.length ? this.html : String.format('{0}',this.text);
38198 this.el.update(String.format(
38199 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38200 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38201 this.parentMenu.autoWidth();
38206 handleClick : function(e){
38207 if(!this.href){ // if no link defined, stop the event automatically
38210 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38214 activate : function(autoExpand){
38215 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38225 shouldDeactivate : function(e){
38226 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38227 if(this.menu && this.menu.isVisible()){
38228 return !this.menu.getEl().getRegion().contains(e.getPoint());
38236 deactivate : function(){
38237 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38242 expandMenu : function(autoActivate){
38243 if(!this.disabled && this.menu){
38244 clearTimeout(this.hideTimer);
38245 delete this.hideTimer;
38246 if(!this.menu.isVisible() && !this.showTimer){
38247 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38248 }else if (this.menu.isVisible() && autoActivate){
38249 this.menu.tryActivate(0, 1);
38255 deferExpand : function(autoActivate){
38256 delete this.showTimer;
38257 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38259 this.menu.tryActivate(0, 1);
38264 hideMenu : function(){
38265 clearTimeout(this.showTimer);
38266 delete this.showTimer;
38267 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38268 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38273 deferHide : function(){
38274 delete this.hideTimer;
38279 * Ext JS Library 1.1.1
38280 * Copyright(c) 2006-2007, Ext JS, LLC.
38282 * Originally Released Under LGPL - original licence link has changed is not relivant.
38285 * <script type="text/javascript">
38289 * @class Roo.menu.CheckItem
38290 * @extends Roo.menu.Item
38291 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38293 * Creates a new CheckItem
38294 * @param {Object} config Configuration options
38296 Roo.menu.CheckItem = function(config){
38297 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38300 * @event beforecheckchange
38301 * Fires before the checked value is set, providing an opportunity to cancel if needed
38302 * @param {Roo.menu.CheckItem} this
38303 * @param {Boolean} checked The new checked value that will be set
38305 "beforecheckchange" : true,
38307 * @event checkchange
38308 * Fires after the checked value has been set
38309 * @param {Roo.menu.CheckItem} this
38310 * @param {Boolean} checked The checked value that was set
38312 "checkchange" : true
38314 if(this.checkHandler){
38315 this.on('checkchange', this.checkHandler, this.scope);
38318 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38320 * @cfg {String} group
38321 * All check items with the same group name will automatically be grouped into a single-select
38322 * radio button group (defaults to '')
38325 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38327 itemCls : "x-menu-item x-menu-check-item",
38329 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38331 groupClass : "x-menu-group-item",
38334 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38335 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38336 * initialized with checked = true will be rendered as checked.
38341 ctype: "Roo.menu.CheckItem",
38344 onRender : function(c){
38345 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38347 this.el.addClass(this.groupClass);
38349 Roo.menu.MenuMgr.registerCheckable(this);
38351 this.checked = false;
38352 this.setChecked(true, true);
38357 destroy : function(){
38359 Roo.menu.MenuMgr.unregisterCheckable(this);
38361 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38365 * Set the checked state of this item
38366 * @param {Boolean} checked The new checked value
38367 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38369 setChecked : function(state, suppressEvent){
38370 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38371 if(this.container){
38372 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38374 this.checked = state;
38375 if(suppressEvent !== true){
38376 this.fireEvent("checkchange", this, state);
38382 handleClick : function(e){
38383 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38384 this.setChecked(!this.checked);
38386 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38390 * Ext JS Library 1.1.1
38391 * Copyright(c) 2006-2007, Ext JS, LLC.
38393 * Originally Released Under LGPL - original licence link has changed is not relivant.
38396 * <script type="text/javascript">
38400 * @class Roo.menu.DateItem
38401 * @extends Roo.menu.Adapter
38402 * A menu item that wraps the {@link Roo.DatPicker} component.
38404 * Creates a new DateItem
38405 * @param {Object} config Configuration options
38407 Roo.menu.DateItem = function(config){
38408 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38409 /** The Roo.DatePicker object @type Roo.DatePicker */
38410 this.picker = this.component;
38411 this.addEvents({select: true});
38413 this.picker.on("render", function(picker){
38414 picker.getEl().swallowEvent("click");
38415 picker.container.addClass("x-menu-date-item");
38418 this.picker.on("select", this.onSelect, this);
38421 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38423 onSelect : function(picker, date){
38424 this.fireEvent("select", this, date, picker);
38425 Roo.menu.DateItem.superclass.handleClick.call(this);
38429 * Ext JS Library 1.1.1
38430 * Copyright(c) 2006-2007, Ext JS, LLC.
38432 * Originally Released Under LGPL - original licence link has changed is not relivant.
38435 * <script type="text/javascript">
38439 * @class Roo.menu.ColorItem
38440 * @extends Roo.menu.Adapter
38441 * A menu item that wraps the {@link Roo.ColorPalette} component.
38443 * Creates a new ColorItem
38444 * @param {Object} config Configuration options
38446 Roo.menu.ColorItem = function(config){
38447 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38448 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38449 this.palette = this.component;
38450 this.relayEvents(this.palette, ["select"]);
38451 if(this.selectHandler){
38452 this.on('select', this.selectHandler, this.scope);
38455 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38457 * Ext JS Library 1.1.1
38458 * Copyright(c) 2006-2007, Ext JS, LLC.
38460 * Originally Released Under LGPL - original licence link has changed is not relivant.
38463 * <script type="text/javascript">
38468 * @class Roo.menu.DateMenu
38469 * @extends Roo.menu.Menu
38470 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38472 * Creates a new DateMenu
38473 * @param {Object} config Configuration options
38475 Roo.menu.DateMenu = function(config){
38476 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38478 var di = new Roo.menu.DateItem(config);
38481 * The {@link Roo.DatePicker} instance for this DateMenu
38484 this.picker = di.picker;
38487 * @param {DatePicker} picker
38488 * @param {Date} date
38490 this.relayEvents(di, ["select"]);
38491 this.on('beforeshow', function(){
38493 this.picker.hideMonthPicker(false);
38497 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38501 * Ext JS Library 1.1.1
38502 * Copyright(c) 2006-2007, Ext JS, LLC.
38504 * Originally Released Under LGPL - original licence link has changed is not relivant.
38507 * <script type="text/javascript">
38512 * @class Roo.menu.ColorMenu
38513 * @extends Roo.menu.Menu
38514 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38516 * Creates a new ColorMenu
38517 * @param {Object} config Configuration options
38519 Roo.menu.ColorMenu = function(config){
38520 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38522 var ci = new Roo.menu.ColorItem(config);
38525 * The {@link Roo.ColorPalette} instance for this ColorMenu
38526 * @type ColorPalette
38528 this.palette = ci.palette;
38531 * @param {ColorPalette} palette
38532 * @param {String} color
38534 this.relayEvents(ci, ["select"]);
38536 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38538 * Ext JS Library 1.1.1
38539 * Copyright(c) 2006-2007, Ext JS, LLC.
38541 * Originally Released Under LGPL - original licence link has changed is not relivant.
38544 * <script type="text/javascript">
38548 * @class Roo.form.Field
38549 * @extends Roo.BoxComponent
38550 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38552 * Creates a new Field
38553 * @param {Object} config Configuration options
38555 Roo.form.Field = function(config){
38556 Roo.form.Field.superclass.constructor.call(this, config);
38559 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38561 * @cfg {String} fieldLabel Label to use when rendering a form.
38564 * @cfg {String} qtip Mouse over tip
38568 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38570 invalidClass : "x-form-invalid",
38572 * @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")
38574 invalidText : "The value in this field is invalid",
38576 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38578 focusClass : "x-form-focus",
38580 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38581 automatic validation (defaults to "keyup").
38583 validationEvent : "keyup",
38585 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38587 validateOnBlur : true,
38589 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38591 validationDelay : 250,
38593 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38594 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38596 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38598 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38600 fieldClass : "x-form-field",
38602 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38605 ----------- ----------------------------------------------------------------------
38606 qtip Display a quick tip when the user hovers over the field
38607 title Display a default browser title attribute popup
38608 under Add a block div beneath the field containing the error text
38609 side Add an error icon to the right of the field with a popup on hover
38610 [element id] Add the error text directly to the innerHTML of the specified element
38613 msgTarget : 'qtip',
38615 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38620 * @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.
38625 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38630 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38632 inputType : undefined,
38635 * @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).
38637 tabIndex : undefined,
38640 isFormField : true,
38645 * @property {Roo.Element} fieldEl
38646 * Element Containing the rendered Field (with label etc.)
38649 * @cfg {Mixed} value A value to initialize this field with.
38654 * @cfg {String} name The field's HTML name attribute.
38657 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38660 loadedValue : false,
38664 initComponent : function(){
38665 Roo.form.Field.superclass.initComponent.call(this);
38669 * Fires when this field receives input focus.
38670 * @param {Roo.form.Field} this
38675 * Fires when this field loses input focus.
38676 * @param {Roo.form.Field} this
38680 * @event specialkey
38681 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38682 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38683 * @param {Roo.form.Field} this
38684 * @param {Roo.EventObject} e The event object
38689 * Fires just before the field blurs if the field value has changed.
38690 * @param {Roo.form.Field} this
38691 * @param {Mixed} newValue The new value
38692 * @param {Mixed} oldValue The original value
38697 * Fires after the field has been marked as invalid.
38698 * @param {Roo.form.Field} this
38699 * @param {String} msg The validation message
38704 * Fires after the field has been validated with no errors.
38705 * @param {Roo.form.Field} this
38710 * Fires after the key up
38711 * @param {Roo.form.Field} this
38712 * @param {Roo.EventObject} e The event Object
38719 * Returns the name attribute of the field if available
38720 * @return {String} name The field name
38722 getName: function(){
38723 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38727 onRender : function(ct, position){
38728 Roo.form.Field.superclass.onRender.call(this, ct, position);
38730 var cfg = this.getAutoCreate();
38732 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38734 if (!cfg.name.length) {
38737 if(this.inputType){
38738 cfg.type = this.inputType;
38740 this.el = ct.createChild(cfg, position);
38742 var type = this.el.dom.type;
38744 if(type == 'password'){
38747 this.el.addClass('x-form-'+type);
38750 this.el.dom.readOnly = true;
38752 if(this.tabIndex !== undefined){
38753 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38756 this.el.addClass([this.fieldClass, this.cls]);
38761 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38762 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38763 * @return {Roo.form.Field} this
38765 applyTo : function(target){
38766 this.allowDomMove = false;
38767 this.el = Roo.get(target);
38768 this.render(this.el.dom.parentNode);
38773 initValue : function(){
38774 if(this.value !== undefined){
38775 this.setValue(this.value);
38776 }else if(this.el.dom.value.length > 0){
38777 this.setValue(this.el.dom.value);
38782 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38783 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38785 isDirty : function() {
38786 if(this.disabled) {
38789 return String(this.getValue()) !== String(this.originalValue);
38793 * stores the current value in loadedValue
38795 resetHasChanged : function()
38797 this.loadedValue = String(this.getValue());
38800 * checks the current value against the 'loaded' value.
38801 * Note - will return false if 'resetHasChanged' has not been called first.
38803 hasChanged : function()
38805 if(this.disabled || this.readOnly) {
38808 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38814 afterRender : function(){
38815 Roo.form.Field.superclass.afterRender.call(this);
38820 fireKey : function(e){
38821 //Roo.log('field ' + e.getKey());
38822 if(e.isNavKeyPress()){
38823 this.fireEvent("specialkey", this, e);
38828 * Resets the current field value to the originally loaded value and clears any validation messages
38830 reset : function(){
38831 this.setValue(this.resetValue);
38832 this.clearInvalid();
38836 initEvents : function(){
38837 // safari killled keypress - so keydown is now used..
38838 this.el.on("keydown" , this.fireKey, this);
38839 this.el.on("focus", this.onFocus, this);
38840 this.el.on("blur", this.onBlur, this);
38841 this.el.relayEvent('keyup', this);
38843 // reference to original value for reset
38844 this.originalValue = this.getValue();
38845 this.resetValue = this.getValue();
38849 onFocus : function(){
38850 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38851 this.el.addClass(this.focusClass);
38853 if(!this.hasFocus){
38854 this.hasFocus = true;
38855 this.startValue = this.getValue();
38856 this.fireEvent("focus", this);
38860 beforeBlur : Roo.emptyFn,
38863 onBlur : function(){
38865 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38866 this.el.removeClass(this.focusClass);
38868 this.hasFocus = false;
38869 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
38872 var v = this.getValue();
38873 if(String(v) !== String(this.startValue)){
38874 this.fireEvent('change', this, v, this.startValue);
38876 this.fireEvent("blur", this);
38880 * Returns whether or not the field value is currently valid
38881 * @param {Boolean} preventMark True to disable marking the field invalid
38882 * @return {Boolean} True if the value is valid, else false
38884 isValid : function(preventMark){
38888 var restore = this.preventMark;
38889 this.preventMark = preventMark === true;
38890 var v = this.validateValue(this.processValue(this.getRawValue()));
38891 this.preventMark = restore;
38896 * Validates the field value
38897 * @return {Boolean} True if the value is valid, else false
38899 validate : function(){
38900 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
38901 this.clearInvalid();
38907 processValue : function(value){
38912 // Subclasses should provide the validation implementation by overriding this
38913 validateValue : function(value){
38918 * Mark this field as invalid
38919 * @param {String} msg The validation message
38921 markInvalid : function(msg){
38922 if(!this.rendered || this.preventMark){ // not rendered
38926 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38928 obj.el.addClass(this.invalidClass);
38929 msg = msg || this.invalidText;
38930 switch(this.msgTarget){
38932 obj.el.dom.qtip = msg;
38933 obj.el.dom.qclass = 'x-form-invalid-tip';
38934 if(Roo.QuickTips){ // fix for floating editors interacting with DND
38935 Roo.QuickTips.enable();
38939 this.el.dom.title = msg;
38943 var elp = this.el.findParent('.x-form-element', 5, true);
38944 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
38945 this.errorEl.setWidth(elp.getWidth(true)-20);
38947 this.errorEl.update(msg);
38948 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
38951 if(!this.errorIcon){
38952 var elp = this.el.findParent('.x-form-element', 5, true);
38953 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
38955 this.alignErrorIcon();
38956 this.errorIcon.dom.qtip = msg;
38957 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
38958 this.errorIcon.show();
38959 this.on('resize', this.alignErrorIcon, this);
38962 var t = Roo.getDom(this.msgTarget);
38964 t.style.display = this.msgDisplay;
38967 this.fireEvent('invalid', this, msg);
38971 alignErrorIcon : function(){
38972 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
38976 * Clear any invalid styles/messages for this field
38978 clearInvalid : function(){
38979 if(!this.rendered || this.preventMark){ // not rendered
38982 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38984 obj.el.removeClass(this.invalidClass);
38985 switch(this.msgTarget){
38987 obj.el.dom.qtip = '';
38990 this.el.dom.title = '';
38994 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
38998 if(this.errorIcon){
38999 this.errorIcon.dom.qtip = '';
39000 this.errorIcon.hide();
39001 this.un('resize', this.alignErrorIcon, this);
39005 var t = Roo.getDom(this.msgTarget);
39007 t.style.display = 'none';
39010 this.fireEvent('valid', this);
39014 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39015 * @return {Mixed} value The field value
39017 getRawValue : function(){
39018 var v = this.el.getValue();
39024 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39025 * @return {Mixed} value The field value
39027 getValue : function(){
39028 var v = this.el.getValue();
39034 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39035 * @param {Mixed} value The value to set
39037 setRawValue : function(v){
39038 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39042 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39043 * @param {Mixed} value The value to set
39045 setValue : function(v){
39048 this.el.dom.value = (v === null || v === undefined ? '' : v);
39053 adjustSize : function(w, h){
39054 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39055 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39059 adjustWidth : function(tag, w){
39060 tag = tag.toLowerCase();
39061 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39062 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39063 if(tag == 'input'){
39066 if(tag == 'textarea'){
39069 }else if(Roo.isOpera){
39070 if(tag == 'input'){
39073 if(tag == 'textarea'){
39083 // anything other than normal should be considered experimental
39084 Roo.form.Field.msgFx = {
39086 show: function(msgEl, f){
39087 msgEl.setDisplayed('block');
39090 hide : function(msgEl, f){
39091 msgEl.setDisplayed(false).update('');
39096 show: function(msgEl, f){
39097 msgEl.slideIn('t', {stopFx:true});
39100 hide : function(msgEl, f){
39101 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39106 show: function(msgEl, f){
39107 msgEl.fixDisplay();
39108 msgEl.alignTo(f.el, 'tl-tr');
39109 msgEl.slideIn('l', {stopFx:true});
39112 hide : function(msgEl, f){
39113 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39118 * Ext JS Library 1.1.1
39119 * Copyright(c) 2006-2007, Ext JS, LLC.
39121 * Originally Released Under LGPL - original licence link has changed is not relivant.
39124 * <script type="text/javascript">
39129 * @class Roo.form.TextField
39130 * @extends Roo.form.Field
39131 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39132 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39134 * Creates a new TextField
39135 * @param {Object} config Configuration options
39137 Roo.form.TextField = function(config){
39138 Roo.form.TextField.superclass.constructor.call(this, config);
39142 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39143 * according to the default logic, but this event provides a hook for the developer to apply additional
39144 * logic at runtime to resize the field if needed.
39145 * @param {Roo.form.Field} this This text field
39146 * @param {Number} width The new field width
39152 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39154 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39158 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39162 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39166 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39170 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39174 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39176 disableKeyFilter : false,
39178 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39182 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39186 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39188 maxLength : Number.MAX_VALUE,
39190 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39192 minLengthText : "The minimum length for this field is {0}",
39194 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39196 maxLengthText : "The maximum length for this field is {0}",
39198 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39200 selectOnFocus : false,
39202 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39204 blankText : "This field is required",
39206 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39207 * If available, this function will be called only after the basic validators all return true, and will be passed the
39208 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39212 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39213 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39214 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39218 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39222 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39228 initEvents : function()
39230 if (this.emptyText) {
39231 this.el.attr('placeholder', this.emptyText);
39234 Roo.form.TextField.superclass.initEvents.call(this);
39235 if(this.validationEvent == 'keyup'){
39236 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39237 this.el.on('keyup', this.filterValidation, this);
39239 else if(this.validationEvent !== false){
39240 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39243 if(this.selectOnFocus){
39244 this.on("focus", this.preFocus, this);
39247 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39248 this.el.on("keypress", this.filterKeys, this);
39251 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39252 this.el.on("click", this.autoSize, this);
39254 if(this.el.is('input[type=password]') && Roo.isSafari){
39255 this.el.on('keydown', this.SafariOnKeyDown, this);
39259 processValue : function(value){
39260 if(this.stripCharsRe){
39261 var newValue = value.replace(this.stripCharsRe, '');
39262 if(newValue !== value){
39263 this.setRawValue(newValue);
39270 filterValidation : function(e){
39271 if(!e.isNavKeyPress()){
39272 this.validationTask.delay(this.validationDelay);
39277 onKeyUp : function(e){
39278 if(!e.isNavKeyPress()){
39284 * Resets the current field value to the originally-loaded value and clears any validation messages.
39287 reset : function(){
39288 Roo.form.TextField.superclass.reset.call(this);
39294 preFocus : function(){
39296 if(this.selectOnFocus){
39297 this.el.dom.select();
39303 filterKeys : function(e){
39304 var k = e.getKey();
39305 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39308 var c = e.getCharCode(), cc = String.fromCharCode(c);
39309 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39312 if(!this.maskRe.test(cc)){
39317 setValue : function(v){
39319 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39325 * Validates a value according to the field's validation rules and marks the field as invalid
39326 * if the validation fails
39327 * @param {Mixed} value The value to validate
39328 * @return {Boolean} True if the value is valid, else false
39330 validateValue : function(value){
39331 if(value.length < 1) { // if it's blank
39332 if(this.allowBlank){
39333 this.clearInvalid();
39336 this.markInvalid(this.blankText);
39340 if(value.length < this.minLength){
39341 this.markInvalid(String.format(this.minLengthText, this.minLength));
39344 if(value.length > this.maxLength){
39345 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39349 var vt = Roo.form.VTypes;
39350 if(!vt[this.vtype](value, this)){
39351 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39355 if(typeof this.validator == "function"){
39356 var msg = this.validator(value);
39358 this.markInvalid(msg);
39362 if(this.regex && !this.regex.test(value)){
39363 this.markInvalid(this.regexText);
39370 * Selects text in this field
39371 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39372 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39374 selectText : function(start, end){
39375 var v = this.getRawValue();
39377 start = start === undefined ? 0 : start;
39378 end = end === undefined ? v.length : end;
39379 var d = this.el.dom;
39380 if(d.setSelectionRange){
39381 d.setSelectionRange(start, end);
39382 }else if(d.createTextRange){
39383 var range = d.createTextRange();
39384 range.moveStart("character", start);
39385 range.moveEnd("character", v.length-end);
39392 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39393 * This only takes effect if grow = true, and fires the autosize event.
39395 autoSize : function(){
39396 if(!this.grow || !this.rendered){
39400 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39403 var v = el.dom.value;
39404 var d = document.createElement('div');
39405 d.appendChild(document.createTextNode(v));
39409 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39410 this.el.setWidth(w);
39411 this.fireEvent("autosize", this, w);
39415 SafariOnKeyDown : function(event)
39417 // this is a workaround for a password hang bug on chrome/ webkit.
39419 var isSelectAll = false;
39421 if(this.el.dom.selectionEnd > 0){
39422 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39424 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39425 event.preventDefault();
39430 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39432 event.preventDefault();
39433 // this is very hacky as keydown always get's upper case.
39435 var cc = String.fromCharCode(event.getCharCode());
39438 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39446 * Ext JS Library 1.1.1
39447 * Copyright(c) 2006-2007, Ext JS, LLC.
39449 * Originally Released Under LGPL - original licence link has changed is not relivant.
39452 * <script type="text/javascript">
39456 * @class Roo.form.Hidden
39457 * @extends Roo.form.TextField
39458 * Simple Hidden element used on forms
39460 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39463 * Creates a new Hidden form element.
39464 * @param {Object} config Configuration options
39469 // easy hidden field...
39470 Roo.form.Hidden = function(config){
39471 Roo.form.Hidden.superclass.constructor.call(this, config);
39474 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39476 inputType: 'hidden',
39479 labelSeparator: '',
39481 itemCls : 'x-form-item-display-none'
39489 * Ext JS Library 1.1.1
39490 * Copyright(c) 2006-2007, Ext JS, LLC.
39492 * Originally Released Under LGPL - original licence link has changed is not relivant.
39495 * <script type="text/javascript">
39499 * @class Roo.form.TriggerField
39500 * @extends Roo.form.TextField
39501 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39502 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39503 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39504 * for which you can provide a custom implementation. For example:
39506 var trigger = new Roo.form.TriggerField();
39507 trigger.onTriggerClick = myTriggerFn;
39508 trigger.applyTo('my-field');
39511 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39512 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39513 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39514 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39516 * Create a new TriggerField.
39517 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39518 * to the base TextField)
39520 Roo.form.TriggerField = function(config){
39521 this.mimicing = false;
39522 Roo.form.TriggerField.superclass.constructor.call(this, config);
39525 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39527 * @cfg {String} triggerClass A CSS class to apply to the trigger
39530 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39531 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39533 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39535 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39539 /** @cfg {Boolean} grow @hide */
39540 /** @cfg {Number} growMin @hide */
39541 /** @cfg {Number} growMax @hide */
39547 autoSize: Roo.emptyFn,
39551 deferHeight : true,
39554 actionMode : 'wrap',
39556 onResize : function(w, h){
39557 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39558 if(typeof w == 'number'){
39559 var x = w - this.trigger.getWidth();
39560 this.el.setWidth(this.adjustWidth('input', x));
39561 this.trigger.setStyle('left', x+'px');
39566 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39569 getResizeEl : function(){
39574 getPositionEl : function(){
39579 alignErrorIcon : function(){
39580 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39584 onRender : function(ct, position){
39585 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39586 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39587 this.trigger = this.wrap.createChild(this.triggerConfig ||
39588 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39589 if(this.hideTrigger){
39590 this.trigger.setDisplayed(false);
39592 this.initTrigger();
39594 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39599 initTrigger : function(){
39600 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39601 this.trigger.addClassOnOver('x-form-trigger-over');
39602 this.trigger.addClassOnClick('x-form-trigger-click');
39606 onDestroy : function(){
39608 this.trigger.removeAllListeners();
39609 this.trigger.remove();
39612 this.wrap.remove();
39614 Roo.form.TriggerField.superclass.onDestroy.call(this);
39618 onFocus : function(){
39619 Roo.form.TriggerField.superclass.onFocus.call(this);
39620 if(!this.mimicing){
39621 this.wrap.addClass('x-trigger-wrap-focus');
39622 this.mimicing = true;
39623 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39624 if(this.monitorTab){
39625 this.el.on("keydown", this.checkTab, this);
39631 checkTab : function(e){
39632 if(e.getKey() == e.TAB){
39633 this.triggerBlur();
39638 onBlur : function(){
39643 mimicBlur : function(e, t){
39644 if(!this.wrap.contains(t) && this.validateBlur()){
39645 this.triggerBlur();
39650 triggerBlur : function(){
39651 this.mimicing = false;
39652 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39653 if(this.monitorTab){
39654 this.el.un("keydown", this.checkTab, this);
39656 this.wrap.removeClass('x-trigger-wrap-focus');
39657 Roo.form.TriggerField.superclass.onBlur.call(this);
39661 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39662 validateBlur : function(e, t){
39667 onDisable : function(){
39668 Roo.form.TriggerField.superclass.onDisable.call(this);
39670 this.wrap.addClass('x-item-disabled');
39675 onEnable : function(){
39676 Roo.form.TriggerField.superclass.onEnable.call(this);
39678 this.wrap.removeClass('x-item-disabled');
39683 onShow : function(){
39684 var ae = this.getActionEl();
39687 ae.dom.style.display = '';
39688 ae.dom.style.visibility = 'visible';
39694 onHide : function(){
39695 var ae = this.getActionEl();
39696 ae.dom.style.display = 'none';
39700 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39701 * by an implementing function.
39703 * @param {EventObject} e
39705 onTriggerClick : Roo.emptyFn
39708 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39709 // to be extended by an implementing class. For an example of implementing this class, see the custom
39710 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39711 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39712 initComponent : function(){
39713 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39715 this.triggerConfig = {
39716 tag:'span', cls:'x-form-twin-triggers', cn:[
39717 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39718 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39722 getTrigger : function(index){
39723 return this.triggers[index];
39726 initTrigger : function(){
39727 var ts = this.trigger.select('.x-form-trigger', true);
39728 this.wrap.setStyle('overflow', 'hidden');
39729 var triggerField = this;
39730 ts.each(function(t, all, index){
39731 t.hide = function(){
39732 var w = triggerField.wrap.getWidth();
39733 this.dom.style.display = 'none';
39734 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39736 t.show = function(){
39737 var w = triggerField.wrap.getWidth();
39738 this.dom.style.display = '';
39739 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39741 var triggerIndex = 'Trigger'+(index+1);
39743 if(this['hide'+triggerIndex]){
39744 t.dom.style.display = 'none';
39746 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39747 t.addClassOnOver('x-form-trigger-over');
39748 t.addClassOnClick('x-form-trigger-click');
39750 this.triggers = ts.elements;
39753 onTrigger1Click : Roo.emptyFn,
39754 onTrigger2Click : Roo.emptyFn
39757 * Ext JS Library 1.1.1
39758 * Copyright(c) 2006-2007, Ext JS, LLC.
39760 * Originally Released Under LGPL - original licence link has changed is not relivant.
39763 * <script type="text/javascript">
39767 * @class Roo.form.TextArea
39768 * @extends Roo.form.TextField
39769 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39770 * support for auto-sizing.
39772 * Creates a new TextArea
39773 * @param {Object} config Configuration options
39775 Roo.form.TextArea = function(config){
39776 Roo.form.TextArea.superclass.constructor.call(this, config);
39777 // these are provided exchanges for backwards compat
39778 // minHeight/maxHeight were replaced by growMin/growMax to be
39779 // compatible with TextField growing config values
39780 if(this.minHeight !== undefined){
39781 this.growMin = this.minHeight;
39783 if(this.maxHeight !== undefined){
39784 this.growMax = this.maxHeight;
39788 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39790 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39794 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39798 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39799 * in the field (equivalent to setting overflow: hidden, defaults to false)
39801 preventScrollbars: false,
39803 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39804 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39808 onRender : function(ct, position){
39810 this.defaultAutoCreate = {
39812 style:"width:300px;height:60px;",
39813 autocomplete: "new-password"
39816 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39818 this.textSizeEl = Roo.DomHelper.append(document.body, {
39819 tag: "pre", cls: "x-form-grow-sizer"
39821 if(this.preventScrollbars){
39822 this.el.setStyle("overflow", "hidden");
39824 this.el.setHeight(this.growMin);
39828 onDestroy : function(){
39829 if(this.textSizeEl){
39830 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39832 Roo.form.TextArea.superclass.onDestroy.call(this);
39836 onKeyUp : function(e){
39837 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39843 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39844 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39846 autoSize : function(){
39847 if(!this.grow || !this.textSizeEl){
39851 var v = el.dom.value;
39852 var ts = this.textSizeEl;
39855 ts.appendChild(document.createTextNode(v));
39858 Roo.fly(ts).setWidth(this.el.getWidth());
39860 v = "  ";
39863 v = v.replace(/\n/g, '<p> </p>');
39865 v += " \n ";
39868 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
39869 if(h != this.lastHeight){
39870 this.lastHeight = h;
39871 this.el.setHeight(h);
39872 this.fireEvent("autosize", this, h);
39877 * Ext JS Library 1.1.1
39878 * Copyright(c) 2006-2007, Ext JS, LLC.
39880 * Originally Released Under LGPL - original licence link has changed is not relivant.
39883 * <script type="text/javascript">
39888 * @class Roo.form.NumberField
39889 * @extends Roo.form.TextField
39890 * Numeric text field that provides automatic keystroke filtering and numeric validation.
39892 * Creates a new NumberField
39893 * @param {Object} config Configuration options
39895 Roo.form.NumberField = function(config){
39896 Roo.form.NumberField.superclass.constructor.call(this, config);
39899 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
39901 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
39903 fieldClass: "x-form-field x-form-num-field",
39905 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39907 allowDecimals : true,
39909 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39911 decimalSeparator : ".",
39913 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39915 decimalPrecision : 2,
39917 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39919 allowNegative : true,
39921 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39923 minValue : Number.NEGATIVE_INFINITY,
39925 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39927 maxValue : Number.MAX_VALUE,
39929 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39931 minText : "The minimum value for this field is {0}",
39933 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39935 maxText : "The maximum value for this field is {0}",
39937 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39938 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39940 nanText : "{0} is not a valid number",
39943 initEvents : function(){
39944 Roo.form.NumberField.superclass.initEvents.call(this);
39945 var allowed = "0123456789";
39946 if(this.allowDecimals){
39947 allowed += this.decimalSeparator;
39949 if(this.allowNegative){
39952 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
39953 var keyPress = function(e){
39954 var k = e.getKey();
39955 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39958 var c = e.getCharCode();
39959 if(allowed.indexOf(String.fromCharCode(c)) === -1){
39963 this.el.on("keypress", keyPress, this);
39967 validateValue : function(value){
39968 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
39971 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39974 var num = this.parseValue(value);
39976 this.markInvalid(String.format(this.nanText, value));
39979 if(num < this.minValue){
39980 this.markInvalid(String.format(this.minText, this.minValue));
39983 if(num > this.maxValue){
39984 this.markInvalid(String.format(this.maxText, this.maxValue));
39990 getValue : function(){
39991 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
39995 parseValue : function(value){
39996 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
39997 return isNaN(value) ? '' : value;
40001 fixPrecision : function(value){
40002 var nan = isNaN(value);
40003 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40004 return nan ? '' : value;
40006 return parseFloat(value).toFixed(this.decimalPrecision);
40009 setValue : function(v){
40010 v = this.fixPrecision(v);
40011 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40015 decimalPrecisionFcn : function(v){
40016 return Math.floor(v);
40019 beforeBlur : function(){
40020 var v = this.parseValue(this.getRawValue());
40027 * Ext JS Library 1.1.1
40028 * Copyright(c) 2006-2007, Ext JS, LLC.
40030 * Originally Released Under LGPL - original licence link has changed is not relivant.
40033 * <script type="text/javascript">
40037 * @class Roo.form.DateField
40038 * @extends Roo.form.TriggerField
40039 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40041 * Create a new DateField
40042 * @param {Object} config
40044 Roo.form.DateField = function(config){
40045 Roo.form.DateField.superclass.constructor.call(this, config);
40051 * Fires when a date is selected
40052 * @param {Roo.form.DateField} combo This combo box
40053 * @param {Date} date The date selected
40060 if(typeof this.minValue == "string") {
40061 this.minValue = this.parseDate(this.minValue);
40063 if(typeof this.maxValue == "string") {
40064 this.maxValue = this.parseDate(this.maxValue);
40066 this.ddMatch = null;
40067 if(this.disabledDates){
40068 var dd = this.disabledDates;
40070 for(var i = 0; i < dd.length; i++){
40072 if(i != dd.length-1) {
40076 this.ddMatch = new RegExp(re + ")");
40080 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40082 * @cfg {String} format
40083 * The default date format string which can be overriden for localization support. The format must be
40084 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40088 * @cfg {String} altFormats
40089 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40090 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40092 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40094 * @cfg {Array} disabledDays
40095 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40097 disabledDays : null,
40099 * @cfg {String} disabledDaysText
40100 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40102 disabledDaysText : "Disabled",
40104 * @cfg {Array} disabledDates
40105 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40106 * expression so they are very powerful. Some examples:
40108 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40109 * <li>["03/08", "09/16"] would disable those days for every year</li>
40110 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40111 * <li>["03/../2006"] would disable every day in March 2006</li>
40112 * <li>["^03"] would disable every day in every March</li>
40114 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40115 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40117 disabledDates : null,
40119 * @cfg {String} disabledDatesText
40120 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40122 disabledDatesText : "Disabled",
40124 * @cfg {Date/String} minValue
40125 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40126 * valid format (defaults to null).
40130 * @cfg {Date/String} maxValue
40131 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40132 * valid format (defaults to null).
40136 * @cfg {String} minText
40137 * The error text to display when the date in the cell is before minValue (defaults to
40138 * 'The date in this field must be after {minValue}').
40140 minText : "The date in this field must be equal to or after {0}",
40142 * @cfg {String} maxText
40143 * The error text to display when the date in the cell is after maxValue (defaults to
40144 * 'The date in this field must be before {maxValue}').
40146 maxText : "The date in this field must be equal to or before {0}",
40148 * @cfg {String} invalidText
40149 * The error text to display when the date in the field is invalid (defaults to
40150 * '{value} is not a valid date - it must be in the format {format}').
40152 invalidText : "{0} is not a valid date - it must be in the format {1}",
40154 * @cfg {String} triggerClass
40155 * An additional CSS class used to style the trigger button. The trigger will always get the
40156 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40157 * which displays a calendar icon).
40159 triggerClass : 'x-form-date-trigger',
40163 * @cfg {Boolean} useIso
40164 * if enabled, then the date field will use a hidden field to store the
40165 * real value as iso formated date. default (false)
40169 * @cfg {String/Object} autoCreate
40170 * A DomHelper element spec, or true for a default element spec (defaults to
40171 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40174 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40177 hiddenField: false,
40179 onRender : function(ct, position)
40181 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40183 //this.el.dom.removeAttribute('name');
40184 Roo.log("Changing name?");
40185 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40186 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40188 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40189 // prevent input submission
40190 this.hiddenName = this.name;
40197 validateValue : function(value)
40199 value = this.formatDate(value);
40200 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40201 Roo.log('super failed');
40204 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40207 var svalue = value;
40208 value = this.parseDate(value);
40210 Roo.log('parse date failed' + svalue);
40211 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40214 var time = value.getTime();
40215 if(this.minValue && time < this.minValue.getTime()){
40216 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40219 if(this.maxValue && time > this.maxValue.getTime()){
40220 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40223 if(this.disabledDays){
40224 var day = value.getDay();
40225 for(var i = 0; i < this.disabledDays.length; i++) {
40226 if(day === this.disabledDays[i]){
40227 this.markInvalid(this.disabledDaysText);
40232 var fvalue = this.formatDate(value);
40233 if(this.ddMatch && this.ddMatch.test(fvalue)){
40234 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40241 // Provides logic to override the default TriggerField.validateBlur which just returns true
40242 validateBlur : function(){
40243 return !this.menu || !this.menu.isVisible();
40246 getName: function()
40248 // returns hidden if it's set..
40249 if (!this.rendered) {return ''};
40250 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40255 * Returns the current date value of the date field.
40256 * @return {Date} The date value
40258 getValue : function(){
40260 return this.hiddenField ?
40261 this.hiddenField.value :
40262 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40266 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40267 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40268 * (the default format used is "m/d/y").
40271 //All of these calls set the same date value (May 4, 2006)
40273 //Pass a date object:
40274 var dt = new Date('5/4/06');
40275 dateField.setValue(dt);
40277 //Pass a date string (default format):
40278 dateField.setValue('5/4/06');
40280 //Pass a date string (custom format):
40281 dateField.format = 'Y-m-d';
40282 dateField.setValue('2006-5-4');
40284 * @param {String/Date} date The date or valid date string
40286 setValue : function(date){
40287 if (this.hiddenField) {
40288 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40290 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40291 // make sure the value field is always stored as a date..
40292 this.value = this.parseDate(date);
40298 parseDate : function(value){
40299 if(!value || value instanceof Date){
40302 var v = Date.parseDate(value, this.format);
40303 if (!v && this.useIso) {
40304 v = Date.parseDate(value, 'Y-m-d');
40306 if(!v && this.altFormats){
40307 if(!this.altFormatsArray){
40308 this.altFormatsArray = this.altFormats.split("|");
40310 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40311 v = Date.parseDate(value, this.altFormatsArray[i]);
40318 formatDate : function(date, fmt){
40319 return (!date || !(date instanceof Date)) ?
40320 date : date.dateFormat(fmt || this.format);
40325 select: function(m, d){
40328 this.fireEvent('select', this, d);
40330 show : function(){ // retain focus styling
40334 this.focus.defer(10, this);
40335 var ml = this.menuListeners;
40336 this.menu.un("select", ml.select, this);
40337 this.menu.un("show", ml.show, this);
40338 this.menu.un("hide", ml.hide, this);
40343 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40344 onTriggerClick : function(){
40348 if(this.menu == null){
40349 this.menu = new Roo.menu.DateMenu();
40351 Roo.apply(this.menu.picker, {
40352 showClear: this.allowBlank,
40353 minDate : this.minValue,
40354 maxDate : this.maxValue,
40355 disabledDatesRE : this.ddMatch,
40356 disabledDatesText : this.disabledDatesText,
40357 disabledDays : this.disabledDays,
40358 disabledDaysText : this.disabledDaysText,
40359 format : this.useIso ? 'Y-m-d' : this.format,
40360 minText : String.format(this.minText, this.formatDate(this.minValue)),
40361 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40363 this.menu.on(Roo.apply({}, this.menuListeners, {
40366 this.menu.picker.setValue(this.getValue() || new Date());
40367 this.menu.show(this.el, "tl-bl?");
40370 beforeBlur : function(){
40371 var v = this.parseDate(this.getRawValue());
40381 isDirty : function() {
40382 if(this.disabled) {
40386 if(typeof(this.startValue) === 'undefined'){
40390 return String(this.getValue()) !== String(this.startValue);
40395 * Ext JS Library 1.1.1
40396 * Copyright(c) 2006-2007, Ext JS, LLC.
40398 * Originally Released Under LGPL - original licence link has changed is not relivant.
40401 * <script type="text/javascript">
40405 * @class Roo.form.MonthField
40406 * @extends Roo.form.TriggerField
40407 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40409 * Create a new MonthField
40410 * @param {Object} config
40412 Roo.form.MonthField = function(config){
40414 Roo.form.MonthField.superclass.constructor.call(this, config);
40420 * Fires when a date is selected
40421 * @param {Roo.form.MonthFieeld} combo This combo box
40422 * @param {Date} date The date selected
40429 if(typeof this.minValue == "string") {
40430 this.minValue = this.parseDate(this.minValue);
40432 if(typeof this.maxValue == "string") {
40433 this.maxValue = this.parseDate(this.maxValue);
40435 this.ddMatch = null;
40436 if(this.disabledDates){
40437 var dd = this.disabledDates;
40439 for(var i = 0; i < dd.length; i++){
40441 if(i != dd.length-1) {
40445 this.ddMatch = new RegExp(re + ")");
40449 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40451 * @cfg {String} format
40452 * The default date format string which can be overriden for localization support. The format must be
40453 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40457 * @cfg {String} altFormats
40458 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40459 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40461 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40463 * @cfg {Array} disabledDays
40464 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40466 disabledDays : [0,1,2,3,4,5,6],
40468 * @cfg {String} disabledDaysText
40469 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40471 disabledDaysText : "Disabled",
40473 * @cfg {Array} disabledDates
40474 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40475 * expression so they are very powerful. Some examples:
40477 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40478 * <li>["03/08", "09/16"] would disable those days for every year</li>
40479 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40480 * <li>["03/../2006"] would disable every day in March 2006</li>
40481 * <li>["^03"] would disable every day in every March</li>
40483 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40484 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40486 disabledDates : null,
40488 * @cfg {String} disabledDatesText
40489 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40491 disabledDatesText : "Disabled",
40493 * @cfg {Date/String} minValue
40494 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40495 * valid format (defaults to null).
40499 * @cfg {Date/String} maxValue
40500 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40501 * valid format (defaults to null).
40505 * @cfg {String} minText
40506 * The error text to display when the date in the cell is before minValue (defaults to
40507 * 'The date in this field must be after {minValue}').
40509 minText : "The date in this field must be equal to or after {0}",
40511 * @cfg {String} maxTextf
40512 * The error text to display when the date in the cell is after maxValue (defaults to
40513 * 'The date in this field must be before {maxValue}').
40515 maxText : "The date in this field must be equal to or before {0}",
40517 * @cfg {String} invalidText
40518 * The error text to display when the date in the field is invalid (defaults to
40519 * '{value} is not a valid date - it must be in the format {format}').
40521 invalidText : "{0} is not a valid date - it must be in the format {1}",
40523 * @cfg {String} triggerClass
40524 * An additional CSS class used to style the trigger button. The trigger will always get the
40525 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40526 * which displays a calendar icon).
40528 triggerClass : 'x-form-date-trigger',
40532 * @cfg {Boolean} useIso
40533 * if enabled, then the date field will use a hidden field to store the
40534 * real value as iso formated date. default (true)
40538 * @cfg {String/Object} autoCreate
40539 * A DomHelper element spec, or true for a default element spec (defaults to
40540 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40543 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40546 hiddenField: false,
40548 hideMonthPicker : false,
40550 onRender : function(ct, position)
40552 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40554 this.el.dom.removeAttribute('name');
40555 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40557 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40558 // prevent input submission
40559 this.hiddenName = this.name;
40566 validateValue : function(value)
40568 value = this.formatDate(value);
40569 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40572 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40575 var svalue = value;
40576 value = this.parseDate(value);
40578 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40581 var time = value.getTime();
40582 if(this.minValue && time < this.minValue.getTime()){
40583 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40586 if(this.maxValue && time > this.maxValue.getTime()){
40587 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40590 /*if(this.disabledDays){
40591 var day = value.getDay();
40592 for(var i = 0; i < this.disabledDays.length; i++) {
40593 if(day === this.disabledDays[i]){
40594 this.markInvalid(this.disabledDaysText);
40600 var fvalue = this.formatDate(value);
40601 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40602 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40610 // Provides logic to override the default TriggerField.validateBlur which just returns true
40611 validateBlur : function(){
40612 return !this.menu || !this.menu.isVisible();
40616 * Returns the current date value of the date field.
40617 * @return {Date} The date value
40619 getValue : function(){
40623 return this.hiddenField ?
40624 this.hiddenField.value :
40625 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40629 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40630 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40631 * (the default format used is "m/d/y").
40634 //All of these calls set the same date value (May 4, 2006)
40636 //Pass a date object:
40637 var dt = new Date('5/4/06');
40638 monthField.setValue(dt);
40640 //Pass a date string (default format):
40641 monthField.setValue('5/4/06');
40643 //Pass a date string (custom format):
40644 monthField.format = 'Y-m-d';
40645 monthField.setValue('2006-5-4');
40647 * @param {String/Date} date The date or valid date string
40649 setValue : function(date){
40650 Roo.log('month setValue' + date);
40651 // can only be first of month..
40653 var val = this.parseDate(date);
40655 if (this.hiddenField) {
40656 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40658 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40659 this.value = this.parseDate(date);
40663 parseDate : function(value){
40664 if(!value || value instanceof Date){
40665 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40668 var v = Date.parseDate(value, this.format);
40669 if (!v && this.useIso) {
40670 v = Date.parseDate(value, 'Y-m-d');
40674 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40678 if(!v && this.altFormats){
40679 if(!this.altFormatsArray){
40680 this.altFormatsArray = this.altFormats.split("|");
40682 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40683 v = Date.parseDate(value, this.altFormatsArray[i]);
40690 formatDate : function(date, fmt){
40691 return (!date || !(date instanceof Date)) ?
40692 date : date.dateFormat(fmt || this.format);
40697 select: function(m, d){
40699 this.fireEvent('select', this, d);
40701 show : function(){ // retain focus styling
40705 this.focus.defer(10, this);
40706 var ml = this.menuListeners;
40707 this.menu.un("select", ml.select, this);
40708 this.menu.un("show", ml.show, this);
40709 this.menu.un("hide", ml.hide, this);
40713 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40714 onTriggerClick : function(){
40718 if(this.menu == null){
40719 this.menu = new Roo.menu.DateMenu();
40723 Roo.apply(this.menu.picker, {
40725 showClear: this.allowBlank,
40726 minDate : this.minValue,
40727 maxDate : this.maxValue,
40728 disabledDatesRE : this.ddMatch,
40729 disabledDatesText : this.disabledDatesText,
40731 format : this.useIso ? 'Y-m-d' : this.format,
40732 minText : String.format(this.minText, this.formatDate(this.minValue)),
40733 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40736 this.menu.on(Roo.apply({}, this.menuListeners, {
40744 // hide month picker get's called when we called by 'before hide';
40746 var ignorehide = true;
40747 p.hideMonthPicker = function(disableAnim){
40751 if(this.monthPicker){
40752 Roo.log("hideMonthPicker called");
40753 if(disableAnim === true){
40754 this.monthPicker.hide();
40756 this.monthPicker.slideOut('t', {duration:.2});
40757 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40758 p.fireEvent("select", this, this.value);
40764 Roo.log('picker set value');
40765 Roo.log(this.getValue());
40766 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40767 m.show(this.el, 'tl-bl?');
40768 ignorehide = false;
40769 // this will trigger hideMonthPicker..
40772 // hidden the day picker
40773 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40779 p.showMonthPicker.defer(100, p);
40785 beforeBlur : function(){
40786 var v = this.parseDate(this.getRawValue());
40792 /** @cfg {Boolean} grow @hide */
40793 /** @cfg {Number} growMin @hide */
40794 /** @cfg {Number} growMax @hide */
40801 * Ext JS Library 1.1.1
40802 * Copyright(c) 2006-2007, Ext JS, LLC.
40804 * Originally Released Under LGPL - original licence link has changed is not relivant.
40807 * <script type="text/javascript">
40812 * @class Roo.form.ComboBox
40813 * @extends Roo.form.TriggerField
40814 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40816 * Create a new ComboBox.
40817 * @param {Object} config Configuration options
40819 Roo.form.ComboBox = function(config){
40820 Roo.form.ComboBox.superclass.constructor.call(this, config);
40824 * Fires when the dropdown list is expanded
40825 * @param {Roo.form.ComboBox} combo This combo box
40830 * Fires when the dropdown list is collapsed
40831 * @param {Roo.form.ComboBox} combo This combo box
40835 * @event beforeselect
40836 * Fires before a list item is selected. Return false to cancel the selection.
40837 * @param {Roo.form.ComboBox} combo This combo box
40838 * @param {Roo.data.Record} record The data record returned from the underlying store
40839 * @param {Number} index The index of the selected item in the dropdown list
40841 'beforeselect' : true,
40844 * Fires when a list item is selected
40845 * @param {Roo.form.ComboBox} combo This combo box
40846 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
40847 * @param {Number} index The index of the selected item in the dropdown list
40851 * @event beforequery
40852 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
40853 * The event object passed has these properties:
40854 * @param {Roo.form.ComboBox} combo This combo box
40855 * @param {String} query The query
40856 * @param {Boolean} forceAll true to force "all" query
40857 * @param {Boolean} cancel true to cancel the query
40858 * @param {Object} e The query event object
40860 'beforequery': true,
40863 * Fires when the 'add' icon is pressed (add a listener to enable add button)
40864 * @param {Roo.form.ComboBox} combo This combo box
40869 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
40870 * @param {Roo.form.ComboBox} combo This combo box
40871 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
40877 if(this.transform){
40878 this.allowDomMove = false;
40879 var s = Roo.getDom(this.transform);
40880 if(!this.hiddenName){
40881 this.hiddenName = s.name;
40884 this.mode = 'local';
40885 var d = [], opts = s.options;
40886 for(var i = 0, len = opts.length;i < len; i++){
40888 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
40890 this.value = value;
40892 d.push([value, o.text]);
40894 this.store = new Roo.data.SimpleStore({
40896 fields: ['value', 'text'],
40899 this.valueField = 'value';
40900 this.displayField = 'text';
40902 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
40903 if(!this.lazyRender){
40904 this.target = true;
40905 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
40906 s.parentNode.removeChild(s); // remove it
40907 this.render(this.el.parentNode);
40909 s.parentNode.removeChild(s); // remove it
40914 this.store = Roo.factory(this.store, Roo.data);
40917 this.selectedIndex = -1;
40918 if(this.mode == 'local'){
40919 if(config.queryDelay === undefined){
40920 this.queryDelay = 10;
40922 if(config.minChars === undefined){
40928 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
40930 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
40933 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
40934 * rendering into an Roo.Editor, defaults to false)
40937 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
40938 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
40941 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
40944 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
40945 * the dropdown list (defaults to undefined, with no header element)
40949 * @cfg {String/Roo.Template} tpl The template to use to render the output
40953 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
40955 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
40957 listWidth: undefined,
40959 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
40960 * mode = 'remote' or 'text' if mode = 'local')
40962 displayField: undefined,
40964 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
40965 * mode = 'remote' or 'value' if mode = 'local').
40966 * Note: use of a valueField requires the user make a selection
40967 * in order for a value to be mapped.
40969 valueField: undefined,
40973 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
40974 * field's data value (defaults to the underlying DOM element's name)
40976 hiddenName: undefined,
40978 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
40982 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
40984 selectedClass: 'x-combo-selected',
40986 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40987 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
40988 * which displays a downward arrow icon).
40990 triggerClass : 'x-form-arrow-trigger',
40992 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
40996 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
40997 * anchor positions (defaults to 'tl-bl')
40999 listAlign: 'tl-bl?',
41001 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41005 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41006 * query specified by the allQuery config option (defaults to 'query')
41008 triggerAction: 'query',
41010 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41011 * (defaults to 4, does not apply if editable = false)
41015 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41016 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41020 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41021 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41025 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41026 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41030 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41031 * when editable = true (defaults to false)
41033 selectOnFocus:false,
41035 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41037 queryParam: 'query',
41039 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41040 * when mode = 'remote' (defaults to 'Loading...')
41042 loadingText: 'Loading...',
41044 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41048 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41052 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41053 * traditional select (defaults to true)
41057 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41061 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41065 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41066 * listWidth has a higher value)
41070 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41071 * allow the user to set arbitrary text into the field (defaults to false)
41073 forceSelection:false,
41075 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41076 * if typeAhead = true (defaults to 250)
41078 typeAheadDelay : 250,
41080 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41081 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41083 valueNotFoundText : undefined,
41085 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41087 blockFocus : false,
41090 * @cfg {Boolean} disableClear Disable showing of clear button.
41092 disableClear : false,
41094 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41096 alwaysQuery : false,
41102 // element that contains real text value.. (when hidden is used..)
41105 onRender : function(ct, position){
41106 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41107 if(this.hiddenName){
41108 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41110 this.hiddenField.value =
41111 this.hiddenValue !== undefined ? this.hiddenValue :
41112 this.value !== undefined ? this.value : '';
41114 // prevent input submission
41115 this.el.dom.removeAttribute('name');
41120 this.el.dom.setAttribute('autocomplete', 'off');
41123 var cls = 'x-combo-list';
41125 this.list = new Roo.Layer({
41126 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41129 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41130 this.list.setWidth(lw);
41131 this.list.swallowEvent('mousewheel');
41132 this.assetHeight = 0;
41135 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41136 this.assetHeight += this.header.getHeight();
41139 this.innerList = this.list.createChild({cls:cls+'-inner'});
41140 this.innerList.on('mouseover', this.onViewOver, this);
41141 this.innerList.on('mousemove', this.onViewMove, this);
41142 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41144 if(this.allowBlank && !this.pageSize && !this.disableClear){
41145 this.footer = this.list.createChild({cls:cls+'-ft'});
41146 this.pageTb = new Roo.Toolbar(this.footer);
41150 this.footer = this.list.createChild({cls:cls+'-ft'});
41151 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41152 {pageSize: this.pageSize});
41156 if (this.pageTb && this.allowBlank && !this.disableClear) {
41158 this.pageTb.add(new Roo.Toolbar.Fill(), {
41159 cls: 'x-btn-icon x-btn-clear',
41161 handler: function()
41164 _this.clearValue();
41165 _this.onSelect(false, -1);
41170 this.assetHeight += this.footer.getHeight();
41175 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41178 this.view = new Roo.View(this.innerList, this.tpl, {
41179 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41182 this.view.on('click', this.onViewClick, this);
41184 this.store.on('beforeload', this.onBeforeLoad, this);
41185 this.store.on('load', this.onLoad, this);
41186 this.store.on('loadexception', this.onLoadException, this);
41188 if(this.resizable){
41189 this.resizer = new Roo.Resizable(this.list, {
41190 pinned:true, handles:'se'
41192 this.resizer.on('resize', function(r, w, h){
41193 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41194 this.listWidth = w;
41195 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41196 this.restrictHeight();
41198 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41200 if(!this.editable){
41201 this.editable = true;
41202 this.setEditable(false);
41206 if (typeof(this.events.add.listeners) != 'undefined') {
41208 this.addicon = this.wrap.createChild(
41209 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41211 this.addicon.on('click', function(e) {
41212 this.fireEvent('add', this);
41215 if (typeof(this.events.edit.listeners) != 'undefined') {
41217 this.editicon = this.wrap.createChild(
41218 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41219 if (this.addicon) {
41220 this.editicon.setStyle('margin-left', '40px');
41222 this.editicon.on('click', function(e) {
41224 // we fire even if inothing is selected..
41225 this.fireEvent('edit', this, this.lastData );
41235 initEvents : function(){
41236 Roo.form.ComboBox.superclass.initEvents.call(this);
41238 this.keyNav = new Roo.KeyNav(this.el, {
41239 "up" : function(e){
41240 this.inKeyMode = true;
41244 "down" : function(e){
41245 if(!this.isExpanded()){
41246 this.onTriggerClick();
41248 this.inKeyMode = true;
41253 "enter" : function(e){
41254 this.onViewClick();
41258 "esc" : function(e){
41262 "tab" : function(e){
41263 this.onViewClick(false);
41264 this.fireEvent("specialkey", this, e);
41270 doRelay : function(foo, bar, hname){
41271 if(hname == 'down' || this.scope.isExpanded()){
41272 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41279 this.queryDelay = Math.max(this.queryDelay || 10,
41280 this.mode == 'local' ? 10 : 250);
41281 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41282 if(this.typeAhead){
41283 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41285 if(this.editable !== false){
41286 this.el.on("keyup", this.onKeyUp, this);
41288 if(this.forceSelection){
41289 this.on('blur', this.doForce, this);
41293 onDestroy : function(){
41295 this.view.setStore(null);
41296 this.view.el.removeAllListeners();
41297 this.view.el.remove();
41298 this.view.purgeListeners();
41301 this.list.destroy();
41304 this.store.un('beforeload', this.onBeforeLoad, this);
41305 this.store.un('load', this.onLoad, this);
41306 this.store.un('loadexception', this.onLoadException, this);
41308 Roo.form.ComboBox.superclass.onDestroy.call(this);
41312 fireKey : function(e){
41313 if(e.isNavKeyPress() && !this.list.isVisible()){
41314 this.fireEvent("specialkey", this, e);
41319 onResize: function(w, h){
41320 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41322 if(typeof w != 'number'){
41323 // we do not handle it!?!?
41326 var tw = this.trigger.getWidth();
41327 tw += this.addicon ? this.addicon.getWidth() : 0;
41328 tw += this.editicon ? this.editicon.getWidth() : 0;
41330 this.el.setWidth( this.adjustWidth('input', x));
41332 this.trigger.setStyle('left', x+'px');
41334 if(this.list && this.listWidth === undefined){
41335 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41336 this.list.setWidth(lw);
41337 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41345 * Allow or prevent the user from directly editing the field text. If false is passed,
41346 * the user will only be able to select from the items defined in the dropdown list. This method
41347 * is the runtime equivalent of setting the 'editable' config option at config time.
41348 * @param {Boolean} value True to allow the user to directly edit the field text
41350 setEditable : function(value){
41351 if(value == this.editable){
41354 this.editable = value;
41356 this.el.dom.setAttribute('readOnly', true);
41357 this.el.on('mousedown', this.onTriggerClick, this);
41358 this.el.addClass('x-combo-noedit');
41360 this.el.dom.setAttribute('readOnly', false);
41361 this.el.un('mousedown', this.onTriggerClick, this);
41362 this.el.removeClass('x-combo-noedit');
41367 onBeforeLoad : function(){
41368 if(!this.hasFocus){
41371 this.innerList.update(this.loadingText ?
41372 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41373 this.restrictHeight();
41374 this.selectedIndex = -1;
41378 onLoad : function(){
41379 if(!this.hasFocus){
41382 if(this.store.getCount() > 0){
41384 this.restrictHeight();
41385 if(this.lastQuery == this.allQuery){
41387 this.el.dom.select();
41389 if(!this.selectByValue(this.value, true)){
41390 this.select(0, true);
41394 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41395 this.taTask.delay(this.typeAheadDelay);
41399 this.onEmptyResults();
41404 onLoadException : function()
41407 Roo.log(this.store.reader.jsonData);
41408 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41409 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41415 onTypeAhead : function(){
41416 if(this.store.getCount() > 0){
41417 var r = this.store.getAt(0);
41418 var newValue = r.data[this.displayField];
41419 var len = newValue.length;
41420 var selStart = this.getRawValue().length;
41421 if(selStart != len){
41422 this.setRawValue(newValue);
41423 this.selectText(selStart, newValue.length);
41429 onSelect : function(record, index){
41430 if(this.fireEvent('beforeselect', this, record, index) !== false){
41431 this.setFromData(index > -1 ? record.data : false);
41433 this.fireEvent('select', this, record, index);
41438 * Returns the currently selected field value or empty string if no value is set.
41439 * @return {String} value The selected value
41441 getValue : function(){
41442 if(this.valueField){
41443 return typeof this.value != 'undefined' ? this.value : '';
41445 return Roo.form.ComboBox.superclass.getValue.call(this);
41449 * Clears any text/value currently set in the field
41451 clearValue : function(){
41452 if(this.hiddenField){
41453 this.hiddenField.value = '';
41456 this.setRawValue('');
41457 this.lastSelectionText = '';
41462 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41463 * will be displayed in the field. If the value does not match the data value of an existing item,
41464 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41465 * Otherwise the field will be blank (although the value will still be set).
41466 * @param {String} value The value to match
41468 setValue : function(v){
41470 if(this.valueField){
41471 var r = this.findRecord(this.valueField, v);
41473 text = r.data[this.displayField];
41474 }else if(this.valueNotFoundText !== undefined){
41475 text = this.valueNotFoundText;
41478 this.lastSelectionText = text;
41479 if(this.hiddenField){
41480 this.hiddenField.value = v;
41482 Roo.form.ComboBox.superclass.setValue.call(this, text);
41486 * @property {Object} the last set data for the element
41491 * Sets the value of the field based on a object which is related to the record format for the store.
41492 * @param {Object} value the value to set as. or false on reset?
41494 setFromData : function(o){
41495 var dv = ''; // display value
41496 var vv = ''; // value value..
41498 if (this.displayField) {
41499 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41501 // this is an error condition!!!
41502 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41505 if(this.valueField){
41506 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41508 if(this.hiddenField){
41509 this.hiddenField.value = vv;
41511 this.lastSelectionText = dv;
41512 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41516 // no hidden field.. - we store the value in 'value', but still display
41517 // display field!!!!
41518 this.lastSelectionText = dv;
41519 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41525 reset : function(){
41526 // overridden so that last data is reset..
41527 this.setValue(this.resetValue);
41528 this.clearInvalid();
41529 this.lastData = false;
41531 this.view.clearSelections();
41535 findRecord : function(prop, value){
41537 if(this.store.getCount() > 0){
41538 this.store.each(function(r){
41539 if(r.data[prop] == value){
41549 getName: function()
41551 // returns hidden if it's set..
41552 if (!this.rendered) {return ''};
41553 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41557 onViewMove : function(e, t){
41558 this.inKeyMode = false;
41562 onViewOver : function(e, t){
41563 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41566 var item = this.view.findItemFromChild(t);
41568 var index = this.view.indexOf(item);
41569 this.select(index, false);
41574 onViewClick : function(doFocus)
41576 var index = this.view.getSelectedIndexes()[0];
41577 var r = this.store.getAt(index);
41579 this.onSelect(r, index);
41581 if(doFocus !== false && !this.blockFocus){
41587 restrictHeight : function(){
41588 this.innerList.dom.style.height = '';
41589 var inner = this.innerList.dom;
41590 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41591 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41592 this.list.beginUpdate();
41593 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41594 this.list.alignTo(this.el, this.listAlign);
41595 this.list.endUpdate();
41599 onEmptyResults : function(){
41604 * Returns true if the dropdown list is expanded, else false.
41606 isExpanded : function(){
41607 return this.list.isVisible();
41611 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41612 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41613 * @param {String} value The data value of the item to select
41614 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41615 * selected item if it is not currently in view (defaults to true)
41616 * @return {Boolean} True if the value matched an item in the list, else false
41618 selectByValue : function(v, scrollIntoView){
41619 if(v !== undefined && v !== null){
41620 var r = this.findRecord(this.valueField || this.displayField, v);
41622 this.select(this.store.indexOf(r), scrollIntoView);
41630 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41631 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41632 * @param {Number} index The zero-based index of the list item to select
41633 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41634 * selected item if it is not currently in view (defaults to true)
41636 select : function(index, scrollIntoView){
41637 this.selectedIndex = index;
41638 this.view.select(index);
41639 if(scrollIntoView !== false){
41640 var el = this.view.getNode(index);
41642 this.innerList.scrollChildIntoView(el, false);
41648 selectNext : function(){
41649 var ct = this.store.getCount();
41651 if(this.selectedIndex == -1){
41653 }else if(this.selectedIndex < ct-1){
41654 this.select(this.selectedIndex+1);
41660 selectPrev : function(){
41661 var ct = this.store.getCount();
41663 if(this.selectedIndex == -1){
41665 }else if(this.selectedIndex != 0){
41666 this.select(this.selectedIndex-1);
41672 onKeyUp : function(e){
41673 if(this.editable !== false && !e.isSpecialKey()){
41674 this.lastKey = e.getKey();
41675 this.dqTask.delay(this.queryDelay);
41680 validateBlur : function(){
41681 return !this.list || !this.list.isVisible();
41685 initQuery : function(){
41686 this.doQuery(this.getRawValue());
41690 doForce : function(){
41691 if(this.el.dom.value.length > 0){
41692 this.el.dom.value =
41693 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41699 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41700 * query allowing the query action to be canceled if needed.
41701 * @param {String} query The SQL query to execute
41702 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41703 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41704 * saved in the current store (defaults to false)
41706 doQuery : function(q, forceAll){
41707 if(q === undefined || q === null){
41712 forceAll: forceAll,
41716 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41720 forceAll = qe.forceAll;
41721 if(forceAll === true || (q.length >= this.minChars)){
41722 if(this.lastQuery != q || this.alwaysQuery){
41723 this.lastQuery = q;
41724 if(this.mode == 'local'){
41725 this.selectedIndex = -1;
41727 this.store.clearFilter();
41729 this.store.filter(this.displayField, q);
41733 this.store.baseParams[this.queryParam] = q;
41735 params: this.getParams(q)
41740 this.selectedIndex = -1;
41747 getParams : function(q){
41749 //p[this.queryParam] = q;
41752 p.limit = this.pageSize;
41758 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41760 collapse : function(){
41761 if(!this.isExpanded()){
41765 Roo.get(document).un('mousedown', this.collapseIf, this);
41766 Roo.get(document).un('mousewheel', this.collapseIf, this);
41767 if (!this.editable) {
41768 Roo.get(document).un('keydown', this.listKeyPress, this);
41770 this.fireEvent('collapse', this);
41774 collapseIf : function(e){
41775 if(!e.within(this.wrap) && !e.within(this.list)){
41781 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41783 expand : function(){
41784 if(this.isExpanded() || !this.hasFocus){
41787 this.list.alignTo(this.el, this.listAlign);
41789 Roo.get(document).on('mousedown', this.collapseIf, this);
41790 Roo.get(document).on('mousewheel', this.collapseIf, this);
41791 if (!this.editable) {
41792 Roo.get(document).on('keydown', this.listKeyPress, this);
41795 this.fireEvent('expand', this);
41799 // Implements the default empty TriggerField.onTriggerClick function
41800 onTriggerClick : function(){
41804 if(this.isExpanded()){
41806 if (!this.blockFocus) {
41811 this.hasFocus = true;
41812 if(this.triggerAction == 'all') {
41813 this.doQuery(this.allQuery, true);
41815 this.doQuery(this.getRawValue());
41817 if (!this.blockFocus) {
41822 listKeyPress : function(e)
41824 //Roo.log('listkeypress');
41825 // scroll to first matching element based on key pres..
41826 if (e.isSpecialKey()) {
41829 var k = String.fromCharCode(e.getKey()).toUpperCase();
41832 var csel = this.view.getSelectedNodes();
41833 var cselitem = false;
41835 var ix = this.view.indexOf(csel[0]);
41836 cselitem = this.store.getAt(ix);
41837 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41843 this.store.each(function(v) {
41845 // start at existing selection.
41846 if (cselitem.id == v.id) {
41852 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
41853 match = this.store.indexOf(v);
41858 if (match === false) {
41859 return true; // no more action?
41862 this.view.select(match);
41863 var sn = Roo.get(this.view.getSelectedNodes()[0]);
41864 sn.scrollIntoView(sn.dom.parentNode, false);
41868 * @cfg {Boolean} grow
41872 * @cfg {Number} growMin
41876 * @cfg {Number} growMax
41884 * Copyright(c) 2010-2012, Roo J Solutions Limited
41891 * @class Roo.form.ComboBoxArray
41892 * @extends Roo.form.TextField
41893 * A facebook style adder... for lists of email / people / countries etc...
41894 * pick multiple items from a combo box, and shows each one.
41896 * Fred [x] Brian [x] [Pick another |v]
41899 * For this to work: it needs various extra information
41900 * - normal combo problay has
41902 * + displayField, valueField
41904 * For our purpose...
41907 * If we change from 'extends' to wrapping...
41914 * Create a new ComboBoxArray.
41915 * @param {Object} config Configuration options
41919 Roo.form.ComboBoxArray = function(config)
41923 * @event beforeremove
41924 * Fires before remove the value from the list
41925 * @param {Roo.form.ComboBoxArray} _self This combo box array
41926 * @param {Roo.form.ComboBoxArray.Item} item removed item
41928 'beforeremove' : true,
41931 * Fires when remove the value from the list
41932 * @param {Roo.form.ComboBoxArray} _self This combo box array
41933 * @param {Roo.form.ComboBoxArray.Item} item removed item
41940 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
41942 this.items = new Roo.util.MixedCollection(false);
41944 // construct the child combo...
41954 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
41957 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
41962 // behavies liek a hiddne field
41963 inputType: 'hidden',
41965 * @cfg {Number} width The width of the box that displays the selected element
41972 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
41976 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
41978 hiddenName : false,
41981 // private the array of items that are displayed..
41983 // private - the hidden field el.
41985 // private - the filed el..
41988 //validateValue : function() { return true; }, // all values are ok!
41989 //onAddClick: function() { },
41991 onRender : function(ct, position)
41994 // create the standard hidden element
41995 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
41998 // give fake names to child combo;
41999 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42000 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
42002 this.combo = Roo.factory(this.combo, Roo.form);
42003 this.combo.onRender(ct, position);
42004 if (typeof(this.combo.width) != 'undefined') {
42005 this.combo.onResize(this.combo.width,0);
42008 this.combo.initEvents();
42010 // assigned so form know we need to do this..
42011 this.store = this.combo.store;
42012 this.valueField = this.combo.valueField;
42013 this.displayField = this.combo.displayField ;
42016 this.combo.wrap.addClass('x-cbarray-grp');
42018 var cbwrap = this.combo.wrap.createChild(
42019 {tag: 'div', cls: 'x-cbarray-cb'},
42024 this.hiddenEl = this.combo.wrap.createChild({
42025 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42027 this.el = this.combo.wrap.createChild({
42028 tag: 'input', type:'hidden' , name: this.name, value : ''
42030 // this.el.dom.removeAttribute("name");
42033 this.outerWrap = this.combo.wrap;
42034 this.wrap = cbwrap;
42036 this.outerWrap.setWidth(this.width);
42037 this.outerWrap.dom.removeChild(this.el.dom);
42039 this.wrap.dom.appendChild(this.el.dom);
42040 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42041 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42043 this.combo.trigger.setStyle('position','relative');
42044 this.combo.trigger.setStyle('left', '0px');
42045 this.combo.trigger.setStyle('top', '2px');
42047 this.combo.el.setStyle('vertical-align', 'text-bottom');
42049 //this.trigger.setStyle('vertical-align', 'top');
42051 // this should use the code from combo really... on('add' ....)
42055 this.adder = this.outerWrap.createChild(
42056 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42058 this.adder.on('click', function(e) {
42059 _t.fireEvent('adderclick', this, e);
42063 //this.adder.on('click', this.onAddClick, _t);
42066 this.combo.on('select', function(cb, rec, ix) {
42067 this.addItem(rec.data);
42070 cb.el.dom.value = '';
42071 //cb.lastData = rec.data;
42080 getName: function()
42082 // returns hidden if it's set..
42083 if (!this.rendered) {return ''};
42084 return this.hiddenName ? this.hiddenName : this.name;
42089 onResize: function(w, h){
42092 // not sure if this is needed..
42093 //this.combo.onResize(w,h);
42095 if(typeof w != 'number'){
42096 // we do not handle it!?!?
42099 var tw = this.combo.trigger.getWidth();
42100 tw += this.addicon ? this.addicon.getWidth() : 0;
42101 tw += this.editicon ? this.editicon.getWidth() : 0;
42103 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42105 this.combo.trigger.setStyle('left', '0px');
42107 if(this.list && this.listWidth === undefined){
42108 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42109 this.list.setWidth(lw);
42110 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42117 addItem: function(rec)
42119 var valueField = this.combo.valueField;
42120 var displayField = this.combo.displayField;
42121 if (this.items.indexOfKey(rec[valueField]) > -1) {
42122 //console.log("GOT " + rec.data.id);
42126 var x = new Roo.form.ComboBoxArray.Item({
42127 //id : rec[this.idField],
42129 displayField : displayField ,
42130 tipField : displayField ,
42134 this.items.add(rec[valueField],x);
42135 // add it before the element..
42136 this.updateHiddenEl();
42137 x.render(this.outerWrap, this.wrap.dom);
42138 // add the image handler..
42141 updateHiddenEl : function()
42144 if (!this.hiddenEl) {
42148 var idField = this.combo.valueField;
42150 this.items.each(function(f) {
42151 ar.push(f.data[idField]);
42154 this.hiddenEl.dom.value = ar.join(',');
42160 this.items.clear();
42162 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42166 this.el.dom.value = '';
42167 if (this.hiddenEl) {
42168 this.hiddenEl.dom.value = '';
42172 getValue: function()
42174 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42176 setValue: function(v) // not a valid action - must use addItems..
42183 if (this.store.isLocal && (typeof(v) == 'string')) {
42184 // then we can use the store to find the values..
42185 // comma seperated at present.. this needs to allow JSON based encoding..
42186 this.hiddenEl.value = v;
42188 Roo.each(v.split(','), function(k) {
42189 Roo.log("CHECK " + this.valueField + ',' + k);
42190 var li = this.store.query(this.valueField, k);
42195 add[this.valueField] = k;
42196 add[this.displayField] = li.item(0).data[this.displayField];
42202 if (typeof(v) == 'object' ) {
42203 // then let's assume it's an array of objects..
42204 Roo.each(v, function(l) {
42212 setFromData: function(v)
42214 // this recieves an object, if setValues is called.
42216 this.el.dom.value = v[this.displayField];
42217 this.hiddenEl.dom.value = v[this.valueField];
42218 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42221 var kv = v[this.valueField];
42222 var dv = v[this.displayField];
42223 kv = typeof(kv) != 'string' ? '' : kv;
42224 dv = typeof(dv) != 'string' ? '' : dv;
42227 var keys = kv.split(',');
42228 var display = dv.split(',');
42229 for (var i = 0 ; i < keys.length; i++) {
42232 add[this.valueField] = keys[i];
42233 add[this.displayField] = display[i];
42241 * Validates the combox array value
42242 * @return {Boolean} True if the value is valid, else false
42244 validate : function(){
42245 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42246 this.clearInvalid();
42252 validateValue : function(value){
42253 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42261 isDirty : function() {
42262 if(this.disabled) {
42267 var d = Roo.decode(String(this.originalValue));
42269 return String(this.getValue()) !== String(this.originalValue);
42272 var originalValue = [];
42274 for (var i = 0; i < d.length; i++){
42275 originalValue.push(d[i][this.valueField]);
42278 return String(this.getValue()) !== String(originalValue.join(','));
42287 * @class Roo.form.ComboBoxArray.Item
42288 * @extends Roo.BoxComponent
42289 * A selected item in the list
42290 * Fred [x] Brian [x] [Pick another |v]
42293 * Create a new item.
42294 * @param {Object} config Configuration options
42297 Roo.form.ComboBoxArray.Item = function(config) {
42298 config.id = Roo.id();
42299 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42302 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42305 displayField : false,
42309 defaultAutoCreate : {
42311 cls: 'x-cbarray-item',
42318 src : Roo.BLANK_IMAGE_URL ,
42326 onRender : function(ct, position)
42328 Roo.form.Field.superclass.onRender.call(this, ct, position);
42331 var cfg = this.getAutoCreate();
42332 this.el = ct.createChild(cfg, position);
42335 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42337 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42338 this.cb.renderer(this.data) :
42339 String.format('{0}',this.data[this.displayField]);
42342 this.el.child('div').dom.setAttribute('qtip',
42343 String.format('{0}',this.data[this.tipField])
42346 this.el.child('img').on('click', this.remove, this);
42350 remove : function()
42352 if(this.cb.disabled){
42356 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42357 this.cb.items.remove(this);
42358 this.el.child('img').un('click', this.remove, this);
42360 this.cb.updateHiddenEl();
42362 this.cb.fireEvent('remove', this.cb, this);
42368 * Ext JS Library 1.1.1
42369 * Copyright(c) 2006-2007, Ext JS, LLC.
42371 * Originally Released Under LGPL - original licence link has changed is not relivant.
42374 * <script type="text/javascript">
42377 * @class Roo.form.Checkbox
42378 * @extends Roo.form.Field
42379 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42381 * Creates a new Checkbox
42382 * @param {Object} config Configuration options
42384 Roo.form.Checkbox = function(config){
42385 Roo.form.Checkbox.superclass.constructor.call(this, config);
42389 * Fires when the checkbox is checked or unchecked.
42390 * @param {Roo.form.Checkbox} this This checkbox
42391 * @param {Boolean} checked The new checked value
42397 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42399 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42401 focusClass : undefined,
42403 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42405 fieldClass: "x-form-field",
42407 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42411 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42412 * {tag: "input", type: "checkbox", autocomplete: "off"})
42414 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42416 * @cfg {String} boxLabel The text that appears beside the checkbox
42420 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42424 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42426 valueOff: '0', // value when not checked..
42428 actionMode : 'viewEl',
42431 itemCls : 'x-menu-check-item x-form-item',
42432 groupClass : 'x-menu-group-item',
42433 inputType : 'hidden',
42436 inSetChecked: false, // check that we are not calling self...
42438 inputElement: false, // real input element?
42439 basedOn: false, // ????
42441 isFormField: true, // not sure where this is needed!!!!
42443 onResize : function(){
42444 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42445 if(!this.boxLabel){
42446 this.el.alignTo(this.wrap, 'c-c');
42450 initEvents : function(){
42451 Roo.form.Checkbox.superclass.initEvents.call(this);
42452 this.el.on("click", this.onClick, this);
42453 this.el.on("change", this.onClick, this);
42457 getResizeEl : function(){
42461 getPositionEl : function(){
42466 onRender : function(ct, position){
42467 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42469 if(this.inputValue !== undefined){
42470 this.el.dom.value = this.inputValue;
42473 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42474 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42475 var viewEl = this.wrap.createChild({
42476 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42477 this.viewEl = viewEl;
42478 this.wrap.on('click', this.onClick, this);
42480 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42481 this.el.on('propertychange', this.setFromHidden, this); //ie
42486 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42487 // viewEl.on('click', this.onClick, this);
42489 //if(this.checked){
42490 this.setChecked(this.checked);
42492 //this.checked = this.el.dom;
42498 initValue : Roo.emptyFn,
42501 * Returns the checked state of the checkbox.
42502 * @return {Boolean} True if checked, else false
42504 getValue : function(){
42506 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42508 return this.valueOff;
42513 onClick : function(){
42514 if (this.disabled) {
42517 this.setChecked(!this.checked);
42519 //if(this.el.dom.checked != this.checked){
42520 // this.setValue(this.el.dom.checked);
42525 * Sets the checked state of the checkbox.
42526 * On is always based on a string comparison between inputValue and the param.
42527 * @param {Boolean/String} value - the value to set
42528 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42530 setValue : function(v,suppressEvent){
42533 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42534 //if(this.el && this.el.dom){
42535 // this.el.dom.checked = this.checked;
42536 // this.el.dom.defaultChecked = this.checked;
42538 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42539 //this.fireEvent("check", this, this.checked);
42542 setChecked : function(state,suppressEvent)
42544 if (this.inSetChecked) {
42545 this.checked = state;
42551 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42553 this.checked = state;
42554 if(suppressEvent !== true){
42555 this.fireEvent('check', this, state);
42557 this.inSetChecked = true;
42558 this.el.dom.value = state ? this.inputValue : this.valueOff;
42559 this.inSetChecked = false;
42562 // handle setting of hidden value by some other method!!?!?
42563 setFromHidden: function()
42568 //console.log("SET FROM HIDDEN");
42569 //alert('setFrom hidden');
42570 this.setValue(this.el.dom.value);
42573 onDestroy : function()
42576 Roo.get(this.viewEl).remove();
42579 Roo.form.Checkbox.superclass.onDestroy.call(this);
42582 setBoxLabel : function(str)
42584 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42589 * Ext JS Library 1.1.1
42590 * Copyright(c) 2006-2007, Ext JS, LLC.
42592 * Originally Released Under LGPL - original licence link has changed is not relivant.
42595 * <script type="text/javascript">
42599 * @class Roo.form.Radio
42600 * @extends Roo.form.Checkbox
42601 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42602 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42604 * Creates a new Radio
42605 * @param {Object} config Configuration options
42607 Roo.form.Radio = function(){
42608 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42610 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42611 inputType: 'radio',
42614 * If this radio is part of a group, it will return the selected value
42617 getGroupValue : function(){
42618 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42622 onRender : function(ct, position){
42623 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42625 if(this.inputValue !== undefined){
42626 this.el.dom.value = this.inputValue;
42629 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42630 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42631 //var viewEl = this.wrap.createChild({
42632 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42633 //this.viewEl = viewEl;
42634 //this.wrap.on('click', this.onClick, this);
42636 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42637 //this.el.on('propertychange', this.setFromHidden, this); //ie
42642 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42643 // viewEl.on('click', this.onClick, this);
42646 this.el.dom.checked = 'checked' ;
42652 });//<script type="text/javascript">
42655 * Based Ext JS Library 1.1.1
42656 * Copyright(c) 2006-2007, Ext JS, LLC.
42662 * @class Roo.HtmlEditorCore
42663 * @extends Roo.Component
42664 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42666 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42669 Roo.HtmlEditorCore = function(config){
42672 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42677 * @event initialize
42678 * Fires when the editor is fully initialized (including the iframe)
42679 * @param {Roo.HtmlEditorCore} this
42684 * Fires when the editor is first receives the focus. Any insertion must wait
42685 * until after this event.
42686 * @param {Roo.HtmlEditorCore} this
42690 * @event beforesync
42691 * Fires before the textarea is updated with content from the editor iframe. Return false
42692 * to cancel the sync.
42693 * @param {Roo.HtmlEditorCore} this
42694 * @param {String} html
42698 * @event beforepush
42699 * Fires before the iframe editor is updated with content from the textarea. Return false
42700 * to cancel the push.
42701 * @param {Roo.HtmlEditorCore} this
42702 * @param {String} html
42707 * Fires when the textarea is updated with content from the editor iframe.
42708 * @param {Roo.HtmlEditorCore} this
42709 * @param {String} html
42714 * Fires when the iframe editor is updated with content from the textarea.
42715 * @param {Roo.HtmlEditorCore} this
42716 * @param {String} html
42721 * @event editorevent
42722 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42723 * @param {Roo.HtmlEditorCore} this
42729 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42731 // defaults : white / black...
42732 this.applyBlacklists();
42739 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42743 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42749 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42754 * @cfg {Number} height (in pixels)
42758 * @cfg {Number} width (in pixels)
42763 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42766 stylesheets: false,
42771 // private properties
42772 validationEvent : false,
42774 initialized : false,
42776 sourceEditMode : false,
42777 onFocus : Roo.emptyFn,
42779 hideMode:'offsets',
42783 // blacklist + whitelisted elements..
42790 * Protected method that will not generally be called directly. It
42791 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42792 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42794 getDocMarkup : function(){
42798 // inherit styels from page...??
42799 if (this.stylesheets === false) {
42801 Roo.get(document.head).select('style').each(function(node) {
42802 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42805 Roo.get(document.head).select('link').each(function(node) {
42806 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42809 } else if (!this.stylesheets.length) {
42811 st = '<style type="text/css">' +
42812 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42818 st += '<style type="text/css">' +
42819 'IMG { cursor: pointer } ' +
42823 return '<html><head>' + st +
42824 //<style type="text/css">' +
42825 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42827 ' </head><body class="roo-htmleditor-body"></body></html>';
42831 onRender : function(ct, position)
42834 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42835 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42838 this.el.dom.style.border = '0 none';
42839 this.el.dom.setAttribute('tabIndex', -1);
42840 this.el.addClass('x-hidden hide');
42844 if(Roo.isIE){ // fix IE 1px bogus margin
42845 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42849 this.frameId = Roo.id();
42853 var iframe = this.owner.wrap.createChild({
42855 cls: 'form-control', // bootstrap..
42857 name: this.frameId,
42858 frameBorder : 'no',
42859 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42864 this.iframe = iframe.dom;
42866 this.assignDocWin();
42868 this.doc.designMode = 'on';
42871 this.doc.write(this.getDocMarkup());
42875 var task = { // must defer to wait for browser to be ready
42877 //console.log("run task?" + this.doc.readyState);
42878 this.assignDocWin();
42879 if(this.doc.body || this.doc.readyState == 'complete'){
42881 this.doc.designMode="on";
42885 Roo.TaskMgr.stop(task);
42886 this.initEditor.defer(10, this);
42893 Roo.TaskMgr.start(task);
42898 onResize : function(w, h)
42900 Roo.log('resize: ' +w + ',' + h );
42901 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
42905 if(typeof w == 'number'){
42907 this.iframe.style.width = w + 'px';
42909 if(typeof h == 'number'){
42911 this.iframe.style.height = h + 'px';
42913 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
42920 * Toggles the editor between standard and source edit mode.
42921 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42923 toggleSourceEdit : function(sourceEditMode){
42925 this.sourceEditMode = sourceEditMode === true;
42927 if(this.sourceEditMode){
42929 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
42932 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
42933 //this.iframe.className = '';
42936 //this.setSize(this.owner.wrap.getSize());
42937 //this.fireEvent('editmodechange', this, this.sourceEditMode);
42944 * Protected method that will not generally be called directly. If you need/want
42945 * custom HTML cleanup, this is the method you should override.
42946 * @param {String} html The HTML to be cleaned
42947 * return {String} The cleaned HTML
42949 cleanHtml : function(html){
42950 html = String(html);
42951 if(html.length > 5){
42952 if(Roo.isSafari){ // strip safari nonsense
42953 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
42956 if(html == ' '){
42963 * HTML Editor -> Textarea
42964 * Protected method that will not generally be called directly. Syncs the contents
42965 * of the editor iframe with the textarea.
42967 syncValue : function(){
42968 if(this.initialized){
42969 var bd = (this.doc.body || this.doc.documentElement);
42970 //this.cleanUpPaste(); -- this is done else where and causes havoc..
42971 var html = bd.innerHTML;
42973 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
42974 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
42976 html = '<div style="'+m[0]+'">' + html + '</div>';
42979 html = this.cleanHtml(html);
42980 // fix up the special chars.. normaly like back quotes in word...
42981 // however we do not want to do this with chinese..
42982 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
42983 var cc = b.charCodeAt();
42985 (cc >= 0x4E00 && cc < 0xA000 ) ||
42986 (cc >= 0x3400 && cc < 0x4E00 ) ||
42987 (cc >= 0xf900 && cc < 0xfb00 )
42993 if(this.owner.fireEvent('beforesync', this, html) !== false){
42994 this.el.dom.value = html;
42995 this.owner.fireEvent('sync', this, html);
43001 * Protected method that will not generally be called directly. Pushes the value of the textarea
43002 * into the iframe editor.
43004 pushValue : function(){
43005 if(this.initialized){
43006 var v = this.el.dom.value.trim();
43008 // if(v.length < 1){
43012 if(this.owner.fireEvent('beforepush', this, v) !== false){
43013 var d = (this.doc.body || this.doc.documentElement);
43015 this.cleanUpPaste();
43016 this.el.dom.value = d.innerHTML;
43017 this.owner.fireEvent('push', this, v);
43023 deferFocus : function(){
43024 this.focus.defer(10, this);
43028 focus : function(){
43029 if(this.win && !this.sourceEditMode){
43036 assignDocWin: function()
43038 var iframe = this.iframe;
43041 this.doc = iframe.contentWindow.document;
43042 this.win = iframe.contentWindow;
43044 // if (!Roo.get(this.frameId)) {
43047 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43048 // this.win = Roo.get(this.frameId).dom.contentWindow;
43050 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43054 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43055 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43060 initEditor : function(){
43061 //console.log("INIT EDITOR");
43062 this.assignDocWin();
43066 this.doc.designMode="on";
43068 this.doc.write(this.getDocMarkup());
43071 var dbody = (this.doc.body || this.doc.documentElement);
43072 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43073 // this copies styles from the containing element into thsi one..
43074 // not sure why we need all of this..
43075 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43077 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43078 //ss['background-attachment'] = 'fixed'; // w3c
43079 dbody.bgProperties = 'fixed'; // ie
43080 //Roo.DomHelper.applyStyles(dbody, ss);
43081 Roo.EventManager.on(this.doc, {
43082 //'mousedown': this.onEditorEvent,
43083 'mouseup': this.onEditorEvent,
43084 'dblclick': this.onEditorEvent,
43085 'click': this.onEditorEvent,
43086 'keyup': this.onEditorEvent,
43091 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43093 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43094 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43096 this.initialized = true;
43098 this.owner.fireEvent('initialize', this);
43103 onDestroy : function(){
43109 //for (var i =0; i < this.toolbars.length;i++) {
43110 // // fixme - ask toolbars for heights?
43111 // this.toolbars[i].onDestroy();
43114 //this.wrap.dom.innerHTML = '';
43115 //this.wrap.remove();
43120 onFirstFocus : function(){
43122 this.assignDocWin();
43125 this.activated = true;
43128 if(Roo.isGecko){ // prevent silly gecko errors
43130 var s = this.win.getSelection();
43131 if(!s.focusNode || s.focusNode.nodeType != 3){
43132 var r = s.getRangeAt(0);
43133 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43138 this.execCmd('useCSS', true);
43139 this.execCmd('styleWithCSS', false);
43142 this.owner.fireEvent('activate', this);
43146 adjustFont: function(btn){
43147 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43148 //if(Roo.isSafari){ // safari
43151 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43152 if(Roo.isSafari){ // safari
43153 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43154 v = (v < 10) ? 10 : v;
43155 v = (v > 48) ? 48 : v;
43156 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43161 v = Math.max(1, v+adjust);
43163 this.execCmd('FontSize', v );
43166 onEditorEvent : function(e)
43168 this.owner.fireEvent('editorevent', this, e);
43169 // this.updateToolbar();
43170 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43173 insertTag : function(tg)
43175 // could be a bit smarter... -> wrap the current selected tRoo..
43176 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43178 range = this.createRange(this.getSelection());
43179 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43180 wrappingNode.appendChild(range.extractContents());
43181 range.insertNode(wrappingNode);
43188 this.execCmd("formatblock", tg);
43192 insertText : function(txt)
43196 var range = this.createRange();
43197 range.deleteContents();
43198 //alert(Sender.getAttribute('label'));
43200 range.insertNode(this.doc.createTextNode(txt));
43206 * Executes a Midas editor command on the editor document and performs necessary focus and
43207 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43208 * @param {String} cmd The Midas command
43209 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43211 relayCmd : function(cmd, value){
43213 this.execCmd(cmd, value);
43214 this.owner.fireEvent('editorevent', this);
43215 //this.updateToolbar();
43216 this.owner.deferFocus();
43220 * Executes a Midas editor command directly on the editor document.
43221 * For visual commands, you should use {@link #relayCmd} instead.
43222 * <b>This should only be called after the editor is initialized.</b>
43223 * @param {String} cmd The Midas command
43224 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43226 execCmd : function(cmd, value){
43227 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43234 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43236 * @param {String} text | dom node..
43238 insertAtCursor : function(text)
43243 if(!this.activated){
43249 var r = this.doc.selection.createRange();
43260 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43264 // from jquery ui (MIT licenced)
43266 var win = this.win;
43268 if (win.getSelection && win.getSelection().getRangeAt) {
43269 range = win.getSelection().getRangeAt(0);
43270 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43271 range.insertNode(node);
43272 } else if (win.document.selection && win.document.selection.createRange) {
43273 // no firefox support
43274 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43275 win.document.selection.createRange().pasteHTML(txt);
43277 // no firefox support
43278 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43279 this.execCmd('InsertHTML', txt);
43288 mozKeyPress : function(e){
43290 var c = e.getCharCode(), cmd;
43293 c = String.fromCharCode(c).toLowerCase();
43307 this.cleanUpPaste.defer(100, this);
43315 e.preventDefault();
43323 fixKeys : function(){ // load time branching for fastest keydown performance
43325 return function(e){
43326 var k = e.getKey(), r;
43329 r = this.doc.selection.createRange();
43332 r.pasteHTML('    ');
43339 r = this.doc.selection.createRange();
43341 var target = r.parentElement();
43342 if(!target || target.tagName.toLowerCase() != 'li'){
43344 r.pasteHTML('<br />');
43350 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43351 this.cleanUpPaste.defer(100, this);
43357 }else if(Roo.isOpera){
43358 return function(e){
43359 var k = e.getKey();
43363 this.execCmd('InsertHTML','    ');
43366 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43367 this.cleanUpPaste.defer(100, this);
43372 }else if(Roo.isSafari){
43373 return function(e){
43374 var k = e.getKey();
43378 this.execCmd('InsertText','\t');
43382 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43383 this.cleanUpPaste.defer(100, this);
43391 getAllAncestors: function()
43393 var p = this.getSelectedNode();
43396 a.push(p); // push blank onto stack..
43397 p = this.getParentElement();
43401 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43405 a.push(this.doc.body);
43409 lastSelNode : false,
43412 getSelection : function()
43414 this.assignDocWin();
43415 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43418 getSelectedNode: function()
43420 // this may only work on Gecko!!!
43422 // should we cache this!!!!
43427 var range = this.createRange(this.getSelection()).cloneRange();
43430 var parent = range.parentElement();
43432 var testRange = range.duplicate();
43433 testRange.moveToElementText(parent);
43434 if (testRange.inRange(range)) {
43437 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43440 parent = parent.parentElement;
43445 // is ancestor a text element.
43446 var ac = range.commonAncestorContainer;
43447 if (ac.nodeType == 3) {
43448 ac = ac.parentNode;
43451 var ar = ac.childNodes;
43454 var other_nodes = [];
43455 var has_other_nodes = false;
43456 for (var i=0;i<ar.length;i++) {
43457 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43460 // fullly contained node.
43462 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43467 // probably selected..
43468 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43469 other_nodes.push(ar[i]);
43473 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43478 has_other_nodes = true;
43480 if (!nodes.length && other_nodes.length) {
43481 nodes= other_nodes;
43483 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43489 createRange: function(sel)
43491 // this has strange effects when using with
43492 // top toolbar - not sure if it's a great idea.
43493 //this.editor.contentWindow.focus();
43494 if (typeof sel != "undefined") {
43496 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43498 return this.doc.createRange();
43501 return this.doc.createRange();
43504 getParentElement: function()
43507 this.assignDocWin();
43508 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43510 var range = this.createRange(sel);
43513 var p = range.commonAncestorContainer;
43514 while (p.nodeType == 3) { // text node
43525 * Range intersection.. the hard stuff...
43529 * [ -- selected range --- ]
43533 * if end is before start or hits it. fail.
43534 * if start is after end or hits it fail.
43536 * if either hits (but other is outside. - then it's not
43542 // @see http://www.thismuchiknow.co.uk/?p=64.
43543 rangeIntersectsNode : function(range, node)
43545 var nodeRange = node.ownerDocument.createRange();
43547 nodeRange.selectNode(node);
43549 nodeRange.selectNodeContents(node);
43552 var rangeStartRange = range.cloneRange();
43553 rangeStartRange.collapse(true);
43555 var rangeEndRange = range.cloneRange();
43556 rangeEndRange.collapse(false);
43558 var nodeStartRange = nodeRange.cloneRange();
43559 nodeStartRange.collapse(true);
43561 var nodeEndRange = nodeRange.cloneRange();
43562 nodeEndRange.collapse(false);
43564 return rangeStartRange.compareBoundaryPoints(
43565 Range.START_TO_START, nodeEndRange) == -1 &&
43566 rangeEndRange.compareBoundaryPoints(
43567 Range.START_TO_START, nodeStartRange) == 1;
43571 rangeCompareNode : function(range, node)
43573 var nodeRange = node.ownerDocument.createRange();
43575 nodeRange.selectNode(node);
43577 nodeRange.selectNodeContents(node);
43581 range.collapse(true);
43583 nodeRange.collapse(true);
43585 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43586 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43588 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43590 var nodeIsBefore = ss == 1;
43591 var nodeIsAfter = ee == -1;
43593 if (nodeIsBefore && nodeIsAfter) {
43596 if (!nodeIsBefore && nodeIsAfter) {
43597 return 1; //right trailed.
43600 if (nodeIsBefore && !nodeIsAfter) {
43601 return 2; // left trailed.
43607 // private? - in a new class?
43608 cleanUpPaste : function()
43610 // cleans up the whole document..
43611 Roo.log('cleanuppaste');
43613 this.cleanUpChildren(this.doc.body);
43614 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43615 if (clean != this.doc.body.innerHTML) {
43616 this.doc.body.innerHTML = clean;
43621 cleanWordChars : function(input) {// change the chars to hex code
43622 var he = Roo.HtmlEditorCore;
43624 var output = input;
43625 Roo.each(he.swapCodes, function(sw) {
43626 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43628 output = output.replace(swapper, sw[1]);
43635 cleanUpChildren : function (n)
43637 if (!n.childNodes.length) {
43640 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43641 this.cleanUpChild(n.childNodes[i]);
43648 cleanUpChild : function (node)
43651 //console.log(node);
43652 if (node.nodeName == "#text") {
43653 // clean up silly Windows -- stuff?
43656 if (node.nodeName == "#comment") {
43657 node.parentNode.removeChild(node);
43658 // clean up silly Windows -- stuff?
43661 var lcname = node.tagName.toLowerCase();
43662 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43663 // whitelist of tags..
43665 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43667 node.parentNode.removeChild(node);
43672 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43674 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43675 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43677 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43678 // remove_keep_children = true;
43681 if (remove_keep_children) {
43682 this.cleanUpChildren(node);
43683 // inserts everything just before this node...
43684 while (node.childNodes.length) {
43685 var cn = node.childNodes[0];
43686 node.removeChild(cn);
43687 node.parentNode.insertBefore(cn, node);
43689 node.parentNode.removeChild(node);
43693 if (!node.attributes || !node.attributes.length) {
43694 this.cleanUpChildren(node);
43698 function cleanAttr(n,v)
43701 if (v.match(/^\./) || v.match(/^\//)) {
43704 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
43707 if (v.match(/^#/)) {
43710 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43711 node.removeAttribute(n);
43715 var cwhite = this.cwhite;
43716 var cblack = this.cblack;
43718 function cleanStyle(n,v)
43720 if (v.match(/expression/)) { //XSS?? should we even bother..
43721 node.removeAttribute(n);
43725 var parts = v.split(/;/);
43728 Roo.each(parts, function(p) {
43729 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43733 var l = p.split(':').shift().replace(/\s+/g,'');
43734 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43736 if ( cwhite.length && cblack.indexOf(l) > -1) {
43737 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43738 //node.removeAttribute(n);
43742 // only allow 'c whitelisted system attributes'
43743 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43744 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43745 //node.removeAttribute(n);
43755 if (clean.length) {
43756 node.setAttribute(n, clean.join(';'));
43758 node.removeAttribute(n);
43764 for (var i = node.attributes.length-1; i > -1 ; i--) {
43765 var a = node.attributes[i];
43768 if (a.name.toLowerCase().substr(0,2)=='on') {
43769 node.removeAttribute(a.name);
43772 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43773 node.removeAttribute(a.name);
43776 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43777 cleanAttr(a.name,a.value); // fixme..
43780 if (a.name == 'style') {
43781 cleanStyle(a.name,a.value);
43784 /// clean up MS crap..
43785 // tecnically this should be a list of valid class'es..
43788 if (a.name == 'class') {
43789 if (a.value.match(/^Mso/)) {
43790 node.className = '';
43793 if (a.value.match(/body/)) {
43794 node.className = '';
43805 this.cleanUpChildren(node);
43811 * Clean up MS wordisms...
43813 cleanWord : function(node)
43818 this.cleanWord(this.doc.body);
43821 if (node.nodeName == "#text") {
43822 // clean up silly Windows -- stuff?
43825 if (node.nodeName == "#comment") {
43826 node.parentNode.removeChild(node);
43827 // clean up silly Windows -- stuff?
43831 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43832 node.parentNode.removeChild(node);
43836 // remove - but keep children..
43837 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43838 while (node.childNodes.length) {
43839 var cn = node.childNodes[0];
43840 node.removeChild(cn);
43841 node.parentNode.insertBefore(cn, node);
43843 node.parentNode.removeChild(node);
43844 this.iterateChildren(node, this.cleanWord);
43848 if (node.className.length) {
43850 var cn = node.className.split(/\W+/);
43852 Roo.each(cn, function(cls) {
43853 if (cls.match(/Mso[a-zA-Z]+/)) {
43858 node.className = cna.length ? cna.join(' ') : '';
43860 node.removeAttribute("class");
43864 if (node.hasAttribute("lang")) {
43865 node.removeAttribute("lang");
43868 if (node.hasAttribute("style")) {
43870 var styles = node.getAttribute("style").split(";");
43872 Roo.each(styles, function(s) {
43873 if (!s.match(/:/)) {
43876 var kv = s.split(":");
43877 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
43880 // what ever is left... we allow.
43883 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43884 if (!nstyle.length) {
43885 node.removeAttribute('style');
43888 this.iterateChildren(node, this.cleanWord);
43894 * iterateChildren of a Node, calling fn each time, using this as the scole..
43895 * @param {DomNode} node node to iterate children of.
43896 * @param {Function} fn method of this class to call on each item.
43898 iterateChildren : function(node, fn)
43900 if (!node.childNodes.length) {
43903 for (var i = node.childNodes.length-1; i > -1 ; i--) {
43904 fn.call(this, node.childNodes[i])
43910 * cleanTableWidths.
43912 * Quite often pasting from word etc.. results in tables with column and widths.
43913 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
43916 cleanTableWidths : function(node)
43921 this.cleanTableWidths(this.doc.body);
43926 if (node.nodeName == "#text" || node.nodeName == "#comment") {
43929 Roo.log(node.tagName);
43930 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
43931 this.iterateChildren(node, this.cleanTableWidths);
43934 if (node.hasAttribute('width')) {
43935 node.removeAttribute('width');
43939 if (node.hasAttribute("style")) {
43942 var styles = node.getAttribute("style").split(";");
43944 Roo.each(styles, function(s) {
43945 if (!s.match(/:/)) {
43948 var kv = s.split(":");
43949 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
43952 // what ever is left... we allow.
43955 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43956 if (!nstyle.length) {
43957 node.removeAttribute('style');
43961 this.iterateChildren(node, this.cleanTableWidths);
43969 domToHTML : function(currentElement, depth, nopadtext) {
43971 depth = depth || 0;
43972 nopadtext = nopadtext || false;
43974 if (!currentElement) {
43975 return this.domToHTML(this.doc.body);
43978 //Roo.log(currentElement);
43980 var allText = false;
43981 var nodeName = currentElement.nodeName;
43982 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
43984 if (nodeName == '#text') {
43986 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
43991 if (nodeName != 'BODY') {
43994 // Prints the node tagName, such as <A>, <IMG>, etc
43997 for(i = 0; i < currentElement.attributes.length;i++) {
43999 var aname = currentElement.attributes.item(i).name;
44000 if (!currentElement.attributes.item(i).value.length) {
44003 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44006 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44015 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44018 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44023 // Traverse the tree
44025 var currentElementChild = currentElement.childNodes.item(i);
44026 var allText = true;
44027 var innerHTML = '';
44029 while (currentElementChild) {
44030 // Formatting code (indent the tree so it looks nice on the screen)
44031 var nopad = nopadtext;
44032 if (lastnode == 'SPAN') {
44036 if (currentElementChild.nodeName == '#text') {
44037 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44038 toadd = nopadtext ? toadd : toadd.trim();
44039 if (!nopad && toadd.length > 80) {
44040 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44042 innerHTML += toadd;
44045 currentElementChild = currentElement.childNodes.item(i);
44051 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44053 // Recursively traverse the tree structure of the child node
44054 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44055 lastnode = currentElementChild.nodeName;
44057 currentElementChild=currentElement.childNodes.item(i);
44063 // The remaining code is mostly for formatting the tree
44064 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44069 ret+= "</"+tagName+">";
44075 applyBlacklists : function()
44077 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44078 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44082 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44083 if (b.indexOf(tag) > -1) {
44086 this.white.push(tag);
44090 Roo.each(w, function(tag) {
44091 if (b.indexOf(tag) > -1) {
44094 if (this.white.indexOf(tag) > -1) {
44097 this.white.push(tag);
44102 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44103 if (w.indexOf(tag) > -1) {
44106 this.black.push(tag);
44110 Roo.each(b, function(tag) {
44111 if (w.indexOf(tag) > -1) {
44114 if (this.black.indexOf(tag) > -1) {
44117 this.black.push(tag);
44122 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44123 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44127 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44128 if (b.indexOf(tag) > -1) {
44131 this.cwhite.push(tag);
44135 Roo.each(w, function(tag) {
44136 if (b.indexOf(tag) > -1) {
44139 if (this.cwhite.indexOf(tag) > -1) {
44142 this.cwhite.push(tag);
44147 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44148 if (w.indexOf(tag) > -1) {
44151 this.cblack.push(tag);
44155 Roo.each(b, function(tag) {
44156 if (w.indexOf(tag) > -1) {
44159 if (this.cblack.indexOf(tag) > -1) {
44162 this.cblack.push(tag);
44167 setStylesheets : function(stylesheets)
44169 if(typeof(stylesheets) == 'string'){
44170 Roo.get(this.iframe.contentDocument.head).createChild({
44172 rel : 'stylesheet',
44181 Roo.each(stylesheets, function(s) {
44186 Roo.get(_this.iframe.contentDocument.head).createChild({
44188 rel : 'stylesheet',
44197 removeStylesheets : function()
44201 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44206 // hide stuff that is not compatible
44220 * @event specialkey
44224 * @cfg {String} fieldClass @hide
44227 * @cfg {String} focusClass @hide
44230 * @cfg {String} autoCreate @hide
44233 * @cfg {String} inputType @hide
44236 * @cfg {String} invalidClass @hide
44239 * @cfg {String} invalidText @hide
44242 * @cfg {String} msgFx @hide
44245 * @cfg {String} validateOnBlur @hide
44249 Roo.HtmlEditorCore.white = [
44250 'area', 'br', 'img', 'input', 'hr', 'wbr',
44252 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44253 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44254 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44255 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44256 'table', 'ul', 'xmp',
44258 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44261 'dir', 'menu', 'ol', 'ul', 'dl',
44267 Roo.HtmlEditorCore.black = [
44268 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44270 'base', 'basefont', 'bgsound', 'blink', 'body',
44271 'frame', 'frameset', 'head', 'html', 'ilayer',
44272 'iframe', 'layer', 'link', 'meta', 'object',
44273 'script', 'style' ,'title', 'xml' // clean later..
44275 Roo.HtmlEditorCore.clean = [
44276 'script', 'style', 'title', 'xml'
44278 Roo.HtmlEditorCore.remove = [
44283 Roo.HtmlEditorCore.ablack = [
44287 Roo.HtmlEditorCore.aclean = [
44288 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44292 Roo.HtmlEditorCore.pwhite= [
44293 'http', 'https', 'mailto'
44296 // white listed style attributes.
44297 Roo.HtmlEditorCore.cwhite= [
44298 // 'text-align', /// default is to allow most things..
44304 // black listed style attributes.
44305 Roo.HtmlEditorCore.cblack= [
44306 // 'font-size' -- this can be set by the project
44310 Roo.HtmlEditorCore.swapCodes =[
44321 //<script type="text/javascript">
44324 * Ext JS Library 1.1.1
44325 * Copyright(c) 2006-2007, Ext JS, LLC.
44331 Roo.form.HtmlEditor = function(config){
44335 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44337 if (!this.toolbars) {
44338 this.toolbars = [];
44340 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44346 * @class Roo.form.HtmlEditor
44347 * @extends Roo.form.Field
44348 * Provides a lightweight HTML Editor component.
44350 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44352 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44353 * supported by this editor.</b><br/><br/>
44354 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44355 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44357 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44359 * @cfg {Boolean} clearUp
44363 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44368 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44373 * @cfg {Number} height (in pixels)
44377 * @cfg {Number} width (in pixels)
44382 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44385 stylesheets: false,
44389 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44394 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44400 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44405 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44413 // private properties
44414 validationEvent : false,
44416 initialized : false,
44419 onFocus : Roo.emptyFn,
44421 hideMode:'offsets',
44423 actionMode : 'container', // defaults to hiding it...
44425 defaultAutoCreate : { // modified by initCompnoent..
44427 style:"width:500px;height:300px;",
44428 autocomplete: "new-password"
44432 initComponent : function(){
44435 * @event initialize
44436 * Fires when the editor is fully initialized (including the iframe)
44437 * @param {HtmlEditor} this
44442 * Fires when the editor is first receives the focus. Any insertion must wait
44443 * until after this event.
44444 * @param {HtmlEditor} this
44448 * @event beforesync
44449 * Fires before the textarea is updated with content from the editor iframe. Return false
44450 * to cancel the sync.
44451 * @param {HtmlEditor} this
44452 * @param {String} html
44456 * @event beforepush
44457 * Fires before the iframe editor is updated with content from the textarea. Return false
44458 * to cancel the push.
44459 * @param {HtmlEditor} this
44460 * @param {String} html
44465 * Fires when the textarea is updated with content from the editor iframe.
44466 * @param {HtmlEditor} this
44467 * @param {String} html
44472 * Fires when the iframe editor is updated with content from the textarea.
44473 * @param {HtmlEditor} this
44474 * @param {String} html
44478 * @event editmodechange
44479 * Fires when the editor switches edit modes
44480 * @param {HtmlEditor} this
44481 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44483 editmodechange: true,
44485 * @event editorevent
44486 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44487 * @param {HtmlEditor} this
44491 * @event firstfocus
44492 * Fires when on first focus - needed by toolbars..
44493 * @param {HtmlEditor} this
44498 * Auto save the htmlEditor value as a file into Events
44499 * @param {HtmlEditor} this
44503 * @event savedpreview
44504 * preview the saved version of htmlEditor
44505 * @param {HtmlEditor} this
44507 savedpreview: true,
44510 * @event stylesheetsclick
44511 * Fires when press the Sytlesheets button
44512 * @param {Roo.HtmlEditorCore} this
44514 stylesheetsclick: true
44516 this.defaultAutoCreate = {
44518 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44519 autocomplete: "new-password"
44524 * Protected method that will not generally be called directly. It
44525 * is called when the editor creates its toolbar. Override this method if you need to
44526 * add custom toolbar buttons.
44527 * @param {HtmlEditor} editor
44529 createToolbar : function(editor){
44530 Roo.log("create toolbars");
44531 if (!editor.toolbars || !editor.toolbars.length) {
44532 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44535 for (var i =0 ; i < editor.toolbars.length;i++) {
44536 editor.toolbars[i] = Roo.factory(
44537 typeof(editor.toolbars[i]) == 'string' ?
44538 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44539 Roo.form.HtmlEditor);
44540 editor.toolbars[i].init(editor);
44548 onRender : function(ct, position)
44551 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44553 this.wrap = this.el.wrap({
44554 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44557 this.editorcore.onRender(ct, position);
44559 if (this.resizable) {
44560 this.resizeEl = new Roo.Resizable(this.wrap, {
44564 minHeight : this.height,
44565 height: this.height,
44566 handles : this.resizable,
44569 resize : function(r, w, h) {
44570 _t.onResize(w,h); // -something
44576 this.createToolbar(this);
44580 this.setSize(this.wrap.getSize());
44582 if (this.resizeEl) {
44583 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44584 // should trigger onReize..
44587 this.keyNav = new Roo.KeyNav(this.el, {
44589 "tab" : function(e){
44590 e.preventDefault();
44592 var value = this.getValue();
44594 var start = this.el.dom.selectionStart;
44595 var end = this.el.dom.selectionEnd;
44599 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44600 this.el.dom.setSelectionRange(end + 1, end + 1);
44604 var f = value.substring(0, start).split("\t");
44606 if(f.pop().length != 0){
44610 this.setValue(f.join("\t") + value.substring(end));
44611 this.el.dom.setSelectionRange(start - 1, start - 1);
44615 "home" : function(e){
44616 e.preventDefault();
44618 var curr = this.el.dom.selectionStart;
44619 var lines = this.getValue().split("\n");
44626 this.el.dom.setSelectionRange(0, 0);
44632 for (var i = 0; i < lines.length;i++) {
44633 pos += lines[i].length;
44643 pos -= lines[i].length;
44649 this.el.dom.setSelectionRange(pos, pos);
44653 this.el.dom.selectionStart = pos;
44654 this.el.dom.selectionEnd = curr;
44657 "end" : function(e){
44658 e.preventDefault();
44660 var curr = this.el.dom.selectionStart;
44661 var lines = this.getValue().split("\n");
44668 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44674 for (var i = 0; i < lines.length;i++) {
44676 pos += lines[i].length;
44690 this.el.dom.setSelectionRange(pos, pos);
44694 this.el.dom.selectionStart = curr;
44695 this.el.dom.selectionEnd = pos;
44700 doRelay : function(foo, bar, hname){
44701 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44707 // if(this.autosave && this.w){
44708 // this.autoSaveFn = setInterval(this.autosave, 1000);
44713 onResize : function(w, h)
44715 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44720 if(typeof w == 'number'){
44721 var aw = w - this.wrap.getFrameWidth('lr');
44722 this.el.setWidth(this.adjustWidth('textarea', aw));
44725 if(typeof h == 'number'){
44727 for (var i =0; i < this.toolbars.length;i++) {
44728 // fixme - ask toolbars for heights?
44729 tbh += this.toolbars[i].tb.el.getHeight();
44730 if (this.toolbars[i].footer) {
44731 tbh += this.toolbars[i].footer.el.getHeight();
44738 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44739 ah -= 5; // knock a few pixes off for look..
44741 this.el.setHeight(this.adjustWidth('textarea', ah));
44745 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44746 this.editorcore.onResize(ew,eh);
44751 * Toggles the editor between standard and source edit mode.
44752 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44754 toggleSourceEdit : function(sourceEditMode)
44756 this.editorcore.toggleSourceEdit(sourceEditMode);
44758 if(this.editorcore.sourceEditMode){
44759 Roo.log('editor - showing textarea');
44762 // Roo.log(this.syncValue());
44763 this.editorcore.syncValue();
44764 this.el.removeClass('x-hidden');
44765 this.el.dom.removeAttribute('tabIndex');
44768 for (var i = 0; i < this.toolbars.length; i++) {
44769 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44770 this.toolbars[i].tb.hide();
44771 this.toolbars[i].footer.hide();
44776 Roo.log('editor - hiding textarea');
44778 // Roo.log(this.pushValue());
44779 this.editorcore.pushValue();
44781 this.el.addClass('x-hidden');
44782 this.el.dom.setAttribute('tabIndex', -1);
44784 for (var i = 0; i < this.toolbars.length; i++) {
44785 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44786 this.toolbars[i].tb.show();
44787 this.toolbars[i].footer.show();
44791 //this.deferFocus();
44794 this.setSize(this.wrap.getSize());
44795 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44797 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44800 // private (for BoxComponent)
44801 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44803 // private (for BoxComponent)
44804 getResizeEl : function(){
44808 // private (for BoxComponent)
44809 getPositionEl : function(){
44814 initEvents : function(){
44815 this.originalValue = this.getValue();
44819 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44822 markInvalid : Roo.emptyFn,
44824 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44827 clearInvalid : Roo.emptyFn,
44829 setValue : function(v){
44830 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44831 this.editorcore.pushValue();
44836 deferFocus : function(){
44837 this.focus.defer(10, this);
44841 focus : function(){
44842 this.editorcore.focus();
44848 onDestroy : function(){
44854 for (var i =0; i < this.toolbars.length;i++) {
44855 // fixme - ask toolbars for heights?
44856 this.toolbars[i].onDestroy();
44859 this.wrap.dom.innerHTML = '';
44860 this.wrap.remove();
44865 onFirstFocus : function(){
44866 //Roo.log("onFirstFocus");
44867 this.editorcore.onFirstFocus();
44868 for (var i =0; i < this.toolbars.length;i++) {
44869 this.toolbars[i].onFirstFocus();
44875 syncValue : function()
44877 this.editorcore.syncValue();
44880 pushValue : function()
44882 this.editorcore.pushValue();
44885 setStylesheets : function(stylesheets)
44887 this.editorcore.setStylesheets(stylesheets);
44890 removeStylesheets : function()
44892 this.editorcore.removeStylesheets();
44896 // hide stuff that is not compatible
44910 * @event specialkey
44914 * @cfg {String} fieldClass @hide
44917 * @cfg {String} focusClass @hide
44920 * @cfg {String} autoCreate @hide
44923 * @cfg {String} inputType @hide
44926 * @cfg {String} invalidClass @hide
44929 * @cfg {String} invalidText @hide
44932 * @cfg {String} msgFx @hide
44935 * @cfg {String} validateOnBlur @hide
44939 // <script type="text/javascript">
44942 * Ext JS Library 1.1.1
44943 * Copyright(c) 2006-2007, Ext JS, LLC.
44949 * @class Roo.form.HtmlEditorToolbar1
44954 new Roo.form.HtmlEditor({
44957 new Roo.form.HtmlEditorToolbar1({
44958 disable : { fonts: 1 , format: 1, ..., ... , ...],
44964 * @cfg {Object} disable List of elements to disable..
44965 * @cfg {Array} btns List of additional buttons.
44969 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
44972 Roo.form.HtmlEditor.ToolbarStandard = function(config)
44975 Roo.apply(this, config);
44977 // default disabled, based on 'good practice'..
44978 this.disable = this.disable || {};
44979 Roo.applyIf(this.disable, {
44982 specialElements : true
44986 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44987 // dont call parent... till later.
44990 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
44997 editorcore : false,
44999 * @cfg {Object} disable List of toolbar elements to disable
45006 * @cfg {String} createLinkText The default text for the create link prompt
45008 createLinkText : 'Please enter the URL for the link:',
45010 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45012 defaultLinkValue : 'http:/'+'/',
45016 * @cfg {Array} fontFamilies An array of available font families
45034 // "á" , ?? a acute?
45039 "°" // , // degrees
45041 // "é" , // e ecute
45042 // "ú" , // u ecute?
45045 specialElements : [
45047 text: "Insert Table",
45050 ihtml : '<table><tr><td>Cell</td></tr></table>'
45054 text: "Insert Image",
45057 ihtml : '<img src="about:blank"/>'
45066 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45067 "input:submit", "input:button", "select", "textarea", "label" ],
45070 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45072 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45080 * @cfg {String} defaultFont default font to use.
45082 defaultFont: 'tahoma',
45084 fontSelect : false,
45087 formatCombo : false,
45089 init : function(editor)
45091 this.editor = editor;
45092 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45093 var editorcore = this.editorcore;
45097 var fid = editorcore.frameId;
45099 function btn(id, toggle, handler){
45100 var xid = fid + '-'+ id ;
45104 cls : 'x-btn-icon x-edit-'+id,
45105 enableToggle:toggle !== false,
45106 scope: _t, // was editor...
45107 handler:handler||_t.relayBtnCmd,
45108 clickEvent:'mousedown',
45109 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45116 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45118 // stop form submits
45119 tb.el.on('click', function(e){
45120 e.preventDefault(); // what does this do?
45123 if(!this.disable.font) { // && !Roo.isSafari){
45124 /* why no safari for fonts
45125 editor.fontSelect = tb.el.createChild({
45128 cls:'x-font-select',
45129 html: this.createFontOptions()
45132 editor.fontSelect.on('change', function(){
45133 var font = editor.fontSelect.dom.value;
45134 editor.relayCmd('fontname', font);
45135 editor.deferFocus();
45139 editor.fontSelect.dom,
45145 if(!this.disable.formats){
45146 this.formatCombo = new Roo.form.ComboBox({
45147 store: new Roo.data.SimpleStore({
45150 data : this.formats // from states.js
45154 //autoCreate : {tag: "div", size: "20"},
45155 displayField:'tag',
45159 triggerAction: 'all',
45160 emptyText:'Add tag',
45161 selectOnFocus:true,
45164 'select': function(c, r, i) {
45165 editorcore.insertTag(r.get('tag'));
45171 tb.addField(this.formatCombo);
45175 if(!this.disable.format){
45180 btn('strikethrough')
45183 if(!this.disable.fontSize){
45188 btn('increasefontsize', false, editorcore.adjustFont),
45189 btn('decreasefontsize', false, editorcore.adjustFont)
45194 if(!this.disable.colors){
45197 id:editorcore.frameId +'-forecolor',
45198 cls:'x-btn-icon x-edit-forecolor',
45199 clickEvent:'mousedown',
45200 tooltip: this.buttonTips['forecolor'] || undefined,
45202 menu : new Roo.menu.ColorMenu({
45203 allowReselect: true,
45204 focus: Roo.emptyFn,
45207 selectHandler: function(cp, color){
45208 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45209 editor.deferFocus();
45212 clickEvent:'mousedown'
45215 id:editorcore.frameId +'backcolor',
45216 cls:'x-btn-icon x-edit-backcolor',
45217 clickEvent:'mousedown',
45218 tooltip: this.buttonTips['backcolor'] || undefined,
45220 menu : new Roo.menu.ColorMenu({
45221 focus: Roo.emptyFn,
45224 allowReselect: true,
45225 selectHandler: function(cp, color){
45227 editorcore.execCmd('useCSS', false);
45228 editorcore.execCmd('hilitecolor', color);
45229 editorcore.execCmd('useCSS', true);
45230 editor.deferFocus();
45232 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45233 Roo.isSafari || Roo.isIE ? '#'+color : color);
45234 editor.deferFocus();
45238 clickEvent:'mousedown'
45243 // now add all the items...
45246 if(!this.disable.alignments){
45249 btn('justifyleft'),
45250 btn('justifycenter'),
45251 btn('justifyright')
45255 //if(!Roo.isSafari){
45256 if(!this.disable.links){
45259 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45263 if(!this.disable.lists){
45266 btn('insertorderedlist'),
45267 btn('insertunorderedlist')
45270 if(!this.disable.sourceEdit){
45273 btn('sourceedit', true, function(btn){
45274 this.toggleSourceEdit(btn.pressed);
45281 // special menu.. - needs to be tidied up..
45282 if (!this.disable.special) {
45285 cls: 'x-edit-none',
45291 for (var i =0; i < this.specialChars.length; i++) {
45292 smenu.menu.items.push({
45294 html: this.specialChars[i],
45295 handler: function(a,b) {
45296 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45297 //editor.insertAtCursor(a.html);
45311 if (!this.disable.cleanStyles) {
45313 cls: 'x-btn-icon x-btn-clear',
45319 for (var i =0; i < this.cleanStyles.length; i++) {
45320 cmenu.menu.items.push({
45321 actiontype : this.cleanStyles[i],
45322 html: 'Remove ' + this.cleanStyles[i],
45323 handler: function(a,b) {
45326 var c = Roo.get(editorcore.doc.body);
45327 c.select('[style]').each(function(s) {
45328 s.dom.style.removeProperty(a.actiontype);
45330 editorcore.syncValue();
45335 cmenu.menu.items.push({
45336 actiontype : 'tablewidths',
45337 html: 'Remove Table Widths',
45338 handler: function(a,b) {
45339 editorcore.cleanTableWidths();
45340 editorcore.syncValue();
45344 cmenu.menu.items.push({
45345 actiontype : 'word',
45346 html: 'Remove MS Word Formating',
45347 handler: function(a,b) {
45348 editorcore.cleanWord();
45349 editorcore.syncValue();
45354 cmenu.menu.items.push({
45355 actiontype : 'all',
45356 html: 'Remove All Styles',
45357 handler: function(a,b) {
45359 var c = Roo.get(editorcore.doc.body);
45360 c.select('[style]').each(function(s) {
45361 s.dom.removeAttribute('style');
45363 editorcore.syncValue();
45368 cmenu.menu.items.push({
45369 actiontype : 'all',
45370 html: 'Remove All CSS Classes',
45371 handler: function(a,b) {
45373 var c = Roo.get(editorcore.doc.body);
45374 c.select('[class]').each(function(s) {
45375 s.dom.className = '';
45377 editorcore.syncValue();
45382 cmenu.menu.items.push({
45383 actiontype : 'tidy',
45384 html: 'Tidy HTML Source',
45385 handler: function(a,b) {
45386 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45387 editorcore.syncValue();
45396 if (!this.disable.specialElements) {
45399 cls: 'x-edit-none',
45404 for (var i =0; i < this.specialElements.length; i++) {
45405 semenu.menu.items.push(
45407 handler: function(a,b) {
45408 editor.insertAtCursor(this.ihtml);
45410 }, this.specialElements[i])
45422 for(var i =0; i< this.btns.length;i++) {
45423 var b = Roo.factory(this.btns[i],Roo.form);
45424 b.cls = 'x-edit-none';
45426 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45427 b.cls += ' x-init-enable';
45430 b.scope = editorcore;
45438 // disable everything...
45440 this.tb.items.each(function(item){
45443 item.id != editorcore.frameId+ '-sourceedit' &&
45444 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45450 this.rendered = true;
45452 // the all the btns;
45453 editor.on('editorevent', this.updateToolbar, this);
45454 // other toolbars need to implement this..
45455 //editor.on('editmodechange', this.updateToolbar, this);
45459 relayBtnCmd : function(btn) {
45460 this.editorcore.relayCmd(btn.cmd);
45462 // private used internally
45463 createLink : function(){
45464 Roo.log("create link?");
45465 var url = prompt(this.createLinkText, this.defaultLinkValue);
45466 if(url && url != 'http:/'+'/'){
45467 this.editorcore.relayCmd('createlink', url);
45473 * Protected method that will not generally be called directly. It triggers
45474 * a toolbar update by reading the markup state of the current selection in the editor.
45476 updateToolbar: function(){
45478 if(!this.editorcore.activated){
45479 this.editor.onFirstFocus();
45483 var btns = this.tb.items.map,
45484 doc = this.editorcore.doc,
45485 frameId = this.editorcore.frameId;
45487 if(!this.disable.font && !Roo.isSafari){
45489 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45490 if(name != this.fontSelect.dom.value){
45491 this.fontSelect.dom.value = name;
45495 if(!this.disable.format){
45496 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45497 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45498 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45499 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45501 if(!this.disable.alignments){
45502 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45503 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45504 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45506 if(!Roo.isSafari && !this.disable.lists){
45507 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45508 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45511 var ans = this.editorcore.getAllAncestors();
45512 if (this.formatCombo) {
45515 var store = this.formatCombo.store;
45516 this.formatCombo.setValue("");
45517 for (var i =0; i < ans.length;i++) {
45518 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45520 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45528 // hides menus... - so this cant be on a menu...
45529 Roo.menu.MenuMgr.hideAll();
45531 //this.editorsyncValue();
45535 createFontOptions : function(){
45536 var buf = [], fs = this.fontFamilies, ff, lc;
45540 for(var i = 0, len = fs.length; i< len; i++){
45542 lc = ff.toLowerCase();
45544 '<option value="',lc,'" style="font-family:',ff,';"',
45545 (this.defaultFont == lc ? ' selected="true">' : '>'),
45550 return buf.join('');
45553 toggleSourceEdit : function(sourceEditMode){
45555 Roo.log("toolbar toogle");
45556 if(sourceEditMode === undefined){
45557 sourceEditMode = !this.sourceEditMode;
45559 this.sourceEditMode = sourceEditMode === true;
45560 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45561 // just toggle the button?
45562 if(btn.pressed !== this.sourceEditMode){
45563 btn.toggle(this.sourceEditMode);
45567 if(sourceEditMode){
45568 Roo.log("disabling buttons");
45569 this.tb.items.each(function(item){
45570 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45576 Roo.log("enabling buttons");
45577 if(this.editorcore.initialized){
45578 this.tb.items.each(function(item){
45584 Roo.log("calling toggole on editor");
45585 // tell the editor that it's been pressed..
45586 this.editor.toggleSourceEdit(sourceEditMode);
45590 * Object collection of toolbar tooltips for the buttons in the editor. The key
45591 * is the command id associated with that button and the value is a valid QuickTips object.
45596 title: 'Bold (Ctrl+B)',
45597 text: 'Make the selected text bold.',
45598 cls: 'x-html-editor-tip'
45601 title: 'Italic (Ctrl+I)',
45602 text: 'Make the selected text italic.',
45603 cls: 'x-html-editor-tip'
45611 title: 'Bold (Ctrl+B)',
45612 text: 'Make the selected text bold.',
45613 cls: 'x-html-editor-tip'
45616 title: 'Italic (Ctrl+I)',
45617 text: 'Make the selected text italic.',
45618 cls: 'x-html-editor-tip'
45621 title: 'Underline (Ctrl+U)',
45622 text: 'Underline the selected text.',
45623 cls: 'x-html-editor-tip'
45626 title: 'Strikethrough',
45627 text: 'Strikethrough the selected text.',
45628 cls: 'x-html-editor-tip'
45630 increasefontsize : {
45631 title: 'Grow Text',
45632 text: 'Increase the font size.',
45633 cls: 'x-html-editor-tip'
45635 decreasefontsize : {
45636 title: 'Shrink Text',
45637 text: 'Decrease the font size.',
45638 cls: 'x-html-editor-tip'
45641 title: 'Text Highlight Color',
45642 text: 'Change the background color of the selected text.',
45643 cls: 'x-html-editor-tip'
45646 title: 'Font Color',
45647 text: 'Change the color of the selected text.',
45648 cls: 'x-html-editor-tip'
45651 title: 'Align Text Left',
45652 text: 'Align text to the left.',
45653 cls: 'x-html-editor-tip'
45656 title: 'Center Text',
45657 text: 'Center text in the editor.',
45658 cls: 'x-html-editor-tip'
45661 title: 'Align Text Right',
45662 text: 'Align text to the right.',
45663 cls: 'x-html-editor-tip'
45665 insertunorderedlist : {
45666 title: 'Bullet List',
45667 text: 'Start a bulleted list.',
45668 cls: 'x-html-editor-tip'
45670 insertorderedlist : {
45671 title: 'Numbered List',
45672 text: 'Start a numbered list.',
45673 cls: 'x-html-editor-tip'
45676 title: 'Hyperlink',
45677 text: 'Make the selected text a hyperlink.',
45678 cls: 'x-html-editor-tip'
45681 title: 'Source Edit',
45682 text: 'Switch to source editing mode.',
45683 cls: 'x-html-editor-tip'
45687 onDestroy : function(){
45690 this.tb.items.each(function(item){
45692 item.menu.removeAll();
45694 item.menu.el.destroy();
45702 onFirstFocus: function() {
45703 this.tb.items.each(function(item){
45712 // <script type="text/javascript">
45715 * Ext JS Library 1.1.1
45716 * Copyright(c) 2006-2007, Ext JS, LLC.
45723 * @class Roo.form.HtmlEditor.ToolbarContext
45728 new Roo.form.HtmlEditor({
45731 { xtype: 'ToolbarStandard', styles : {} }
45732 { xtype: 'ToolbarContext', disable : {} }
45738 * @config : {Object} disable List of elements to disable.. (not done yet.)
45739 * @config : {Object} styles Map of styles available.
45743 Roo.form.HtmlEditor.ToolbarContext = function(config)
45746 Roo.apply(this, config);
45747 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45748 // dont call parent... till later.
45749 this.styles = this.styles || {};
45754 Roo.form.HtmlEditor.ToolbarContext.types = {
45766 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45832 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45837 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45847 style : 'fontFamily',
45848 displayField: 'display',
45849 optname : 'font-family',
45898 // should we really allow this??
45899 // should this just be
45910 style : 'fontFamily',
45911 displayField: 'display',
45912 optname : 'font-family',
45919 style : 'fontFamily',
45920 displayField: 'display',
45921 optname : 'font-family',
45928 style : 'fontFamily',
45929 displayField: 'display',
45930 optname : 'font-family',
45941 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
45942 Roo.form.HtmlEditor.ToolbarContext.stores = false;
45944 Roo.form.HtmlEditor.ToolbarContext.options = {
45946 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
45947 [ 'Courier New', 'Courier New'],
45948 [ 'Tahoma', 'Tahoma'],
45949 [ 'Times New Roman,serif', 'Times'],
45950 [ 'Verdana','Verdana' ]
45954 // fixme - these need to be configurable..
45957 //Roo.form.HtmlEditor.ToolbarContext.types
45960 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
45967 editorcore : false,
45969 * @cfg {Object} disable List of toolbar elements to disable
45974 * @cfg {Object} styles List of styles
45975 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
45977 * These must be defined in the page, so they get rendered correctly..
45988 init : function(editor)
45990 this.editor = editor;
45991 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45992 var editorcore = this.editorcore;
45994 var fid = editorcore.frameId;
45996 function btn(id, toggle, handler){
45997 var xid = fid + '-'+ id ;
46001 cls : 'x-btn-icon x-edit-'+id,
46002 enableToggle:toggle !== false,
46003 scope: editorcore, // was editor...
46004 handler:handler||editorcore.relayBtnCmd,
46005 clickEvent:'mousedown',
46006 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46010 // create a new element.
46011 var wdiv = editor.wrap.createChild({
46013 }, editor.wrap.dom.firstChild.nextSibling, true);
46015 // can we do this more than once??
46017 // stop form submits
46020 // disable everything...
46021 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46022 this.toolbars = {};
46024 for (var i in ty) {
46026 this.toolbars[i] = this.buildToolbar(ty[i],i);
46028 this.tb = this.toolbars.BODY;
46030 this.buildFooter();
46031 this.footer.show();
46032 editor.on('hide', function( ) { this.footer.hide() }, this);
46033 editor.on('show', function( ) { this.footer.show() }, this);
46036 this.rendered = true;
46038 // the all the btns;
46039 editor.on('editorevent', this.updateToolbar, this);
46040 // other toolbars need to implement this..
46041 //editor.on('editmodechange', this.updateToolbar, this);
46047 * Protected method that will not generally be called directly. It triggers
46048 * a toolbar update by reading the markup state of the current selection in the editor.
46050 * Note you can force an update by calling on('editorevent', scope, false)
46052 updateToolbar: function(editor,ev,sel){
46055 // capture mouse up - this is handy for selecting images..
46056 // perhaps should go somewhere else...
46057 if(!this.editorcore.activated){
46058 this.editor.onFirstFocus();
46064 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46065 // selectNode - might want to handle IE?
46067 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46068 ev.target && ev.target.tagName == 'IMG') {
46069 // they have click on an image...
46070 // let's see if we can change the selection...
46073 var nodeRange = sel.ownerDocument.createRange();
46075 nodeRange.selectNode(sel);
46077 nodeRange.selectNodeContents(sel);
46079 //nodeRange.collapse(true);
46080 var s = this.editorcore.win.getSelection();
46081 s.removeAllRanges();
46082 s.addRange(nodeRange);
46086 var updateFooter = sel ? false : true;
46089 var ans = this.editorcore.getAllAncestors();
46092 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46095 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46096 sel = sel ? sel : this.editorcore.doc.body;
46097 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46100 // pick a menu that exists..
46101 var tn = sel.tagName.toUpperCase();
46102 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46104 tn = sel.tagName.toUpperCase();
46106 var lastSel = this.tb.selectedNode;
46108 this.tb.selectedNode = sel;
46110 // if current menu does not match..
46112 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46115 ///console.log("show: " + tn);
46116 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46119 this.tb.items.first().el.innerHTML = tn + ': ';
46122 // update attributes
46123 if (this.tb.fields) {
46124 this.tb.fields.each(function(e) {
46126 e.setValue(sel.style[e.stylename]);
46129 e.setValue(sel.getAttribute(e.attrname));
46133 var hasStyles = false;
46134 for(var i in this.styles) {
46141 var st = this.tb.fields.item(0);
46143 st.store.removeAll();
46146 var cn = sel.className.split(/\s+/);
46149 if (this.styles['*']) {
46151 Roo.each(this.styles['*'], function(v) {
46152 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46155 if (this.styles[tn]) {
46156 Roo.each(this.styles[tn], function(v) {
46157 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46161 st.store.loadData(avs);
46165 // flag our selected Node.
46166 this.tb.selectedNode = sel;
46169 Roo.menu.MenuMgr.hideAll();
46173 if (!updateFooter) {
46174 //this.footDisp.dom.innerHTML = '';
46177 // update the footer
46181 this.footerEls = ans.reverse();
46182 Roo.each(this.footerEls, function(a,i) {
46183 if (!a) { return; }
46184 html += html.length ? ' > ' : '';
46186 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46191 var sz = this.footDisp.up('td').getSize();
46192 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46193 this.footDisp.dom.style.marginLeft = '5px';
46195 this.footDisp.dom.style.overflow = 'hidden';
46197 this.footDisp.dom.innerHTML = html;
46199 //this.editorsyncValue();
46206 onDestroy : function(){
46209 this.tb.items.each(function(item){
46211 item.menu.removeAll();
46213 item.menu.el.destroy();
46221 onFirstFocus: function() {
46222 // need to do this for all the toolbars..
46223 this.tb.items.each(function(item){
46227 buildToolbar: function(tlist, nm)
46229 var editor = this.editor;
46230 var editorcore = this.editorcore;
46231 // create a new element.
46232 var wdiv = editor.wrap.createChild({
46234 }, editor.wrap.dom.firstChild.nextSibling, true);
46237 var tb = new Roo.Toolbar(wdiv);
46240 tb.add(nm+ ": ");
46243 for(var i in this.styles) {
46248 if (styles && styles.length) {
46250 // this needs a multi-select checkbox...
46251 tb.addField( new Roo.form.ComboBox({
46252 store: new Roo.data.SimpleStore({
46254 fields: ['val', 'selected'],
46257 name : '-roo-edit-className',
46258 attrname : 'className',
46259 displayField: 'val',
46263 triggerAction: 'all',
46264 emptyText:'Select Style',
46265 selectOnFocus:true,
46268 'select': function(c, r, i) {
46269 // initial support only for on class per el..
46270 tb.selectedNode.className = r ? r.get('val') : '';
46271 editorcore.syncValue();
46278 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46279 var tbops = tbc.options;
46281 for (var i in tlist) {
46283 var item = tlist[i];
46284 tb.add(item.title + ": ");
46287 //optname == used so you can configure the options available..
46288 var opts = item.opts ? item.opts : false;
46289 if (item.optname) {
46290 opts = tbops[item.optname];
46295 // opts == pulldown..
46296 tb.addField( new Roo.form.ComboBox({
46297 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46299 fields: ['val', 'display'],
46302 name : '-roo-edit-' + i,
46304 stylename : item.style ? item.style : false,
46305 displayField: item.displayField ? item.displayField : 'val',
46306 valueField : 'val',
46308 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46310 triggerAction: 'all',
46311 emptyText:'Select',
46312 selectOnFocus:true,
46313 width: item.width ? item.width : 130,
46315 'select': function(c, r, i) {
46317 tb.selectedNode.style[c.stylename] = r.get('val');
46320 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46329 tb.addField( new Roo.form.TextField({
46332 //allowBlank:false,
46337 tb.addField( new Roo.form.TextField({
46338 name: '-roo-edit-' + i,
46345 'change' : function(f, nv, ov) {
46346 tb.selectedNode.setAttribute(f.attrname, nv);
46347 editorcore.syncValue();
46360 text: 'Stylesheets',
46363 click : function ()
46365 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46373 text: 'Remove Tag',
46376 click : function ()
46379 // undo does not work.
46381 var sn = tb.selectedNode;
46383 var pn = sn.parentNode;
46385 var stn = sn.childNodes[0];
46386 var en = sn.childNodes[sn.childNodes.length - 1 ];
46387 while (sn.childNodes.length) {
46388 var node = sn.childNodes[0];
46389 sn.removeChild(node);
46391 pn.insertBefore(node, sn);
46394 pn.removeChild(sn);
46395 var range = editorcore.createRange();
46397 range.setStart(stn,0);
46398 range.setEnd(en,0); //????
46399 //range.selectNode(sel);
46402 var selection = editorcore.getSelection();
46403 selection.removeAllRanges();
46404 selection.addRange(range);
46408 //_this.updateToolbar(null, null, pn);
46409 _this.updateToolbar(null, null, null);
46410 _this.footDisp.dom.innerHTML = '';
46420 tb.el.on('click', function(e){
46421 e.preventDefault(); // what does this do?
46423 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46426 // dont need to disable them... as they will get hidden
46431 buildFooter : function()
46434 var fel = this.editor.wrap.createChild();
46435 this.footer = new Roo.Toolbar(fel);
46436 // toolbar has scrolly on left / right?
46437 var footDisp= new Roo.Toolbar.Fill();
46443 handler : function() {
46444 _t.footDisp.scrollTo('left',0,true)
46448 this.footer.add( footDisp );
46453 handler : function() {
46455 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46459 var fel = Roo.get(footDisp.el);
46460 fel.addClass('x-editor-context');
46461 this.footDispWrap = fel;
46462 this.footDispWrap.overflow = 'hidden';
46464 this.footDisp = fel.createChild();
46465 this.footDispWrap.on('click', this.onContextClick, this)
46469 onContextClick : function (ev,dom)
46471 ev.preventDefault();
46472 var cn = dom.className;
46474 if (!cn.match(/x-ed-loc-/)) {
46477 var n = cn.split('-').pop();
46478 var ans = this.footerEls;
46482 var range = this.editorcore.createRange();
46484 range.selectNodeContents(sel);
46485 //range.selectNode(sel);
46488 var selection = this.editorcore.getSelection();
46489 selection.removeAllRanges();
46490 selection.addRange(range);
46494 this.updateToolbar(null, null, sel);
46511 * Ext JS Library 1.1.1
46512 * Copyright(c) 2006-2007, Ext JS, LLC.
46514 * Originally Released Under LGPL - original licence link has changed is not relivant.
46517 * <script type="text/javascript">
46521 * @class Roo.form.BasicForm
46522 * @extends Roo.util.Observable
46523 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46525 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46526 * @param {Object} config Configuration options
46528 Roo.form.BasicForm = function(el, config){
46529 this.allItems = [];
46530 this.childForms = [];
46531 Roo.apply(this, config);
46533 * The Roo.form.Field items in this form.
46534 * @type MixedCollection
46538 this.items = new Roo.util.MixedCollection(false, function(o){
46539 return o.id || (o.id = Roo.id());
46543 * @event beforeaction
46544 * Fires before any action is performed. Return false to cancel the action.
46545 * @param {Form} this
46546 * @param {Action} action The action to be performed
46548 beforeaction: true,
46550 * @event actionfailed
46551 * Fires when an action fails.
46552 * @param {Form} this
46553 * @param {Action} action The action that failed
46555 actionfailed : true,
46557 * @event actioncomplete
46558 * Fires when an action is completed.
46559 * @param {Form} this
46560 * @param {Action} action The action that completed
46562 actioncomplete : true
46567 Roo.form.BasicForm.superclass.constructor.call(this);
46570 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46572 * @cfg {String} method
46573 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46576 * @cfg {DataReader} reader
46577 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46578 * This is optional as there is built-in support for processing JSON.
46581 * @cfg {DataReader} errorReader
46582 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46583 * This is completely optional as there is built-in support for processing JSON.
46586 * @cfg {String} url
46587 * The URL to use for form actions if one isn't supplied in the action options.
46590 * @cfg {Boolean} fileUpload
46591 * Set to true if this form is a file upload.
46595 * @cfg {Object} baseParams
46596 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46601 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46606 activeAction : null,
46609 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46610 * or setValues() data instead of when the form was first created.
46612 trackResetOnLoad : false,
46616 * childForms - used for multi-tab forms
46619 childForms : false,
46622 * allItems - full list of fields.
46628 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46629 * element by passing it or its id or mask the form itself by passing in true.
46632 waitMsgTarget : false,
46635 initEl : function(el){
46636 this.el = Roo.get(el);
46637 this.id = this.el.id || Roo.id();
46638 this.el.on('submit', this.onSubmit, this);
46639 this.el.addClass('x-form');
46643 onSubmit : function(e){
46648 * Returns true if client-side validation on the form is successful.
46651 isValid : function(){
46653 this.items.each(function(f){
46662 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46665 isDirty : function(){
46667 this.items.each(function(f){
46677 * Returns true if any fields in this form have changed since their original load. (New version)
46681 hasChanged : function()
46684 this.items.each(function(f){
46685 if(f.hasChanged()){
46694 * Resets all hasChanged to 'false' -
46695 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46696 * So hasChanged storage is only to be used for this purpose
46699 resetHasChanged : function()
46701 this.items.each(function(f){
46702 f.resetHasChanged();
46709 * Performs a predefined action (submit or load) or custom actions you define on this form.
46710 * @param {String} actionName The name of the action type
46711 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46712 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46713 * accept other config options):
46715 Property Type Description
46716 ---------------- --------------- ----------------------------------------------------------------------------------
46717 url String The url for the action (defaults to the form's url)
46718 method String The form method to use (defaults to the form's method, or POST if not defined)
46719 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46720 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46721 validate the form on the client (defaults to false)
46723 * @return {BasicForm} this
46725 doAction : function(action, options){
46726 if(typeof action == 'string'){
46727 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46729 if(this.fireEvent('beforeaction', this, action) !== false){
46730 this.beforeAction(action);
46731 action.run.defer(100, action);
46737 * Shortcut to do a submit action.
46738 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46739 * @return {BasicForm} this
46741 submit : function(options){
46742 this.doAction('submit', options);
46747 * Shortcut to do a load action.
46748 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46749 * @return {BasicForm} this
46751 load : function(options){
46752 this.doAction('load', options);
46757 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46758 * @param {Record} record The record to edit
46759 * @return {BasicForm} this
46761 updateRecord : function(record){
46762 record.beginEdit();
46763 var fs = record.fields;
46764 fs.each(function(f){
46765 var field = this.findField(f.name);
46767 record.set(f.name, field.getValue());
46775 * Loads an Roo.data.Record into this form.
46776 * @param {Record} record The record to load
46777 * @return {BasicForm} this
46779 loadRecord : function(record){
46780 this.setValues(record.data);
46785 beforeAction : function(action){
46786 var o = action.options;
46789 if(this.waitMsgTarget === true){
46790 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46791 }else if(this.waitMsgTarget){
46792 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46793 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46795 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46801 afterAction : function(action, success){
46802 this.activeAction = null;
46803 var o = action.options;
46805 if(this.waitMsgTarget === true){
46807 }else if(this.waitMsgTarget){
46808 this.waitMsgTarget.unmask();
46810 Roo.MessageBox.updateProgress(1);
46811 Roo.MessageBox.hide();
46818 Roo.callback(o.success, o.scope, [this, action]);
46819 this.fireEvent('actioncomplete', this, action);
46823 // failure condition..
46824 // we have a scenario where updates need confirming.
46825 // eg. if a locking scenario exists..
46826 // we look for { errors : { needs_confirm : true }} in the response.
46828 (typeof(action.result) != 'undefined') &&
46829 (typeof(action.result.errors) != 'undefined') &&
46830 (typeof(action.result.errors.needs_confirm) != 'undefined')
46833 Roo.MessageBox.confirm(
46834 "Change requires confirmation",
46835 action.result.errorMsg,
46840 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46850 Roo.callback(o.failure, o.scope, [this, action]);
46851 // show an error message if no failed handler is set..
46852 if (!this.hasListener('actionfailed')) {
46853 Roo.MessageBox.alert("Error",
46854 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46855 action.result.errorMsg :
46856 "Saving Failed, please check your entries or try again"
46860 this.fireEvent('actionfailed', this, action);
46866 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46867 * @param {String} id The value to search for
46870 findField : function(id){
46871 var field = this.items.get(id);
46873 this.items.each(function(f){
46874 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
46880 return field || null;
46884 * Add a secondary form to this one,
46885 * Used to provide tabbed forms. One form is primary, with hidden values
46886 * which mirror the elements from the other forms.
46888 * @param {Roo.form.Form} form to add.
46891 addForm : function(form)
46894 if (this.childForms.indexOf(form) > -1) {
46898 this.childForms.push(form);
46900 Roo.each(form.allItems, function (fe) {
46902 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
46903 if (this.findField(n)) { // already added..
46906 var add = new Roo.form.Hidden({
46909 add.render(this.el);
46916 * Mark fields in this form invalid in bulk.
46917 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
46918 * @return {BasicForm} this
46920 markInvalid : function(errors){
46921 if(errors instanceof Array){
46922 for(var i = 0, len = errors.length; i < len; i++){
46923 var fieldError = errors[i];
46924 var f = this.findField(fieldError.id);
46926 f.markInvalid(fieldError.msg);
46932 if(typeof errors[id] != 'function' && (field = this.findField(id))){
46933 field.markInvalid(errors[id]);
46937 Roo.each(this.childForms || [], function (f) {
46938 f.markInvalid(errors);
46945 * Set values for fields in this form in bulk.
46946 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
46947 * @return {BasicForm} this
46949 setValues : function(values){
46950 if(values instanceof Array){ // array of objects
46951 for(var i = 0, len = values.length; i < len; i++){
46953 var f = this.findField(v.id);
46955 f.setValue(v.value);
46956 if(this.trackResetOnLoad){
46957 f.originalValue = f.getValue();
46961 }else{ // object hash
46964 if(typeof values[id] != 'function' && (field = this.findField(id))){
46966 if (field.setFromData &&
46967 field.valueField &&
46968 field.displayField &&
46969 // combos' with local stores can
46970 // be queried via setValue()
46971 // to set their value..
46972 (field.store && !field.store.isLocal)
46976 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
46977 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
46978 field.setFromData(sd);
46981 field.setValue(values[id]);
46985 if(this.trackResetOnLoad){
46986 field.originalValue = field.getValue();
46991 this.resetHasChanged();
46994 Roo.each(this.childForms || [], function (f) {
46995 f.setValues(values);
46996 f.resetHasChanged();
47003 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47004 * they are returned as an array.
47005 * @param {Boolean} asString
47008 getValues : function(asString){
47009 if (this.childForms) {
47010 // copy values from the child forms
47011 Roo.each(this.childForms, function (f) {
47012 this.setValues(f.getValues());
47018 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47019 if(asString === true){
47022 return Roo.urlDecode(fs);
47026 * Returns the fields in this form as an object with key/value pairs.
47027 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47030 getFieldValues : function(with_hidden)
47032 if (this.childForms) {
47033 // copy values from the child forms
47034 // should this call getFieldValues - probably not as we do not currently copy
47035 // hidden fields when we generate..
47036 Roo.each(this.childForms, function (f) {
47037 this.setValues(f.getValues());
47042 this.items.each(function(f){
47043 if (!f.getName()) {
47046 var v = f.getValue();
47047 if (f.inputType =='radio') {
47048 if (typeof(ret[f.getName()]) == 'undefined') {
47049 ret[f.getName()] = ''; // empty..
47052 if (!f.el.dom.checked) {
47056 v = f.el.dom.value;
47060 // not sure if this supported any more..
47061 if ((typeof(v) == 'object') && f.getRawValue) {
47062 v = f.getRawValue() ; // dates..
47064 // combo boxes where name != hiddenName...
47065 if (f.name != f.getName()) {
47066 ret[f.name] = f.getRawValue();
47068 ret[f.getName()] = v;
47075 * Clears all invalid messages in this form.
47076 * @return {BasicForm} this
47078 clearInvalid : function(){
47079 this.items.each(function(f){
47083 Roo.each(this.childForms || [], function (f) {
47092 * Resets this form.
47093 * @return {BasicForm} this
47095 reset : function(){
47096 this.items.each(function(f){
47100 Roo.each(this.childForms || [], function (f) {
47103 this.resetHasChanged();
47109 * Add Roo.form components to this form.
47110 * @param {Field} field1
47111 * @param {Field} field2 (optional)
47112 * @param {Field} etc (optional)
47113 * @return {BasicForm} this
47116 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47122 * Removes a field from the items collection (does NOT remove its markup).
47123 * @param {Field} field
47124 * @return {BasicForm} this
47126 remove : function(field){
47127 this.items.remove(field);
47132 * Looks at the fields in this form, checks them for an id attribute,
47133 * and calls applyTo on the existing dom element with that id.
47134 * @return {BasicForm} this
47136 render : function(){
47137 this.items.each(function(f){
47138 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47146 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47147 * @param {Object} values
47148 * @return {BasicForm} this
47150 applyToFields : function(o){
47151 this.items.each(function(f){
47158 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47159 * @param {Object} values
47160 * @return {BasicForm} this
47162 applyIfToFields : function(o){
47163 this.items.each(function(f){
47171 Roo.BasicForm = Roo.form.BasicForm;/*
47173 * Ext JS Library 1.1.1
47174 * Copyright(c) 2006-2007, Ext JS, LLC.
47176 * Originally Released Under LGPL - original licence link has changed is not relivant.
47179 * <script type="text/javascript">
47183 * @class Roo.form.Form
47184 * @extends Roo.form.BasicForm
47185 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47187 * @param {Object} config Configuration options
47189 Roo.form.Form = function(config){
47191 if (config.items) {
47192 xitems = config.items;
47193 delete config.items;
47197 Roo.form.Form.superclass.constructor.call(this, null, config);
47198 this.url = this.url || this.action;
47200 this.root = new Roo.form.Layout(Roo.applyIf({
47204 this.active = this.root;
47206 * Array of all the buttons that have been added to this form via {@link addButton}
47210 this.allItems = [];
47213 * @event clientvalidation
47214 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47215 * @param {Form} this
47216 * @param {Boolean} valid true if the form has passed client-side validation
47218 clientvalidation: true,
47221 * Fires when the form is rendered
47222 * @param {Roo.form.Form} form
47227 if (this.progressUrl) {
47228 // push a hidden field onto the list of fields..
47232 name : 'UPLOAD_IDENTIFIER'
47237 Roo.each(xitems, this.addxtype, this);
47243 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47245 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47248 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47251 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47253 buttonAlign:'center',
47256 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47261 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47262 * This property cascades to child containers if not set.
47267 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47268 * fires a looping event with that state. This is required to bind buttons to the valid
47269 * state using the config value formBind:true on the button.
47271 monitorValid : false,
47274 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47279 * @cfg {String} progressUrl - Url to return progress data
47282 progressUrl : false,
47285 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47286 * fields are added and the column is closed. If no fields are passed the column remains open
47287 * until end() is called.
47288 * @param {Object} config The config to pass to the column
47289 * @param {Field} field1 (optional)
47290 * @param {Field} field2 (optional)
47291 * @param {Field} etc (optional)
47292 * @return Column The column container object
47294 column : function(c){
47295 var col = new Roo.form.Column(c);
47297 if(arguments.length > 1){ // duplicate code required because of Opera
47298 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47305 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47306 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47307 * until end() is called.
47308 * @param {Object} config The config to pass to the fieldset
47309 * @param {Field} field1 (optional)
47310 * @param {Field} field2 (optional)
47311 * @param {Field} etc (optional)
47312 * @return FieldSet The fieldset container object
47314 fieldset : function(c){
47315 var fs = new Roo.form.FieldSet(c);
47317 if(arguments.length > 1){ // duplicate code required because of Opera
47318 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47325 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47326 * fields are added and the container is closed. If no fields are passed the container remains open
47327 * until end() is called.
47328 * @param {Object} config The config to pass to the Layout
47329 * @param {Field} field1 (optional)
47330 * @param {Field} field2 (optional)
47331 * @param {Field} etc (optional)
47332 * @return Layout The container object
47334 container : function(c){
47335 var l = new Roo.form.Layout(c);
47337 if(arguments.length > 1){ // duplicate code required because of Opera
47338 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47345 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47346 * @param {Object} container A Roo.form.Layout or subclass of Layout
47347 * @return {Form} this
47349 start : function(c){
47350 // cascade label info
47351 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47352 this.active.stack.push(c);
47353 c.ownerCt = this.active;
47359 * Closes the current open container
47360 * @return {Form} this
47363 if(this.active == this.root){
47366 this.active = this.active.ownerCt;
47371 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47372 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47373 * as the label of the field.
47374 * @param {Field} field1
47375 * @param {Field} field2 (optional)
47376 * @param {Field} etc. (optional)
47377 * @return {Form} this
47380 this.active.stack.push.apply(this.active.stack, arguments);
47381 this.allItems.push.apply(this.allItems,arguments);
47383 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47384 if(a[i].isFormField){
47389 Roo.form.Form.superclass.add.apply(this, r);
47399 * Find any element that has been added to a form, using it's ID or name
47400 * This can include framesets, columns etc. along with regular fields..
47401 * @param {String} id - id or name to find.
47403 * @return {Element} e - or false if nothing found.
47405 findbyId : function(id)
47411 Roo.each(this.allItems, function(f){
47412 if (f.id == id || f.name == id ){
47423 * Render this form into the passed container. This should only be called once!
47424 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47425 * @return {Form} this
47427 render : function(ct)
47433 var o = this.autoCreate || {
47435 method : this.method || 'POST',
47436 id : this.id || Roo.id()
47438 this.initEl(ct.createChild(o));
47440 this.root.render(this.el);
47444 this.items.each(function(f){
47445 f.render('x-form-el-'+f.id);
47448 if(this.buttons.length > 0){
47449 // tables are required to maintain order and for correct IE layout
47450 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47451 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47452 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47454 var tr = tb.getElementsByTagName('tr')[0];
47455 for(var i = 0, len = this.buttons.length; i < len; i++) {
47456 var b = this.buttons[i];
47457 var td = document.createElement('td');
47458 td.className = 'x-form-btn-td';
47459 b.render(tr.appendChild(td));
47462 if(this.monitorValid){ // initialize after render
47463 this.startMonitoring();
47465 this.fireEvent('rendered', this);
47470 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47471 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47472 * object or a valid Roo.DomHelper element config
47473 * @param {Function} handler The function called when the button is clicked
47474 * @param {Object} scope (optional) The scope of the handler function
47475 * @return {Roo.Button}
47477 addButton : function(config, handler, scope){
47481 minWidth: this.minButtonWidth,
47484 if(typeof config == "string"){
47487 Roo.apply(bc, config);
47489 var btn = new Roo.Button(null, bc);
47490 this.buttons.push(btn);
47495 * Adds a series of form elements (using the xtype property as the factory method.
47496 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47497 * @param {Object} config
47500 addxtype : function()
47502 var ar = Array.prototype.slice.call(arguments, 0);
47504 for(var i = 0; i < ar.length; i++) {
47506 continue; // skip -- if this happends something invalid got sent, we
47507 // should ignore it, as basically that interface element will not show up
47508 // and that should be pretty obvious!!
47511 if (Roo.form[ar[i].xtype]) {
47513 var fe = Roo.factory(ar[i], Roo.form);
47519 fe.store.form = this;
47524 this.allItems.push(fe);
47525 if (fe.items && fe.addxtype) {
47526 fe.addxtype.apply(fe, fe.items);
47536 // console.log('adding ' + ar[i].xtype);
47538 if (ar[i].xtype == 'Button') {
47539 //console.log('adding button');
47540 //console.log(ar[i]);
47541 this.addButton(ar[i]);
47542 this.allItems.push(fe);
47546 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47547 alert('end is not supported on xtype any more, use items');
47549 // //console.log('adding end');
47557 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47558 * option "monitorValid"
47560 startMonitoring : function(){
47563 Roo.TaskMgr.start({
47564 run : this.bindHandler,
47565 interval : this.monitorPoll || 200,
47572 * Stops monitoring of the valid state of this form
47574 stopMonitoring : function(){
47575 this.bound = false;
47579 bindHandler : function(){
47581 return false; // stops binding
47584 this.items.each(function(f){
47585 if(!f.isValid(true)){
47590 for(var i = 0, len = this.buttons.length; i < len; i++){
47591 var btn = this.buttons[i];
47592 if(btn.formBind === true && btn.disabled === valid){
47593 btn.setDisabled(!valid);
47596 this.fireEvent('clientvalidation', this, valid);
47610 Roo.Form = Roo.form.Form;
47613 * Ext JS Library 1.1.1
47614 * Copyright(c) 2006-2007, Ext JS, LLC.
47616 * Originally Released Under LGPL - original licence link has changed is not relivant.
47619 * <script type="text/javascript">
47622 // as we use this in bootstrap.
47623 Roo.namespace('Roo.form');
47625 * @class Roo.form.Action
47626 * Internal Class used to handle form actions
47628 * @param {Roo.form.BasicForm} el The form element or its id
47629 * @param {Object} config Configuration options
47634 // define the action interface
47635 Roo.form.Action = function(form, options){
47637 this.options = options || {};
47640 * Client Validation Failed
47643 Roo.form.Action.CLIENT_INVALID = 'client';
47645 * Server Validation Failed
47648 Roo.form.Action.SERVER_INVALID = 'server';
47650 * Connect to Server Failed
47653 Roo.form.Action.CONNECT_FAILURE = 'connect';
47655 * Reading Data from Server Failed
47658 Roo.form.Action.LOAD_FAILURE = 'load';
47660 Roo.form.Action.prototype = {
47662 failureType : undefined,
47663 response : undefined,
47664 result : undefined,
47666 // interface method
47667 run : function(options){
47671 // interface method
47672 success : function(response){
47676 // interface method
47677 handleResponse : function(response){
47681 // default connection failure
47682 failure : function(response){
47684 this.response = response;
47685 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47686 this.form.afterAction(this, false);
47689 processResponse : function(response){
47690 this.response = response;
47691 if(!response.responseText){
47694 this.result = this.handleResponse(response);
47695 return this.result;
47698 // utility functions used internally
47699 getUrl : function(appendParams){
47700 var url = this.options.url || this.form.url || this.form.el.dom.action;
47702 var p = this.getParams();
47704 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47710 getMethod : function(){
47711 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47714 getParams : function(){
47715 var bp = this.form.baseParams;
47716 var p = this.options.params;
47718 if(typeof p == "object"){
47719 p = Roo.urlEncode(Roo.applyIf(p, bp));
47720 }else if(typeof p == 'string' && bp){
47721 p += '&' + Roo.urlEncode(bp);
47724 p = Roo.urlEncode(bp);
47729 createCallback : function(){
47731 success: this.success,
47732 failure: this.failure,
47734 timeout: (this.form.timeout*1000),
47735 upload: this.form.fileUpload ? this.success : undefined
47740 Roo.form.Action.Submit = function(form, options){
47741 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47744 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47747 haveProgress : false,
47748 uploadComplete : false,
47750 // uploadProgress indicator.
47751 uploadProgress : function()
47753 if (!this.form.progressUrl) {
47757 if (!this.haveProgress) {
47758 Roo.MessageBox.progress("Uploading", "Uploading");
47760 if (this.uploadComplete) {
47761 Roo.MessageBox.hide();
47765 this.haveProgress = true;
47767 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47769 var c = new Roo.data.Connection();
47771 url : this.form.progressUrl,
47776 success : function(req){
47777 //console.log(data);
47781 rdata = Roo.decode(req.responseText)
47783 Roo.log("Invalid data from server..");
47787 if (!rdata || !rdata.success) {
47789 Roo.MessageBox.alert(Roo.encode(rdata));
47792 var data = rdata.data;
47794 if (this.uploadComplete) {
47795 Roo.MessageBox.hide();
47800 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47801 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47804 this.uploadProgress.defer(2000,this);
47807 failure: function(data) {
47808 Roo.log('progress url failed ');
47819 // run get Values on the form, so it syncs any secondary forms.
47820 this.form.getValues();
47822 var o = this.options;
47823 var method = this.getMethod();
47824 var isPost = method == 'POST';
47825 if(o.clientValidation === false || this.form.isValid()){
47827 if (this.form.progressUrl) {
47828 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47829 (new Date() * 1) + '' + Math.random());
47834 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47835 form:this.form.el.dom,
47836 url:this.getUrl(!isPost),
47838 params:isPost ? this.getParams() : null,
47839 isUpload: this.form.fileUpload
47842 this.uploadProgress();
47844 }else if (o.clientValidation !== false){ // client validation failed
47845 this.failureType = Roo.form.Action.CLIENT_INVALID;
47846 this.form.afterAction(this, false);
47850 success : function(response)
47852 this.uploadComplete= true;
47853 if (this.haveProgress) {
47854 Roo.MessageBox.hide();
47858 var result = this.processResponse(response);
47859 if(result === true || result.success){
47860 this.form.afterAction(this, true);
47864 this.form.markInvalid(result.errors);
47865 this.failureType = Roo.form.Action.SERVER_INVALID;
47867 this.form.afterAction(this, false);
47869 failure : function(response)
47871 this.uploadComplete= true;
47872 if (this.haveProgress) {
47873 Roo.MessageBox.hide();
47876 this.response = response;
47877 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47878 this.form.afterAction(this, false);
47881 handleResponse : function(response){
47882 if(this.form.errorReader){
47883 var rs = this.form.errorReader.read(response);
47886 for(var i = 0, len = rs.records.length; i < len; i++) {
47887 var r = rs.records[i];
47888 errors[i] = r.data;
47891 if(errors.length < 1){
47895 success : rs.success,
47901 ret = Roo.decode(response.responseText);
47905 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
47915 Roo.form.Action.Load = function(form, options){
47916 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
47917 this.reader = this.form.reader;
47920 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
47925 Roo.Ajax.request(Roo.apply(
47926 this.createCallback(), {
47927 method:this.getMethod(),
47928 url:this.getUrl(false),
47929 params:this.getParams()
47933 success : function(response){
47935 var result = this.processResponse(response);
47936 if(result === true || !result.success || !result.data){
47937 this.failureType = Roo.form.Action.LOAD_FAILURE;
47938 this.form.afterAction(this, false);
47941 this.form.clearInvalid();
47942 this.form.setValues(result.data);
47943 this.form.afterAction(this, true);
47946 handleResponse : function(response){
47947 if(this.form.reader){
47948 var rs = this.form.reader.read(response);
47949 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
47951 success : rs.success,
47955 return Roo.decode(response.responseText);
47959 Roo.form.Action.ACTION_TYPES = {
47960 'load' : Roo.form.Action.Load,
47961 'submit' : Roo.form.Action.Submit
47964 * Ext JS Library 1.1.1
47965 * Copyright(c) 2006-2007, Ext JS, LLC.
47967 * Originally Released Under LGPL - original licence link has changed is not relivant.
47970 * <script type="text/javascript">
47974 * @class Roo.form.Layout
47975 * @extends Roo.Component
47976 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
47978 * @param {Object} config Configuration options
47980 Roo.form.Layout = function(config){
47982 if (config.items) {
47983 xitems = config.items;
47984 delete config.items;
47986 Roo.form.Layout.superclass.constructor.call(this, config);
47988 Roo.each(xitems, this.addxtype, this);
47992 Roo.extend(Roo.form.Layout, Roo.Component, {
47994 * @cfg {String/Object} autoCreate
47995 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
47998 * @cfg {String/Object/Function} style
47999 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
48000 * a function which returns such a specification.
48003 * @cfg {String} labelAlign
48004 * Valid values are "left," "top" and "right" (defaults to "left")
48007 * @cfg {Number} labelWidth
48008 * Fixed width in pixels of all field labels (defaults to undefined)
48011 * @cfg {Boolean} clear
48012 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
48016 * @cfg {String} labelSeparator
48017 * The separator to use after field labels (defaults to ':')
48019 labelSeparator : ':',
48021 * @cfg {Boolean} hideLabels
48022 * True to suppress the display of field labels in this layout (defaults to false)
48024 hideLabels : false,
48027 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48032 onRender : function(ct, position){
48033 if(this.el){ // from markup
48034 this.el = Roo.get(this.el);
48035 }else { // generate
48036 var cfg = this.getAutoCreate();
48037 this.el = ct.createChild(cfg, position);
48040 this.el.applyStyles(this.style);
48042 if(this.labelAlign){
48043 this.el.addClass('x-form-label-'+this.labelAlign);
48045 if(this.hideLabels){
48046 this.labelStyle = "display:none";
48047 this.elementStyle = "padding-left:0;";
48049 if(typeof this.labelWidth == 'number'){
48050 this.labelStyle = "width:"+this.labelWidth+"px;";
48051 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48053 if(this.labelAlign == 'top'){
48054 this.labelStyle = "width:auto;";
48055 this.elementStyle = "padding-left:0;";
48058 var stack = this.stack;
48059 var slen = stack.length;
48061 if(!this.fieldTpl){
48062 var t = new Roo.Template(
48063 '<div class="x-form-item {5}">',
48064 '<label for="{0}" style="{2}">{1}{4}</label>',
48065 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48067 '</div><div class="x-form-clear-left"></div>'
48069 t.disableFormats = true;
48071 Roo.form.Layout.prototype.fieldTpl = t;
48073 for(var i = 0; i < slen; i++) {
48074 if(stack[i].isFormField){
48075 this.renderField(stack[i]);
48077 this.renderComponent(stack[i]);
48082 this.el.createChild({cls:'x-form-clear'});
48087 renderField : function(f){
48088 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48091 f.labelStyle||this.labelStyle||'', //2
48092 this.elementStyle||'', //3
48093 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48094 f.itemCls||this.itemCls||'' //5
48095 ], true).getPrevSibling());
48099 renderComponent : function(c){
48100 c.render(c.isLayout ? this.el : this.el.createChild());
48103 * Adds a object form elements (using the xtype property as the factory method.)
48104 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48105 * @param {Object} config
48107 addxtype : function(o)
48109 // create the lement.
48110 o.form = this.form;
48111 var fe = Roo.factory(o, Roo.form);
48112 this.form.allItems.push(fe);
48113 this.stack.push(fe);
48115 if (fe.isFormField) {
48116 this.form.items.add(fe);
48124 * @class Roo.form.Column
48125 * @extends Roo.form.Layout
48126 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48128 * @param {Object} config Configuration options
48130 Roo.form.Column = function(config){
48131 Roo.form.Column.superclass.constructor.call(this, config);
48134 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48136 * @cfg {Number/String} width
48137 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48140 * @cfg {String/Object} autoCreate
48141 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48145 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48148 onRender : function(ct, position){
48149 Roo.form.Column.superclass.onRender.call(this, ct, position);
48151 this.el.setWidth(this.width);
48158 * @class Roo.form.Row
48159 * @extends Roo.form.Layout
48160 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48162 * @param {Object} config Configuration options
48166 Roo.form.Row = function(config){
48167 Roo.form.Row.superclass.constructor.call(this, config);
48170 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48172 * @cfg {Number/String} width
48173 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48176 * @cfg {Number/String} height
48177 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48179 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48183 onRender : function(ct, position){
48184 //console.log('row render');
48186 var t = new Roo.Template(
48187 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48188 '<label for="{0}" style="{2}">{1}{4}</label>',
48189 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48193 t.disableFormats = true;
48195 Roo.form.Layout.prototype.rowTpl = t;
48197 this.fieldTpl = this.rowTpl;
48199 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48200 var labelWidth = 100;
48202 if ((this.labelAlign != 'top')) {
48203 if (typeof this.labelWidth == 'number') {
48204 labelWidth = this.labelWidth
48206 this.padWidth = 20 + labelWidth;
48210 Roo.form.Column.superclass.onRender.call(this, ct, position);
48212 this.el.setWidth(this.width);
48215 this.el.setHeight(this.height);
48220 renderField : function(f){
48221 f.fieldEl = this.fieldTpl.append(this.el, [
48222 f.id, f.fieldLabel,
48223 f.labelStyle||this.labelStyle||'',
48224 this.elementStyle||'',
48225 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48226 f.itemCls||this.itemCls||'',
48227 f.width ? f.width + this.padWidth : 160 + this.padWidth
48234 * @class Roo.form.FieldSet
48235 * @extends Roo.form.Layout
48236 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48238 * @param {Object} config Configuration options
48240 Roo.form.FieldSet = function(config){
48241 Roo.form.FieldSet.superclass.constructor.call(this, config);
48244 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48246 * @cfg {String} legend
48247 * The text to display as the legend for the FieldSet (defaults to '')
48250 * @cfg {String/Object} autoCreate
48251 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48255 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48258 onRender : function(ct, position){
48259 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48261 this.setLegend(this.legend);
48266 setLegend : function(text){
48268 this.el.child('legend').update(text);
48273 * Ext JS Library 1.1.1
48274 * Copyright(c) 2006-2007, Ext JS, LLC.
48276 * Originally Released Under LGPL - original licence link has changed is not relivant.
48279 * <script type="text/javascript">
48282 * @class Roo.form.VTypes
48283 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48286 Roo.form.VTypes = function(){
48287 // closure these in so they are only created once.
48288 var alpha = /^[a-zA-Z_]+$/;
48289 var alphanum = /^[a-zA-Z0-9_]+$/;
48290 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48291 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48293 // All these messages and functions are configurable
48296 * The function used to validate email addresses
48297 * @param {String} value The email address
48299 'email' : function(v){
48300 return email.test(v);
48303 * The error text to display when the email validation function returns false
48306 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48308 * The keystroke filter mask to be applied on email input
48311 'emailMask' : /[a-z0-9_\.\-@]/i,
48314 * The function used to validate URLs
48315 * @param {String} value The URL
48317 'url' : function(v){
48318 return url.test(v);
48321 * The error text to display when the url validation function returns false
48324 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48327 * The function used to validate alpha values
48328 * @param {String} value The value
48330 'alpha' : function(v){
48331 return alpha.test(v);
48334 * The error text to display when the alpha validation function returns false
48337 'alphaText' : 'This field should only contain letters and _',
48339 * The keystroke filter mask to be applied on alpha input
48342 'alphaMask' : /[a-z_]/i,
48345 * The function used to validate alphanumeric values
48346 * @param {String} value The value
48348 'alphanum' : function(v){
48349 return alphanum.test(v);
48352 * The error text to display when the alphanumeric validation function returns false
48355 'alphanumText' : 'This field should only contain letters, numbers and _',
48357 * The keystroke filter mask to be applied on alphanumeric input
48360 'alphanumMask' : /[a-z0-9_]/i
48362 }();//<script type="text/javascript">
48365 * @class Roo.form.FCKeditor
48366 * @extends Roo.form.TextArea
48367 * Wrapper around the FCKEditor http://www.fckeditor.net
48369 * Creates a new FCKeditor
48370 * @param {Object} config Configuration options
48372 Roo.form.FCKeditor = function(config){
48373 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48376 * @event editorinit
48377 * Fired when the editor is initialized - you can add extra handlers here..
48378 * @param {FCKeditor} this
48379 * @param {Object} the FCK object.
48386 Roo.form.FCKeditor.editors = { };
48387 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48389 //defaultAutoCreate : {
48390 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48394 * @cfg {Object} fck options - see fck manual for details.
48399 * @cfg {Object} fck toolbar set (Basic or Default)
48401 toolbarSet : 'Basic',
48403 * @cfg {Object} fck BasePath
48405 basePath : '/fckeditor/',
48413 onRender : function(ct, position)
48416 this.defaultAutoCreate = {
48418 style:"width:300px;height:60px;",
48419 autocomplete: "new-password"
48422 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48425 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48426 if(this.preventScrollbars){
48427 this.el.setStyle("overflow", "hidden");
48429 this.el.setHeight(this.growMin);
48432 //console.log('onrender' + this.getId() );
48433 Roo.form.FCKeditor.editors[this.getId()] = this;
48436 this.replaceTextarea() ;
48440 getEditor : function() {
48441 return this.fckEditor;
48444 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48445 * @param {Mixed} value The value to set
48449 setValue : function(value)
48451 //console.log('setValue: ' + value);
48453 if(typeof(value) == 'undefined') { // not sure why this is happending...
48456 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48458 //if(!this.el || !this.getEditor()) {
48459 // this.value = value;
48460 //this.setValue.defer(100,this,[value]);
48464 if(!this.getEditor()) {
48468 this.getEditor().SetData(value);
48475 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48476 * @return {Mixed} value The field value
48478 getValue : function()
48481 if (this.frame && this.frame.dom.style.display == 'none') {
48482 return Roo.form.FCKeditor.superclass.getValue.call(this);
48485 if(!this.el || !this.getEditor()) {
48487 // this.getValue.defer(100,this);
48492 var value=this.getEditor().GetData();
48493 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48494 return Roo.form.FCKeditor.superclass.getValue.call(this);
48500 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48501 * @return {Mixed} value The field value
48503 getRawValue : function()
48505 if (this.frame && this.frame.dom.style.display == 'none') {
48506 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48509 if(!this.el || !this.getEditor()) {
48510 //this.getRawValue.defer(100,this);
48517 var value=this.getEditor().GetData();
48518 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48519 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48523 setSize : function(w,h) {
48527 //if (this.frame && this.frame.dom.style.display == 'none') {
48528 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48531 //if(!this.el || !this.getEditor()) {
48532 // this.setSize.defer(100,this, [w,h]);
48538 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48540 this.frame.dom.setAttribute('width', w);
48541 this.frame.dom.setAttribute('height', h);
48542 this.frame.setSize(w,h);
48546 toggleSourceEdit : function(value) {
48550 this.el.dom.style.display = value ? '' : 'none';
48551 this.frame.dom.style.display = value ? 'none' : '';
48556 focus: function(tag)
48558 if (this.frame.dom.style.display == 'none') {
48559 return Roo.form.FCKeditor.superclass.focus.call(this);
48561 if(!this.el || !this.getEditor()) {
48562 this.focus.defer(100,this, [tag]);
48569 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48570 this.getEditor().Focus();
48572 if (!this.getEditor().Selection.GetSelection()) {
48573 this.focus.defer(100,this, [tag]);
48578 var r = this.getEditor().EditorDocument.createRange();
48579 r.setStart(tgs[0],0);
48580 r.setEnd(tgs[0],0);
48581 this.getEditor().Selection.GetSelection().removeAllRanges();
48582 this.getEditor().Selection.GetSelection().addRange(r);
48583 this.getEditor().Focus();
48590 replaceTextarea : function()
48592 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48595 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48597 // We must check the elements firstly using the Id and then the name.
48598 var oTextarea = document.getElementById( this.getId() );
48600 var colElementsByName = document.getElementsByName( this.getId() ) ;
48602 oTextarea.style.display = 'none' ;
48604 if ( oTextarea.tabIndex ) {
48605 this.TabIndex = oTextarea.tabIndex ;
48608 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48609 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48610 this.frame = Roo.get(this.getId() + '___Frame')
48613 _getConfigHtml : function()
48617 for ( var o in this.fckconfig ) {
48618 sConfig += sConfig.length > 0 ? '&' : '';
48619 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48622 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48626 _getIFrameHtml : function()
48628 var sFile = 'fckeditor.html' ;
48629 /* no idea what this is about..
48632 if ( (/fcksource=true/i).test( window.top.location.search ) )
48633 sFile = 'fckeditor.original.html' ;
48638 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48639 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48642 var html = '<iframe id="' + this.getId() +
48643 '___Frame" src="' + sLink +
48644 '" width="' + this.width +
48645 '" height="' + this.height + '"' +
48646 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48647 ' frameborder="0" scrolling="no"></iframe>' ;
48652 _insertHtmlBefore : function( html, element )
48654 if ( element.insertAdjacentHTML ) {
48656 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48658 var oRange = document.createRange() ;
48659 oRange.setStartBefore( element ) ;
48660 var oFragment = oRange.createContextualFragment( html );
48661 element.parentNode.insertBefore( oFragment, element ) ;
48674 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48676 function FCKeditor_OnComplete(editorInstance){
48677 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48678 f.fckEditor = editorInstance;
48679 //console.log("loaded");
48680 f.fireEvent('editorinit', f, editorInstance);
48700 //<script type="text/javascript">
48702 * @class Roo.form.GridField
48703 * @extends Roo.form.Field
48704 * Embed a grid (or editable grid into a form)
48707 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48709 * xgrid.store = Roo.data.Store
48710 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48711 * xgrid.store.reader = Roo.data.JsonReader
48715 * Creates a new GridField
48716 * @param {Object} config Configuration options
48718 Roo.form.GridField = function(config){
48719 Roo.form.GridField.superclass.constructor.call(this, config);
48723 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48725 * @cfg {Number} width - used to restrict width of grid..
48729 * @cfg {Number} height - used to restrict height of grid..
48733 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48739 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48740 * {tag: "input", type: "checkbox", autocomplete: "off"})
48742 // defaultAutoCreate : { tag: 'div' },
48743 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48745 * @cfg {String} addTitle Text to include for adding a title.
48749 onResize : function(){
48750 Roo.form.Field.superclass.onResize.apply(this, arguments);
48753 initEvents : function(){
48754 // Roo.form.Checkbox.superclass.initEvents.call(this);
48755 // has no events...
48760 getResizeEl : function(){
48764 getPositionEl : function(){
48769 onRender : function(ct, position){
48771 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48772 var style = this.style;
48775 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48776 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48777 this.viewEl = this.wrap.createChild({ tag: 'div' });
48779 this.viewEl.applyStyles(style);
48782 this.viewEl.setWidth(this.width);
48785 this.viewEl.setHeight(this.height);
48787 //if(this.inputValue !== undefined){
48788 //this.setValue(this.value);
48791 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48794 this.grid.render();
48795 this.grid.getDataSource().on('remove', this.refreshValue, this);
48796 this.grid.getDataSource().on('update', this.refreshValue, this);
48797 this.grid.on('afteredit', this.refreshValue, this);
48803 * Sets the value of the item.
48804 * @param {String} either an object or a string..
48806 setValue : function(v){
48808 v = v || []; // empty set..
48809 // this does not seem smart - it really only affects memoryproxy grids..
48810 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48811 var ds = this.grid.getDataSource();
48812 // assumes a json reader..
48814 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48815 ds.loadData( data);
48817 // clear selection so it does not get stale.
48818 if (this.grid.sm) {
48819 this.grid.sm.clearSelections();
48822 Roo.form.GridField.superclass.setValue.call(this, v);
48823 this.refreshValue();
48824 // should load data in the grid really....
48828 refreshValue: function() {
48830 this.grid.getDataSource().each(function(r) {
48833 this.el.dom.value = Roo.encode(val);
48841 * Ext JS Library 1.1.1
48842 * Copyright(c) 2006-2007, Ext JS, LLC.
48844 * Originally Released Under LGPL - original licence link has changed is not relivant.
48847 * <script type="text/javascript">
48850 * @class Roo.form.DisplayField
48851 * @extends Roo.form.Field
48852 * A generic Field to display non-editable data.
48853 * @cfg {Boolean} closable (true|false) default false
48855 * Creates a new Display Field item.
48856 * @param {Object} config Configuration options
48858 Roo.form.DisplayField = function(config){
48859 Roo.form.DisplayField.superclass.constructor.call(this, config);
48864 * Fires after the click the close btn
48865 * @param {Roo.form.DisplayField} this
48871 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
48872 inputType: 'hidden',
48878 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48880 focusClass : undefined,
48882 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48884 fieldClass: 'x-form-field',
48887 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
48889 valueRenderer: undefined,
48893 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48894 * {tag: "input", type: "checkbox", autocomplete: "off"})
48897 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
48901 onResize : function(){
48902 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
48906 initEvents : function(){
48907 // Roo.form.Checkbox.superclass.initEvents.call(this);
48908 // has no events...
48911 this.closeEl.on('click', this.onClose, this);
48917 getResizeEl : function(){
48921 getPositionEl : function(){
48926 onRender : function(ct, position){
48928 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
48929 //if(this.inputValue !== undefined){
48930 this.wrap = this.el.wrap();
48932 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
48935 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
48938 if (this.bodyStyle) {
48939 this.viewEl.applyStyles(this.bodyStyle);
48941 //this.viewEl.setStyle('padding', '2px');
48943 this.setValue(this.value);
48948 initValue : Roo.emptyFn,
48953 onClick : function(){
48958 * Sets the checked state of the checkbox.
48959 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
48961 setValue : function(v){
48963 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
48964 // this might be called before we have a dom element..
48965 if (!this.viewEl) {
48968 this.viewEl.dom.innerHTML = html;
48969 Roo.form.DisplayField.superclass.setValue.call(this, v);
48973 onClose : function(e)
48975 e.preventDefault();
48977 this.fireEvent('close', this);
48986 * @class Roo.form.DayPicker
48987 * @extends Roo.form.Field
48988 * A Day picker show [M] [T] [W] ....
48990 * Creates a new Day Picker
48991 * @param {Object} config Configuration options
48993 Roo.form.DayPicker= function(config){
48994 Roo.form.DayPicker.superclass.constructor.call(this, config);
48998 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
49000 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49002 focusClass : undefined,
49004 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49006 fieldClass: "x-form-field",
49009 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49010 * {tag: "input", type: "checkbox", autocomplete: "off"})
49012 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
49015 actionMode : 'viewEl',
49019 inputType : 'hidden',
49022 inputElement: false, // real input element?
49023 basedOn: false, // ????
49025 isFormField: true, // not sure where this is needed!!!!
49027 onResize : function(){
49028 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49029 if(!this.boxLabel){
49030 this.el.alignTo(this.wrap, 'c-c');
49034 initEvents : function(){
49035 Roo.form.Checkbox.superclass.initEvents.call(this);
49036 this.el.on("click", this.onClick, this);
49037 this.el.on("change", this.onClick, this);
49041 getResizeEl : function(){
49045 getPositionEl : function(){
49051 onRender : function(ct, position){
49052 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49054 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49056 var r1 = '<table><tr>';
49057 var r2 = '<tr class="x-form-daypick-icons">';
49058 for (var i=0; i < 7; i++) {
49059 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49060 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49063 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49064 viewEl.select('img').on('click', this.onClick, this);
49065 this.viewEl = viewEl;
49068 // this will not work on Chrome!!!
49069 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49070 this.el.on('propertychange', this.setFromHidden, this); //ie
49078 initValue : Roo.emptyFn,
49081 * Returns the checked state of the checkbox.
49082 * @return {Boolean} True if checked, else false
49084 getValue : function(){
49085 return this.el.dom.value;
49090 onClick : function(e){
49091 //this.setChecked(!this.checked);
49092 Roo.get(e.target).toggleClass('x-menu-item-checked');
49093 this.refreshValue();
49094 //if(this.el.dom.checked != this.checked){
49095 // this.setValue(this.el.dom.checked);
49100 refreshValue : function()
49103 this.viewEl.select('img',true).each(function(e,i,n) {
49104 val += e.is(".x-menu-item-checked") ? String(n) : '';
49106 this.setValue(val, true);
49110 * Sets the checked state of the checkbox.
49111 * On is always based on a string comparison between inputValue and the param.
49112 * @param {Boolean/String} value - the value to set
49113 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49115 setValue : function(v,suppressEvent){
49116 if (!this.el.dom) {
49119 var old = this.el.dom.value ;
49120 this.el.dom.value = v;
49121 if (suppressEvent) {
49125 // update display..
49126 this.viewEl.select('img',true).each(function(e,i,n) {
49128 var on = e.is(".x-menu-item-checked");
49129 var newv = v.indexOf(String(n)) > -1;
49131 e.toggleClass('x-menu-item-checked');
49137 this.fireEvent('change', this, v, old);
49142 // handle setting of hidden value by some other method!!?!?
49143 setFromHidden: function()
49148 //console.log("SET FROM HIDDEN");
49149 //alert('setFrom hidden');
49150 this.setValue(this.el.dom.value);
49153 onDestroy : function()
49156 Roo.get(this.viewEl).remove();
49159 Roo.form.DayPicker.superclass.onDestroy.call(this);
49163 * RooJS Library 1.1.1
49164 * Copyright(c) 2008-2011 Alan Knowles
49171 * @class Roo.form.ComboCheck
49172 * @extends Roo.form.ComboBox
49173 * A combobox for multiple select items.
49175 * FIXME - could do with a reset button..
49178 * Create a new ComboCheck
49179 * @param {Object} config Configuration options
49181 Roo.form.ComboCheck = function(config){
49182 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49183 // should verify some data...
49185 // hiddenName = required..
49186 // displayField = required
49187 // valudField == required
49188 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49190 Roo.each(req, function(e) {
49191 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49192 throw "Roo.form.ComboCheck : missing value for: " + e;
49199 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49204 selectedClass: 'x-menu-item-checked',
49207 onRender : function(ct, position){
49213 var cls = 'x-combo-list';
49216 this.tpl = new Roo.Template({
49217 html : '<div class="'+cls+'-item x-menu-check-item">' +
49218 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49219 '<span>{' + this.displayField + '}</span>' +
49226 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49227 this.view.singleSelect = false;
49228 this.view.multiSelect = true;
49229 this.view.toggleSelect = true;
49230 this.pageTb.add(new Roo.Toolbar.Fill(), {
49233 handler: function()
49240 onViewOver : function(e, t){
49246 onViewClick : function(doFocus,index){
49250 select: function () {
49251 //Roo.log("SELECT CALLED");
49254 selectByValue : function(xv, scrollIntoView){
49255 var ar = this.getValueArray();
49258 Roo.each(ar, function(v) {
49259 if(v === undefined || v === null){
49262 var r = this.findRecord(this.valueField, v);
49264 sels.push(this.store.indexOf(r))
49268 this.view.select(sels);
49274 onSelect : function(record, index){
49275 // Roo.log("onselect Called");
49276 // this is only called by the clear button now..
49277 this.view.clearSelections();
49278 this.setValue('[]');
49279 if (this.value != this.valueBefore) {
49280 this.fireEvent('change', this, this.value, this.valueBefore);
49281 this.valueBefore = this.value;
49284 getValueArray : function()
49289 //Roo.log(this.value);
49290 if (typeof(this.value) == 'undefined') {
49293 var ar = Roo.decode(this.value);
49294 return ar instanceof Array ? ar : []; //?? valid?
49297 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49302 expand : function ()
49305 Roo.form.ComboCheck.superclass.expand.call(this);
49306 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49307 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49312 collapse : function(){
49313 Roo.form.ComboCheck.superclass.collapse.call(this);
49314 var sl = this.view.getSelectedIndexes();
49315 var st = this.store;
49319 Roo.each(sl, function(i) {
49321 nv.push(r.get(this.valueField));
49323 this.setValue(Roo.encode(nv));
49324 if (this.value != this.valueBefore) {
49326 this.fireEvent('change', this, this.value, this.valueBefore);
49327 this.valueBefore = this.value;
49332 setValue : function(v){
49336 var vals = this.getValueArray();
49338 Roo.each(vals, function(k) {
49339 var r = this.findRecord(this.valueField, k);
49341 tv.push(r.data[this.displayField]);
49342 }else if(this.valueNotFoundText !== undefined){
49343 tv.push( this.valueNotFoundText );
49348 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49349 this.hiddenField.value = v;
49355 * Ext JS Library 1.1.1
49356 * Copyright(c) 2006-2007, Ext JS, LLC.
49358 * Originally Released Under LGPL - original licence link has changed is not relivant.
49361 * <script type="text/javascript">
49365 * @class Roo.form.Signature
49366 * @extends Roo.form.Field
49370 * @param {Object} config Configuration options
49373 Roo.form.Signature = function(config){
49374 Roo.form.Signature.superclass.constructor.call(this, config);
49376 this.addEvents({// not in used??
49379 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49380 * @param {Roo.form.Signature} combo This combo box
49385 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49386 * @param {Roo.form.ComboBox} combo This combo box
49387 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49393 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49395 * @cfg {Object} labels Label to use when rendering a form.
49399 * confirm : "Confirm"
49404 confirm : "Confirm"
49407 * @cfg {Number} width The signature panel width (defaults to 300)
49411 * @cfg {Number} height The signature panel height (defaults to 100)
49415 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49417 allowBlank : false,
49420 // {Object} signPanel The signature SVG panel element (defaults to {})
49422 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49423 isMouseDown : false,
49424 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49425 isConfirmed : false,
49426 // {String} signatureTmp SVG mapping string (defaults to empty string)
49430 defaultAutoCreate : { // modified by initCompnoent..
49436 onRender : function(ct, position){
49438 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49440 this.wrap = this.el.wrap({
49441 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49444 this.createToolbar(this);
49445 this.signPanel = this.wrap.createChild({
49447 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49451 this.svgID = Roo.id();
49452 this.svgEl = this.signPanel.createChild({
49453 xmlns : 'http://www.w3.org/2000/svg',
49455 id : this.svgID + "-svg",
49457 height: this.height,
49458 viewBox: '0 0 '+this.width+' '+this.height,
49462 id: this.svgID + "-svg-r",
49464 height: this.height,
49469 id: this.svgID + "-svg-l",
49471 y1: (this.height*0.8), // start set the line in 80% of height
49472 x2: this.width, // end
49473 y2: (this.height*0.8), // end set the line in 80% of height
49475 'stroke-width': "1",
49476 'stroke-dasharray': "3",
49477 'shape-rendering': "crispEdges",
49478 'pointer-events': "none"
49482 id: this.svgID + "-svg-p",
49484 'stroke-width': "3",
49486 'pointer-events': 'none'
49491 this.svgBox = this.svgEl.dom.getScreenCTM();
49493 createSVG : function(){
49494 var svg = this.signPanel;
49495 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49498 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49499 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49500 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49501 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49502 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49503 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49504 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49507 isTouchEvent : function(e){
49508 return e.type.match(/^touch/);
49510 getCoords : function (e) {
49511 var pt = this.svgEl.dom.createSVGPoint();
49514 if (this.isTouchEvent(e)) {
49515 pt.x = e.targetTouches[0].clientX;
49516 pt.y = e.targetTouches[0].clientY;
49518 var a = this.svgEl.dom.getScreenCTM();
49519 var b = a.inverse();
49520 var mx = pt.matrixTransform(b);
49521 return mx.x + ',' + mx.y;
49523 //mouse event headler
49524 down : function (e) {
49525 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49526 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49528 this.isMouseDown = true;
49530 e.preventDefault();
49532 move : function (e) {
49533 if (this.isMouseDown) {
49534 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49535 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49538 e.preventDefault();
49540 up : function (e) {
49541 this.isMouseDown = false;
49542 var sp = this.signatureTmp.split(' ');
49545 if(!sp[sp.length-2].match(/^L/)){
49549 this.signatureTmp = sp.join(" ");
49552 if(this.getValue() != this.signatureTmp){
49553 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49554 this.isConfirmed = false;
49556 e.preventDefault();
49560 * Protected method that will not generally be called directly. It
49561 * is called when the editor creates its toolbar. Override this method if you need to
49562 * add custom toolbar buttons.
49563 * @param {HtmlEditor} editor
49565 createToolbar : function(editor){
49566 function btn(id, toggle, handler){
49567 var xid = fid + '-'+ id ;
49571 cls : 'x-btn-icon x-edit-'+id,
49572 enableToggle:toggle !== false,
49573 scope: editor, // was editor...
49574 handler:handler||editor.relayBtnCmd,
49575 clickEvent:'mousedown',
49576 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49582 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49586 cls : ' x-signature-btn x-signature-'+id,
49587 scope: editor, // was editor...
49588 handler: this.reset,
49589 clickEvent:'mousedown',
49590 text: this.labels.clear
49597 cls : ' x-signature-btn x-signature-'+id,
49598 scope: editor, // was editor...
49599 handler: this.confirmHandler,
49600 clickEvent:'mousedown',
49601 text: this.labels.confirm
49608 * when user is clicked confirm then show this image.....
49610 * @return {String} Image Data URI
49612 getImageDataURI : function(){
49613 var svg = this.svgEl.dom.parentNode.innerHTML;
49614 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49619 * @return {Boolean} this.isConfirmed
49621 getConfirmed : function(){
49622 return this.isConfirmed;
49626 * @return {Number} this.width
49628 getWidth : function(){
49633 * @return {Number} this.height
49635 getHeight : function(){
49636 return this.height;
49639 getSignature : function(){
49640 return this.signatureTmp;
49643 reset : function(){
49644 this.signatureTmp = '';
49645 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49646 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49647 this.isConfirmed = false;
49648 Roo.form.Signature.superclass.reset.call(this);
49650 setSignature : function(s){
49651 this.signatureTmp = s;
49652 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49653 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49655 this.isConfirmed = false;
49656 Roo.form.Signature.superclass.reset.call(this);
49659 // Roo.log(this.signPanel.dom.contentWindow.up())
49662 setConfirmed : function(){
49666 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49669 confirmHandler : function(){
49670 if(!this.getSignature()){
49674 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49675 this.setValue(this.getSignature());
49676 this.isConfirmed = true;
49678 this.fireEvent('confirm', this);
49681 // Subclasses should provide the validation implementation by overriding this
49682 validateValue : function(value){
49683 if(this.allowBlank){
49687 if(this.isConfirmed){
49694 * Ext JS Library 1.1.1
49695 * Copyright(c) 2006-2007, Ext JS, LLC.
49697 * Originally Released Under LGPL - original licence link has changed is not relivant.
49700 * <script type="text/javascript">
49705 * @class Roo.form.ComboBox
49706 * @extends Roo.form.TriggerField
49707 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49709 * Create a new ComboBox.
49710 * @param {Object} config Configuration options
49712 Roo.form.Select = function(config){
49713 Roo.form.Select.superclass.constructor.call(this, config);
49717 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49719 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49722 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49723 * rendering into an Roo.Editor, defaults to false)
49726 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49727 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49730 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49733 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49734 * the dropdown list (defaults to undefined, with no header element)
49738 * @cfg {String/Roo.Template} tpl The template to use to render the output
49742 defaultAutoCreate : {tag: "select" },
49744 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49746 listWidth: undefined,
49748 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49749 * mode = 'remote' or 'text' if mode = 'local')
49751 displayField: undefined,
49753 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49754 * mode = 'remote' or 'value' if mode = 'local').
49755 * Note: use of a valueField requires the user make a selection
49756 * in order for a value to be mapped.
49758 valueField: undefined,
49762 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49763 * field's data value (defaults to the underlying DOM element's name)
49765 hiddenName: undefined,
49767 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49771 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49773 selectedClass: 'x-combo-selected',
49775 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49776 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49777 * which displays a downward arrow icon).
49779 triggerClass : 'x-form-arrow-trigger',
49781 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49785 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49786 * anchor positions (defaults to 'tl-bl')
49788 listAlign: 'tl-bl?',
49790 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49794 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49795 * query specified by the allQuery config option (defaults to 'query')
49797 triggerAction: 'query',
49799 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49800 * (defaults to 4, does not apply if editable = false)
49804 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49805 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49809 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49810 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49814 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49815 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49819 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49820 * when editable = true (defaults to false)
49822 selectOnFocus:false,
49824 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49826 queryParam: 'query',
49828 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49829 * when mode = 'remote' (defaults to 'Loading...')
49831 loadingText: 'Loading...',
49833 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49837 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49841 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49842 * traditional select (defaults to true)
49846 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49850 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49854 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49855 * listWidth has a higher value)
49859 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49860 * allow the user to set arbitrary text into the field (defaults to false)
49862 forceSelection:false,
49864 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49865 * if typeAhead = true (defaults to 250)
49867 typeAheadDelay : 250,
49869 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
49870 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
49872 valueNotFoundText : undefined,
49875 * @cfg {String} defaultValue The value displayed after loading the store.
49880 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
49882 blockFocus : false,
49885 * @cfg {Boolean} disableClear Disable showing of clear button.
49887 disableClear : false,
49889 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
49891 alwaysQuery : false,
49897 // element that contains real text value.. (when hidden is used..)
49900 onRender : function(ct, position){
49901 Roo.form.Field.prototype.onRender.call(this, ct, position);
49904 this.store.on('beforeload', this.onBeforeLoad, this);
49905 this.store.on('load', this.onLoad, this);
49906 this.store.on('loadexception', this.onLoadException, this);
49907 this.store.load({});
49915 initEvents : function(){
49916 //Roo.form.ComboBox.superclass.initEvents.call(this);
49920 onDestroy : function(){
49923 this.store.un('beforeload', this.onBeforeLoad, this);
49924 this.store.un('load', this.onLoad, this);
49925 this.store.un('loadexception', this.onLoadException, this);
49927 //Roo.form.ComboBox.superclass.onDestroy.call(this);
49931 fireKey : function(e){
49932 if(e.isNavKeyPress() && !this.list.isVisible()){
49933 this.fireEvent("specialkey", this, e);
49938 onResize: function(w, h){
49946 * Allow or prevent the user from directly editing the field text. If false is passed,
49947 * the user will only be able to select from the items defined in the dropdown list. This method
49948 * is the runtime equivalent of setting the 'editable' config option at config time.
49949 * @param {Boolean} value True to allow the user to directly edit the field text
49951 setEditable : function(value){
49956 onBeforeLoad : function(){
49958 Roo.log("Select before load");
49961 this.innerList.update(this.loadingText ?
49962 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
49963 //this.restrictHeight();
49964 this.selectedIndex = -1;
49968 onLoad : function(){
49971 var dom = this.el.dom;
49972 dom.innerHTML = '';
49973 var od = dom.ownerDocument;
49975 if (this.emptyText) {
49976 var op = od.createElement('option');
49977 op.setAttribute('value', '');
49978 op.innerHTML = String.format('{0}', this.emptyText);
49979 dom.appendChild(op);
49981 if(this.store.getCount() > 0){
49983 var vf = this.valueField;
49984 var df = this.displayField;
49985 this.store.data.each(function(r) {
49986 // which colmsn to use... testing - cdoe / title..
49987 var op = od.createElement('option');
49988 op.setAttribute('value', r.data[vf]);
49989 op.innerHTML = String.format('{0}', r.data[df]);
49990 dom.appendChild(op);
49992 if (typeof(this.defaultValue != 'undefined')) {
49993 this.setValue(this.defaultValue);
49998 //this.onEmptyResults();
50003 onLoadException : function()
50005 dom.innerHTML = '';
50007 Roo.log("Select on load exception");
50011 Roo.log(this.store.reader.jsonData);
50012 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
50013 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50019 onTypeAhead : function(){
50024 onSelect : function(record, index){
50025 Roo.log('on select?');
50027 if(this.fireEvent('beforeselect', this, record, index) !== false){
50028 this.setFromData(index > -1 ? record.data : false);
50030 this.fireEvent('select', this, record, index);
50035 * Returns the currently selected field value or empty string if no value is set.
50036 * @return {String} value The selected value
50038 getValue : function(){
50039 var dom = this.el.dom;
50040 this.value = dom.options[dom.selectedIndex].value;
50046 * Clears any text/value currently set in the field
50048 clearValue : function(){
50050 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50055 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50056 * will be displayed in the field. If the value does not match the data value of an existing item,
50057 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50058 * Otherwise the field will be blank (although the value will still be set).
50059 * @param {String} value The value to match
50061 setValue : function(v){
50062 var d = this.el.dom;
50063 for (var i =0; i < d.options.length;i++) {
50064 if (v == d.options[i].value) {
50065 d.selectedIndex = i;
50073 * @property {Object} the last set data for the element
50078 * Sets the value of the field based on a object which is related to the record format for the store.
50079 * @param {Object} value the value to set as. or false on reset?
50081 setFromData : function(o){
50082 Roo.log('setfrom data?');
50088 reset : function(){
50092 findRecord : function(prop, value){
50097 if(this.store.getCount() > 0){
50098 this.store.each(function(r){
50099 if(r.data[prop] == value){
50109 getName: function()
50111 // returns hidden if it's set..
50112 if (!this.rendered) {return ''};
50113 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50121 onEmptyResults : function(){
50122 Roo.log('empty results');
50127 * Returns true if the dropdown list is expanded, else false.
50129 isExpanded : function(){
50134 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50135 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50136 * @param {String} value The data value of the item to select
50137 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50138 * selected item if it is not currently in view (defaults to true)
50139 * @return {Boolean} True if the value matched an item in the list, else false
50141 selectByValue : function(v, scrollIntoView){
50142 Roo.log('select By Value');
50145 if(v !== undefined && v !== null){
50146 var r = this.findRecord(this.valueField || this.displayField, v);
50148 this.select(this.store.indexOf(r), scrollIntoView);
50156 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50157 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50158 * @param {Number} index The zero-based index of the list item to select
50159 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50160 * selected item if it is not currently in view (defaults to true)
50162 select : function(index, scrollIntoView){
50163 Roo.log('select ');
50166 this.selectedIndex = index;
50167 this.view.select(index);
50168 if(scrollIntoView !== false){
50169 var el = this.view.getNode(index);
50171 this.innerList.scrollChildIntoView(el, false);
50179 validateBlur : function(){
50186 initQuery : function(){
50187 this.doQuery(this.getRawValue());
50191 doForce : function(){
50192 if(this.el.dom.value.length > 0){
50193 this.el.dom.value =
50194 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50200 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50201 * query allowing the query action to be canceled if needed.
50202 * @param {String} query The SQL query to execute
50203 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50204 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50205 * saved in the current store (defaults to false)
50207 doQuery : function(q, forceAll){
50209 Roo.log('doQuery?');
50210 if(q === undefined || q === null){
50215 forceAll: forceAll,
50219 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50223 forceAll = qe.forceAll;
50224 if(forceAll === true || (q.length >= this.minChars)){
50225 if(this.lastQuery != q || this.alwaysQuery){
50226 this.lastQuery = q;
50227 if(this.mode == 'local'){
50228 this.selectedIndex = -1;
50230 this.store.clearFilter();
50232 this.store.filter(this.displayField, q);
50236 this.store.baseParams[this.queryParam] = q;
50238 params: this.getParams(q)
50243 this.selectedIndex = -1;
50250 getParams : function(q){
50252 //p[this.queryParam] = q;
50255 p.limit = this.pageSize;
50261 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50263 collapse : function(){
50268 collapseIf : function(e){
50273 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50275 expand : function(){
50283 * @cfg {Boolean} grow
50287 * @cfg {Number} growMin
50291 * @cfg {Number} growMax
50299 setWidth : function()
50303 getResizeEl : function(){
50306 });//<script type="text/javasscript">
50310 * @class Roo.DDView
50311 * A DnD enabled version of Roo.View.
50312 * @param {Element/String} container The Element in which to create the View.
50313 * @param {String} tpl The template string used to create the markup for each element of the View
50314 * @param {Object} config The configuration properties. These include all the config options of
50315 * {@link Roo.View} plus some specific to this class.<br>
50317 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50318 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50320 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50321 .x-view-drag-insert-above {
50322 border-top:1px dotted #3366cc;
50324 .x-view-drag-insert-below {
50325 border-bottom:1px dotted #3366cc;
50331 Roo.DDView = function(container, tpl, config) {
50332 Roo.DDView.superclass.constructor.apply(this, arguments);
50333 this.getEl().setStyle("outline", "0px none");
50334 this.getEl().unselectable();
50335 if (this.dragGroup) {
50336 this.setDraggable(this.dragGroup.split(","));
50338 if (this.dropGroup) {
50339 this.setDroppable(this.dropGroup.split(","));
50341 if (this.deletable) {
50342 this.setDeletable();
50344 this.isDirtyFlag = false;
50350 Roo.extend(Roo.DDView, Roo.View, {
50351 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50352 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50353 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50354 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50358 reset: Roo.emptyFn,
50360 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50362 validate: function() {
50366 destroy: function() {
50367 this.purgeListeners();
50368 this.getEl.removeAllListeners();
50369 this.getEl().remove();
50370 if (this.dragZone) {
50371 if (this.dragZone.destroy) {
50372 this.dragZone.destroy();
50375 if (this.dropZone) {
50376 if (this.dropZone.destroy) {
50377 this.dropZone.destroy();
50382 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50383 getName: function() {
50387 /** Loads the View from a JSON string representing the Records to put into the Store. */
50388 setValue: function(v) {
50390 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50393 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50394 this.store.proxy = new Roo.data.MemoryProxy(data);
50398 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50399 getValue: function() {
50401 this.store.each(function(rec) {
50402 result += rec.id + ',';
50404 return result.substr(0, result.length - 1) + ')';
50407 getIds: function() {
50408 var i = 0, result = new Array(this.store.getCount());
50409 this.store.each(function(rec) {
50410 result[i++] = rec.id;
50415 isDirty: function() {
50416 return this.isDirtyFlag;
50420 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50421 * whole Element becomes the target, and this causes the drop gesture to append.
50423 getTargetFromEvent : function(e) {
50424 var target = e.getTarget();
50425 while ((target !== null) && (target.parentNode != this.el.dom)) {
50426 target = target.parentNode;
50429 target = this.el.dom.lastChild || this.el.dom;
50435 * Create the drag data which consists of an object which has the property "ddel" as
50436 * the drag proxy element.
50438 getDragData : function(e) {
50439 var target = this.findItemFromChild(e.getTarget());
50441 this.handleSelection(e);
50442 var selNodes = this.getSelectedNodes();
50445 copy: this.copy || (this.allowCopy && e.ctrlKey),
50449 var selectedIndices = this.getSelectedIndexes();
50450 for (var i = 0; i < selectedIndices.length; i++) {
50451 dragData.records.push(this.store.getAt(selectedIndices[i]));
50453 if (selNodes.length == 1) {
50454 dragData.ddel = target.cloneNode(true); // the div element
50456 var div = document.createElement('div'); // create the multi element drag "ghost"
50457 div.className = 'multi-proxy';
50458 for (var i = 0, len = selNodes.length; i < len; i++) {
50459 div.appendChild(selNodes[i].cloneNode(true));
50461 dragData.ddel = div;
50463 //console.log(dragData)
50464 //console.log(dragData.ddel.innerHTML)
50467 //console.log('nodragData')
50471 /** Specify to which ddGroup items in this DDView may be dragged. */
50472 setDraggable: function(ddGroup) {
50473 if (ddGroup instanceof Array) {
50474 Roo.each(ddGroup, this.setDraggable, this);
50477 if (this.dragZone) {
50478 this.dragZone.addToGroup(ddGroup);
50480 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50481 containerScroll: true,
50485 // Draggability implies selection. DragZone's mousedown selects the element.
50486 if (!this.multiSelect) { this.singleSelect = true; }
50488 // Wire the DragZone's handlers up to methods in *this*
50489 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50493 /** Specify from which ddGroup this DDView accepts drops. */
50494 setDroppable: function(ddGroup) {
50495 if (ddGroup instanceof Array) {
50496 Roo.each(ddGroup, this.setDroppable, this);
50499 if (this.dropZone) {
50500 this.dropZone.addToGroup(ddGroup);
50502 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50503 containerScroll: true,
50507 // Wire the DropZone's handlers up to methods in *this*
50508 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50509 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50510 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50511 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50512 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50516 /** Decide whether to drop above or below a View node. */
50517 getDropPoint : function(e, n, dd){
50518 if (n == this.el.dom) { return "above"; }
50519 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50520 var c = t + (b - t) / 2;
50521 var y = Roo.lib.Event.getPageY(e);
50529 onNodeEnter : function(n, dd, e, data){
50533 onNodeOver : function(n, dd, e, data){
50534 var pt = this.getDropPoint(e, n, dd);
50535 // set the insert point style on the target node
50536 var dragElClass = this.dropNotAllowed;
50539 if (pt == "above"){
50540 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50541 targetElClass = "x-view-drag-insert-above";
50543 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50544 targetElClass = "x-view-drag-insert-below";
50546 if (this.lastInsertClass != targetElClass){
50547 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50548 this.lastInsertClass = targetElClass;
50551 return dragElClass;
50554 onNodeOut : function(n, dd, e, data){
50555 this.removeDropIndicators(n);
50558 onNodeDrop : function(n, dd, e, data){
50559 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50562 var pt = this.getDropPoint(e, n, dd);
50563 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50564 if (pt == "below") { insertAt++; }
50565 for (var i = 0; i < data.records.length; i++) {
50566 var r = data.records[i];
50567 var dup = this.store.getById(r.id);
50568 if (dup && (dd != this.dragZone)) {
50569 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50572 this.store.insert(insertAt++, r.copy());
50574 data.source.isDirtyFlag = true;
50576 this.store.insert(insertAt++, r);
50578 this.isDirtyFlag = true;
50581 this.dragZone.cachedTarget = null;
50585 removeDropIndicators : function(n){
50587 Roo.fly(n).removeClass([
50588 "x-view-drag-insert-above",
50589 "x-view-drag-insert-below"]);
50590 this.lastInsertClass = "_noclass";
50595 * Utility method. Add a delete option to the DDView's context menu.
50596 * @param {String} imageUrl The URL of the "delete" icon image.
50598 setDeletable: function(imageUrl) {
50599 if (!this.singleSelect && !this.multiSelect) {
50600 this.singleSelect = true;
50602 var c = this.getContextMenu();
50603 this.contextMenu.on("itemclick", function(item) {
50606 this.remove(this.getSelectedIndexes());
50610 this.contextMenu.add({
50617 /** Return the context menu for this DDView. */
50618 getContextMenu: function() {
50619 if (!this.contextMenu) {
50620 // Create the View's context menu
50621 this.contextMenu = new Roo.menu.Menu({
50622 id: this.id + "-contextmenu"
50624 this.el.on("contextmenu", this.showContextMenu, this);
50626 return this.contextMenu;
50629 disableContextMenu: function() {
50630 if (this.contextMenu) {
50631 this.el.un("contextmenu", this.showContextMenu, this);
50635 showContextMenu: function(e, item) {
50636 item = this.findItemFromChild(e.getTarget());
50639 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50640 this.contextMenu.showAt(e.getXY());
50645 * Remove {@link Roo.data.Record}s at the specified indices.
50646 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50648 remove: function(selectedIndices) {
50649 selectedIndices = [].concat(selectedIndices);
50650 for (var i = 0; i < selectedIndices.length; i++) {
50651 var rec = this.store.getAt(selectedIndices[i]);
50652 this.store.remove(rec);
50657 * Double click fires the event, but also, if this is draggable, and there is only one other
50658 * related DropZone, it transfers the selected node.
50660 onDblClick : function(e){
50661 var item = this.findItemFromChild(e.getTarget());
50663 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50666 if (this.dragGroup) {
50667 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50668 while (targets.indexOf(this.dropZone) > -1) {
50669 targets.remove(this.dropZone);
50671 if (targets.length == 1) {
50672 this.dragZone.cachedTarget = null;
50673 var el = Roo.get(targets[0].getEl());
50674 var box = el.getBox(true);
50675 targets[0].onNodeDrop(el.dom, {
50677 xy: [box.x, box.y + box.height - 1]
50678 }, null, this.getDragData(e));
50684 handleSelection: function(e) {
50685 this.dragZone.cachedTarget = null;
50686 var item = this.findItemFromChild(e.getTarget());
50688 this.clearSelections(true);
50691 if (item && (this.multiSelect || this.singleSelect)){
50692 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50693 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50694 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50695 this.unselect(item);
50697 this.select(item, this.multiSelect && e.ctrlKey);
50698 this.lastSelection = item;
50703 onItemClick : function(item, index, e){
50704 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50710 unselect : function(nodeInfo, suppressEvent){
50711 var node = this.getNode(nodeInfo);
50712 if(node && this.isSelected(node)){
50713 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50714 Roo.fly(node).removeClass(this.selectedClass);
50715 this.selections.remove(node);
50716 if(!suppressEvent){
50717 this.fireEvent("selectionchange", this, this.selections);
50725 * Ext JS Library 1.1.1
50726 * Copyright(c) 2006-2007, Ext JS, LLC.
50728 * Originally Released Under LGPL - original licence link has changed is not relivant.
50731 * <script type="text/javascript">
50735 * @class Roo.LayoutManager
50736 * @extends Roo.util.Observable
50737 * Base class for layout managers.
50739 Roo.LayoutManager = function(container, config){
50740 Roo.LayoutManager.superclass.constructor.call(this);
50741 this.el = Roo.get(container);
50742 // ie scrollbar fix
50743 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50744 document.body.scroll = "no";
50745 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50746 this.el.position('relative');
50748 this.id = this.el.id;
50749 this.el.addClass("x-layout-container");
50750 /** false to disable window resize monitoring @type Boolean */
50751 this.monitorWindowResize = true;
50756 * Fires when a layout is performed.
50757 * @param {Roo.LayoutManager} this
50761 * @event regionresized
50762 * Fires when the user resizes a region.
50763 * @param {Roo.LayoutRegion} region The resized region
50764 * @param {Number} newSize The new size (width for east/west, height for north/south)
50766 "regionresized" : true,
50768 * @event regioncollapsed
50769 * Fires when a region is collapsed.
50770 * @param {Roo.LayoutRegion} region The collapsed region
50772 "regioncollapsed" : true,
50774 * @event regionexpanded
50775 * Fires when a region is expanded.
50776 * @param {Roo.LayoutRegion} region The expanded region
50778 "regionexpanded" : true
50780 this.updating = false;
50781 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50784 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50786 * Returns true if this layout is currently being updated
50787 * @return {Boolean}
50789 isUpdating : function(){
50790 return this.updating;
50794 * Suspend the LayoutManager from doing auto-layouts while
50795 * making multiple add or remove calls
50797 beginUpdate : function(){
50798 this.updating = true;
50802 * Restore auto-layouts and optionally disable the manager from performing a layout
50803 * @param {Boolean} noLayout true to disable a layout update
50805 endUpdate : function(noLayout){
50806 this.updating = false;
50812 layout: function(){
50816 onRegionResized : function(region, newSize){
50817 this.fireEvent("regionresized", region, newSize);
50821 onRegionCollapsed : function(region){
50822 this.fireEvent("regioncollapsed", region);
50825 onRegionExpanded : function(region){
50826 this.fireEvent("regionexpanded", region);
50830 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50831 * performs box-model adjustments.
50832 * @return {Object} The size as an object {width: (the width), height: (the height)}
50834 getViewSize : function(){
50836 if(this.el.dom != document.body){
50837 size = this.el.getSize();
50839 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50841 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50842 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50847 * Returns the Element this layout is bound to.
50848 * @return {Roo.Element}
50850 getEl : function(){
50855 * Returns the specified region.
50856 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50857 * @return {Roo.LayoutRegion}
50859 getRegion : function(target){
50860 return this.regions[target.toLowerCase()];
50863 onWindowResize : function(){
50864 if(this.monitorWindowResize){
50870 * Ext JS Library 1.1.1
50871 * Copyright(c) 2006-2007, Ext JS, LLC.
50873 * Originally Released Under LGPL - original licence link has changed is not relivant.
50876 * <script type="text/javascript">
50879 * @class Roo.BorderLayout
50880 * @extends Roo.LayoutManager
50881 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
50882 * please see: <br><br>
50883 * <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>
50884 * <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>
50887 var layout = new Roo.BorderLayout(document.body, {
50921 preferredTabWidth: 150
50926 var CP = Roo.ContentPanel;
50928 layout.beginUpdate();
50929 layout.add("north", new CP("north", "North"));
50930 layout.add("south", new CP("south", {title: "South", closable: true}));
50931 layout.add("west", new CP("west", {title: "West"}));
50932 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
50933 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
50934 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
50935 layout.getRegion("center").showPanel("center1");
50936 layout.endUpdate();
50939 <b>The container the layout is rendered into can be either the body element or any other element.
50940 If it is not the body element, the container needs to either be an absolute positioned element,
50941 or you will need to add "position:relative" to the css of the container. You will also need to specify
50942 the container size if it is not the body element.</b>
50945 * Create a new BorderLayout
50946 * @param {String/HTMLElement/Element} container The container this layout is bound to
50947 * @param {Object} config Configuration options
50949 Roo.BorderLayout = function(container, config){
50950 config = config || {};
50951 Roo.BorderLayout.superclass.constructor.call(this, container, config);
50952 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
50953 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
50954 var target = this.factory.validRegions[i];
50955 if(config[target]){
50956 this.addRegion(target, config[target]);
50961 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
50963 * Creates and adds a new region if it doesn't already exist.
50964 * @param {String} target The target region key (north, south, east, west or center).
50965 * @param {Object} config The regions config object
50966 * @return {BorderLayoutRegion} The new region
50968 addRegion : function(target, config){
50969 if(!this.regions[target]){
50970 var r = this.factory.create(target, this, config);
50971 this.bindRegion(target, r);
50973 return this.regions[target];
50977 bindRegion : function(name, r){
50978 this.regions[name] = r;
50979 r.on("visibilitychange", this.layout, this);
50980 r.on("paneladded", this.layout, this);
50981 r.on("panelremoved", this.layout, this);
50982 r.on("invalidated", this.layout, this);
50983 r.on("resized", this.onRegionResized, this);
50984 r.on("collapsed", this.onRegionCollapsed, this);
50985 r.on("expanded", this.onRegionExpanded, this);
50989 * Performs a layout update.
50991 layout : function(){
50992 if(this.updating) {
50995 var size = this.getViewSize();
50996 var w = size.width;
50997 var h = size.height;
51002 //var x = 0, y = 0;
51004 var rs = this.regions;
51005 var north = rs["north"];
51006 var south = rs["south"];
51007 var west = rs["west"];
51008 var east = rs["east"];
51009 var center = rs["center"];
51010 //if(this.hideOnLayout){ // not supported anymore
51011 //c.el.setStyle("display", "none");
51013 if(north && north.isVisible()){
51014 var b = north.getBox();
51015 var m = north.getMargins();
51016 b.width = w - (m.left+m.right);
51019 centerY = b.height + b.y + m.bottom;
51020 centerH -= centerY;
51021 north.updateBox(this.safeBox(b));
51023 if(south && south.isVisible()){
51024 var b = south.getBox();
51025 var m = south.getMargins();
51026 b.width = w - (m.left+m.right);
51028 var totalHeight = (b.height + m.top + m.bottom);
51029 b.y = h - totalHeight + m.top;
51030 centerH -= totalHeight;
51031 south.updateBox(this.safeBox(b));
51033 if(west && west.isVisible()){
51034 var b = west.getBox();
51035 var m = west.getMargins();
51036 b.height = centerH - (m.top+m.bottom);
51038 b.y = centerY + m.top;
51039 var totalWidth = (b.width + m.left + m.right);
51040 centerX += totalWidth;
51041 centerW -= totalWidth;
51042 west.updateBox(this.safeBox(b));
51044 if(east && east.isVisible()){
51045 var b = east.getBox();
51046 var m = east.getMargins();
51047 b.height = centerH - (m.top+m.bottom);
51048 var totalWidth = (b.width + m.left + m.right);
51049 b.x = w - totalWidth + m.left;
51050 b.y = centerY + m.top;
51051 centerW -= totalWidth;
51052 east.updateBox(this.safeBox(b));
51055 var m = center.getMargins();
51057 x: centerX + m.left,
51058 y: centerY + m.top,
51059 width: centerW - (m.left+m.right),
51060 height: centerH - (m.top+m.bottom)
51062 //if(this.hideOnLayout){
51063 //center.el.setStyle("display", "block");
51065 center.updateBox(this.safeBox(centerBox));
51068 this.fireEvent("layout", this);
51072 safeBox : function(box){
51073 box.width = Math.max(0, box.width);
51074 box.height = Math.max(0, box.height);
51079 * Adds a ContentPanel (or subclass) to this layout.
51080 * @param {String} target The target region key (north, south, east, west or center).
51081 * @param {Roo.ContentPanel} panel The panel to add
51082 * @return {Roo.ContentPanel} The added panel
51084 add : function(target, panel){
51086 target = target.toLowerCase();
51087 return this.regions[target].add(panel);
51091 * Remove a ContentPanel (or subclass) to this layout.
51092 * @param {String} target The target region key (north, south, east, west or center).
51093 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51094 * @return {Roo.ContentPanel} The removed panel
51096 remove : function(target, panel){
51097 target = target.toLowerCase();
51098 return this.regions[target].remove(panel);
51102 * Searches all regions for a panel with the specified id
51103 * @param {String} panelId
51104 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51106 findPanel : function(panelId){
51107 var rs = this.regions;
51108 for(var target in rs){
51109 if(typeof rs[target] != "function"){
51110 var p = rs[target].getPanel(panelId);
51120 * Searches all regions for a panel with the specified id and activates (shows) it.
51121 * @param {String/ContentPanel} panelId The panels id or the panel itself
51122 * @return {Roo.ContentPanel} The shown panel or null
51124 showPanel : function(panelId) {
51125 var rs = this.regions;
51126 for(var target in rs){
51127 var r = rs[target];
51128 if(typeof r != "function"){
51129 if(r.hasPanel(panelId)){
51130 return r.showPanel(panelId);
51138 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51139 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51141 restoreState : function(provider){
51143 provider = Roo.state.Manager;
51145 var sm = new Roo.LayoutStateManager();
51146 sm.init(this, provider);
51150 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51151 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51152 * a valid ContentPanel config object. Example:
51154 // Create the main layout
51155 var layout = new Roo.BorderLayout('main-ct', {
51166 // Create and add multiple ContentPanels at once via configs
51169 id: 'source-files',
51171 title:'Ext Source Files',
51184 * @param {Object} regions An object containing ContentPanel configs by region name
51186 batchAdd : function(regions){
51187 this.beginUpdate();
51188 for(var rname in regions){
51189 var lr = this.regions[rname];
51191 this.addTypedPanels(lr, regions[rname]);
51198 addTypedPanels : function(lr, ps){
51199 if(typeof ps == 'string'){
51200 lr.add(new Roo.ContentPanel(ps));
51202 else if(ps instanceof Array){
51203 for(var i =0, len = ps.length; i < len; i++){
51204 this.addTypedPanels(lr, ps[i]);
51207 else if(!ps.events){ // raw config?
51209 delete ps.el; // prevent conflict
51210 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51212 else { // panel object assumed!
51217 * Adds a xtype elements to the layout.
51221 xtype : 'ContentPanel',
51228 xtype : 'NestedLayoutPanel',
51234 items : [ ... list of content panels or nested layout panels.. ]
51238 * @param {Object} cfg Xtype definition of item to add.
51240 addxtype : function(cfg)
51242 // basically accepts a pannel...
51243 // can accept a layout region..!?!?
51244 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51246 if (!cfg.xtype.match(/Panel$/)) {
51251 if (typeof(cfg.region) == 'undefined') {
51252 Roo.log("Failed to add Panel, region was not set");
51256 var region = cfg.region;
51262 xitems = cfg.items;
51269 case 'ContentPanel': // ContentPanel (el, cfg)
51270 case 'ScrollPanel': // ContentPanel (el, cfg)
51272 if(cfg.autoCreate) {
51273 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51275 var el = this.el.createChild();
51276 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51279 this.add(region, ret);
51283 case 'TreePanel': // our new panel!
51284 cfg.el = this.el.createChild();
51285 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51286 this.add(region, ret);
51289 case 'NestedLayoutPanel':
51290 // create a new Layout (which is a Border Layout...
51291 var el = this.el.createChild();
51292 var clayout = cfg.layout;
51294 clayout.items = clayout.items || [];
51295 // replace this exitems with the clayout ones..
51296 xitems = clayout.items;
51299 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51300 cfg.background = false;
51302 var layout = new Roo.BorderLayout(el, clayout);
51304 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51305 //console.log('adding nested layout panel ' + cfg.toSource());
51306 this.add(region, ret);
51307 nb = {}; /// find first...
51312 // needs grid and region
51314 //var el = this.getRegion(region).el.createChild();
51315 var el = this.el.createChild();
51316 // create the grid first...
51318 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51320 if (region == 'center' && this.active ) {
51321 cfg.background = false;
51323 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51325 this.add(region, ret);
51326 if (cfg.background) {
51327 ret.on('activate', function(gp) {
51328 if (!gp.grid.rendered) {
51343 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51345 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51346 this.add(region, ret);
51349 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51353 // GridPanel (grid, cfg)
51356 this.beginUpdate();
51360 Roo.each(xitems, function(i) {
51361 region = nb && i.region ? i.region : false;
51363 var add = ret.addxtype(i);
51366 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51367 if (!i.background) {
51368 abn[region] = nb[region] ;
51375 // make the last non-background panel active..
51376 //if (nb) { Roo.log(abn); }
51379 for(var r in abn) {
51380 region = this.getRegion(r);
51382 // tried using nb[r], but it does not work..
51384 region.showPanel(abn[r]);
51395 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51396 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51397 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51398 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51401 var CP = Roo.ContentPanel;
51403 var layout = Roo.BorderLayout.create({
51407 panels: [new CP("north", "North")]
51416 panels: [new CP("west", {title: "West"})]
51425 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51434 panels: [new CP("south", {title: "South", closable: true})]
51441 preferredTabWidth: 150,
51443 new CP("center1", {title: "Close Me", closable: true}),
51444 new CP("center2", {title: "Center Panel", closable: false})
51449 layout.getRegion("center").showPanel("center1");
51454 Roo.BorderLayout.create = function(config, targetEl){
51455 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51456 layout.beginUpdate();
51457 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51458 for(var j = 0, jlen = regions.length; j < jlen; j++){
51459 var lr = regions[j];
51460 if(layout.regions[lr] && config[lr].panels){
51461 var r = layout.regions[lr];
51462 var ps = config[lr].panels;
51463 layout.addTypedPanels(r, ps);
51466 layout.endUpdate();
51471 Roo.BorderLayout.RegionFactory = {
51473 validRegions : ["north","south","east","west","center"],
51476 create : function(target, mgr, config){
51477 target = target.toLowerCase();
51478 if(config.lightweight || config.basic){
51479 return new Roo.BasicLayoutRegion(mgr, config, target);
51483 return new Roo.NorthLayoutRegion(mgr, config);
51485 return new Roo.SouthLayoutRegion(mgr, config);
51487 return new Roo.EastLayoutRegion(mgr, config);
51489 return new Roo.WestLayoutRegion(mgr, config);
51491 return new Roo.CenterLayoutRegion(mgr, config);
51493 throw 'Layout region "'+target+'" not supported.';
51497 * Ext JS Library 1.1.1
51498 * Copyright(c) 2006-2007, Ext JS, LLC.
51500 * Originally Released Under LGPL - original licence link has changed is not relivant.
51503 * <script type="text/javascript">
51507 * @class Roo.BasicLayoutRegion
51508 * @extends Roo.util.Observable
51509 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51510 * and does not have a titlebar, tabs or any other features. All it does is size and position
51511 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51513 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51515 this.position = pos;
51518 * @scope Roo.BasicLayoutRegion
51522 * @event beforeremove
51523 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51524 * @param {Roo.LayoutRegion} this
51525 * @param {Roo.ContentPanel} panel The panel
51526 * @param {Object} e The cancel event object
51528 "beforeremove" : true,
51530 * @event invalidated
51531 * Fires when the layout for this region is changed.
51532 * @param {Roo.LayoutRegion} this
51534 "invalidated" : true,
51536 * @event visibilitychange
51537 * Fires when this region is shown or hidden
51538 * @param {Roo.LayoutRegion} this
51539 * @param {Boolean} visibility true or false
51541 "visibilitychange" : true,
51543 * @event paneladded
51544 * Fires when a panel is added.
51545 * @param {Roo.LayoutRegion} this
51546 * @param {Roo.ContentPanel} panel The panel
51548 "paneladded" : true,
51550 * @event panelremoved
51551 * Fires when a panel is removed.
51552 * @param {Roo.LayoutRegion} this
51553 * @param {Roo.ContentPanel} panel The panel
51555 "panelremoved" : true,
51557 * @event beforecollapse
51558 * Fires when this region before collapse.
51559 * @param {Roo.LayoutRegion} this
51561 "beforecollapse" : true,
51564 * Fires when this region is collapsed.
51565 * @param {Roo.LayoutRegion} this
51567 "collapsed" : true,
51570 * Fires when this region is expanded.
51571 * @param {Roo.LayoutRegion} this
51576 * Fires when this region is slid into view.
51577 * @param {Roo.LayoutRegion} this
51579 "slideshow" : true,
51582 * Fires when this region slides out of view.
51583 * @param {Roo.LayoutRegion} this
51585 "slidehide" : true,
51587 * @event panelactivated
51588 * Fires when a panel is activated.
51589 * @param {Roo.LayoutRegion} this
51590 * @param {Roo.ContentPanel} panel The activated panel
51592 "panelactivated" : true,
51595 * Fires when the user resizes this region.
51596 * @param {Roo.LayoutRegion} this
51597 * @param {Number} newSize The new size (width for east/west, height for north/south)
51601 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51602 this.panels = new Roo.util.MixedCollection();
51603 this.panels.getKey = this.getPanelId.createDelegate(this);
51605 this.activePanel = null;
51606 // ensure listeners are added...
51608 if (config.listeners || config.events) {
51609 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51610 listeners : config.listeners || {},
51611 events : config.events || {}
51615 if(skipConfig !== true){
51616 this.applyConfig(config);
51620 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51621 getPanelId : function(p){
51625 applyConfig : function(config){
51626 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51627 this.config = config;
51632 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51633 * the width, for horizontal (north, south) the height.
51634 * @param {Number} newSize The new width or height
51636 resizeTo : function(newSize){
51637 var el = this.el ? this.el :
51638 (this.activePanel ? this.activePanel.getEl() : null);
51640 switch(this.position){
51643 el.setWidth(newSize);
51644 this.fireEvent("resized", this, newSize);
51648 el.setHeight(newSize);
51649 this.fireEvent("resized", this, newSize);
51655 getBox : function(){
51656 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51659 getMargins : function(){
51660 return this.margins;
51663 updateBox : function(box){
51665 var el = this.activePanel.getEl();
51666 el.dom.style.left = box.x + "px";
51667 el.dom.style.top = box.y + "px";
51668 this.activePanel.setSize(box.width, box.height);
51672 * Returns the container element for this region.
51673 * @return {Roo.Element}
51675 getEl : function(){
51676 return this.activePanel;
51680 * Returns true if this region is currently visible.
51681 * @return {Boolean}
51683 isVisible : function(){
51684 return this.activePanel ? true : false;
51687 setActivePanel : function(panel){
51688 panel = this.getPanel(panel);
51689 if(this.activePanel && this.activePanel != panel){
51690 this.activePanel.setActiveState(false);
51691 this.activePanel.getEl().setLeftTop(-10000,-10000);
51693 this.activePanel = panel;
51694 panel.setActiveState(true);
51696 panel.setSize(this.box.width, this.box.height);
51698 this.fireEvent("panelactivated", this, panel);
51699 this.fireEvent("invalidated");
51703 * Show the specified panel.
51704 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51705 * @return {Roo.ContentPanel} The shown panel or null
51707 showPanel : function(panel){
51708 if(panel = this.getPanel(panel)){
51709 this.setActivePanel(panel);
51715 * Get the active panel for this region.
51716 * @return {Roo.ContentPanel} The active panel or null
51718 getActivePanel : function(){
51719 return this.activePanel;
51723 * Add the passed ContentPanel(s)
51724 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51725 * @return {Roo.ContentPanel} The panel added (if only one was added)
51727 add : function(panel){
51728 if(arguments.length > 1){
51729 for(var i = 0, len = arguments.length; i < len; i++) {
51730 this.add(arguments[i]);
51734 if(this.hasPanel(panel)){
51735 this.showPanel(panel);
51738 var el = panel.getEl();
51739 if(el.dom.parentNode != this.mgr.el.dom){
51740 this.mgr.el.dom.appendChild(el.dom);
51742 if(panel.setRegion){
51743 panel.setRegion(this);
51745 this.panels.add(panel);
51746 el.setStyle("position", "absolute");
51747 if(!panel.background){
51748 this.setActivePanel(panel);
51749 if(this.config.initialSize && this.panels.getCount()==1){
51750 this.resizeTo(this.config.initialSize);
51753 this.fireEvent("paneladded", this, panel);
51758 * Returns true if the panel is in this region.
51759 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51760 * @return {Boolean}
51762 hasPanel : function(panel){
51763 if(typeof panel == "object"){ // must be panel obj
51764 panel = panel.getId();
51766 return this.getPanel(panel) ? true : false;
51770 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51771 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51772 * @param {Boolean} preservePanel Overrides the config preservePanel option
51773 * @return {Roo.ContentPanel} The panel that was removed
51775 remove : function(panel, preservePanel){
51776 panel = this.getPanel(panel);
51781 this.fireEvent("beforeremove", this, panel, e);
51782 if(e.cancel === true){
51785 var panelId = panel.getId();
51786 this.panels.removeKey(panelId);
51791 * Returns the panel specified or null if it's not in this region.
51792 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51793 * @return {Roo.ContentPanel}
51795 getPanel : function(id){
51796 if(typeof id == "object"){ // must be panel obj
51799 return this.panels.get(id);
51803 * Returns this regions position (north/south/east/west/center).
51806 getPosition: function(){
51807 return this.position;
51811 * Ext JS Library 1.1.1
51812 * Copyright(c) 2006-2007, Ext JS, LLC.
51814 * Originally Released Under LGPL - original licence link has changed is not relivant.
51817 * <script type="text/javascript">
51821 * @class Roo.LayoutRegion
51822 * @extends Roo.BasicLayoutRegion
51823 * This class represents a region in a layout manager.
51824 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51825 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51826 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51827 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51828 * @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})
51829 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51830 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51831 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51832 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51833 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51834 * @cfg {String} title The title for the region (overrides panel titles)
51835 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51836 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51837 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51838 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51839 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51840 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51841 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51842 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51843 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51844 * @cfg {Boolean} showPin True to show a pin button
51845 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51846 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51847 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51848 * @cfg {Number} width For East/West panels
51849 * @cfg {Number} height For North/South panels
51850 * @cfg {Boolean} split To show the splitter
51851 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51853 Roo.LayoutRegion = function(mgr, config, pos){
51854 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51855 var dh = Roo.DomHelper;
51856 /** This region's container element
51857 * @type Roo.Element */
51858 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51859 /** This region's title element
51860 * @type Roo.Element */
51862 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51863 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51864 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51866 this.titleEl.enableDisplayMode();
51867 /** This region's title text element
51868 * @type HTMLElement */
51869 this.titleTextEl = this.titleEl.dom.firstChild;
51870 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
51871 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
51872 this.closeBtn.enableDisplayMode();
51873 this.closeBtn.on("click", this.closeClicked, this);
51874 this.closeBtn.hide();
51876 this.createBody(config);
51877 this.visible = true;
51878 this.collapsed = false;
51880 if(config.hideWhenEmpty){
51882 this.on("paneladded", this.validateVisibility, this);
51883 this.on("panelremoved", this.validateVisibility, this);
51885 this.applyConfig(config);
51888 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
51890 createBody : function(){
51891 /** This region's body element
51892 * @type Roo.Element */
51893 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
51896 applyConfig : function(c){
51897 if(c.collapsible && this.position != "center" && !this.collapsedEl){
51898 var dh = Roo.DomHelper;
51899 if(c.titlebar !== false){
51900 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
51901 this.collapseBtn.on("click", this.collapse, this);
51902 this.collapseBtn.enableDisplayMode();
51904 if(c.showPin === true || this.showPin){
51905 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
51906 this.stickBtn.enableDisplayMode();
51907 this.stickBtn.on("click", this.expand, this);
51908 this.stickBtn.hide();
51911 /** This region's collapsed element
51912 * @type Roo.Element */
51913 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
51914 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
51916 if(c.floatable !== false){
51917 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
51918 this.collapsedEl.on("click", this.collapseClick, this);
51921 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
51922 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
51923 id: "message", unselectable: "on", style:{"float":"left"}});
51924 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
51926 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
51927 this.expandBtn.on("click", this.expand, this);
51929 if(this.collapseBtn){
51930 this.collapseBtn.setVisible(c.collapsible == true);
51932 this.cmargins = c.cmargins || this.cmargins ||
51933 (this.position == "west" || this.position == "east" ?
51934 {top: 0, left: 2, right:2, bottom: 0} :
51935 {top: 2, left: 0, right:0, bottom: 2});
51936 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51937 this.bottomTabs = c.tabPosition != "top";
51938 this.autoScroll = c.autoScroll || false;
51939 if(this.autoScroll){
51940 this.bodyEl.setStyle("overflow", "auto");
51942 this.bodyEl.setStyle("overflow", "hidden");
51944 //if(c.titlebar !== false){
51945 if((!c.titlebar && !c.title) || c.titlebar === false){
51946 this.titleEl.hide();
51948 this.titleEl.show();
51950 this.titleTextEl.innerHTML = c.title;
51954 this.duration = c.duration || .30;
51955 this.slideDuration = c.slideDuration || .45;
51958 this.collapse(true);
51965 * Returns true if this region is currently visible.
51966 * @return {Boolean}
51968 isVisible : function(){
51969 return this.visible;
51973 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
51974 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
51976 setCollapsedTitle : function(title){
51977 title = title || " ";
51978 if(this.collapsedTitleTextEl){
51979 this.collapsedTitleTextEl.innerHTML = title;
51983 getBox : function(){
51985 if(!this.collapsed){
51986 b = this.el.getBox(false, true);
51988 b = this.collapsedEl.getBox(false, true);
51993 getMargins : function(){
51994 return this.collapsed ? this.cmargins : this.margins;
51997 highlight : function(){
51998 this.el.addClass("x-layout-panel-dragover");
52001 unhighlight : function(){
52002 this.el.removeClass("x-layout-panel-dragover");
52005 updateBox : function(box){
52007 if(!this.collapsed){
52008 this.el.dom.style.left = box.x + "px";
52009 this.el.dom.style.top = box.y + "px";
52010 this.updateBody(box.width, box.height);
52012 this.collapsedEl.dom.style.left = box.x + "px";
52013 this.collapsedEl.dom.style.top = box.y + "px";
52014 this.collapsedEl.setSize(box.width, box.height);
52017 this.tabs.autoSizeTabs();
52021 updateBody : function(w, h){
52023 this.el.setWidth(w);
52024 w -= this.el.getBorderWidth("rl");
52025 if(this.config.adjustments){
52026 w += this.config.adjustments[0];
52030 this.el.setHeight(h);
52031 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52032 h -= this.el.getBorderWidth("tb");
52033 if(this.config.adjustments){
52034 h += this.config.adjustments[1];
52036 this.bodyEl.setHeight(h);
52038 h = this.tabs.syncHeight(h);
52041 if(this.panelSize){
52042 w = w !== null ? w : this.panelSize.width;
52043 h = h !== null ? h : this.panelSize.height;
52045 if(this.activePanel){
52046 var el = this.activePanel.getEl();
52047 w = w !== null ? w : el.getWidth();
52048 h = h !== null ? h : el.getHeight();
52049 this.panelSize = {width: w, height: h};
52050 this.activePanel.setSize(w, h);
52052 if(Roo.isIE && this.tabs){
52053 this.tabs.el.repaint();
52058 * Returns the container element for this region.
52059 * @return {Roo.Element}
52061 getEl : function(){
52066 * Hides this region.
52069 if(!this.collapsed){
52070 this.el.dom.style.left = "-2000px";
52073 this.collapsedEl.dom.style.left = "-2000px";
52074 this.collapsedEl.hide();
52076 this.visible = false;
52077 this.fireEvent("visibilitychange", this, false);
52081 * Shows this region if it was previously hidden.
52084 if(!this.collapsed){
52087 this.collapsedEl.show();
52089 this.visible = true;
52090 this.fireEvent("visibilitychange", this, true);
52093 closeClicked : function(){
52094 if(this.activePanel){
52095 this.remove(this.activePanel);
52099 collapseClick : function(e){
52101 e.stopPropagation();
52104 e.stopPropagation();
52110 * Collapses this region.
52111 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52113 collapse : function(skipAnim, skipCheck = false){
52114 if(this.collapsed) {
52118 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52120 this.collapsed = true;
52122 this.split.el.hide();
52124 if(this.config.animate && skipAnim !== true){
52125 this.fireEvent("invalidated", this);
52126 this.animateCollapse();
52128 this.el.setLocation(-20000,-20000);
52130 this.collapsedEl.show();
52131 this.fireEvent("collapsed", this);
52132 this.fireEvent("invalidated", this);
52138 animateCollapse : function(){
52143 * Expands this region if it was previously collapsed.
52144 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52145 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52147 expand : function(e, skipAnim){
52149 e.stopPropagation();
52151 if(!this.collapsed || this.el.hasActiveFx()) {
52155 this.afterSlideIn();
52158 this.collapsed = false;
52159 if(this.config.animate && skipAnim !== true){
52160 this.animateExpand();
52164 this.split.el.show();
52166 this.collapsedEl.setLocation(-2000,-2000);
52167 this.collapsedEl.hide();
52168 this.fireEvent("invalidated", this);
52169 this.fireEvent("expanded", this);
52173 animateExpand : function(){
52177 initTabs : function()
52179 this.bodyEl.setStyle("overflow", "hidden");
52180 var ts = new Roo.TabPanel(
52183 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52184 disableTooltips: this.config.disableTabTips,
52185 toolbar : this.config.toolbar
52188 if(this.config.hideTabs){
52189 ts.stripWrap.setDisplayed(false);
52192 ts.resizeTabs = this.config.resizeTabs === true;
52193 ts.minTabWidth = this.config.minTabWidth || 40;
52194 ts.maxTabWidth = this.config.maxTabWidth || 250;
52195 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52196 ts.monitorResize = false;
52197 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52198 ts.bodyEl.addClass('x-layout-tabs-body');
52199 this.panels.each(this.initPanelAsTab, this);
52202 initPanelAsTab : function(panel){
52203 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52204 this.config.closeOnTab && panel.isClosable());
52205 if(panel.tabTip !== undefined){
52206 ti.setTooltip(panel.tabTip);
52208 ti.on("activate", function(){
52209 this.setActivePanel(panel);
52211 if(this.config.closeOnTab){
52212 ti.on("beforeclose", function(t, e){
52214 this.remove(panel);
52220 updatePanelTitle : function(panel, title){
52221 if(this.activePanel == panel){
52222 this.updateTitle(title);
52225 var ti = this.tabs.getTab(panel.getEl().id);
52227 if(panel.tabTip !== undefined){
52228 ti.setTooltip(panel.tabTip);
52233 updateTitle : function(title){
52234 if(this.titleTextEl && !this.config.title){
52235 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52239 setActivePanel : function(panel){
52240 panel = this.getPanel(panel);
52241 if(this.activePanel && this.activePanel != panel){
52242 this.activePanel.setActiveState(false);
52244 this.activePanel = panel;
52245 panel.setActiveState(true);
52246 if(this.panelSize){
52247 panel.setSize(this.panelSize.width, this.panelSize.height);
52250 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52252 this.updateTitle(panel.getTitle());
52254 this.fireEvent("invalidated", this);
52256 this.fireEvent("panelactivated", this, panel);
52260 * Shows the specified panel.
52261 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52262 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52264 showPanel : function(panel)
52266 panel = this.getPanel(panel);
52269 var tab = this.tabs.getTab(panel.getEl().id);
52270 if(tab.isHidden()){
52271 this.tabs.unhideTab(tab.id);
52275 this.setActivePanel(panel);
52282 * Get the active panel for this region.
52283 * @return {Roo.ContentPanel} The active panel or null
52285 getActivePanel : function(){
52286 return this.activePanel;
52289 validateVisibility : function(){
52290 if(this.panels.getCount() < 1){
52291 this.updateTitle(" ");
52292 this.closeBtn.hide();
52295 if(!this.isVisible()){
52302 * Adds the passed ContentPanel(s) to this region.
52303 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52304 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52306 add : function(panel){
52307 if(arguments.length > 1){
52308 for(var i = 0, len = arguments.length; i < len; i++) {
52309 this.add(arguments[i]);
52313 if(this.hasPanel(panel)){
52314 this.showPanel(panel);
52317 panel.setRegion(this);
52318 this.panels.add(panel);
52319 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52320 this.bodyEl.dom.appendChild(panel.getEl().dom);
52321 if(panel.background !== true){
52322 this.setActivePanel(panel);
52324 this.fireEvent("paneladded", this, panel);
52330 this.initPanelAsTab(panel);
52332 if(panel.background !== true){
52333 this.tabs.activate(panel.getEl().id);
52335 this.fireEvent("paneladded", this, panel);
52340 * Hides the tab for the specified panel.
52341 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52343 hidePanel : function(panel){
52344 if(this.tabs && (panel = this.getPanel(panel))){
52345 this.tabs.hideTab(panel.getEl().id);
52350 * Unhides the tab for a previously hidden panel.
52351 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52353 unhidePanel : function(panel){
52354 if(this.tabs && (panel = this.getPanel(panel))){
52355 this.tabs.unhideTab(panel.getEl().id);
52359 clearPanels : function(){
52360 while(this.panels.getCount() > 0){
52361 this.remove(this.panels.first());
52366 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52367 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52368 * @param {Boolean} preservePanel Overrides the config preservePanel option
52369 * @return {Roo.ContentPanel} The panel that was removed
52371 remove : function(panel, preservePanel){
52372 panel = this.getPanel(panel);
52377 this.fireEvent("beforeremove", this, panel, e);
52378 if(e.cancel === true){
52381 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52382 var panelId = panel.getId();
52383 this.panels.removeKey(panelId);
52385 document.body.appendChild(panel.getEl().dom);
52388 this.tabs.removeTab(panel.getEl().id);
52389 }else if (!preservePanel){
52390 this.bodyEl.dom.removeChild(panel.getEl().dom);
52392 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52393 var p = this.panels.first();
52394 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52395 tempEl.appendChild(p.getEl().dom);
52396 this.bodyEl.update("");
52397 this.bodyEl.dom.appendChild(p.getEl().dom);
52399 this.updateTitle(p.getTitle());
52401 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52402 this.setActivePanel(p);
52404 panel.setRegion(null);
52405 if(this.activePanel == panel){
52406 this.activePanel = null;
52408 if(this.config.autoDestroy !== false && preservePanel !== true){
52409 try{panel.destroy();}catch(e){}
52411 this.fireEvent("panelremoved", this, panel);
52416 * Returns the TabPanel component used by this region
52417 * @return {Roo.TabPanel}
52419 getTabs : function(){
52423 createTool : function(parentEl, className){
52424 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52425 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52426 btn.addClassOnOver("x-layout-tools-button-over");
52431 * Ext JS Library 1.1.1
52432 * Copyright(c) 2006-2007, Ext JS, LLC.
52434 * Originally Released Under LGPL - original licence link has changed is not relivant.
52437 * <script type="text/javascript">
52443 * @class Roo.SplitLayoutRegion
52444 * @extends Roo.LayoutRegion
52445 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52447 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52448 this.cursor = cursor;
52449 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52452 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52453 splitTip : "Drag to resize.",
52454 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52455 useSplitTips : false,
52457 applyConfig : function(config){
52458 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52461 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52462 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52463 /** The SplitBar for this region
52464 * @type Roo.SplitBar */
52465 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52466 this.split.on("moved", this.onSplitMove, this);
52467 this.split.useShim = config.useShim === true;
52468 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52469 if(this.useSplitTips){
52470 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52472 if(config.collapsible){
52473 this.split.el.on("dblclick", this.collapse, this);
52476 if(typeof config.minSize != "undefined"){
52477 this.split.minSize = config.minSize;
52479 if(typeof config.maxSize != "undefined"){
52480 this.split.maxSize = config.maxSize;
52482 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52483 this.hideSplitter();
52488 getHMaxSize : function(){
52489 var cmax = this.config.maxSize || 10000;
52490 var center = this.mgr.getRegion("center");
52491 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52494 getVMaxSize : function(){
52495 var cmax = this.config.maxSize || 10000;
52496 var center = this.mgr.getRegion("center");
52497 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52500 onSplitMove : function(split, newSize){
52501 this.fireEvent("resized", this, newSize);
52505 * Returns the {@link Roo.SplitBar} for this region.
52506 * @return {Roo.SplitBar}
52508 getSplitBar : function(){
52513 this.hideSplitter();
52514 Roo.SplitLayoutRegion.superclass.hide.call(this);
52517 hideSplitter : function(){
52519 this.split.el.setLocation(-2000,-2000);
52520 this.split.el.hide();
52526 this.split.el.show();
52528 Roo.SplitLayoutRegion.superclass.show.call(this);
52531 beforeSlide: function(){
52532 if(Roo.isGecko){// firefox overflow auto bug workaround
52533 this.bodyEl.clip();
52535 this.tabs.bodyEl.clip();
52537 if(this.activePanel){
52538 this.activePanel.getEl().clip();
52540 if(this.activePanel.beforeSlide){
52541 this.activePanel.beforeSlide();
52547 afterSlide : function(){
52548 if(Roo.isGecko){// firefox overflow auto bug workaround
52549 this.bodyEl.unclip();
52551 this.tabs.bodyEl.unclip();
52553 if(this.activePanel){
52554 this.activePanel.getEl().unclip();
52555 if(this.activePanel.afterSlide){
52556 this.activePanel.afterSlide();
52562 initAutoHide : function(){
52563 if(this.autoHide !== false){
52564 if(!this.autoHideHd){
52565 var st = new Roo.util.DelayedTask(this.slideIn, this);
52566 this.autoHideHd = {
52567 "mouseout": function(e){
52568 if(!e.within(this.el, true)){
52572 "mouseover" : function(e){
52578 this.el.on(this.autoHideHd);
52582 clearAutoHide : function(){
52583 if(this.autoHide !== false){
52584 this.el.un("mouseout", this.autoHideHd.mouseout);
52585 this.el.un("mouseover", this.autoHideHd.mouseover);
52589 clearMonitor : function(){
52590 Roo.get(document).un("click", this.slideInIf, this);
52593 // these names are backwards but not changed for compat
52594 slideOut : function(){
52595 if(this.isSlid || this.el.hasActiveFx()){
52598 this.isSlid = true;
52599 if(this.collapseBtn){
52600 this.collapseBtn.hide();
52602 this.closeBtnState = this.closeBtn.getStyle('display');
52603 this.closeBtn.hide();
52605 this.stickBtn.show();
52608 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52609 this.beforeSlide();
52610 this.el.setStyle("z-index", 10001);
52611 this.el.slideIn(this.getSlideAnchor(), {
52612 callback: function(){
52614 this.initAutoHide();
52615 Roo.get(document).on("click", this.slideInIf, this);
52616 this.fireEvent("slideshow", this);
52623 afterSlideIn : function(){
52624 this.clearAutoHide();
52625 this.isSlid = false;
52626 this.clearMonitor();
52627 this.el.setStyle("z-index", "");
52628 if(this.collapseBtn){
52629 this.collapseBtn.show();
52631 this.closeBtn.setStyle('display', this.closeBtnState);
52633 this.stickBtn.hide();
52635 this.fireEvent("slidehide", this);
52638 slideIn : function(cb){
52639 if(!this.isSlid || this.el.hasActiveFx()){
52643 this.isSlid = false;
52644 this.beforeSlide();
52645 this.el.slideOut(this.getSlideAnchor(), {
52646 callback: function(){
52647 this.el.setLeftTop(-10000, -10000);
52649 this.afterSlideIn();
52657 slideInIf : function(e){
52658 if(!e.within(this.el)){
52663 animateCollapse : function(){
52664 this.beforeSlide();
52665 this.el.setStyle("z-index", 20000);
52666 var anchor = this.getSlideAnchor();
52667 this.el.slideOut(anchor, {
52668 callback : function(){
52669 this.el.setStyle("z-index", "");
52670 this.collapsedEl.slideIn(anchor, {duration:.3});
52672 this.el.setLocation(-10000,-10000);
52674 this.fireEvent("collapsed", this);
52681 animateExpand : function(){
52682 this.beforeSlide();
52683 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52684 this.el.setStyle("z-index", 20000);
52685 this.collapsedEl.hide({
52688 this.el.slideIn(this.getSlideAnchor(), {
52689 callback : function(){
52690 this.el.setStyle("z-index", "");
52693 this.split.el.show();
52695 this.fireEvent("invalidated", this);
52696 this.fireEvent("expanded", this);
52724 getAnchor : function(){
52725 return this.anchors[this.position];
52728 getCollapseAnchor : function(){
52729 return this.canchors[this.position];
52732 getSlideAnchor : function(){
52733 return this.sanchors[this.position];
52736 getAlignAdj : function(){
52737 var cm = this.cmargins;
52738 switch(this.position){
52754 getExpandAdj : function(){
52755 var c = this.collapsedEl, cm = this.cmargins;
52756 switch(this.position){
52758 return [-(cm.right+c.getWidth()+cm.left), 0];
52761 return [cm.right+c.getWidth()+cm.left, 0];
52764 return [0, -(cm.top+cm.bottom+c.getHeight())];
52767 return [0, cm.top+cm.bottom+c.getHeight()];
52773 * Ext JS Library 1.1.1
52774 * Copyright(c) 2006-2007, Ext JS, LLC.
52776 * Originally Released Under LGPL - original licence link has changed is not relivant.
52779 * <script type="text/javascript">
52782 * These classes are private internal classes
52784 Roo.CenterLayoutRegion = function(mgr, config){
52785 Roo.LayoutRegion.call(this, mgr, config, "center");
52786 this.visible = true;
52787 this.minWidth = config.minWidth || 20;
52788 this.minHeight = config.minHeight || 20;
52791 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52793 // center panel can't be hidden
52797 // center panel can't be hidden
52800 getMinWidth: function(){
52801 return this.minWidth;
52804 getMinHeight: function(){
52805 return this.minHeight;
52810 Roo.NorthLayoutRegion = function(mgr, config){
52811 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52813 this.split.placement = Roo.SplitBar.TOP;
52814 this.split.orientation = Roo.SplitBar.VERTICAL;
52815 this.split.el.addClass("x-layout-split-v");
52817 var size = config.initialSize || config.height;
52818 if(typeof size != "undefined"){
52819 this.el.setHeight(size);
52822 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52823 orientation: Roo.SplitBar.VERTICAL,
52824 getBox : function(){
52825 if(this.collapsed){
52826 return this.collapsedEl.getBox();
52828 var box = this.el.getBox();
52830 box.height += this.split.el.getHeight();
52835 updateBox : function(box){
52836 if(this.split && !this.collapsed){
52837 box.height -= this.split.el.getHeight();
52838 this.split.el.setLeft(box.x);
52839 this.split.el.setTop(box.y+box.height);
52840 this.split.el.setWidth(box.width);
52842 if(this.collapsed){
52843 this.updateBody(box.width, null);
52845 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52849 Roo.SouthLayoutRegion = function(mgr, config){
52850 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52852 this.split.placement = Roo.SplitBar.BOTTOM;
52853 this.split.orientation = Roo.SplitBar.VERTICAL;
52854 this.split.el.addClass("x-layout-split-v");
52856 var size = config.initialSize || config.height;
52857 if(typeof size != "undefined"){
52858 this.el.setHeight(size);
52861 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52862 orientation: Roo.SplitBar.VERTICAL,
52863 getBox : function(){
52864 if(this.collapsed){
52865 return this.collapsedEl.getBox();
52867 var box = this.el.getBox();
52869 var sh = this.split.el.getHeight();
52876 updateBox : function(box){
52877 if(this.split && !this.collapsed){
52878 var sh = this.split.el.getHeight();
52881 this.split.el.setLeft(box.x);
52882 this.split.el.setTop(box.y-sh);
52883 this.split.el.setWidth(box.width);
52885 if(this.collapsed){
52886 this.updateBody(box.width, null);
52888 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52892 Roo.EastLayoutRegion = function(mgr, config){
52893 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
52895 this.split.placement = Roo.SplitBar.RIGHT;
52896 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52897 this.split.el.addClass("x-layout-split-h");
52899 var size = config.initialSize || config.width;
52900 if(typeof size != "undefined"){
52901 this.el.setWidth(size);
52904 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
52905 orientation: Roo.SplitBar.HORIZONTAL,
52906 getBox : function(){
52907 if(this.collapsed){
52908 return this.collapsedEl.getBox();
52910 var box = this.el.getBox();
52912 var sw = this.split.el.getWidth();
52919 updateBox : function(box){
52920 if(this.split && !this.collapsed){
52921 var sw = this.split.el.getWidth();
52923 this.split.el.setLeft(box.x);
52924 this.split.el.setTop(box.y);
52925 this.split.el.setHeight(box.height);
52928 if(this.collapsed){
52929 this.updateBody(null, box.height);
52931 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52935 Roo.WestLayoutRegion = function(mgr, config){
52936 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
52938 this.split.placement = Roo.SplitBar.LEFT;
52939 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52940 this.split.el.addClass("x-layout-split-h");
52942 var size = config.initialSize || config.width;
52943 if(typeof size != "undefined"){
52944 this.el.setWidth(size);
52947 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
52948 orientation: Roo.SplitBar.HORIZONTAL,
52949 getBox : function(){
52950 if(this.collapsed){
52951 return this.collapsedEl.getBox();
52953 var box = this.el.getBox();
52955 box.width += this.split.el.getWidth();
52960 updateBox : function(box){
52961 if(this.split && !this.collapsed){
52962 var sw = this.split.el.getWidth();
52964 this.split.el.setLeft(box.x+box.width);
52965 this.split.el.setTop(box.y);
52966 this.split.el.setHeight(box.height);
52968 if(this.collapsed){
52969 this.updateBody(null, box.height);
52971 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52976 * Ext JS Library 1.1.1
52977 * Copyright(c) 2006-2007, Ext JS, LLC.
52979 * Originally Released Under LGPL - original licence link has changed is not relivant.
52982 * <script type="text/javascript">
52987 * Private internal class for reading and applying state
52989 Roo.LayoutStateManager = function(layout){
52990 // default empty state
52999 Roo.LayoutStateManager.prototype = {
53000 init : function(layout, provider){
53001 this.provider = provider;
53002 var state = provider.get(layout.id+"-layout-state");
53004 var wasUpdating = layout.isUpdating();
53006 layout.beginUpdate();
53008 for(var key in state){
53009 if(typeof state[key] != "function"){
53010 var rstate = state[key];
53011 var r = layout.getRegion(key);
53014 r.resizeTo(rstate.size);
53016 if(rstate.collapsed == true){
53019 r.expand(null, true);
53025 layout.endUpdate();
53027 this.state = state;
53029 this.layout = layout;
53030 layout.on("regionresized", this.onRegionResized, this);
53031 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53032 layout.on("regionexpanded", this.onRegionExpanded, this);
53035 storeState : function(){
53036 this.provider.set(this.layout.id+"-layout-state", this.state);
53039 onRegionResized : function(region, newSize){
53040 this.state[region.getPosition()].size = newSize;
53044 onRegionCollapsed : function(region){
53045 this.state[region.getPosition()].collapsed = true;
53049 onRegionExpanded : function(region){
53050 this.state[region.getPosition()].collapsed = false;
53055 * Ext JS Library 1.1.1
53056 * Copyright(c) 2006-2007, Ext JS, LLC.
53058 * Originally Released Under LGPL - original licence link has changed is not relivant.
53061 * <script type="text/javascript">
53064 * @class Roo.ContentPanel
53065 * @extends Roo.util.Observable
53066 * A basic ContentPanel element.
53067 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53068 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53069 * @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
53070 * @cfg {Boolean} closable True if the panel can be closed/removed
53071 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53072 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53073 * @cfg {Toolbar} toolbar A toolbar for this panel
53074 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53075 * @cfg {String} title The title for this panel
53076 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53077 * @cfg {String} url Calls {@link #setUrl} with this value
53078 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53079 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53080 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53081 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53084 * Create a new ContentPanel.
53085 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53086 * @param {String/Object} config A string to set only the title or a config object
53087 * @param {String} content (optional) Set the HTML content for this panel
53088 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53090 Roo.ContentPanel = function(el, config, content){
53094 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53098 if (config && config.parentLayout) {
53099 el = config.parentLayout.el.createChild();
53102 if(el.autoCreate){ // xtype is available if this is called from factory
53106 this.el = Roo.get(el);
53107 if(!this.el && config && config.autoCreate){
53108 if(typeof config.autoCreate == "object"){
53109 if(!config.autoCreate.id){
53110 config.autoCreate.id = config.id||el;
53112 this.el = Roo.DomHelper.append(document.body,
53113 config.autoCreate, true);
53115 this.el = Roo.DomHelper.append(document.body,
53116 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53119 this.closable = false;
53120 this.loaded = false;
53121 this.active = false;
53122 if(typeof config == "string"){
53123 this.title = config;
53125 Roo.apply(this, config);
53128 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53129 this.wrapEl = this.el.wrap();
53130 this.toolbar.container = this.el.insertSibling(false, 'before');
53131 this.toolbar = new Roo.Toolbar(this.toolbar);
53134 // xtype created footer. - not sure if will work as we normally have to render first..
53135 if (this.footer && !this.footer.el && this.footer.xtype) {
53136 if (!this.wrapEl) {
53137 this.wrapEl = this.el.wrap();
53140 this.footer.container = this.wrapEl.createChild();
53142 this.footer = Roo.factory(this.footer, Roo);
53147 this.resizeEl = Roo.get(this.resizeEl, true);
53149 this.resizeEl = this.el;
53151 // handle view.xtype
53159 * Fires when this panel is activated.
53160 * @param {Roo.ContentPanel} this
53164 * @event deactivate
53165 * Fires when this panel is activated.
53166 * @param {Roo.ContentPanel} this
53168 "deactivate" : true,
53172 * Fires when this panel is resized if fitToFrame is true.
53173 * @param {Roo.ContentPanel} this
53174 * @param {Number} width The width after any component adjustments
53175 * @param {Number} height The height after any component adjustments
53181 * Fires when this tab is created
53182 * @param {Roo.ContentPanel} this
53193 if(this.autoScroll){
53194 this.resizeEl.setStyle("overflow", "auto");
53196 // fix randome scrolling
53197 this.el.on('scroll', function() {
53198 Roo.log('fix random scolling');
53199 this.scrollTo('top',0);
53202 content = content || this.content;
53204 this.setContent(content);
53206 if(config && config.url){
53207 this.setUrl(this.url, this.params, this.loadOnce);
53212 Roo.ContentPanel.superclass.constructor.call(this);
53214 if (this.view && typeof(this.view.xtype) != 'undefined') {
53215 this.view.el = this.el.appendChild(document.createElement("div"));
53216 this.view = Roo.factory(this.view);
53217 this.view.render && this.view.render(false, '');
53221 this.fireEvent('render', this);
53224 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53226 setRegion : function(region){
53227 this.region = region;
53229 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53231 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53236 * Returns the toolbar for this Panel if one was configured.
53237 * @return {Roo.Toolbar}
53239 getToolbar : function(){
53240 return this.toolbar;
53243 setActiveState : function(active){
53244 this.active = active;
53246 this.fireEvent("deactivate", this);
53248 this.fireEvent("activate", this);
53252 * Updates this panel's element
53253 * @param {String} content The new content
53254 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53256 setContent : function(content, loadScripts){
53257 this.el.update(content, loadScripts);
53260 ignoreResize : function(w, h){
53261 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53264 this.lastSize = {width: w, height: h};
53269 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53270 * @return {Roo.UpdateManager} The UpdateManager
53272 getUpdateManager : function(){
53273 return this.el.getUpdateManager();
53276 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53277 * @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:
53280 url: "your-url.php",
53281 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53282 callback: yourFunction,
53283 scope: yourObject, //(optional scope)
53286 text: "Loading...",
53291 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53292 * 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.
53293 * @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}
53294 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53295 * @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.
53296 * @return {Roo.ContentPanel} this
53299 var um = this.el.getUpdateManager();
53300 um.update.apply(um, arguments);
53306 * 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.
53307 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53308 * @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)
53309 * @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)
53310 * @return {Roo.UpdateManager} The UpdateManager
53312 setUrl : function(url, params, loadOnce){
53313 if(this.refreshDelegate){
53314 this.removeListener("activate", this.refreshDelegate);
53316 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53317 this.on("activate", this.refreshDelegate);
53318 return this.el.getUpdateManager();
53321 _handleRefresh : function(url, params, loadOnce){
53322 if(!loadOnce || !this.loaded){
53323 var updater = this.el.getUpdateManager();
53324 updater.update(url, params, this._setLoaded.createDelegate(this));
53328 _setLoaded : function(){
53329 this.loaded = true;
53333 * Returns this panel's id
53336 getId : function(){
53341 * Returns this panel's element - used by regiosn to add.
53342 * @return {Roo.Element}
53344 getEl : function(){
53345 return this.wrapEl || this.el;
53348 adjustForComponents : function(width, height)
53350 //Roo.log('adjustForComponents ');
53351 if(this.resizeEl != this.el){
53352 width -= this.el.getFrameWidth('lr');
53353 height -= this.el.getFrameWidth('tb');
53356 var te = this.toolbar.getEl();
53357 height -= te.getHeight();
53358 te.setWidth(width);
53361 var te = this.footer.getEl();
53362 Roo.log("footer:" + te.getHeight());
53364 height -= te.getHeight();
53365 te.setWidth(width);
53369 if(this.adjustments){
53370 width += this.adjustments[0];
53371 height += this.adjustments[1];
53373 return {"width": width, "height": height};
53376 setSize : function(width, height){
53377 if(this.fitToFrame && !this.ignoreResize(width, height)){
53378 if(this.fitContainer && this.resizeEl != this.el){
53379 this.el.setSize(width, height);
53381 var size = this.adjustForComponents(width, height);
53382 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53383 this.fireEvent('resize', this, size.width, size.height);
53388 * Returns this panel's title
53391 getTitle : function(){
53396 * Set this panel's title
53397 * @param {String} title
53399 setTitle : function(title){
53400 this.title = title;
53402 this.region.updatePanelTitle(this, title);
53407 * Returns true is this panel was configured to be closable
53408 * @return {Boolean}
53410 isClosable : function(){
53411 return this.closable;
53414 beforeSlide : function(){
53416 this.resizeEl.clip();
53419 afterSlide : function(){
53421 this.resizeEl.unclip();
53425 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53426 * Will fail silently if the {@link #setUrl} method has not been called.
53427 * This does not activate the panel, just updates its content.
53429 refresh : function(){
53430 if(this.refreshDelegate){
53431 this.loaded = false;
53432 this.refreshDelegate();
53437 * Destroys this panel
53439 destroy : function(){
53440 this.el.removeAllListeners();
53441 var tempEl = document.createElement("span");
53442 tempEl.appendChild(this.el.dom);
53443 tempEl.innerHTML = "";
53449 * form - if the content panel contains a form - this is a reference to it.
53450 * @type {Roo.form.Form}
53454 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53455 * This contains a reference to it.
53461 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53471 * @param {Object} cfg Xtype definition of item to add.
53474 addxtype : function(cfg) {
53476 if (cfg.xtype.match(/^Form$/)) {
53479 //if (this.footer) {
53480 // el = this.footer.container.insertSibling(false, 'before');
53482 el = this.el.createChild();
53485 this.form = new Roo.form.Form(cfg);
53488 if ( this.form.allItems.length) {
53489 this.form.render(el.dom);
53493 // should only have one of theses..
53494 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53495 // views.. should not be just added - used named prop 'view''
53497 cfg.el = this.el.appendChild(document.createElement("div"));
53500 var ret = new Roo.factory(cfg);
53502 ret.render && ret.render(false, ''); // render blank..
53511 * @class Roo.GridPanel
53512 * @extends Roo.ContentPanel
53514 * Create a new GridPanel.
53515 * @param {Roo.grid.Grid} grid The grid for this panel
53516 * @param {String/Object} config A string to set only the panel's title, or a config object
53518 Roo.GridPanel = function(grid, config){
53521 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53522 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53524 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53526 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53529 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53531 // xtype created footer. - not sure if will work as we normally have to render first..
53532 if (this.footer && !this.footer.el && this.footer.xtype) {
53534 this.footer.container = this.grid.getView().getFooterPanel(true);
53535 this.footer.dataSource = this.grid.dataSource;
53536 this.footer = Roo.factory(this.footer, Roo);
53540 grid.monitorWindowResize = false; // turn off autosizing
53541 grid.autoHeight = false;
53542 grid.autoWidth = false;
53544 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53547 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53548 getId : function(){
53549 return this.grid.id;
53553 * Returns the grid for this panel
53554 * @return {Roo.grid.Grid}
53556 getGrid : function(){
53560 setSize : function(width, height){
53561 if(!this.ignoreResize(width, height)){
53562 var grid = this.grid;
53563 var size = this.adjustForComponents(width, height);
53564 grid.getGridEl().setSize(size.width, size.height);
53569 beforeSlide : function(){
53570 this.grid.getView().scroller.clip();
53573 afterSlide : function(){
53574 this.grid.getView().scroller.unclip();
53577 destroy : function(){
53578 this.grid.destroy();
53580 Roo.GridPanel.superclass.destroy.call(this);
53586 * @class Roo.NestedLayoutPanel
53587 * @extends Roo.ContentPanel
53589 * Create a new NestedLayoutPanel.
53592 * @param {Roo.BorderLayout} layout The layout for this panel
53593 * @param {String/Object} config A string to set only the title or a config object
53595 Roo.NestedLayoutPanel = function(layout, config)
53597 // construct with only one argument..
53598 /* FIXME - implement nicer consturctors
53599 if (layout.layout) {
53601 layout = config.layout;
53602 delete config.layout;
53604 if (layout.xtype && !layout.getEl) {
53605 // then layout needs constructing..
53606 layout = Roo.factory(layout, Roo);
53611 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53613 layout.monitorWindowResize = false; // turn off autosizing
53614 this.layout = layout;
53615 this.layout.getEl().addClass("x-layout-nested-layout");
53622 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53624 setSize : function(width, height){
53625 if(!this.ignoreResize(width, height)){
53626 var size = this.adjustForComponents(width, height);
53627 var el = this.layout.getEl();
53628 el.setSize(size.width, size.height);
53629 var touch = el.dom.offsetWidth;
53630 this.layout.layout();
53631 // ie requires a double layout on the first pass
53632 if(Roo.isIE && !this.initialized){
53633 this.initialized = true;
53634 this.layout.layout();
53639 // activate all subpanels if not currently active..
53641 setActiveState : function(active){
53642 this.active = active;
53644 this.fireEvent("deactivate", this);
53648 this.fireEvent("activate", this);
53649 // not sure if this should happen before or after..
53650 if (!this.layout) {
53651 return; // should not happen..
53654 for (var r in this.layout.regions) {
53655 reg = this.layout.getRegion(r);
53656 if (reg.getActivePanel()) {
53657 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53658 reg.setActivePanel(reg.getActivePanel());
53661 if (!reg.panels.length) {
53664 reg.showPanel(reg.getPanel(0));
53673 * Returns the nested BorderLayout for this panel
53674 * @return {Roo.BorderLayout}
53676 getLayout : function(){
53677 return this.layout;
53681 * Adds a xtype elements to the layout of the nested panel
53685 xtype : 'ContentPanel',
53692 xtype : 'NestedLayoutPanel',
53698 items : [ ... list of content panels or nested layout panels.. ]
53702 * @param {Object} cfg Xtype definition of item to add.
53704 addxtype : function(cfg) {
53705 return this.layout.addxtype(cfg);
53710 Roo.ScrollPanel = function(el, config, content){
53711 config = config || {};
53712 config.fitToFrame = true;
53713 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53715 this.el.dom.style.overflow = "hidden";
53716 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53717 this.el.removeClass("x-layout-inactive-content");
53718 this.el.on("mousewheel", this.onWheel, this);
53720 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53721 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53722 up.unselectable(); down.unselectable();
53723 up.on("click", this.scrollUp, this);
53724 down.on("click", this.scrollDown, this);
53725 up.addClassOnOver("x-scroller-btn-over");
53726 down.addClassOnOver("x-scroller-btn-over");
53727 up.addClassOnClick("x-scroller-btn-click");
53728 down.addClassOnClick("x-scroller-btn-click");
53729 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53731 this.resizeEl = this.el;
53732 this.el = wrap; this.up = up; this.down = down;
53735 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53737 wheelIncrement : 5,
53738 scrollUp : function(){
53739 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53742 scrollDown : function(){
53743 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53746 afterScroll : function(){
53747 var el = this.resizeEl;
53748 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53749 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53750 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53753 setSize : function(){
53754 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53755 this.afterScroll();
53758 onWheel : function(e){
53759 var d = e.getWheelDelta();
53760 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53761 this.afterScroll();
53765 setContent : function(content, loadScripts){
53766 this.resizeEl.update(content, loadScripts);
53780 * @class Roo.TreePanel
53781 * @extends Roo.ContentPanel
53783 * Create a new TreePanel. - defaults to fit/scoll contents.
53784 * @param {String/Object} config A string to set only the panel's title, or a config object
53785 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53787 Roo.TreePanel = function(config){
53788 var el = config.el;
53789 var tree = config.tree;
53790 delete config.tree;
53791 delete config.el; // hopefull!
53793 // wrapper for IE7 strict & safari scroll issue
53795 var treeEl = el.createChild();
53796 config.resizeEl = treeEl;
53800 Roo.TreePanel.superclass.constructor.call(this, el, config);
53803 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53804 //console.log(tree);
53805 this.on('activate', function()
53807 if (this.tree.rendered) {
53810 //console.log('render tree');
53811 this.tree.render();
53813 // this should not be needed.. - it's actually the 'el' that resizes?
53814 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53816 //this.on('resize', function (cp, w, h) {
53817 // this.tree.innerCt.setWidth(w);
53818 // this.tree.innerCt.setHeight(h);
53819 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53826 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53843 * Ext JS Library 1.1.1
53844 * Copyright(c) 2006-2007, Ext JS, LLC.
53846 * Originally Released Under LGPL - original licence link has changed is not relivant.
53849 * <script type="text/javascript">
53854 * @class Roo.ReaderLayout
53855 * @extends Roo.BorderLayout
53856 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53857 * center region containing two nested regions (a top one for a list view and one for item preview below),
53858 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53859 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53860 * expedites the setup of the overall layout and regions for this common application style.
53863 var reader = new Roo.ReaderLayout();
53864 var CP = Roo.ContentPanel; // shortcut for adding
53866 reader.beginUpdate();
53867 reader.add("north", new CP("north", "North"));
53868 reader.add("west", new CP("west", {title: "West"}));
53869 reader.add("east", new CP("east", {title: "East"}));
53871 reader.regions.listView.add(new CP("listView", "List"));
53872 reader.regions.preview.add(new CP("preview", "Preview"));
53873 reader.endUpdate();
53876 * Create a new ReaderLayout
53877 * @param {Object} config Configuration options
53878 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
53879 * document.body if omitted)
53881 Roo.ReaderLayout = function(config, renderTo){
53882 var c = config || {size:{}};
53883 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
53884 north: c.north !== false ? Roo.apply({
53888 }, c.north) : false,
53889 west: c.west !== false ? Roo.apply({
53897 margins:{left:5,right:0,bottom:5,top:5},
53898 cmargins:{left:5,right:5,bottom:5,top:5}
53899 }, c.west) : false,
53900 east: c.east !== false ? Roo.apply({
53908 margins:{left:0,right:5,bottom:5,top:5},
53909 cmargins:{left:5,right:5,bottom:5,top:5}
53910 }, c.east) : false,
53911 center: Roo.apply({
53912 tabPosition: 'top',
53916 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
53920 this.el.addClass('x-reader');
53922 this.beginUpdate();
53924 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
53925 south: c.preview !== false ? Roo.apply({
53932 cmargins:{top:5,left:0, right:0, bottom:0}
53933 }, c.preview) : false,
53934 center: Roo.apply({
53940 this.add('center', new Roo.NestedLayoutPanel(inner,
53941 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
53945 this.regions.preview = inner.getRegion('south');
53946 this.regions.listView = inner.getRegion('center');
53949 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
53951 * Ext JS Library 1.1.1
53952 * Copyright(c) 2006-2007, Ext JS, LLC.
53954 * Originally Released Under LGPL - original licence link has changed is not relivant.
53957 * <script type="text/javascript">
53961 * @class Roo.grid.Grid
53962 * @extends Roo.util.Observable
53963 * This class represents the primary interface of a component based grid control.
53964 * <br><br>Usage:<pre><code>
53965 var grid = new Roo.grid.Grid("my-container-id", {
53968 selModel: mySelectionModel,
53969 autoSizeColumns: true,
53970 monitorWindowResize: false,
53971 trackMouseOver: true
53976 * <b>Common Problems:</b><br/>
53977 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
53978 * element will correct this<br/>
53979 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
53980 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
53981 * are unpredictable.<br/>
53982 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
53983 * grid to calculate dimensions/offsets.<br/>
53985 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53986 * The container MUST have some type of size defined for the grid to fill. The container will be
53987 * automatically set to position relative if it isn't already.
53988 * @param {Object} config A config object that sets properties on this grid.
53990 Roo.grid.Grid = function(container, config){
53991 // initialize the container
53992 this.container = Roo.get(container);
53993 this.container.update("");
53994 this.container.setStyle("overflow", "hidden");
53995 this.container.addClass('x-grid-container');
53997 this.id = this.container.id;
53999 Roo.apply(this, config);
54000 // check and correct shorthanded configs
54002 this.dataSource = this.ds;
54006 this.colModel = this.cm;
54010 this.selModel = this.sm;
54014 if (this.selModel) {
54015 this.selModel = Roo.factory(this.selModel, Roo.grid);
54016 this.sm = this.selModel;
54017 this.sm.xmodule = this.xmodule || false;
54019 if (typeof(this.colModel.config) == 'undefined') {
54020 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54021 this.cm = this.colModel;
54022 this.cm.xmodule = this.xmodule || false;
54024 if (this.dataSource) {
54025 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54026 this.ds = this.dataSource;
54027 this.ds.xmodule = this.xmodule || false;
54034 this.container.setWidth(this.width);
54038 this.container.setHeight(this.height);
54045 * The raw click event for the entire grid.
54046 * @param {Roo.EventObject} e
54051 * The raw dblclick event for the entire grid.
54052 * @param {Roo.EventObject} e
54056 * @event contextmenu
54057 * The raw contextmenu event for the entire grid.
54058 * @param {Roo.EventObject} e
54060 "contextmenu" : true,
54063 * The raw mousedown event for the entire grid.
54064 * @param {Roo.EventObject} e
54066 "mousedown" : true,
54069 * The raw mouseup event for the entire grid.
54070 * @param {Roo.EventObject} e
54075 * The raw mouseover event for the entire grid.
54076 * @param {Roo.EventObject} e
54078 "mouseover" : true,
54081 * The raw mouseout event for the entire grid.
54082 * @param {Roo.EventObject} e
54087 * The raw keypress event for the entire grid.
54088 * @param {Roo.EventObject} e
54093 * The raw keydown event for the entire grid.
54094 * @param {Roo.EventObject} e
54102 * Fires when a cell is clicked
54103 * @param {Grid} this
54104 * @param {Number} rowIndex
54105 * @param {Number} columnIndex
54106 * @param {Roo.EventObject} e
54108 "cellclick" : true,
54110 * @event celldblclick
54111 * Fires when a cell is double clicked
54112 * @param {Grid} this
54113 * @param {Number} rowIndex
54114 * @param {Number} columnIndex
54115 * @param {Roo.EventObject} e
54117 "celldblclick" : true,
54120 * Fires when a row is clicked
54121 * @param {Grid} this
54122 * @param {Number} rowIndex
54123 * @param {Roo.EventObject} e
54127 * @event rowdblclick
54128 * Fires when a row is double clicked
54129 * @param {Grid} this
54130 * @param {Number} rowIndex
54131 * @param {Roo.EventObject} e
54133 "rowdblclick" : true,
54135 * @event headerclick
54136 * Fires when a header is clicked
54137 * @param {Grid} this
54138 * @param {Number} columnIndex
54139 * @param {Roo.EventObject} e
54141 "headerclick" : true,
54143 * @event headerdblclick
54144 * Fires when a header cell is double clicked
54145 * @param {Grid} this
54146 * @param {Number} columnIndex
54147 * @param {Roo.EventObject} e
54149 "headerdblclick" : true,
54151 * @event rowcontextmenu
54152 * Fires when a row is right clicked
54153 * @param {Grid} this
54154 * @param {Number} rowIndex
54155 * @param {Roo.EventObject} e
54157 "rowcontextmenu" : true,
54159 * @event cellcontextmenu
54160 * Fires when a cell is right clicked
54161 * @param {Grid} this
54162 * @param {Number} rowIndex
54163 * @param {Number} cellIndex
54164 * @param {Roo.EventObject} e
54166 "cellcontextmenu" : true,
54168 * @event headercontextmenu
54169 * Fires when a header is right clicked
54170 * @param {Grid} this
54171 * @param {Number} columnIndex
54172 * @param {Roo.EventObject} e
54174 "headercontextmenu" : true,
54176 * @event bodyscroll
54177 * Fires when the body element is scrolled
54178 * @param {Number} scrollLeft
54179 * @param {Number} scrollTop
54181 "bodyscroll" : true,
54183 * @event columnresize
54184 * Fires when the user resizes a column
54185 * @param {Number} columnIndex
54186 * @param {Number} newSize
54188 "columnresize" : true,
54190 * @event columnmove
54191 * Fires when the user moves a column
54192 * @param {Number} oldIndex
54193 * @param {Number} newIndex
54195 "columnmove" : true,
54198 * Fires when row(s) start being dragged
54199 * @param {Grid} this
54200 * @param {Roo.GridDD} dd The drag drop object
54201 * @param {event} e The raw browser event
54203 "startdrag" : true,
54206 * Fires when a drag operation is complete
54207 * @param {Grid} this
54208 * @param {Roo.GridDD} dd The drag drop object
54209 * @param {event} e The raw browser event
54214 * Fires when dragged row(s) are dropped on a valid DD target
54215 * @param {Grid} this
54216 * @param {Roo.GridDD} dd The drag drop object
54217 * @param {String} targetId The target drag drop object
54218 * @param {event} e The raw browser event
54223 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54224 * @param {Grid} this
54225 * @param {Roo.GridDD} dd The drag drop object
54226 * @param {String} targetId The target drag drop object
54227 * @param {event} e The raw browser event
54232 * Fires when the dragged row(s) first cross another DD target while being dragged
54233 * @param {Grid} this
54234 * @param {Roo.GridDD} dd The drag drop object
54235 * @param {String} targetId The target drag drop object
54236 * @param {event} e The raw browser event
54238 "dragenter" : true,
54241 * Fires when the dragged row(s) leave another DD target while being dragged
54242 * @param {Grid} this
54243 * @param {Roo.GridDD} dd The drag drop object
54244 * @param {String} targetId The target drag drop object
54245 * @param {event} e The raw browser event
54250 * Fires when a row is rendered, so you can change add a style to it.
54251 * @param {GridView} gridview The grid view
54252 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54258 * Fires when the grid is rendered
54259 * @param {Grid} grid
54264 Roo.grid.Grid.superclass.constructor.call(this);
54266 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54269 * @cfg {String} ddGroup - drag drop group.
54273 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54275 minColumnWidth : 25,
54278 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54279 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54280 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54282 autoSizeColumns : false,
54285 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54287 autoSizeHeaders : true,
54290 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54292 monitorWindowResize : true,
54295 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54296 * rows measured to get a columns size. Default is 0 (all rows).
54298 maxRowsToMeasure : 0,
54301 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54303 trackMouseOver : true,
54306 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54310 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54312 enableDragDrop : false,
54315 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54317 enableColumnMove : true,
54320 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54322 enableColumnHide : true,
54325 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54327 enableRowHeightSync : false,
54330 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54335 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54337 autoHeight : false,
54340 * @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.
54342 autoExpandColumn : false,
54345 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54348 autoExpandMin : 50,
54351 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54353 autoExpandMax : 1000,
54356 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54361 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54365 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54375 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54376 * of a fixed width. Default is false.
54379 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54382 * Called once after all setup has been completed and the grid is ready to be rendered.
54383 * @return {Roo.grid.Grid} this
54385 render : function()
54387 var c = this.container;
54388 // try to detect autoHeight/width mode
54389 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54390 this.autoHeight = true;
54392 var view = this.getView();
54395 c.on("click", this.onClick, this);
54396 c.on("dblclick", this.onDblClick, this);
54397 c.on("contextmenu", this.onContextMenu, this);
54398 c.on("keydown", this.onKeyDown, this);
54400 c.on("touchstart", this.onTouchStart, this);
54403 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54405 this.getSelectionModel().init(this);
54410 this.loadMask = new Roo.LoadMask(this.container,
54411 Roo.apply({store:this.dataSource}, this.loadMask));
54415 if (this.toolbar && this.toolbar.xtype) {
54416 this.toolbar.container = this.getView().getHeaderPanel(true);
54417 this.toolbar = new Roo.Toolbar(this.toolbar);
54419 if (this.footer && this.footer.xtype) {
54420 this.footer.dataSource = this.getDataSource();
54421 this.footer.container = this.getView().getFooterPanel(true);
54422 this.footer = Roo.factory(this.footer, Roo);
54424 if (this.dropTarget && this.dropTarget.xtype) {
54425 delete this.dropTarget.xtype;
54426 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54430 this.rendered = true;
54431 this.fireEvent('render', this);
54436 * Reconfigures the grid to use a different Store and Column Model.
54437 * The View will be bound to the new objects and refreshed.
54438 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54439 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54441 reconfigure : function(dataSource, colModel){
54443 this.loadMask.destroy();
54444 this.loadMask = new Roo.LoadMask(this.container,
54445 Roo.apply({store:dataSource}, this.loadMask));
54447 this.view.bind(dataSource, colModel);
54448 this.dataSource = dataSource;
54449 this.colModel = colModel;
54450 this.view.refresh(true);
54454 onKeyDown : function(e){
54455 this.fireEvent("keydown", e);
54459 * Destroy this grid.
54460 * @param {Boolean} removeEl True to remove the element
54462 destroy : function(removeEl, keepListeners){
54464 this.loadMask.destroy();
54466 var c = this.container;
54467 c.removeAllListeners();
54468 this.view.destroy();
54469 this.colModel.purgeListeners();
54470 if(!keepListeners){
54471 this.purgeListeners();
54474 if(removeEl === true){
54480 processEvent : function(name, e){
54481 // does this fire select???
54482 //Roo.log('grid:processEvent ' + name);
54484 if (name != 'touchstart' ) {
54485 this.fireEvent(name, e);
54488 var t = e.getTarget();
54490 var header = v.findHeaderIndex(t);
54491 if(header !== false){
54492 var ename = name == 'touchstart' ? 'click' : name;
54494 this.fireEvent("header" + ename, this, header, e);
54496 var row = v.findRowIndex(t);
54497 var cell = v.findCellIndex(t);
54498 if (name == 'touchstart') {
54499 // first touch is always a click.
54500 // hopefull this happens after selection is updated.?
54503 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54504 var cs = this.selModel.getSelectedCell();
54505 if (row == cs[0] && cell == cs[1]){
54509 if (typeof(this.selModel.getSelections) != 'undefined') {
54510 var cs = this.selModel.getSelections();
54511 var ds = this.dataSource;
54512 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54523 this.fireEvent("row" + name, this, row, e);
54524 if(cell !== false){
54525 this.fireEvent("cell" + name, this, row, cell, e);
54532 onClick : function(e){
54533 this.processEvent("click", e);
54536 onTouchStart : function(e){
54537 this.processEvent("touchstart", e);
54541 onContextMenu : function(e, t){
54542 this.processEvent("contextmenu", e);
54546 onDblClick : function(e){
54547 this.processEvent("dblclick", e);
54551 walkCells : function(row, col, step, fn, scope){
54552 var cm = this.colModel, clen = cm.getColumnCount();
54553 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54565 if(fn.call(scope || this, row, col, cm) === true){
54583 if(fn.call(scope || this, row, col, cm) === true){
54595 getSelections : function(){
54596 return this.selModel.getSelections();
54600 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54601 * but if manual update is required this method will initiate it.
54603 autoSize : function(){
54605 this.view.layout();
54606 if(this.view.adjustForScroll){
54607 this.view.adjustForScroll();
54613 * Returns the grid's underlying element.
54614 * @return {Element} The element
54616 getGridEl : function(){
54617 return this.container;
54620 // private for compatibility, overridden by editor grid
54621 stopEditing : function(){},
54624 * Returns the grid's SelectionModel.
54625 * @return {SelectionModel}
54627 getSelectionModel : function(){
54628 if(!this.selModel){
54629 this.selModel = new Roo.grid.RowSelectionModel();
54631 return this.selModel;
54635 * Returns the grid's DataSource.
54636 * @return {DataSource}
54638 getDataSource : function(){
54639 return this.dataSource;
54643 * Returns the grid's ColumnModel.
54644 * @return {ColumnModel}
54646 getColumnModel : function(){
54647 return this.colModel;
54651 * Returns the grid's GridView object.
54652 * @return {GridView}
54654 getView : function(){
54656 this.view = new Roo.grid.GridView(this.viewConfig);
54661 * Called to get grid's drag proxy text, by default returns this.ddText.
54664 getDragDropText : function(){
54665 var count = this.selModel.getCount();
54666 return String.format(this.ddText, count, count == 1 ? '' : 's');
54670 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54671 * %0 is replaced with the number of selected rows.
54674 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54676 * Ext JS Library 1.1.1
54677 * Copyright(c) 2006-2007, Ext JS, LLC.
54679 * Originally Released Under LGPL - original licence link has changed is not relivant.
54682 * <script type="text/javascript">
54685 Roo.grid.AbstractGridView = function(){
54689 "beforerowremoved" : true,
54690 "beforerowsinserted" : true,
54691 "beforerefresh" : true,
54692 "rowremoved" : true,
54693 "rowsinserted" : true,
54694 "rowupdated" : true,
54697 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54700 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54701 rowClass : "x-grid-row",
54702 cellClass : "x-grid-cell",
54703 tdClass : "x-grid-td",
54704 hdClass : "x-grid-hd",
54705 splitClass : "x-grid-hd-split",
54707 init: function(grid){
54709 var cid = this.grid.getGridEl().id;
54710 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54711 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54712 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54713 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54716 getColumnRenderers : function(){
54717 var renderers = [];
54718 var cm = this.grid.colModel;
54719 var colCount = cm.getColumnCount();
54720 for(var i = 0; i < colCount; i++){
54721 renderers[i] = cm.getRenderer(i);
54726 getColumnIds : function(){
54728 var cm = this.grid.colModel;
54729 var colCount = cm.getColumnCount();
54730 for(var i = 0; i < colCount; i++){
54731 ids[i] = cm.getColumnId(i);
54736 getDataIndexes : function(){
54737 if(!this.indexMap){
54738 this.indexMap = this.buildIndexMap();
54740 return this.indexMap.colToData;
54743 getColumnIndexByDataIndex : function(dataIndex){
54744 if(!this.indexMap){
54745 this.indexMap = this.buildIndexMap();
54747 return this.indexMap.dataToCol[dataIndex];
54751 * Set a css style for a column dynamically.
54752 * @param {Number} colIndex The index of the column
54753 * @param {String} name The css property name
54754 * @param {String} value The css value
54756 setCSSStyle : function(colIndex, name, value){
54757 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54758 Roo.util.CSS.updateRule(selector, name, value);
54761 generateRules : function(cm){
54762 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54763 Roo.util.CSS.removeStyleSheet(rulesId);
54764 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54765 var cid = cm.getColumnId(i);
54766 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54767 this.tdSelector, cid, " {\n}\n",
54768 this.hdSelector, cid, " {\n}\n",
54769 this.splitSelector, cid, " {\n}\n");
54771 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54775 * Ext JS Library 1.1.1
54776 * Copyright(c) 2006-2007, Ext JS, LLC.
54778 * Originally Released Under LGPL - original licence link has changed is not relivant.
54781 * <script type="text/javascript">
54785 // This is a support class used internally by the Grid components
54786 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54788 this.view = grid.getView();
54789 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54790 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54792 this.setHandleElId(Roo.id(hd));
54793 this.setOuterHandleElId(Roo.id(hd2));
54795 this.scroll = false;
54797 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54799 getDragData : function(e){
54800 var t = Roo.lib.Event.getTarget(e);
54801 var h = this.view.findHeaderCell(t);
54803 return {ddel: h.firstChild, header:h};
54808 onInitDrag : function(e){
54809 this.view.headersDisabled = true;
54810 var clone = this.dragData.ddel.cloneNode(true);
54811 clone.id = Roo.id();
54812 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54813 this.proxy.update(clone);
54817 afterValidDrop : function(){
54819 setTimeout(function(){
54820 v.headersDisabled = false;
54824 afterInvalidDrop : function(){
54826 setTimeout(function(){
54827 v.headersDisabled = false;
54833 * Ext JS Library 1.1.1
54834 * Copyright(c) 2006-2007, Ext JS, LLC.
54836 * Originally Released Under LGPL - original licence link has changed is not relivant.
54839 * <script type="text/javascript">
54842 // This is a support class used internally by the Grid components
54843 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54845 this.view = grid.getView();
54846 // split the proxies so they don't interfere with mouse events
54847 this.proxyTop = Roo.DomHelper.append(document.body, {
54848 cls:"col-move-top", html:" "
54850 this.proxyBottom = Roo.DomHelper.append(document.body, {
54851 cls:"col-move-bottom", html:" "
54853 this.proxyTop.hide = this.proxyBottom.hide = function(){
54854 this.setLeftTop(-100,-100);
54855 this.setStyle("visibility", "hidden");
54857 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54858 // temporarily disabled
54859 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54860 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54862 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54863 proxyOffsets : [-4, -9],
54864 fly: Roo.Element.fly,
54866 getTargetFromEvent : function(e){
54867 var t = Roo.lib.Event.getTarget(e);
54868 var cindex = this.view.findCellIndex(t);
54869 if(cindex !== false){
54870 return this.view.getHeaderCell(cindex);
54875 nextVisible : function(h){
54876 var v = this.view, cm = this.grid.colModel;
54879 if(!cm.isHidden(v.getCellIndex(h))){
54887 prevVisible : function(h){
54888 var v = this.view, cm = this.grid.colModel;
54891 if(!cm.isHidden(v.getCellIndex(h))){
54899 positionIndicator : function(h, n, e){
54900 var x = Roo.lib.Event.getPageX(e);
54901 var r = Roo.lib.Dom.getRegion(n.firstChild);
54902 var px, pt, py = r.top + this.proxyOffsets[1];
54903 if((r.right - x) <= (r.right-r.left)/2){
54904 px = r.right+this.view.borderWidth;
54910 var oldIndex = this.view.getCellIndex(h);
54911 var newIndex = this.view.getCellIndex(n);
54913 if(this.grid.colModel.isFixed(newIndex)){
54917 var locked = this.grid.colModel.isLocked(newIndex);
54922 if(oldIndex < newIndex){
54925 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
54928 px += this.proxyOffsets[0];
54929 this.proxyTop.setLeftTop(px, py);
54930 this.proxyTop.show();
54931 if(!this.bottomOffset){
54932 this.bottomOffset = this.view.mainHd.getHeight();
54934 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
54935 this.proxyBottom.show();
54939 onNodeEnter : function(n, dd, e, data){
54940 if(data.header != n){
54941 this.positionIndicator(data.header, n, e);
54945 onNodeOver : function(n, dd, e, data){
54946 var result = false;
54947 if(data.header != n){
54948 result = this.positionIndicator(data.header, n, e);
54951 this.proxyTop.hide();
54952 this.proxyBottom.hide();
54954 return result ? this.dropAllowed : this.dropNotAllowed;
54957 onNodeOut : function(n, dd, e, data){
54958 this.proxyTop.hide();
54959 this.proxyBottom.hide();
54962 onNodeDrop : function(n, dd, e, data){
54963 var h = data.header;
54965 var cm = this.grid.colModel;
54966 var x = Roo.lib.Event.getPageX(e);
54967 var r = Roo.lib.Dom.getRegion(n.firstChild);
54968 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
54969 var oldIndex = this.view.getCellIndex(h);
54970 var newIndex = this.view.getCellIndex(n);
54971 var locked = cm.isLocked(newIndex);
54975 if(oldIndex < newIndex){
54978 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
54981 cm.setLocked(oldIndex, locked, true);
54982 cm.moveColumn(oldIndex, newIndex);
54983 this.grid.fireEvent("columnmove", oldIndex, newIndex);
54991 * Ext JS Library 1.1.1
54992 * Copyright(c) 2006-2007, Ext JS, LLC.
54994 * Originally Released Under LGPL - original licence link has changed is not relivant.
54997 * <script type="text/javascript">
55001 * @class Roo.grid.GridView
55002 * @extends Roo.util.Observable
55005 * @param {Object} config
55007 Roo.grid.GridView = function(config){
55008 Roo.grid.GridView.superclass.constructor.call(this);
55011 Roo.apply(this, config);
55014 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
55016 unselectable : 'unselectable="on"',
55017 unselectableCls : 'x-unselectable',
55020 rowClass : "x-grid-row",
55022 cellClass : "x-grid-col",
55024 tdClass : "x-grid-td",
55026 hdClass : "x-grid-hd",
55028 splitClass : "x-grid-split",
55030 sortClasses : ["sort-asc", "sort-desc"],
55032 enableMoveAnim : false,
55036 dh : Roo.DomHelper,
55038 fly : Roo.Element.fly,
55040 css : Roo.util.CSS,
55046 scrollIncrement : 22,
55048 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55050 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55052 bind : function(ds, cm){
55054 this.ds.un("load", this.onLoad, this);
55055 this.ds.un("datachanged", this.onDataChange, this);
55056 this.ds.un("add", this.onAdd, this);
55057 this.ds.un("remove", this.onRemove, this);
55058 this.ds.un("update", this.onUpdate, this);
55059 this.ds.un("clear", this.onClear, this);
55062 ds.on("load", this.onLoad, this);
55063 ds.on("datachanged", this.onDataChange, this);
55064 ds.on("add", this.onAdd, this);
55065 ds.on("remove", this.onRemove, this);
55066 ds.on("update", this.onUpdate, this);
55067 ds.on("clear", this.onClear, this);
55072 this.cm.un("widthchange", this.onColWidthChange, this);
55073 this.cm.un("headerchange", this.onHeaderChange, this);
55074 this.cm.un("hiddenchange", this.onHiddenChange, this);
55075 this.cm.un("columnmoved", this.onColumnMove, this);
55076 this.cm.un("columnlockchange", this.onColumnLock, this);
55079 this.generateRules(cm);
55080 cm.on("widthchange", this.onColWidthChange, this);
55081 cm.on("headerchange", this.onHeaderChange, this);
55082 cm.on("hiddenchange", this.onHiddenChange, this);
55083 cm.on("columnmoved", this.onColumnMove, this);
55084 cm.on("columnlockchange", this.onColumnLock, this);
55089 init: function(grid){
55090 Roo.grid.GridView.superclass.init.call(this, grid);
55092 this.bind(grid.dataSource, grid.colModel);
55094 grid.on("headerclick", this.handleHeaderClick, this);
55096 if(grid.trackMouseOver){
55097 grid.on("mouseover", this.onRowOver, this);
55098 grid.on("mouseout", this.onRowOut, this);
55100 grid.cancelTextSelection = function(){};
55101 this.gridId = grid.id;
55103 var tpls = this.templates || {};
55106 tpls.master = new Roo.Template(
55107 '<div class="x-grid" hidefocus="true">',
55108 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55109 '<div class="x-grid-topbar"></div>',
55110 '<div class="x-grid-scroller"><div></div></div>',
55111 '<div class="x-grid-locked">',
55112 '<div class="x-grid-header">{lockedHeader}</div>',
55113 '<div class="x-grid-body">{lockedBody}</div>',
55115 '<div class="x-grid-viewport">',
55116 '<div class="x-grid-header">{header}</div>',
55117 '<div class="x-grid-body">{body}</div>',
55119 '<div class="x-grid-bottombar"></div>',
55121 '<div class="x-grid-resize-proxy"> </div>',
55124 tpls.master.disableformats = true;
55128 tpls.header = new Roo.Template(
55129 '<table border="0" cellspacing="0" cellpadding="0">',
55130 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55133 tpls.header.disableformats = true;
55135 tpls.header.compile();
55138 tpls.hcell = new Roo.Template(
55139 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55140 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55143 tpls.hcell.disableFormats = true;
55145 tpls.hcell.compile();
55148 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55149 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55150 tpls.hsplit.disableFormats = true;
55152 tpls.hsplit.compile();
55155 tpls.body = new Roo.Template(
55156 '<table border="0" cellspacing="0" cellpadding="0">',
55157 "<tbody>{rows}</tbody>",
55160 tpls.body.disableFormats = true;
55162 tpls.body.compile();
55165 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55166 tpls.row.disableFormats = true;
55168 tpls.row.compile();
55171 tpls.cell = new Roo.Template(
55172 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55173 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55174 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55177 tpls.cell.disableFormats = true;
55179 tpls.cell.compile();
55181 this.templates = tpls;
55184 // remap these for backwards compat
55185 onColWidthChange : function(){
55186 this.updateColumns.apply(this, arguments);
55188 onHeaderChange : function(){
55189 this.updateHeaders.apply(this, arguments);
55191 onHiddenChange : function(){
55192 this.handleHiddenChange.apply(this, arguments);
55194 onColumnMove : function(){
55195 this.handleColumnMove.apply(this, arguments);
55197 onColumnLock : function(){
55198 this.handleLockChange.apply(this, arguments);
55201 onDataChange : function(){
55203 this.updateHeaderSortState();
55206 onClear : function(){
55210 onUpdate : function(ds, record){
55211 this.refreshRow(record);
55214 refreshRow : function(record){
55215 var ds = this.ds, index;
55216 if(typeof record == 'number'){
55218 record = ds.getAt(index);
55220 index = ds.indexOf(record);
55222 this.insertRows(ds, index, index, true);
55223 this.onRemove(ds, record, index+1, true);
55224 this.syncRowHeights(index, index);
55226 this.fireEvent("rowupdated", this, index, record);
55229 onAdd : function(ds, records, index){
55230 this.insertRows(ds, index, index + (records.length-1));
55233 onRemove : function(ds, record, index, isUpdate){
55234 if(isUpdate !== true){
55235 this.fireEvent("beforerowremoved", this, index, record);
55237 var bt = this.getBodyTable(), lt = this.getLockedTable();
55238 if(bt.rows[index]){
55239 bt.firstChild.removeChild(bt.rows[index]);
55241 if(lt.rows[index]){
55242 lt.firstChild.removeChild(lt.rows[index]);
55244 if(isUpdate !== true){
55245 this.stripeRows(index);
55246 this.syncRowHeights(index, index);
55248 this.fireEvent("rowremoved", this, index, record);
55252 onLoad : function(){
55253 this.scrollToTop();
55257 * Scrolls the grid to the top
55259 scrollToTop : function(){
55261 this.scroller.dom.scrollTop = 0;
55267 * Gets a panel in the header of the grid that can be used for toolbars etc.
55268 * After modifying the contents of this panel a call to grid.autoSize() may be
55269 * required to register any changes in size.
55270 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55271 * @return Roo.Element
55273 getHeaderPanel : function(doShow){
55275 this.headerPanel.show();
55277 return this.headerPanel;
55281 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55282 * After modifying the contents of this panel a call to grid.autoSize() may be
55283 * required to register any changes in size.
55284 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55285 * @return Roo.Element
55287 getFooterPanel : function(doShow){
55289 this.footerPanel.show();
55291 return this.footerPanel;
55294 initElements : function(){
55295 var E = Roo.Element;
55296 var el = this.grid.getGridEl().dom.firstChild;
55297 var cs = el.childNodes;
55299 this.el = new E(el);
55301 this.focusEl = new E(el.firstChild);
55302 this.focusEl.swallowEvent("click", true);
55304 this.headerPanel = new E(cs[1]);
55305 this.headerPanel.enableDisplayMode("block");
55307 this.scroller = new E(cs[2]);
55308 this.scrollSizer = new E(this.scroller.dom.firstChild);
55310 this.lockedWrap = new E(cs[3]);
55311 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55312 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55314 this.mainWrap = new E(cs[4]);
55315 this.mainHd = new E(this.mainWrap.dom.firstChild);
55316 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55318 this.footerPanel = new E(cs[5]);
55319 this.footerPanel.enableDisplayMode("block");
55321 this.resizeProxy = new E(cs[6]);
55323 this.headerSelector = String.format(
55324 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55325 this.lockedHd.id, this.mainHd.id
55328 this.splitterSelector = String.format(
55329 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55330 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55333 idToCssName : function(s)
55335 return s.replace(/[^a-z0-9]+/ig, '-');
55338 getHeaderCell : function(index){
55339 return Roo.DomQuery.select(this.headerSelector)[index];
55342 getHeaderCellMeasure : function(index){
55343 return this.getHeaderCell(index).firstChild;
55346 getHeaderCellText : function(index){
55347 return this.getHeaderCell(index).firstChild.firstChild;
55350 getLockedTable : function(){
55351 return this.lockedBody.dom.firstChild;
55354 getBodyTable : function(){
55355 return this.mainBody.dom.firstChild;
55358 getLockedRow : function(index){
55359 return this.getLockedTable().rows[index];
55362 getRow : function(index){
55363 return this.getBodyTable().rows[index];
55366 getRowComposite : function(index){
55368 this.rowEl = new Roo.CompositeElementLite();
55370 var els = [], lrow, mrow;
55371 if(lrow = this.getLockedRow(index)){
55374 if(mrow = this.getRow(index)){
55377 this.rowEl.elements = els;
55381 * Gets the 'td' of the cell
55383 * @param {Integer} rowIndex row to select
55384 * @param {Integer} colIndex column to select
55388 getCell : function(rowIndex, colIndex){
55389 var locked = this.cm.getLockedCount();
55391 if(colIndex < locked){
55392 source = this.lockedBody.dom.firstChild;
55394 source = this.mainBody.dom.firstChild;
55395 colIndex -= locked;
55397 return source.rows[rowIndex].childNodes[colIndex];
55400 getCellText : function(rowIndex, colIndex){
55401 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55404 getCellBox : function(cell){
55405 var b = this.fly(cell).getBox();
55406 if(Roo.isOpera){ // opera fails to report the Y
55407 b.y = cell.offsetTop + this.mainBody.getY();
55412 getCellIndex : function(cell){
55413 var id = String(cell.className).match(this.cellRE);
55415 return parseInt(id[1], 10);
55420 findHeaderIndex : function(n){
55421 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55422 return r ? this.getCellIndex(r) : false;
55425 findHeaderCell : function(n){
55426 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55427 return r ? r : false;
55430 findRowIndex : function(n){
55434 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55435 return r ? r.rowIndex : false;
55438 findCellIndex : function(node){
55439 var stop = this.el.dom;
55440 while(node && node != stop){
55441 if(this.findRE.test(node.className)){
55442 return this.getCellIndex(node);
55444 node = node.parentNode;
55449 getColumnId : function(index){
55450 return this.cm.getColumnId(index);
55453 getSplitters : function()
55455 if(this.splitterSelector){
55456 return Roo.DomQuery.select(this.splitterSelector);
55462 getSplitter : function(index){
55463 return this.getSplitters()[index];
55466 onRowOver : function(e, t){
55468 if((row = this.findRowIndex(t)) !== false){
55469 this.getRowComposite(row).addClass("x-grid-row-over");
55473 onRowOut : function(e, t){
55475 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55476 this.getRowComposite(row).removeClass("x-grid-row-over");
55480 renderHeaders : function(){
55482 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55483 var cb = [], lb = [], sb = [], lsb = [], p = {};
55484 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55485 p.cellId = "x-grid-hd-0-" + i;
55486 p.splitId = "x-grid-csplit-0-" + i;
55487 p.id = cm.getColumnId(i);
55488 p.value = cm.getColumnHeader(i) || "";
55489 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55490 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55491 if(!cm.isLocked(i)){
55492 cb[cb.length] = ct.apply(p);
55493 sb[sb.length] = st.apply(p);
55495 lb[lb.length] = ct.apply(p);
55496 lsb[lsb.length] = st.apply(p);
55499 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55500 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55503 updateHeaders : function(){
55504 var html = this.renderHeaders();
55505 this.lockedHd.update(html[0]);
55506 this.mainHd.update(html[1]);
55510 * Focuses the specified row.
55511 * @param {Number} row The row index
55513 focusRow : function(row)
55515 //Roo.log('GridView.focusRow');
55516 var x = this.scroller.dom.scrollLeft;
55517 this.focusCell(row, 0, false);
55518 this.scroller.dom.scrollLeft = x;
55522 * Focuses the specified cell.
55523 * @param {Number} row The row index
55524 * @param {Number} col The column index
55525 * @param {Boolean} hscroll false to disable horizontal scrolling
55527 focusCell : function(row, col, hscroll)
55529 //Roo.log('GridView.focusCell');
55530 var el = this.ensureVisible(row, col, hscroll);
55531 this.focusEl.alignTo(el, "tl-tl");
55533 this.focusEl.focus();
55535 this.focusEl.focus.defer(1, this.focusEl);
55540 * Scrolls the specified cell into view
55541 * @param {Number} row The row index
55542 * @param {Number} col The column index
55543 * @param {Boolean} hscroll false to disable horizontal scrolling
55545 ensureVisible : function(row, col, hscroll)
55547 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55548 //return null; //disable for testing.
55549 if(typeof row != "number"){
55550 row = row.rowIndex;
55552 if(row < 0 && row >= this.ds.getCount()){
55555 col = (col !== undefined ? col : 0);
55556 var cm = this.grid.colModel;
55557 while(cm.isHidden(col)){
55561 var el = this.getCell(row, col);
55565 var c = this.scroller.dom;
55567 var ctop = parseInt(el.offsetTop, 10);
55568 var cleft = parseInt(el.offsetLeft, 10);
55569 var cbot = ctop + el.offsetHeight;
55570 var cright = cleft + el.offsetWidth;
55572 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55573 var stop = parseInt(c.scrollTop, 10);
55574 var sleft = parseInt(c.scrollLeft, 10);
55575 var sbot = stop + ch;
55576 var sright = sleft + c.clientWidth;
55578 Roo.log('GridView.ensureVisible:' +
55580 ' c.clientHeight:' + c.clientHeight +
55581 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55589 c.scrollTop = ctop;
55590 //Roo.log("set scrolltop to ctop DISABLE?");
55591 }else if(cbot > sbot){
55592 //Roo.log("set scrolltop to cbot-ch");
55593 c.scrollTop = cbot-ch;
55596 if(hscroll !== false){
55598 c.scrollLeft = cleft;
55599 }else if(cright > sright){
55600 c.scrollLeft = cright-c.clientWidth;
55607 updateColumns : function(){
55608 this.grid.stopEditing();
55609 var cm = this.grid.colModel, colIds = this.getColumnIds();
55610 //var totalWidth = cm.getTotalWidth();
55612 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55613 //if(cm.isHidden(i)) continue;
55614 var w = cm.getColumnWidth(i);
55615 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55616 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55618 this.updateSplitters();
55621 generateRules : function(cm){
55622 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55623 Roo.util.CSS.removeStyleSheet(rulesId);
55624 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55625 var cid = cm.getColumnId(i);
55627 if(cm.config[i].align){
55628 align = 'text-align:'+cm.config[i].align+';';
55631 if(cm.isHidden(i)){
55632 hidden = 'display:none;';
55634 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55636 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55637 this.hdSelector, cid, " {\n", align, width, "}\n",
55638 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55639 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55641 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55644 updateSplitters : function(){
55645 var cm = this.cm, s = this.getSplitters();
55646 if(s){ // splitters not created yet
55647 var pos = 0, locked = true;
55648 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55649 if(cm.isHidden(i)) {
55652 var w = cm.getColumnWidth(i); // make sure it's a number
55653 if(!cm.isLocked(i) && locked){
55658 s[i].style.left = (pos-this.splitOffset) + "px";
55663 handleHiddenChange : function(colModel, colIndex, hidden){
55665 this.hideColumn(colIndex);
55667 this.unhideColumn(colIndex);
55671 hideColumn : function(colIndex){
55672 var cid = this.getColumnId(colIndex);
55673 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55674 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55676 this.updateHeaders();
55678 this.updateSplitters();
55682 unhideColumn : function(colIndex){
55683 var cid = this.getColumnId(colIndex);
55684 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55685 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55688 this.updateHeaders();
55690 this.updateSplitters();
55694 insertRows : function(dm, firstRow, lastRow, isUpdate){
55695 if(firstRow == 0 && lastRow == dm.getCount()-1){
55699 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55701 var s = this.getScrollState();
55702 var markup = this.renderRows(firstRow, lastRow);
55703 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55704 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55705 this.restoreScroll(s);
55707 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55708 this.syncRowHeights(firstRow, lastRow);
55709 this.stripeRows(firstRow);
55715 bufferRows : function(markup, target, index){
55716 var before = null, trows = target.rows, tbody = target.tBodies[0];
55717 if(index < trows.length){
55718 before = trows[index];
55720 var b = document.createElement("div");
55721 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55722 var rows = b.firstChild.rows;
55723 for(var i = 0, len = rows.length; i < len; i++){
55725 tbody.insertBefore(rows[0], before);
55727 tbody.appendChild(rows[0]);
55734 deleteRows : function(dm, firstRow, lastRow){
55735 if(dm.getRowCount()<1){
55736 this.fireEvent("beforerefresh", this);
55737 this.mainBody.update("");
55738 this.lockedBody.update("");
55739 this.fireEvent("refresh", this);
55741 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55742 var bt = this.getBodyTable();
55743 var tbody = bt.firstChild;
55744 var rows = bt.rows;
55745 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55746 tbody.removeChild(rows[firstRow]);
55748 this.stripeRows(firstRow);
55749 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55753 updateRows : function(dataSource, firstRow, lastRow){
55754 var s = this.getScrollState();
55756 this.restoreScroll(s);
55759 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55763 this.updateHeaderSortState();
55766 getScrollState : function(){
55768 var sb = this.scroller.dom;
55769 return {left: sb.scrollLeft, top: sb.scrollTop};
55772 stripeRows : function(startRow){
55773 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55776 startRow = startRow || 0;
55777 var rows = this.getBodyTable().rows;
55778 var lrows = this.getLockedTable().rows;
55779 var cls = ' x-grid-row-alt ';
55780 for(var i = startRow, len = rows.length; i < len; i++){
55781 var row = rows[i], lrow = lrows[i];
55782 var isAlt = ((i+1) % 2 == 0);
55783 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55784 if(isAlt == hasAlt){
55788 row.className += " x-grid-row-alt";
55790 row.className = row.className.replace("x-grid-row-alt", "");
55793 lrow.className = row.className;
55798 restoreScroll : function(state){
55799 //Roo.log('GridView.restoreScroll');
55800 var sb = this.scroller.dom;
55801 sb.scrollLeft = state.left;
55802 sb.scrollTop = state.top;
55806 syncScroll : function(){
55807 //Roo.log('GridView.syncScroll');
55808 var sb = this.scroller.dom;
55809 var sh = this.mainHd.dom;
55810 var bs = this.mainBody.dom;
55811 var lv = this.lockedBody.dom;
55812 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55813 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55816 handleScroll : function(e){
55818 var sb = this.scroller.dom;
55819 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55823 handleWheel : function(e){
55824 var d = e.getWheelDelta();
55825 this.scroller.dom.scrollTop -= d*22;
55826 // set this here to prevent jumpy scrolling on large tables
55827 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55831 renderRows : function(startRow, endRow){
55832 // pull in all the crap needed to render rows
55833 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55834 var colCount = cm.getColumnCount();
55836 if(ds.getCount() < 1){
55840 // build a map for all the columns
55842 for(var i = 0; i < colCount; i++){
55843 var name = cm.getDataIndex(i);
55845 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55846 renderer : cm.getRenderer(i),
55847 id : cm.getColumnId(i),
55848 locked : cm.isLocked(i),
55849 has_editor : cm.isCellEditable(i)
55853 startRow = startRow || 0;
55854 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55856 // records to render
55857 var rs = ds.getRange(startRow, endRow);
55859 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55862 // As much as I hate to duplicate code, this was branched because FireFox really hates
55863 // [].join("") on strings. The performance difference was substantial enough to
55864 // branch this function
55865 doRender : Roo.isGecko ?
55866 function(cs, rs, ds, startRow, colCount, stripe){
55867 var ts = this.templates, ct = ts.cell, rt = ts.row;
55869 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55871 var hasListener = this.grid.hasListener('rowclass');
55873 for(var j = 0, len = rs.length; j < len; j++){
55874 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
55875 for(var i = 0; i < colCount; i++){
55877 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55879 p.css = p.attr = "";
55880 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55881 if(p.value == undefined || p.value === "") {
55882 p.value = " ";
55885 p.css += ' x-grid-editable-cell';
55887 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
55888 p.css += ' x-grid-dirty-cell';
55890 var markup = ct.apply(p);
55898 if(stripe && ((rowIndex+1) % 2 == 0)){
55899 alt.push("x-grid-row-alt")
55902 alt.push( " x-grid-dirty-row");
55905 if(this.getRowClass){
55906 alt.push(this.getRowClass(r, rowIndex));
55912 rowIndex : rowIndex,
55915 this.grid.fireEvent('rowclass', this, rowcfg);
55916 alt.push(rowcfg.rowClass);
55918 rp.alt = alt.join(" ");
55919 lbuf+= rt.apply(rp);
55921 buf+= rt.apply(rp);
55923 return [lbuf, buf];
55925 function(cs, rs, ds, startRow, colCount, stripe){
55926 var ts = this.templates, ct = ts.cell, rt = ts.row;
55928 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55929 var hasListener = this.grid.hasListener('rowclass');
55932 for(var j = 0, len = rs.length; j < len; j++){
55933 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
55934 for(var i = 0; i < colCount; i++){
55936 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55938 p.css = p.attr = "";
55939 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55940 if(p.value == undefined || p.value === "") {
55941 p.value = " ";
55945 p.css += ' x-grid-editable-cell';
55947 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
55948 p.css += ' x-grid-dirty-cell'
55951 var markup = ct.apply(p);
55953 cb[cb.length] = markup;
55955 lcb[lcb.length] = markup;
55959 if(stripe && ((rowIndex+1) % 2 == 0)){
55960 alt.push( "x-grid-row-alt");
55963 alt.push(" x-grid-dirty-row");
55966 if(this.getRowClass){
55967 alt.push( this.getRowClass(r, rowIndex));
55973 rowIndex : rowIndex,
55976 this.grid.fireEvent('rowclass', this, rowcfg);
55977 alt.push(rowcfg.rowClass);
55980 rp.alt = alt.join(" ");
55981 rp.cells = lcb.join("");
55982 lbuf[lbuf.length] = rt.apply(rp);
55983 rp.cells = cb.join("");
55984 buf[buf.length] = rt.apply(rp);
55986 return [lbuf.join(""), buf.join("")];
55989 renderBody : function(){
55990 var markup = this.renderRows();
55991 var bt = this.templates.body;
55992 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
55996 * Refreshes the grid
55997 * @param {Boolean} headersToo
55999 refresh : function(headersToo){
56000 this.fireEvent("beforerefresh", this);
56001 this.grid.stopEditing();
56002 var result = this.renderBody();
56003 this.lockedBody.update(result[0]);
56004 this.mainBody.update(result[1]);
56005 if(headersToo === true){
56006 this.updateHeaders();
56007 this.updateColumns();
56008 this.updateSplitters();
56009 this.updateHeaderSortState();
56011 this.syncRowHeights();
56013 this.fireEvent("refresh", this);
56016 handleColumnMove : function(cm, oldIndex, newIndex){
56017 this.indexMap = null;
56018 var s = this.getScrollState();
56019 this.refresh(true);
56020 this.restoreScroll(s);
56021 this.afterMove(newIndex);
56024 afterMove : function(colIndex){
56025 if(this.enableMoveAnim && Roo.enableFx){
56026 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56028 // if multisort - fix sortOrder, and reload..
56029 if (this.grid.dataSource.multiSort) {
56030 // the we can call sort again..
56031 var dm = this.grid.dataSource;
56032 var cm = this.grid.colModel;
56034 for(var i = 0; i < cm.config.length; i++ ) {
56036 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56037 continue; // dont' bother, it's not in sort list or being set.
56040 so.push(cm.config[i].dataIndex);
56043 dm.load(dm.lastOptions);
56050 updateCell : function(dm, rowIndex, dataIndex){
56051 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56052 if(typeof colIndex == "undefined"){ // not present in grid
56055 var cm = this.grid.colModel;
56056 var cell = this.getCell(rowIndex, colIndex);
56057 var cellText = this.getCellText(rowIndex, colIndex);
56060 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56061 id : cm.getColumnId(colIndex),
56062 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56064 var renderer = cm.getRenderer(colIndex);
56065 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56066 if(typeof val == "undefined" || val === "") {
56069 cellText.innerHTML = val;
56070 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56071 this.syncRowHeights(rowIndex, rowIndex);
56074 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56076 if(this.grid.autoSizeHeaders){
56077 var h = this.getHeaderCellMeasure(colIndex);
56078 maxWidth = Math.max(maxWidth, h.scrollWidth);
56081 if(this.cm.isLocked(colIndex)){
56082 tb = this.getLockedTable();
56085 tb = this.getBodyTable();
56086 index = colIndex - this.cm.getLockedCount();
56089 var rows = tb.rows;
56090 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56091 for(var i = 0; i < stopIndex; i++){
56092 var cell = rows[i].childNodes[index].firstChild;
56093 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56096 return maxWidth + /*margin for error in IE*/ 5;
56099 * Autofit a column to its content.
56100 * @param {Number} colIndex
56101 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56103 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56104 if(this.cm.isHidden(colIndex)){
56105 return; // can't calc a hidden column
56108 var cid = this.cm.getColumnId(colIndex);
56109 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56110 if(this.grid.autoSizeHeaders){
56111 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56114 var newWidth = this.calcColumnWidth(colIndex);
56115 this.cm.setColumnWidth(colIndex,
56116 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56117 if(!suppressEvent){
56118 this.grid.fireEvent("columnresize", colIndex, newWidth);
56123 * Autofits all columns to their content and then expands to fit any extra space in the grid
56125 autoSizeColumns : function(){
56126 var cm = this.grid.colModel;
56127 var colCount = cm.getColumnCount();
56128 for(var i = 0; i < colCount; i++){
56129 this.autoSizeColumn(i, true, true);
56131 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56134 this.updateColumns();
56140 * Autofits all columns to the grid's width proportionate with their current size
56141 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56143 fitColumns : function(reserveScrollSpace){
56144 var cm = this.grid.colModel;
56145 var colCount = cm.getColumnCount();
56149 for (i = 0; i < colCount; i++){
56150 if(!cm.isHidden(i) && !cm.isFixed(i)){
56151 w = cm.getColumnWidth(i);
56157 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56158 if(reserveScrollSpace){
56161 var frac = (avail - cm.getTotalWidth())/width;
56162 while (cols.length){
56165 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56167 this.updateColumns();
56171 onRowSelect : function(rowIndex){
56172 var row = this.getRowComposite(rowIndex);
56173 row.addClass("x-grid-row-selected");
56176 onRowDeselect : function(rowIndex){
56177 var row = this.getRowComposite(rowIndex);
56178 row.removeClass("x-grid-row-selected");
56181 onCellSelect : function(row, col){
56182 var cell = this.getCell(row, col);
56184 Roo.fly(cell).addClass("x-grid-cell-selected");
56188 onCellDeselect : function(row, col){
56189 var cell = this.getCell(row, col);
56191 Roo.fly(cell).removeClass("x-grid-cell-selected");
56195 updateHeaderSortState : function(){
56197 // sort state can be single { field: xxx, direction : yyy}
56198 // or { xxx=>ASC , yyy : DESC ..... }
56201 if (!this.ds.multiSort) {
56202 var state = this.ds.getSortState();
56206 mstate[state.field] = state.direction;
56207 // FIXME... - this is not used here.. but might be elsewhere..
56208 this.sortState = state;
56211 mstate = this.ds.sortToggle;
56213 //remove existing sort classes..
56215 var sc = this.sortClasses;
56216 var hds = this.el.select(this.headerSelector).removeClass(sc);
56218 for(var f in mstate) {
56220 var sortColumn = this.cm.findColumnIndex(f);
56222 if(sortColumn != -1){
56223 var sortDir = mstate[f];
56224 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56233 handleHeaderClick : function(g, index,e){
56235 Roo.log("header click");
56238 // touch events on header are handled by context
56239 this.handleHdCtx(g,index,e);
56244 if(this.headersDisabled){
56247 var dm = g.dataSource, cm = g.colModel;
56248 if(!cm.isSortable(index)){
56253 if (dm.multiSort) {
56254 // update the sortOrder
56256 for(var i = 0; i < cm.config.length; i++ ) {
56258 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56259 continue; // dont' bother, it's not in sort list or being set.
56262 so.push(cm.config[i].dataIndex);
56268 dm.sort(cm.getDataIndex(index));
56272 destroy : function(){
56274 this.colMenu.removeAll();
56275 Roo.menu.MenuMgr.unregister(this.colMenu);
56276 this.colMenu.getEl().remove();
56277 delete this.colMenu;
56280 this.hmenu.removeAll();
56281 Roo.menu.MenuMgr.unregister(this.hmenu);
56282 this.hmenu.getEl().remove();
56285 if(this.grid.enableColumnMove){
56286 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56288 for(var dd in dds){
56289 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56290 var elid = dds[dd].dragElId;
56292 Roo.get(elid).remove();
56293 } else if(dds[dd].config.isTarget){
56294 dds[dd].proxyTop.remove();
56295 dds[dd].proxyBottom.remove();
56298 if(Roo.dd.DDM.locationCache[dd]){
56299 delete Roo.dd.DDM.locationCache[dd];
56302 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56305 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56306 this.bind(null, null);
56307 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56310 handleLockChange : function(){
56311 this.refresh(true);
56314 onDenyColumnLock : function(){
56318 onDenyColumnHide : function(){
56322 handleHdMenuClick : function(item){
56323 var index = this.hdCtxIndex;
56324 var cm = this.cm, ds = this.ds;
56327 ds.sort(cm.getDataIndex(index), "ASC");
56330 ds.sort(cm.getDataIndex(index), "DESC");
56333 var lc = cm.getLockedCount();
56334 if(cm.getColumnCount(true) <= lc+1){
56335 this.onDenyColumnLock();
56339 cm.setLocked(index, true, true);
56340 cm.moveColumn(index, lc);
56341 this.grid.fireEvent("columnmove", index, lc);
56343 cm.setLocked(index, true);
56347 var lc = cm.getLockedCount();
56348 if((lc-1) != index){
56349 cm.setLocked(index, false, true);
56350 cm.moveColumn(index, lc-1);
56351 this.grid.fireEvent("columnmove", index, lc-1);
56353 cm.setLocked(index, false);
56356 case 'wider': // used to expand cols on touch..
56358 var cw = cm.getColumnWidth(index);
56359 cw += (item.id == 'wider' ? 1 : -1) * 50;
56360 cw = Math.max(0, cw);
56361 cw = Math.min(cw,4000);
56362 cm.setColumnWidth(index, cw);
56366 index = cm.getIndexById(item.id.substr(4));
56368 if(item.checked && cm.getColumnCount(true) <= 1){
56369 this.onDenyColumnHide();
56372 cm.setHidden(index, item.checked);
56378 beforeColMenuShow : function(){
56379 var cm = this.cm, colCount = cm.getColumnCount();
56380 this.colMenu.removeAll();
56381 for(var i = 0; i < colCount; i++){
56382 this.colMenu.add(new Roo.menu.CheckItem({
56383 id: "col-"+cm.getColumnId(i),
56384 text: cm.getColumnHeader(i),
56385 checked: !cm.isHidden(i),
56391 handleHdCtx : function(g, index, e){
56393 var hd = this.getHeaderCell(index);
56394 this.hdCtxIndex = index;
56395 var ms = this.hmenu.items, cm = this.cm;
56396 ms.get("asc").setDisabled(!cm.isSortable(index));
56397 ms.get("desc").setDisabled(!cm.isSortable(index));
56398 if(this.grid.enableColLock !== false){
56399 ms.get("lock").setDisabled(cm.isLocked(index));
56400 ms.get("unlock").setDisabled(!cm.isLocked(index));
56402 this.hmenu.show(hd, "tl-bl");
56405 handleHdOver : function(e){
56406 var hd = this.findHeaderCell(e.getTarget());
56407 if(hd && !this.headersDisabled){
56408 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56409 this.fly(hd).addClass("x-grid-hd-over");
56414 handleHdOut : function(e){
56415 var hd = this.findHeaderCell(e.getTarget());
56417 this.fly(hd).removeClass("x-grid-hd-over");
56421 handleSplitDblClick : function(e, t){
56422 var i = this.getCellIndex(t);
56423 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56424 this.autoSizeColumn(i, true);
56429 render : function(){
56432 var colCount = cm.getColumnCount();
56434 if(this.grid.monitorWindowResize === true){
56435 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56437 var header = this.renderHeaders();
56438 var body = this.templates.body.apply({rows:""});
56439 var html = this.templates.master.apply({
56442 lockedHeader: header[0],
56446 //this.updateColumns();
56448 this.grid.getGridEl().dom.innerHTML = html;
56450 this.initElements();
56452 // a kludge to fix the random scolling effect in webkit
56453 this.el.on("scroll", function() {
56454 this.el.dom.scrollTop=0; // hopefully not recursive..
56457 this.scroller.on("scroll", this.handleScroll, this);
56458 this.lockedBody.on("mousewheel", this.handleWheel, this);
56459 this.mainBody.on("mousewheel", this.handleWheel, this);
56461 this.mainHd.on("mouseover", this.handleHdOver, this);
56462 this.mainHd.on("mouseout", this.handleHdOut, this);
56463 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56464 {delegate: "."+this.splitClass});
56466 this.lockedHd.on("mouseover", this.handleHdOver, this);
56467 this.lockedHd.on("mouseout", this.handleHdOut, this);
56468 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56469 {delegate: "."+this.splitClass});
56471 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56472 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56475 this.updateSplitters();
56477 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56478 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56479 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56482 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56483 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56485 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56486 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56488 if(this.grid.enableColLock !== false){
56489 this.hmenu.add('-',
56490 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56491 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56495 this.hmenu.add('-',
56496 {id:"wider", text: this.columnsWiderText},
56497 {id:"narrow", text: this.columnsNarrowText }
56503 if(this.grid.enableColumnHide !== false){
56505 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56506 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56507 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56509 this.hmenu.add('-',
56510 {id:"columns", text: this.columnsText, menu: this.colMenu}
56513 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56515 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56518 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56519 this.dd = new Roo.grid.GridDragZone(this.grid, {
56520 ddGroup : this.grid.ddGroup || 'GridDD'
56526 for(var i = 0; i < colCount; i++){
56527 if(cm.isHidden(i)){
56528 this.hideColumn(i);
56530 if(cm.config[i].align){
56531 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56532 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56536 this.updateHeaderSortState();
56538 this.beforeInitialResize();
56541 // two part rendering gives faster view to the user
56542 this.renderPhase2.defer(1, this);
56545 renderPhase2 : function(){
56546 // render the rows now
56548 if(this.grid.autoSizeColumns){
56549 this.autoSizeColumns();
56553 beforeInitialResize : function(){
56557 onColumnSplitterMoved : function(i, w){
56558 this.userResized = true;
56559 var cm = this.grid.colModel;
56560 cm.setColumnWidth(i, w, true);
56561 var cid = cm.getColumnId(i);
56562 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56563 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56564 this.updateSplitters();
56566 this.grid.fireEvent("columnresize", i, w);
56569 syncRowHeights : function(startIndex, endIndex){
56570 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56571 startIndex = startIndex || 0;
56572 var mrows = this.getBodyTable().rows;
56573 var lrows = this.getLockedTable().rows;
56574 var len = mrows.length-1;
56575 endIndex = Math.min(endIndex || len, len);
56576 for(var i = startIndex; i <= endIndex; i++){
56577 var m = mrows[i], l = lrows[i];
56578 var h = Math.max(m.offsetHeight, l.offsetHeight);
56579 m.style.height = l.style.height = h + "px";
56584 layout : function(initialRender, is2ndPass){
56586 var auto = g.autoHeight;
56587 var scrollOffset = 16;
56588 var c = g.getGridEl(), cm = this.cm,
56589 expandCol = g.autoExpandColumn,
56591 //c.beginMeasure();
56593 if(!c.dom.offsetWidth){ // display:none?
56595 this.lockedWrap.show();
56596 this.mainWrap.show();
56601 var hasLock = this.cm.isLocked(0);
56603 var tbh = this.headerPanel.getHeight();
56604 var bbh = this.footerPanel.getHeight();
56607 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56608 var newHeight = ch + c.getBorderWidth("tb");
56610 newHeight = Math.min(g.maxHeight, newHeight);
56612 c.setHeight(newHeight);
56616 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56619 var s = this.scroller;
56621 var csize = c.getSize(true);
56623 this.el.setSize(csize.width, csize.height);
56625 this.headerPanel.setWidth(csize.width);
56626 this.footerPanel.setWidth(csize.width);
56628 var hdHeight = this.mainHd.getHeight();
56629 var vw = csize.width;
56630 var vh = csize.height - (tbh + bbh);
56634 var bt = this.getBodyTable();
56636 if(cm.getLockedCount() == cm.config.length){
56637 bt = this.getLockedTable();
56640 var ltWidth = hasLock ?
56641 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56643 var scrollHeight = bt.offsetHeight;
56644 var scrollWidth = ltWidth + bt.offsetWidth;
56645 var vscroll = false, hscroll = false;
56647 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56649 var lw = this.lockedWrap, mw = this.mainWrap;
56650 var lb = this.lockedBody, mb = this.mainBody;
56652 setTimeout(function(){
56653 var t = s.dom.offsetTop;
56654 var w = s.dom.clientWidth,
56655 h = s.dom.clientHeight;
56658 lw.setSize(ltWidth, h);
56660 mw.setLeftTop(ltWidth, t);
56661 mw.setSize(w-ltWidth, h);
56663 lb.setHeight(h-hdHeight);
56664 mb.setHeight(h-hdHeight);
56666 if(is2ndPass !== true && !gv.userResized && expandCol){
56667 // high speed resize without full column calculation
56669 var ci = cm.getIndexById(expandCol);
56671 ci = cm.findColumnIndex(expandCol);
56673 ci = Math.max(0, ci); // make sure it's got at least the first col.
56674 var expandId = cm.getColumnId(ci);
56675 var tw = cm.getTotalWidth(false);
56676 var currentWidth = cm.getColumnWidth(ci);
56677 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56678 if(currentWidth != cw){
56679 cm.setColumnWidth(ci, cw, true);
56680 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56681 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56682 gv.updateSplitters();
56683 gv.layout(false, true);
56695 onWindowResize : function(){
56696 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56702 appendFooter : function(parentEl){
56706 sortAscText : "Sort Ascending",
56707 sortDescText : "Sort Descending",
56708 lockText : "Lock Column",
56709 unlockText : "Unlock Column",
56710 columnsText : "Columns",
56712 columnsWiderText : "Wider",
56713 columnsNarrowText : "Thinner"
56717 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56718 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56719 this.proxy.el.addClass('x-grid3-col-dd');
56722 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56723 handleMouseDown : function(e){
56727 callHandleMouseDown : function(e){
56728 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56733 * Ext JS Library 1.1.1
56734 * Copyright(c) 2006-2007, Ext JS, LLC.
56736 * Originally Released Under LGPL - original licence link has changed is not relivant.
56739 * <script type="text/javascript">
56743 // This is a support class used internally by the Grid components
56744 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56746 this.view = grid.getView();
56747 this.proxy = this.view.resizeProxy;
56748 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56749 "gridSplitters" + this.grid.getGridEl().id, {
56750 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56752 this.setHandleElId(Roo.id(hd));
56753 this.setOuterHandleElId(Roo.id(hd2));
56754 this.scroll = false;
56756 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56757 fly: Roo.Element.fly,
56759 b4StartDrag : function(x, y){
56760 this.view.headersDisabled = true;
56761 this.proxy.setHeight(this.view.mainWrap.getHeight());
56762 var w = this.cm.getColumnWidth(this.cellIndex);
56763 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56764 this.resetConstraints();
56765 this.setXConstraint(minw, 1000);
56766 this.setYConstraint(0, 0);
56767 this.minX = x - minw;
56768 this.maxX = x + 1000;
56770 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56774 handleMouseDown : function(e){
56775 ev = Roo.EventObject.setEvent(e);
56776 var t = this.fly(ev.getTarget());
56777 if(t.hasClass("x-grid-split")){
56778 this.cellIndex = this.view.getCellIndex(t.dom);
56779 this.split = t.dom;
56780 this.cm = this.grid.colModel;
56781 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56782 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56787 endDrag : function(e){
56788 this.view.headersDisabled = false;
56789 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56790 var diff = endX - this.startPos;
56791 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56794 autoOffset : function(){
56795 this.setDelta(0,0);
56799 * Ext JS Library 1.1.1
56800 * Copyright(c) 2006-2007, Ext JS, LLC.
56802 * Originally Released Under LGPL - original licence link has changed is not relivant.
56805 * <script type="text/javascript">
56809 // This is a support class used internally by the Grid components
56810 Roo.grid.GridDragZone = function(grid, config){
56811 this.view = grid.getView();
56812 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56813 if(this.view.lockedBody){
56814 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56815 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56817 this.scroll = false;
56819 this.ddel = document.createElement('div');
56820 this.ddel.className = 'x-grid-dd-wrap';
56823 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56824 ddGroup : "GridDD",
56826 getDragData : function(e){
56827 var t = Roo.lib.Event.getTarget(e);
56828 var rowIndex = this.view.findRowIndex(t);
56829 var sm = this.grid.selModel;
56831 //Roo.log(rowIndex);
56833 if (sm.getSelectedCell) {
56834 // cell selection..
56835 if (!sm.getSelectedCell()) {
56838 if (rowIndex != sm.getSelectedCell()[0]) {
56844 if(rowIndex !== false){
56849 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56851 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56854 if (e.hasModifier()){
56855 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56858 Roo.log("getDragData");
56863 rowIndex: rowIndex,
56864 selections:sm.getSelections ? sm.getSelections() : (
56865 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
56872 onInitDrag : function(e){
56873 var data = this.dragData;
56874 this.ddel.innerHTML = this.grid.getDragDropText();
56875 this.proxy.update(this.ddel);
56876 // fire start drag?
56879 afterRepair : function(){
56880 this.dragging = false;
56883 getRepairXY : function(e, data){
56887 onEndDrag : function(data, e){
56891 onValidDrop : function(dd, e, id){
56896 beforeInvalidDrop : function(e, id){
56901 * Ext JS Library 1.1.1
56902 * Copyright(c) 2006-2007, Ext JS, LLC.
56904 * Originally Released Under LGPL - original licence link has changed is not relivant.
56907 * <script type="text/javascript">
56912 * @class Roo.grid.ColumnModel
56913 * @extends Roo.util.Observable
56914 * This is the default implementation of a ColumnModel used by the Grid. It defines
56915 * the columns in the grid.
56918 var colModel = new Roo.grid.ColumnModel([
56919 {header: "Ticker", width: 60, sortable: true, locked: true},
56920 {header: "Company Name", width: 150, sortable: true},
56921 {header: "Market Cap.", width: 100, sortable: true},
56922 {header: "$ Sales", width: 100, sortable: true, renderer: money},
56923 {header: "Employees", width: 100, sortable: true, resizable: false}
56928 * The config options listed for this class are options which may appear in each
56929 * individual column definition.
56930 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
56932 * @param {Object} config An Array of column config objects. See this class's
56933 * config objects for details.
56935 Roo.grid.ColumnModel = function(config){
56937 * The config passed into the constructor
56939 this.config = config;
56942 // if no id, create one
56943 // if the column does not have a dataIndex mapping,
56944 // map it to the order it is in the config
56945 for(var i = 0, len = config.length; i < len; i++){
56947 if(typeof c.dataIndex == "undefined"){
56950 if(typeof c.renderer == "string"){
56951 c.renderer = Roo.util.Format[c.renderer];
56953 if(typeof c.id == "undefined"){
56956 if(c.editor && c.editor.xtype){
56957 c.editor = Roo.factory(c.editor, Roo.grid);
56959 if(c.editor && c.editor.isFormField){
56960 c.editor = new Roo.grid.GridEditor(c.editor);
56962 this.lookup[c.id] = c;
56966 * The width of columns which have no width specified (defaults to 100)
56969 this.defaultWidth = 100;
56972 * Default sortable of columns which have no sortable specified (defaults to false)
56975 this.defaultSortable = false;
56979 * @event widthchange
56980 * Fires when the width of a column changes.
56981 * @param {ColumnModel} this
56982 * @param {Number} columnIndex The column index
56983 * @param {Number} newWidth The new width
56985 "widthchange": true,
56987 * @event headerchange
56988 * Fires when the text of a header changes.
56989 * @param {ColumnModel} this
56990 * @param {Number} columnIndex The column index
56991 * @param {Number} newText The new header text
56993 "headerchange": true,
56995 * @event hiddenchange
56996 * Fires when a column is hidden or "unhidden".
56997 * @param {ColumnModel} this
56998 * @param {Number} columnIndex The column index
56999 * @param {Boolean} hidden true if hidden, false otherwise
57001 "hiddenchange": true,
57003 * @event columnmoved
57004 * Fires when a column is moved.
57005 * @param {ColumnModel} this
57006 * @param {Number} oldIndex
57007 * @param {Number} newIndex
57009 "columnmoved" : true,
57011 * @event columlockchange
57012 * Fires when a column's locked state is changed
57013 * @param {ColumnModel} this
57014 * @param {Number} colIndex
57015 * @param {Boolean} locked true if locked
57017 "columnlockchange" : true
57019 Roo.grid.ColumnModel.superclass.constructor.call(this);
57021 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57023 * @cfg {String} header The header text to display in the Grid view.
57026 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57027 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57028 * specified, the column's index is used as an index into the Record's data Array.
57031 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57032 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57035 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57036 * Defaults to the value of the {@link #defaultSortable} property.
57037 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57040 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57043 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57046 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57049 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57052 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57053 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57054 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57055 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57058 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57061 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57064 * @cfg {String} cursor (Optional)
57067 * @cfg {String} tooltip (Optional)
57070 * @cfg {Number} xs (Optional)
57073 * @cfg {Number} sm (Optional)
57076 * @cfg {Number} md (Optional)
57079 * @cfg {Number} lg (Optional)
57082 * Returns the id of the column at the specified index.
57083 * @param {Number} index The column index
57084 * @return {String} the id
57086 getColumnId : function(index){
57087 return this.config[index].id;
57091 * Returns the column for a specified id.
57092 * @param {String} id The column id
57093 * @return {Object} the column
57095 getColumnById : function(id){
57096 return this.lookup[id];
57101 * Returns the column for a specified dataIndex.
57102 * @param {String} dataIndex The column dataIndex
57103 * @return {Object|Boolean} the column or false if not found
57105 getColumnByDataIndex: function(dataIndex){
57106 var index = this.findColumnIndex(dataIndex);
57107 return index > -1 ? this.config[index] : false;
57111 * Returns the index for a specified column id.
57112 * @param {String} id The column id
57113 * @return {Number} the index, or -1 if not found
57115 getIndexById : function(id){
57116 for(var i = 0, len = this.config.length; i < len; i++){
57117 if(this.config[i].id == id){
57125 * Returns the index for a specified column dataIndex.
57126 * @param {String} dataIndex The column dataIndex
57127 * @return {Number} the index, or -1 if not found
57130 findColumnIndex : function(dataIndex){
57131 for(var i = 0, len = this.config.length; i < len; i++){
57132 if(this.config[i].dataIndex == dataIndex){
57140 moveColumn : function(oldIndex, newIndex){
57141 var c = this.config[oldIndex];
57142 this.config.splice(oldIndex, 1);
57143 this.config.splice(newIndex, 0, c);
57144 this.dataMap = null;
57145 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57148 isLocked : function(colIndex){
57149 return this.config[colIndex].locked === true;
57152 setLocked : function(colIndex, value, suppressEvent){
57153 if(this.isLocked(colIndex) == value){
57156 this.config[colIndex].locked = value;
57157 if(!suppressEvent){
57158 this.fireEvent("columnlockchange", this, colIndex, value);
57162 getTotalLockedWidth : function(){
57163 var totalWidth = 0;
57164 for(var i = 0; i < this.config.length; i++){
57165 if(this.isLocked(i) && !this.isHidden(i)){
57166 this.totalWidth += this.getColumnWidth(i);
57172 getLockedCount : function(){
57173 for(var i = 0, len = this.config.length; i < len; i++){
57174 if(!this.isLocked(i)){
57179 return this.config.length;
57183 * Returns the number of columns.
57186 getColumnCount : function(visibleOnly){
57187 if(visibleOnly === true){
57189 for(var i = 0, len = this.config.length; i < len; i++){
57190 if(!this.isHidden(i)){
57196 return this.config.length;
57200 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57201 * @param {Function} fn
57202 * @param {Object} scope (optional)
57203 * @return {Array} result
57205 getColumnsBy : function(fn, scope){
57207 for(var i = 0, len = this.config.length; i < len; i++){
57208 var c = this.config[i];
57209 if(fn.call(scope||this, c, i) === true){
57217 * Returns true if the specified column is sortable.
57218 * @param {Number} col The column index
57219 * @return {Boolean}
57221 isSortable : function(col){
57222 if(typeof this.config[col].sortable == "undefined"){
57223 return this.defaultSortable;
57225 return this.config[col].sortable;
57229 * Returns the rendering (formatting) function defined for the column.
57230 * @param {Number} col The column index.
57231 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57233 getRenderer : function(col){
57234 if(!this.config[col].renderer){
57235 return Roo.grid.ColumnModel.defaultRenderer;
57237 return this.config[col].renderer;
57241 * Sets the rendering (formatting) function for a column.
57242 * @param {Number} col The column index
57243 * @param {Function} fn The function to use to process the cell's raw data
57244 * to return HTML markup for the grid view. The render function is called with
57245 * the following parameters:<ul>
57246 * <li>Data value.</li>
57247 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57248 * <li>css A CSS style string to apply to the table cell.</li>
57249 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57250 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57251 * <li>Row index</li>
57252 * <li>Column index</li>
57253 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57255 setRenderer : function(col, fn){
57256 this.config[col].renderer = fn;
57260 * Returns the width for the specified column.
57261 * @param {Number} col The column index
57264 getColumnWidth : function(col){
57265 return this.config[col].width * 1 || this.defaultWidth;
57269 * Sets the width for a column.
57270 * @param {Number} col The column index
57271 * @param {Number} width The new width
57273 setColumnWidth : function(col, width, suppressEvent){
57274 this.config[col].width = width;
57275 this.totalWidth = null;
57276 if(!suppressEvent){
57277 this.fireEvent("widthchange", this, col, width);
57282 * Returns the total width of all columns.
57283 * @param {Boolean} includeHidden True to include hidden column widths
57286 getTotalWidth : function(includeHidden){
57287 if(!this.totalWidth){
57288 this.totalWidth = 0;
57289 for(var i = 0, len = this.config.length; i < len; i++){
57290 if(includeHidden || !this.isHidden(i)){
57291 this.totalWidth += this.getColumnWidth(i);
57295 return this.totalWidth;
57299 * Returns the header for the specified column.
57300 * @param {Number} col The column index
57303 getColumnHeader : function(col){
57304 return this.config[col].header;
57308 * Sets the header for a column.
57309 * @param {Number} col The column index
57310 * @param {String} header The new header
57312 setColumnHeader : function(col, header){
57313 this.config[col].header = header;
57314 this.fireEvent("headerchange", this, col, header);
57318 * Returns the tooltip for the specified column.
57319 * @param {Number} col The column index
57322 getColumnTooltip : function(col){
57323 return this.config[col].tooltip;
57326 * Sets the tooltip for a column.
57327 * @param {Number} col The column index
57328 * @param {String} tooltip The new tooltip
57330 setColumnTooltip : function(col, tooltip){
57331 this.config[col].tooltip = tooltip;
57335 * Returns the dataIndex for the specified column.
57336 * @param {Number} col The column index
57339 getDataIndex : function(col){
57340 return this.config[col].dataIndex;
57344 * Sets the dataIndex for a column.
57345 * @param {Number} col The column index
57346 * @param {Number} dataIndex The new dataIndex
57348 setDataIndex : function(col, dataIndex){
57349 this.config[col].dataIndex = dataIndex;
57355 * Returns true if the cell is editable.
57356 * @param {Number} colIndex The column index
57357 * @param {Number} rowIndex The row index - this is nto actually used..?
57358 * @return {Boolean}
57360 isCellEditable : function(colIndex, rowIndex){
57361 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57365 * Returns the editor defined for the cell/column.
57366 * return false or null to disable editing.
57367 * @param {Number} colIndex The column index
57368 * @param {Number} rowIndex The row index
57371 getCellEditor : function(colIndex, rowIndex){
57372 return this.config[colIndex].editor;
57376 * Sets if a column is editable.
57377 * @param {Number} col The column index
57378 * @param {Boolean} editable True if the column is editable
57380 setEditable : function(col, editable){
57381 this.config[col].editable = editable;
57386 * Returns true if the column is hidden.
57387 * @param {Number} colIndex The column index
57388 * @return {Boolean}
57390 isHidden : function(colIndex){
57391 return this.config[colIndex].hidden;
57396 * Returns true if the column width cannot be changed
57398 isFixed : function(colIndex){
57399 return this.config[colIndex].fixed;
57403 * Returns true if the column can be resized
57404 * @return {Boolean}
57406 isResizable : function(colIndex){
57407 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57410 * Sets if a column is hidden.
57411 * @param {Number} colIndex The column index
57412 * @param {Boolean} hidden True if the column is hidden
57414 setHidden : function(colIndex, hidden){
57415 this.config[colIndex].hidden = hidden;
57416 this.totalWidth = null;
57417 this.fireEvent("hiddenchange", this, colIndex, hidden);
57421 * Sets the editor for a column.
57422 * @param {Number} col The column index
57423 * @param {Object} editor The editor object
57425 setEditor : function(col, editor){
57426 this.config[col].editor = editor;
57430 Roo.grid.ColumnModel.defaultRenderer = function(value)
57432 if(typeof value == "object") {
57435 if(typeof value == "string" && value.length < 1){
57439 return String.format("{0}", value);
57442 // Alias for backwards compatibility
57443 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57446 * Ext JS Library 1.1.1
57447 * Copyright(c) 2006-2007, Ext JS, LLC.
57449 * Originally Released Under LGPL - original licence link has changed is not relivant.
57452 * <script type="text/javascript">
57456 * @class Roo.grid.AbstractSelectionModel
57457 * @extends Roo.util.Observable
57458 * Abstract base class for grid SelectionModels. It provides the interface that should be
57459 * implemented by descendant classes. This class should not be directly instantiated.
57462 Roo.grid.AbstractSelectionModel = function(){
57463 this.locked = false;
57464 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57467 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57468 /** @ignore Called by the grid automatically. Do not call directly. */
57469 init : function(grid){
57475 * Locks the selections.
57478 this.locked = true;
57482 * Unlocks the selections.
57484 unlock : function(){
57485 this.locked = false;
57489 * Returns true if the selections are locked.
57490 * @return {Boolean}
57492 isLocked : function(){
57493 return this.locked;
57497 * Ext JS Library 1.1.1
57498 * Copyright(c) 2006-2007, Ext JS, LLC.
57500 * Originally Released Under LGPL - original licence link has changed is not relivant.
57503 * <script type="text/javascript">
57506 * @extends Roo.grid.AbstractSelectionModel
57507 * @class Roo.grid.RowSelectionModel
57508 * The default SelectionModel used by {@link Roo.grid.Grid}.
57509 * It supports multiple selections and keyboard selection/navigation.
57511 * @param {Object} config
57513 Roo.grid.RowSelectionModel = function(config){
57514 Roo.apply(this, config);
57515 this.selections = new Roo.util.MixedCollection(false, function(o){
57520 this.lastActive = false;
57524 * @event selectionchange
57525 * Fires when the selection changes
57526 * @param {SelectionModel} this
57528 "selectionchange" : true,
57530 * @event afterselectionchange
57531 * Fires after the selection changes (eg. by key press or clicking)
57532 * @param {SelectionModel} this
57534 "afterselectionchange" : true,
57536 * @event beforerowselect
57537 * Fires when a row is selected being selected, return false to cancel.
57538 * @param {SelectionModel} this
57539 * @param {Number} rowIndex The selected index
57540 * @param {Boolean} keepExisting False if other selections will be cleared
57542 "beforerowselect" : true,
57545 * Fires when a row is selected.
57546 * @param {SelectionModel} this
57547 * @param {Number} rowIndex The selected index
57548 * @param {Roo.data.Record} r The record
57550 "rowselect" : true,
57552 * @event rowdeselect
57553 * Fires when a row is deselected.
57554 * @param {SelectionModel} this
57555 * @param {Number} rowIndex The selected index
57557 "rowdeselect" : true
57559 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57560 this.locked = false;
57563 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57565 * @cfg {Boolean} singleSelect
57566 * True to allow selection of only one row at a time (defaults to false)
57568 singleSelect : false,
57571 initEvents : function(){
57573 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57574 this.grid.on("mousedown", this.handleMouseDown, this);
57575 }else{ // allow click to work like normal
57576 this.grid.on("rowclick", this.handleDragableRowClick, this);
57579 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57580 "up" : function(e){
57582 this.selectPrevious(e.shiftKey);
57583 }else if(this.last !== false && this.lastActive !== false){
57584 var last = this.last;
57585 this.selectRange(this.last, this.lastActive-1);
57586 this.grid.getView().focusRow(this.lastActive);
57587 if(last !== false){
57591 this.selectFirstRow();
57593 this.fireEvent("afterselectionchange", this);
57595 "down" : function(e){
57597 this.selectNext(e.shiftKey);
57598 }else if(this.last !== false && this.lastActive !== false){
57599 var last = this.last;
57600 this.selectRange(this.last, this.lastActive+1);
57601 this.grid.getView().focusRow(this.lastActive);
57602 if(last !== false){
57606 this.selectFirstRow();
57608 this.fireEvent("afterselectionchange", this);
57613 var view = this.grid.view;
57614 view.on("refresh", this.onRefresh, this);
57615 view.on("rowupdated", this.onRowUpdated, this);
57616 view.on("rowremoved", this.onRemove, this);
57620 onRefresh : function(){
57621 var ds = this.grid.dataSource, i, v = this.grid.view;
57622 var s = this.selections;
57623 s.each(function(r){
57624 if((i = ds.indexOfId(r.id)) != -1){
57626 s.add(ds.getAt(i)); // updating the selection relate data
57634 onRemove : function(v, index, r){
57635 this.selections.remove(r);
57639 onRowUpdated : function(v, index, r){
57640 if(this.isSelected(r)){
57641 v.onRowSelect(index);
57647 * @param {Array} records The records to select
57648 * @param {Boolean} keepExisting (optional) True to keep existing selections
57650 selectRecords : function(records, keepExisting){
57652 this.clearSelections();
57654 var ds = this.grid.dataSource;
57655 for(var i = 0, len = records.length; i < len; i++){
57656 this.selectRow(ds.indexOf(records[i]), true);
57661 * Gets the number of selected rows.
57664 getCount : function(){
57665 return this.selections.length;
57669 * Selects the first row in the grid.
57671 selectFirstRow : function(){
57676 * Select the last row.
57677 * @param {Boolean} keepExisting (optional) True to keep existing selections
57679 selectLastRow : function(keepExisting){
57680 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57684 * Selects the row immediately following the last selected row.
57685 * @param {Boolean} keepExisting (optional) True to keep existing selections
57687 selectNext : function(keepExisting){
57688 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57689 this.selectRow(this.last+1, keepExisting);
57690 this.grid.getView().focusRow(this.last);
57695 * Selects the row that precedes the last selected row.
57696 * @param {Boolean} keepExisting (optional) True to keep existing selections
57698 selectPrevious : function(keepExisting){
57700 this.selectRow(this.last-1, keepExisting);
57701 this.grid.getView().focusRow(this.last);
57706 * Returns the selected records
57707 * @return {Array} Array of selected records
57709 getSelections : function(){
57710 return [].concat(this.selections.items);
57714 * Returns the first selected record.
57717 getSelected : function(){
57718 return this.selections.itemAt(0);
57723 * Clears all selections.
57725 clearSelections : function(fast){
57730 var ds = this.grid.dataSource;
57731 var s = this.selections;
57732 s.each(function(r){
57733 this.deselectRow(ds.indexOfId(r.id));
57737 this.selections.clear();
57744 * Selects all rows.
57746 selectAll : function(){
57750 this.selections.clear();
57751 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57752 this.selectRow(i, true);
57757 * Returns True if there is a selection.
57758 * @return {Boolean}
57760 hasSelection : function(){
57761 return this.selections.length > 0;
57765 * Returns True if the specified row is selected.
57766 * @param {Number/Record} record The record or index of the record to check
57767 * @return {Boolean}
57769 isSelected : function(index){
57770 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57771 return (r && this.selections.key(r.id) ? true : false);
57775 * Returns True if the specified record id is selected.
57776 * @param {String} id The id of record to check
57777 * @return {Boolean}
57779 isIdSelected : function(id){
57780 return (this.selections.key(id) ? true : false);
57784 handleMouseDown : function(e, t){
57785 var view = this.grid.getView(), rowIndex;
57786 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57789 if(e.shiftKey && this.last !== false){
57790 var last = this.last;
57791 this.selectRange(last, rowIndex, e.ctrlKey);
57792 this.last = last; // reset the last
57793 view.focusRow(rowIndex);
57795 var isSelected = this.isSelected(rowIndex);
57796 if(e.button !== 0 && isSelected){
57797 view.focusRow(rowIndex);
57798 }else if(e.ctrlKey && isSelected){
57799 this.deselectRow(rowIndex);
57800 }else if(!isSelected){
57801 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57802 view.focusRow(rowIndex);
57805 this.fireEvent("afterselectionchange", this);
57808 handleDragableRowClick : function(grid, rowIndex, e)
57810 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57811 this.selectRow(rowIndex, false);
57812 grid.view.focusRow(rowIndex);
57813 this.fireEvent("afterselectionchange", this);
57818 * Selects multiple rows.
57819 * @param {Array} rows Array of the indexes of the row to select
57820 * @param {Boolean} keepExisting (optional) True to keep existing selections
57822 selectRows : function(rows, keepExisting){
57824 this.clearSelections();
57826 for(var i = 0, len = rows.length; i < len; i++){
57827 this.selectRow(rows[i], true);
57832 * Selects a range of rows. All rows in between startRow and endRow are also selected.
57833 * @param {Number} startRow The index of the first row in the range
57834 * @param {Number} endRow The index of the last row in the range
57835 * @param {Boolean} keepExisting (optional) True to retain existing selections
57837 selectRange : function(startRow, endRow, keepExisting){
57842 this.clearSelections();
57844 if(startRow <= endRow){
57845 for(var i = startRow; i <= endRow; i++){
57846 this.selectRow(i, true);
57849 for(var i = startRow; i >= endRow; i--){
57850 this.selectRow(i, true);
57856 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57857 * @param {Number} startRow The index of the first row in the range
57858 * @param {Number} endRow The index of the last row in the range
57860 deselectRange : function(startRow, endRow, preventViewNotify){
57864 for(var i = startRow; i <= endRow; i++){
57865 this.deselectRow(i, preventViewNotify);
57871 * @param {Number} row The index of the row to select
57872 * @param {Boolean} keepExisting (optional) True to keep existing selections
57874 selectRow : function(index, keepExisting, preventViewNotify){
57875 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
57878 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
57879 if(!keepExisting || this.singleSelect){
57880 this.clearSelections();
57882 var r = this.grid.dataSource.getAt(index);
57883 this.selections.add(r);
57884 this.last = this.lastActive = index;
57885 if(!preventViewNotify){
57886 this.grid.getView().onRowSelect(index);
57888 this.fireEvent("rowselect", this, index, r);
57889 this.fireEvent("selectionchange", this);
57895 * @param {Number} row The index of the row to deselect
57897 deselectRow : function(index, preventViewNotify){
57901 if(this.last == index){
57904 if(this.lastActive == index){
57905 this.lastActive = false;
57907 var r = this.grid.dataSource.getAt(index);
57908 this.selections.remove(r);
57909 if(!preventViewNotify){
57910 this.grid.getView().onRowDeselect(index);
57912 this.fireEvent("rowdeselect", this, index);
57913 this.fireEvent("selectionchange", this);
57917 restoreLast : function(){
57919 this.last = this._last;
57924 acceptsNav : function(row, col, cm){
57925 return !cm.isHidden(col) && cm.isCellEditable(col, row);
57929 onEditorKey : function(field, e){
57930 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
57935 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
57937 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
57939 }else if(k == e.ENTER && !e.ctrlKey){
57943 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
57945 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
57947 }else if(k == e.ESC){
57951 g.startEditing(newCell[0], newCell[1]);
57956 * Ext JS Library 1.1.1
57957 * Copyright(c) 2006-2007, Ext JS, LLC.
57959 * Originally Released Under LGPL - original licence link has changed is not relivant.
57962 * <script type="text/javascript">
57965 * @class Roo.grid.CellSelectionModel
57966 * @extends Roo.grid.AbstractSelectionModel
57967 * This class provides the basic implementation for cell selection in a grid.
57969 * @param {Object} config The object containing the configuration of this model.
57970 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
57972 Roo.grid.CellSelectionModel = function(config){
57973 Roo.apply(this, config);
57975 this.selection = null;
57979 * @event beforerowselect
57980 * Fires before a cell is selected.
57981 * @param {SelectionModel} this
57982 * @param {Number} rowIndex The selected row index
57983 * @param {Number} colIndex The selected cell index
57985 "beforecellselect" : true,
57987 * @event cellselect
57988 * Fires when a cell is selected.
57989 * @param {SelectionModel} this
57990 * @param {Number} rowIndex The selected row index
57991 * @param {Number} colIndex The selected cell index
57993 "cellselect" : true,
57995 * @event selectionchange
57996 * Fires when the active selection changes.
57997 * @param {SelectionModel} this
57998 * @param {Object} selection null for no selection or an object (o) with two properties
58000 <li>o.record: the record object for the row the selection is in</li>
58001 <li>o.cell: An array of [rowIndex, columnIndex]</li>
58004 "selectionchange" : true,
58007 * Fires when the tab (or enter) was pressed on the last editable cell
58008 * You can use this to trigger add new row.
58009 * @param {SelectionModel} this
58013 * @event beforeeditnext
58014 * Fires before the next editable sell is made active
58015 * You can use this to skip to another cell or fire the tabend
58016 * if you set cell to false
58017 * @param {Object} eventdata object : { cell : [ row, col ] }
58019 "beforeeditnext" : true
58021 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58024 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58026 enter_is_tab: false,
58029 initEvents : function(){
58030 this.grid.on("mousedown", this.handleMouseDown, this);
58031 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58032 var view = this.grid.view;
58033 view.on("refresh", this.onViewChange, this);
58034 view.on("rowupdated", this.onRowUpdated, this);
58035 view.on("beforerowremoved", this.clearSelections, this);
58036 view.on("beforerowsinserted", this.clearSelections, this);
58037 if(this.grid.isEditor){
58038 this.grid.on("beforeedit", this.beforeEdit, this);
58043 beforeEdit : function(e){
58044 this.select(e.row, e.column, false, true, e.record);
58048 onRowUpdated : function(v, index, r){
58049 if(this.selection && this.selection.record == r){
58050 v.onCellSelect(index, this.selection.cell[1]);
58055 onViewChange : function(){
58056 this.clearSelections(true);
58060 * Returns the currently selected cell,.
58061 * @return {Array} The selected cell (row, column) or null if none selected.
58063 getSelectedCell : function(){
58064 return this.selection ? this.selection.cell : null;
58068 * Clears all selections.
58069 * @param {Boolean} true to prevent the gridview from being notified about the change.
58071 clearSelections : function(preventNotify){
58072 var s = this.selection;
58074 if(preventNotify !== true){
58075 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58077 this.selection = null;
58078 this.fireEvent("selectionchange", this, null);
58083 * Returns true if there is a selection.
58084 * @return {Boolean}
58086 hasSelection : function(){
58087 return this.selection ? true : false;
58091 handleMouseDown : function(e, t){
58092 var v = this.grid.getView();
58093 if(this.isLocked()){
58096 var row = v.findRowIndex(t);
58097 var cell = v.findCellIndex(t);
58098 if(row !== false && cell !== false){
58099 this.select(row, cell);
58105 * @param {Number} rowIndex
58106 * @param {Number} collIndex
58108 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58109 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58110 this.clearSelections();
58111 r = r || this.grid.dataSource.getAt(rowIndex);
58114 cell : [rowIndex, colIndex]
58116 if(!preventViewNotify){
58117 var v = this.grid.getView();
58118 v.onCellSelect(rowIndex, colIndex);
58119 if(preventFocus !== true){
58120 v.focusCell(rowIndex, colIndex);
58123 this.fireEvent("cellselect", this, rowIndex, colIndex);
58124 this.fireEvent("selectionchange", this, this.selection);
58129 isSelectable : function(rowIndex, colIndex, cm){
58130 return !cm.isHidden(colIndex);
58134 handleKeyDown : function(e){
58135 //Roo.log('Cell Sel Model handleKeyDown');
58136 if(!e.isNavKeyPress()){
58139 var g = this.grid, s = this.selection;
58142 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58144 this.select(cell[0], cell[1]);
58149 var walk = function(row, col, step){
58150 return g.walkCells(row, col, step, sm.isSelectable, sm);
58152 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58159 // handled by onEditorKey
58160 if (g.isEditor && g.editing) {
58164 newCell = walk(r, c-1, -1);
58166 newCell = walk(r, c+1, 1);
58171 newCell = walk(r+1, c, 1);
58175 newCell = walk(r-1, c, -1);
58179 newCell = walk(r, c+1, 1);
58183 newCell = walk(r, c-1, -1);
58188 if(g.isEditor && !g.editing){
58189 g.startEditing(r, c);
58198 this.select(newCell[0], newCell[1]);
58204 acceptsNav : function(row, col, cm){
58205 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58209 * @param {Number} field (not used) - as it's normally used as a listener
58210 * @param {Number} e - event - fake it by using
58212 * var e = Roo.EventObjectImpl.prototype;
58213 * e.keyCode = e.TAB
58217 onEditorKey : function(field, e){
58219 var k = e.getKey(),
58222 ed = g.activeEditor,
58224 ///Roo.log('onEditorKey' + k);
58227 if (this.enter_is_tab && k == e.ENTER) {
58233 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58235 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58241 } else if(k == e.ENTER && !e.ctrlKey){
58244 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58246 } else if(k == e.ESC){
58251 var ecall = { cell : newCell, forward : forward };
58252 this.fireEvent('beforeeditnext', ecall );
58253 newCell = ecall.cell;
58254 forward = ecall.forward;
58258 //Roo.log('next cell after edit');
58259 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58260 } else if (forward) {
58261 // tabbed past last
58262 this.fireEvent.defer(100, this, ['tabend',this]);
58267 * Ext JS Library 1.1.1
58268 * Copyright(c) 2006-2007, Ext JS, LLC.
58270 * Originally Released Under LGPL - original licence link has changed is not relivant.
58273 * <script type="text/javascript">
58277 * @class Roo.grid.EditorGrid
58278 * @extends Roo.grid.Grid
58279 * Class for creating and editable grid.
58280 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58281 * The container MUST have some type of size defined for the grid to fill. The container will be
58282 * automatically set to position relative if it isn't already.
58283 * @param {Object} dataSource The data model to bind to
58284 * @param {Object} colModel The column model with info about this grid's columns
58286 Roo.grid.EditorGrid = function(container, config){
58287 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58288 this.getGridEl().addClass("xedit-grid");
58290 if(!this.selModel){
58291 this.selModel = new Roo.grid.CellSelectionModel();
58294 this.activeEditor = null;
58298 * @event beforeedit
58299 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58300 * <ul style="padding:5px;padding-left:16px;">
58301 * <li>grid - This grid</li>
58302 * <li>record - The record being edited</li>
58303 * <li>field - The field name being edited</li>
58304 * <li>value - The value for the field being edited.</li>
58305 * <li>row - The grid row index</li>
58306 * <li>column - The grid column index</li>
58307 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58309 * @param {Object} e An edit event (see above for description)
58311 "beforeedit" : true,
58314 * Fires after a cell is edited. <br />
58315 * <ul style="padding:5px;padding-left:16px;">
58316 * <li>grid - This grid</li>
58317 * <li>record - The record being edited</li>
58318 * <li>field - The field name being edited</li>
58319 * <li>value - The value being set</li>
58320 * <li>originalValue - The original value for the field, before the edit.</li>
58321 * <li>row - The grid row index</li>
58322 * <li>column - The grid column index</li>
58324 * @param {Object} e An edit event (see above for description)
58326 "afteredit" : true,
58328 * @event validateedit
58329 * Fires after a cell is edited, but before the value is set in the record.
58330 * You can use this to modify the value being set in the field, Return false
58331 * to cancel the change. The edit event object has the following properties <br />
58332 * <ul style="padding:5px;padding-left:16px;">
58333 * <li>editor - This editor</li>
58334 * <li>grid - This grid</li>
58335 * <li>record - The record being edited</li>
58336 * <li>field - The field name being edited</li>
58337 * <li>value - The value being set</li>
58338 * <li>originalValue - The original value for the field, before the edit.</li>
58339 * <li>row - The grid row index</li>
58340 * <li>column - The grid column index</li>
58341 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58343 * @param {Object} e An edit event (see above for description)
58345 "validateedit" : true
58347 this.on("bodyscroll", this.stopEditing, this);
58348 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58351 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58353 * @cfg {Number} clicksToEdit
58354 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58361 trackMouseOver: false, // causes very odd FF errors
58363 onCellDblClick : function(g, row, col){
58364 this.startEditing(row, col);
58367 onEditComplete : function(ed, value, startValue){
58368 this.editing = false;
58369 this.activeEditor = null;
58370 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58372 var field = this.colModel.getDataIndex(ed.col);
58377 originalValue: startValue,
58384 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58387 if(String(value) !== String(startValue)){
58389 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58390 r.set(field, e.value);
58391 // if we are dealing with a combo box..
58392 // then we also set the 'name' colum to be the displayField
58393 if (ed.field.displayField && ed.field.name) {
58394 r.set(ed.field.name, ed.field.el.dom.value);
58397 delete e.cancel; //?? why!!!
58398 this.fireEvent("afteredit", e);
58401 this.fireEvent("afteredit", e); // always fire it!
58403 this.view.focusCell(ed.row, ed.col);
58407 * Starts editing the specified for the specified row/column
58408 * @param {Number} rowIndex
58409 * @param {Number} colIndex
58411 startEditing : function(row, col){
58412 this.stopEditing();
58413 if(this.colModel.isCellEditable(col, row)){
58414 this.view.ensureVisible(row, col, true);
58416 var r = this.dataSource.getAt(row);
58417 var field = this.colModel.getDataIndex(col);
58418 var cell = Roo.get(this.view.getCell(row,col));
58423 value: r.data[field],
58428 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58429 this.editing = true;
58430 var ed = this.colModel.getCellEditor(col, row);
58436 ed.render(ed.parentEl || document.body);
58442 (function(){ // complex but required for focus issues in safari, ie and opera
58446 ed.on("complete", this.onEditComplete, this, {single: true});
58447 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58448 this.activeEditor = ed;
58449 var v = r.data[field];
58450 ed.startEdit(this.view.getCell(row, col), v);
58451 // combo's with 'displayField and name set
58452 if (ed.field.displayField && ed.field.name) {
58453 ed.field.el.dom.value = r.data[ed.field.name];
58457 }).defer(50, this);
58463 * Stops any active editing
58465 stopEditing : function(){
58466 if(this.activeEditor){
58467 this.activeEditor.completeEdit();
58469 this.activeEditor = null;
58473 * Called to get grid's drag proxy text, by default returns this.ddText.
58476 getDragDropText : function(){
58477 var count = this.selModel.getSelectedCell() ? 1 : 0;
58478 return String.format(this.ddText, count, count == 1 ? '' : 's');
58483 * Ext JS Library 1.1.1
58484 * Copyright(c) 2006-2007, Ext JS, LLC.
58486 * Originally Released Under LGPL - original licence link has changed is not relivant.
58489 * <script type="text/javascript">
58492 // private - not really -- you end up using it !
58493 // This is a support class used internally by the Grid components
58496 * @class Roo.grid.GridEditor
58497 * @extends Roo.Editor
58498 * Class for creating and editable grid elements.
58499 * @param {Object} config any settings (must include field)
58501 Roo.grid.GridEditor = function(field, config){
58502 if (!config && field.field) {
58504 field = Roo.factory(config.field, Roo.form);
58506 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58507 field.monitorTab = false;
58510 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58513 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58516 alignment: "tl-tl",
58519 cls: "x-small-editor x-grid-editor",
58524 * Ext JS Library 1.1.1
58525 * Copyright(c) 2006-2007, Ext JS, LLC.
58527 * Originally Released Under LGPL - original licence link has changed is not relivant.
58530 * <script type="text/javascript">
58535 Roo.grid.PropertyRecord = Roo.data.Record.create([
58536 {name:'name',type:'string'}, 'value'
58540 Roo.grid.PropertyStore = function(grid, source){
58542 this.store = new Roo.data.Store({
58543 recordType : Roo.grid.PropertyRecord
58545 this.store.on('update', this.onUpdate, this);
58547 this.setSource(source);
58549 Roo.grid.PropertyStore.superclass.constructor.call(this);
58554 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58555 setSource : function(o){
58557 this.store.removeAll();
58560 if(this.isEditableValue(o[k])){
58561 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58564 this.store.loadRecords({records: data}, {}, true);
58567 onUpdate : function(ds, record, type){
58568 if(type == Roo.data.Record.EDIT){
58569 var v = record.data['value'];
58570 var oldValue = record.modified['value'];
58571 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58572 this.source[record.id] = v;
58574 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58581 getProperty : function(row){
58582 return this.store.getAt(row);
58585 isEditableValue: function(val){
58586 if(val && val instanceof Date){
58588 }else if(typeof val == 'object' || typeof val == 'function'){
58594 setValue : function(prop, value){
58595 this.source[prop] = value;
58596 this.store.getById(prop).set('value', value);
58599 getSource : function(){
58600 return this.source;
58604 Roo.grid.PropertyColumnModel = function(grid, store){
58607 g.PropertyColumnModel.superclass.constructor.call(this, [
58608 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58609 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58611 this.store = store;
58612 this.bselect = Roo.DomHelper.append(document.body, {
58613 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58614 {tag: 'option', value: 'true', html: 'true'},
58615 {tag: 'option', value: 'false', html: 'false'}
58618 Roo.id(this.bselect);
58621 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58622 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58623 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58624 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58625 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58627 this.renderCellDelegate = this.renderCell.createDelegate(this);
58628 this.renderPropDelegate = this.renderProp.createDelegate(this);
58631 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58635 valueText : 'Value',
58637 dateFormat : 'm/j/Y',
58640 renderDate : function(dateVal){
58641 return dateVal.dateFormat(this.dateFormat);
58644 renderBool : function(bVal){
58645 return bVal ? 'true' : 'false';
58648 isCellEditable : function(colIndex, rowIndex){
58649 return colIndex == 1;
58652 getRenderer : function(col){
58654 this.renderCellDelegate : this.renderPropDelegate;
58657 renderProp : function(v){
58658 return this.getPropertyName(v);
58661 renderCell : function(val){
58663 if(val instanceof Date){
58664 rv = this.renderDate(val);
58665 }else if(typeof val == 'boolean'){
58666 rv = this.renderBool(val);
58668 return Roo.util.Format.htmlEncode(rv);
58671 getPropertyName : function(name){
58672 var pn = this.grid.propertyNames;
58673 return pn && pn[name] ? pn[name] : name;
58676 getCellEditor : function(colIndex, rowIndex){
58677 var p = this.store.getProperty(rowIndex);
58678 var n = p.data['name'], val = p.data['value'];
58680 if(typeof(this.grid.customEditors[n]) == 'string'){
58681 return this.editors[this.grid.customEditors[n]];
58683 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58684 return this.grid.customEditors[n];
58686 if(val instanceof Date){
58687 return this.editors['date'];
58688 }else if(typeof val == 'number'){
58689 return this.editors['number'];
58690 }else if(typeof val == 'boolean'){
58691 return this.editors['boolean'];
58693 return this.editors['string'];
58699 * @class Roo.grid.PropertyGrid
58700 * @extends Roo.grid.EditorGrid
58701 * This class represents the interface of a component based property grid control.
58702 * <br><br>Usage:<pre><code>
58703 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58711 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58712 * The container MUST have some type of size defined for the grid to fill. The container will be
58713 * automatically set to position relative if it isn't already.
58714 * @param {Object} config A config object that sets properties on this grid.
58716 Roo.grid.PropertyGrid = function(container, config){
58717 config = config || {};
58718 var store = new Roo.grid.PropertyStore(this);
58719 this.store = store;
58720 var cm = new Roo.grid.PropertyColumnModel(this, store);
58721 store.store.sort('name', 'ASC');
58722 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58725 enableColLock:false,
58726 enableColumnMove:false,
58728 trackMouseOver: false,
58731 this.getGridEl().addClass('x-props-grid');
58732 this.lastEditRow = null;
58733 this.on('columnresize', this.onColumnResize, this);
58736 * @event beforepropertychange
58737 * Fires before a property changes (return false to stop?)
58738 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58739 * @param {String} id Record Id
58740 * @param {String} newval New Value
58741 * @param {String} oldval Old Value
58743 "beforepropertychange": true,
58745 * @event propertychange
58746 * Fires after a property changes
58747 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58748 * @param {String} id Record Id
58749 * @param {String} newval New Value
58750 * @param {String} oldval Old Value
58752 "propertychange": true
58754 this.customEditors = this.customEditors || {};
58756 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58759 * @cfg {Object} customEditors map of colnames=> custom editors.
58760 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58761 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58762 * false disables editing of the field.
58766 * @cfg {Object} propertyNames map of property Names to their displayed value
58769 render : function(){
58770 Roo.grid.PropertyGrid.superclass.render.call(this);
58771 this.autoSize.defer(100, this);
58774 autoSize : function(){
58775 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58777 this.view.fitColumns();
58781 onColumnResize : function(){
58782 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58786 * Sets the data for the Grid
58787 * accepts a Key => Value object of all the elements avaiable.
58788 * @param {Object} data to appear in grid.
58790 setSource : function(source){
58791 this.store.setSource(source);
58795 * Gets all the data from the grid.
58796 * @return {Object} data data stored in grid
58798 getSource : function(){
58799 return this.store.getSource();
58808 * @class Roo.grid.Calendar
58809 * @extends Roo.util.Grid
58810 * This class extends the Grid to provide a calendar widget
58811 * <br><br>Usage:<pre><code>
58812 var grid = new Roo.grid.Calendar("my-container-id", {
58815 selModel: mySelectionModel,
58816 autoSizeColumns: true,
58817 monitorWindowResize: false,
58818 trackMouseOver: true
58819 eventstore : real data store..
58825 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58826 * The container MUST have some type of size defined for the grid to fill. The container will be
58827 * automatically set to position relative if it isn't already.
58828 * @param {Object} config A config object that sets properties on this grid.
58830 Roo.grid.Calendar = function(container, config){
58831 // initialize the container
58832 this.container = Roo.get(container);
58833 this.container.update("");
58834 this.container.setStyle("overflow", "hidden");
58835 this.container.addClass('x-grid-container');
58837 this.id = this.container.id;
58839 Roo.apply(this, config);
58840 // check and correct shorthanded configs
58844 for (var r = 0;r < 6;r++) {
58847 for (var c =0;c < 7;c++) {
58851 if (this.eventStore) {
58852 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58853 this.eventStore.on('load',this.onLoad, this);
58854 this.eventStore.on('beforeload',this.clearEvents, this);
58858 this.dataSource = new Roo.data.Store({
58859 proxy: new Roo.data.MemoryProxy(rows),
58860 reader: new Roo.data.ArrayReader({}, [
58861 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58864 this.dataSource.load();
58865 this.ds = this.dataSource;
58866 this.ds.xmodule = this.xmodule || false;
58869 var cellRender = function(v,x,r)
58871 return String.format(
58872 '<div class="fc-day fc-widget-content"><div>' +
58873 '<div class="fc-event-container"></div>' +
58874 '<div class="fc-day-number">{0}</div>'+
58876 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
58877 '</div></div>', v);
58882 this.colModel = new Roo.grid.ColumnModel( [
58884 xtype: 'ColumnModel',
58886 dataIndex : 'weekday0',
58888 renderer : cellRender
58891 xtype: 'ColumnModel',
58893 dataIndex : 'weekday1',
58895 renderer : cellRender
58898 xtype: 'ColumnModel',
58900 dataIndex : 'weekday2',
58901 header : 'Tuesday',
58902 renderer : cellRender
58905 xtype: 'ColumnModel',
58907 dataIndex : 'weekday3',
58908 header : 'Wednesday',
58909 renderer : cellRender
58912 xtype: 'ColumnModel',
58914 dataIndex : 'weekday4',
58915 header : 'Thursday',
58916 renderer : cellRender
58919 xtype: 'ColumnModel',
58921 dataIndex : 'weekday5',
58923 renderer : cellRender
58926 xtype: 'ColumnModel',
58928 dataIndex : 'weekday6',
58929 header : 'Saturday',
58930 renderer : cellRender
58933 this.cm = this.colModel;
58934 this.cm.xmodule = this.xmodule || false;
58938 //this.selModel = new Roo.grid.CellSelectionModel();
58939 //this.sm = this.selModel;
58940 //this.selModel.init(this);
58944 this.container.setWidth(this.width);
58948 this.container.setHeight(this.height);
58955 * The raw click event for the entire grid.
58956 * @param {Roo.EventObject} e
58961 * The raw dblclick event for the entire grid.
58962 * @param {Roo.EventObject} e
58966 * @event contextmenu
58967 * The raw contextmenu event for the entire grid.
58968 * @param {Roo.EventObject} e
58970 "contextmenu" : true,
58973 * The raw mousedown event for the entire grid.
58974 * @param {Roo.EventObject} e
58976 "mousedown" : true,
58979 * The raw mouseup event for the entire grid.
58980 * @param {Roo.EventObject} e
58985 * The raw mouseover event for the entire grid.
58986 * @param {Roo.EventObject} e
58988 "mouseover" : true,
58991 * The raw mouseout event for the entire grid.
58992 * @param {Roo.EventObject} e
58997 * The raw keypress event for the entire grid.
58998 * @param {Roo.EventObject} e
59003 * The raw keydown event for the entire grid.
59004 * @param {Roo.EventObject} e
59012 * Fires when a cell is clicked
59013 * @param {Grid} this
59014 * @param {Number} rowIndex
59015 * @param {Number} columnIndex
59016 * @param {Roo.EventObject} e
59018 "cellclick" : true,
59020 * @event celldblclick
59021 * Fires when a cell is double clicked
59022 * @param {Grid} this
59023 * @param {Number} rowIndex
59024 * @param {Number} columnIndex
59025 * @param {Roo.EventObject} e
59027 "celldblclick" : true,
59030 * Fires when a row is clicked
59031 * @param {Grid} this
59032 * @param {Number} rowIndex
59033 * @param {Roo.EventObject} e
59037 * @event rowdblclick
59038 * Fires when a row is double clicked
59039 * @param {Grid} this
59040 * @param {Number} rowIndex
59041 * @param {Roo.EventObject} e
59043 "rowdblclick" : true,
59045 * @event headerclick
59046 * Fires when a header is clicked
59047 * @param {Grid} this
59048 * @param {Number} columnIndex
59049 * @param {Roo.EventObject} e
59051 "headerclick" : true,
59053 * @event headerdblclick
59054 * Fires when a header cell is double clicked
59055 * @param {Grid} this
59056 * @param {Number} columnIndex
59057 * @param {Roo.EventObject} e
59059 "headerdblclick" : true,
59061 * @event rowcontextmenu
59062 * Fires when a row is right clicked
59063 * @param {Grid} this
59064 * @param {Number} rowIndex
59065 * @param {Roo.EventObject} e
59067 "rowcontextmenu" : true,
59069 * @event cellcontextmenu
59070 * Fires when a cell is right clicked
59071 * @param {Grid} this
59072 * @param {Number} rowIndex
59073 * @param {Number} cellIndex
59074 * @param {Roo.EventObject} e
59076 "cellcontextmenu" : true,
59078 * @event headercontextmenu
59079 * Fires when a header is right clicked
59080 * @param {Grid} this
59081 * @param {Number} columnIndex
59082 * @param {Roo.EventObject} e
59084 "headercontextmenu" : true,
59086 * @event bodyscroll
59087 * Fires when the body element is scrolled
59088 * @param {Number} scrollLeft
59089 * @param {Number} scrollTop
59091 "bodyscroll" : true,
59093 * @event columnresize
59094 * Fires when the user resizes a column
59095 * @param {Number} columnIndex
59096 * @param {Number} newSize
59098 "columnresize" : true,
59100 * @event columnmove
59101 * Fires when the user moves a column
59102 * @param {Number} oldIndex
59103 * @param {Number} newIndex
59105 "columnmove" : true,
59108 * Fires when row(s) start being dragged
59109 * @param {Grid} this
59110 * @param {Roo.GridDD} dd The drag drop object
59111 * @param {event} e The raw browser event
59113 "startdrag" : true,
59116 * Fires when a drag operation is complete
59117 * @param {Grid} this
59118 * @param {Roo.GridDD} dd The drag drop object
59119 * @param {event} e The raw browser event
59124 * Fires when dragged row(s) are dropped on a valid DD target
59125 * @param {Grid} this
59126 * @param {Roo.GridDD} dd The drag drop object
59127 * @param {String} targetId The target drag drop object
59128 * @param {event} e The raw browser event
59133 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59134 * @param {Grid} this
59135 * @param {Roo.GridDD} dd The drag drop object
59136 * @param {String} targetId The target drag drop object
59137 * @param {event} e The raw browser event
59142 * Fires when the dragged row(s) first cross another DD target while being dragged
59143 * @param {Grid} this
59144 * @param {Roo.GridDD} dd The drag drop object
59145 * @param {String} targetId The target drag drop object
59146 * @param {event} e The raw browser event
59148 "dragenter" : true,
59151 * Fires when the dragged row(s) leave another DD target while being dragged
59152 * @param {Grid} this
59153 * @param {Roo.GridDD} dd The drag drop object
59154 * @param {String} targetId The target drag drop object
59155 * @param {event} e The raw browser event
59160 * Fires when a row is rendered, so you can change add a style to it.
59161 * @param {GridView} gridview The grid view
59162 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59168 * Fires when the grid is rendered
59169 * @param {Grid} grid
59174 * Fires when a date is selected
59175 * @param {DatePicker} this
59176 * @param {Date} date The selected date
59180 * @event monthchange
59181 * Fires when the displayed month changes
59182 * @param {DatePicker} this
59183 * @param {Date} date The selected month
59185 'monthchange': true,
59187 * @event evententer
59188 * Fires when mouse over an event
59189 * @param {Calendar} this
59190 * @param {event} Event
59192 'evententer': true,
59194 * @event eventleave
59195 * Fires when the mouse leaves an
59196 * @param {Calendar} this
59199 'eventleave': true,
59201 * @event eventclick
59202 * Fires when the mouse click an
59203 * @param {Calendar} this
59206 'eventclick': true,
59208 * @event eventrender
59209 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59210 * @param {Calendar} this
59211 * @param {data} data to be modified
59213 'eventrender': true
59217 Roo.grid.Grid.superclass.constructor.call(this);
59218 this.on('render', function() {
59219 this.view.el.addClass('x-grid-cal');
59221 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59225 if (!Roo.grid.Calendar.style) {
59226 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59229 '.x-grid-cal .x-grid-col' : {
59230 height: 'auto !important',
59231 'vertical-align': 'top'
59233 '.x-grid-cal .fc-event-hori' : {
59244 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59246 * @cfg {Store} eventStore The store that loads events.
59251 activeDate : false,
59254 monitorWindowResize : false,
59257 resizeColumns : function() {
59258 var col = (this.view.el.getWidth() / 7) - 3;
59259 // loop through cols, and setWidth
59260 for(var i =0 ; i < 7 ; i++){
59261 this.cm.setColumnWidth(i, col);
59264 setDate :function(date) {
59266 Roo.log('setDate?');
59268 this.resizeColumns();
59269 var vd = this.activeDate;
59270 this.activeDate = date;
59271 // if(vd && this.el){
59272 // var t = date.getTime();
59273 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59274 // Roo.log('using add remove');
59276 // this.fireEvent('monthchange', this, date);
59278 // this.cells.removeClass("fc-state-highlight");
59279 // this.cells.each(function(c){
59280 // if(c.dateValue == t){
59281 // c.addClass("fc-state-highlight");
59282 // setTimeout(function(){
59283 // try{c.dom.firstChild.focus();}catch(e){}
59293 var days = date.getDaysInMonth();
59295 var firstOfMonth = date.getFirstDateOfMonth();
59296 var startingPos = firstOfMonth.getDay()-this.startDay;
59298 if(startingPos < this.startDay){
59302 var pm = date.add(Date.MONTH, -1);
59303 var prevStart = pm.getDaysInMonth()-startingPos;
59307 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59309 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59310 //this.cells.addClassOnOver('fc-state-hover');
59312 var cells = this.cells.elements;
59313 var textEls = this.textNodes;
59315 //Roo.each(cells, function(cell){
59316 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59319 days += startingPos;
59321 // convert everything to numbers so it's fast
59322 var day = 86400000;
59323 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59326 //Roo.log(prevStart);
59328 var today = new Date().clearTime().getTime();
59329 var sel = date.clearTime().getTime();
59330 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59331 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59332 var ddMatch = this.disabledDatesRE;
59333 var ddText = this.disabledDatesText;
59334 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59335 var ddaysText = this.disabledDaysText;
59336 var format = this.format;
59338 var setCellClass = function(cal, cell){
59340 //Roo.log('set Cell Class');
59342 var t = d.getTime();
59347 cell.dateValue = t;
59349 cell.className += " fc-today";
59350 cell.className += " fc-state-highlight";
59351 cell.title = cal.todayText;
59354 // disable highlight in other month..
59355 cell.className += " fc-state-highlight";
59360 //cell.className = " fc-state-disabled";
59361 cell.title = cal.minText;
59365 //cell.className = " fc-state-disabled";
59366 cell.title = cal.maxText;
59370 if(ddays.indexOf(d.getDay()) != -1){
59371 // cell.title = ddaysText;
59372 // cell.className = " fc-state-disabled";
59375 if(ddMatch && format){
59376 var fvalue = d.dateFormat(format);
59377 if(ddMatch.test(fvalue)){
59378 cell.title = ddText.replace("%0", fvalue);
59379 cell.className = " fc-state-disabled";
59383 if (!cell.initialClassName) {
59384 cell.initialClassName = cell.dom.className;
59387 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59392 for(; i < startingPos; i++) {
59393 cells[i].dayName = (++prevStart);
59394 Roo.log(textEls[i]);
59395 d.setDate(d.getDate()+1);
59397 //cells[i].className = "fc-past fc-other-month";
59398 setCellClass(this, cells[i]);
59403 for(; i < days; i++){
59404 intDay = i - startingPos + 1;
59405 cells[i].dayName = (intDay);
59406 d.setDate(d.getDate()+1);
59408 cells[i].className = ''; // "x-date-active";
59409 setCellClass(this, cells[i]);
59413 for(; i < 42; i++) {
59414 //textEls[i].innerHTML = (++extraDays);
59416 d.setDate(d.getDate()+1);
59417 cells[i].dayName = (++extraDays);
59418 cells[i].className = "fc-future fc-other-month";
59419 setCellClass(this, cells[i]);
59422 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59424 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59426 // this will cause all the cells to mis
59429 for (var r = 0;r < 6;r++) {
59430 for (var c =0;c < 7;c++) {
59431 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59435 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59436 for(i=0;i<cells.length;i++) {
59438 this.cells.elements[i].dayName = cells[i].dayName ;
59439 this.cells.elements[i].className = cells[i].className;
59440 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59441 this.cells.elements[i].title = cells[i].title ;
59442 this.cells.elements[i].dateValue = cells[i].dateValue ;
59448 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59449 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59451 ////if(totalRows != 6){
59452 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59453 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59456 this.fireEvent('monthchange', this, date);
59461 * Returns the grid's SelectionModel.
59462 * @return {SelectionModel}
59464 getSelectionModel : function(){
59465 if(!this.selModel){
59466 this.selModel = new Roo.grid.CellSelectionModel();
59468 return this.selModel;
59472 this.eventStore.load()
59478 findCell : function(dt) {
59479 dt = dt.clearTime().getTime();
59481 this.cells.each(function(c){
59482 //Roo.log("check " +c.dateValue + '?=' + dt);
59483 if(c.dateValue == dt){
59493 findCells : function(rec) {
59494 var s = rec.data.start_dt.clone().clearTime().getTime();
59496 var e= rec.data.end_dt.clone().clearTime().getTime();
59499 this.cells.each(function(c){
59500 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59502 if(c.dateValue > e){
59505 if(c.dateValue < s){
59514 findBestRow: function(cells)
59518 for (var i =0 ; i < cells.length;i++) {
59519 ret = Math.max(cells[i].rows || 0,ret);
59526 addItem : function(rec)
59528 // look for vertical location slot in
59529 var cells = this.findCells(rec);
59531 rec.row = this.findBestRow(cells);
59533 // work out the location.
59537 for(var i =0; i < cells.length; i++) {
59545 if (crow.start.getY() == cells[i].getY()) {
59547 crow.end = cells[i];
59563 for (var i = 0; i < cells.length;i++) {
59564 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59571 clearEvents: function() {
59573 if (!this.eventStore.getCount()) {
59576 // reset number of rows in cells.
59577 Roo.each(this.cells.elements, function(c){
59581 this.eventStore.each(function(e) {
59582 this.clearEvent(e);
59587 clearEvent : function(ev)
59590 Roo.each(ev.els, function(el) {
59591 el.un('mouseenter' ,this.onEventEnter, this);
59592 el.un('mouseleave' ,this.onEventLeave, this);
59600 renderEvent : function(ev,ctr) {
59602 ctr = this.view.el.select('.fc-event-container',true).first();
59606 this.clearEvent(ev);
59612 var cells = ev.cells;
59613 var rows = ev.rows;
59614 this.fireEvent('eventrender', this, ev);
59616 for(var i =0; i < rows.length; i++) {
59620 cls += ' fc-event-start';
59622 if ((i+1) == rows.length) {
59623 cls += ' fc-event-end';
59626 //Roo.log(ev.data);
59627 // how many rows should it span..
59628 var cg = this.eventTmpl.append(ctr,Roo.apply({
59631 }, ev.data) , true);
59634 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59635 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59636 cg.on('click', this.onEventClick, this, ev);
59640 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59641 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59644 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59645 cg.setWidth(ebox.right - sbox.x -2);
59649 renderEvents: function()
59651 // first make sure there is enough space..
59653 if (!this.eventTmpl) {
59654 this.eventTmpl = new Roo.Template(
59655 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59656 '<div class="fc-event-inner">' +
59657 '<span class="fc-event-time">{time}</span>' +
59658 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59660 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59668 this.cells.each(function(c) {
59669 //Roo.log(c.select('.fc-day-content div',true).first());
59670 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59673 var ctr = this.view.el.select('.fc-event-container',true).first();
59676 this.eventStore.each(function(ev){
59678 this.renderEvent(ev);
59682 this.view.layout();
59686 onEventEnter: function (e, el,event,d) {
59687 this.fireEvent('evententer', this, el, event);
59690 onEventLeave: function (e, el,event,d) {
59691 this.fireEvent('eventleave', this, el, event);
59694 onEventClick: function (e, el,event,d) {
59695 this.fireEvent('eventclick', this, el, event);
59698 onMonthChange: function () {
59702 onLoad: function () {
59704 //Roo.log('calendar onload');
59706 if(this.eventStore.getCount() > 0){
59710 this.eventStore.each(function(d){
59715 if (typeof(add.end_dt) == 'undefined') {
59716 Roo.log("Missing End time in calendar data: ");
59720 if (typeof(add.start_dt) == 'undefined') {
59721 Roo.log("Missing Start time in calendar data: ");
59725 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59726 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59727 add.id = add.id || d.id;
59728 add.title = add.title || '??';
59736 this.renderEvents();
59746 render : function ()
59750 if (!this.view.el.hasClass('course-timesheet')) {
59751 this.view.el.addClass('course-timesheet');
59753 if (this.tsStyle) {
59758 Roo.log(_this.grid.view.el.getWidth());
59761 this.tsStyle = Roo.util.CSS.createStyleSheet({
59762 '.course-timesheet .x-grid-row' : {
59765 '.x-grid-row td' : {
59766 'vertical-align' : 0
59768 '.course-edit-link' : {
59770 'text-overflow' : 'ellipsis',
59771 'overflow' : 'hidden',
59772 'white-space' : 'nowrap',
59773 'cursor' : 'pointer'
59778 '.de-act-sup-link' : {
59779 'color' : 'purple',
59780 'text-decoration' : 'line-through'
59784 'text-decoration' : 'line-through'
59786 '.course-timesheet .course-highlight' : {
59787 'border-top-style': 'dashed !important',
59788 'border-bottom-bottom': 'dashed !important'
59790 '.course-timesheet .course-item' : {
59791 'font-family' : 'tahoma, arial, helvetica',
59792 'font-size' : '11px',
59793 'overflow' : 'hidden',
59794 'padding-left' : '10px',
59795 'padding-right' : '10px',
59796 'padding-top' : '10px'
59804 monitorWindowResize : false,
59805 cellrenderer : function(v,x,r)
59810 xtype: 'CellSelectionModel',
59817 beforeload : function (_self, options)
59819 options.params = options.params || {};
59820 options.params._month = _this.monthField.getValue();
59821 options.params.limit = 9999;
59822 options.params['sort'] = 'when_dt';
59823 options.params['dir'] = 'ASC';
59824 this.proxy.loadResponse = this.loadResponse;
59826 //this.addColumns();
59828 load : function (_self, records, options)
59830 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59831 // if you click on the translation.. you can edit it...
59832 var el = Roo.get(this);
59833 var id = el.dom.getAttribute('data-id');
59834 var d = el.dom.getAttribute('data-date');
59835 var t = el.dom.getAttribute('data-time');
59836 //var id = this.child('span').dom.textContent;
59839 Pman.Dialog.CourseCalendar.show({
59843 productitem_active : id ? 1 : 0
59845 _this.grid.ds.load({});
59850 _this.panel.fireEvent('resize', [ '', '' ]);
59853 loadResponse : function(o, success, response){
59854 // this is overridden on before load..
59856 Roo.log("our code?");
59857 //Roo.log(success);
59858 //Roo.log(response)
59859 delete this.activeRequest;
59861 this.fireEvent("loadexception", this, o, response);
59862 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59867 result = o.reader.read(response);
59869 Roo.log("load exception?");
59870 this.fireEvent("loadexception", this, o, response, e);
59871 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59874 Roo.log("ready...");
59875 // loop through result.records;
59876 // and set this.tdate[date] = [] << array of records..
59878 Roo.each(result.records, function(r){
59880 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
59881 _this.tdata[r.data.when_dt.format('j')] = [];
59883 _this.tdata[r.data.when_dt.format('j')].push(r.data);
59886 //Roo.log(_this.tdata);
59888 result.records = [];
59889 result.totalRecords = 6;
59891 // let's generate some duumy records for the rows.
59892 //var st = _this.dateField.getValue();
59894 // work out monday..
59895 //st = st.add(Date.DAY, -1 * st.format('w'));
59897 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59899 var firstOfMonth = date.getFirstDayOfMonth();
59900 var days = date.getDaysInMonth();
59902 var firstAdded = false;
59903 for (var i = 0; i < result.totalRecords ; i++) {
59904 //var d= st.add(Date.DAY, i);
59907 for(var w = 0 ; w < 7 ; w++){
59908 if(!firstAdded && firstOfMonth != w){
59915 var dd = (d > 0 && d < 10) ? "0"+d : d;
59916 row['weekday'+w] = String.format(
59917 '<span style="font-size: 16px;"><b>{0}</b></span>'+
59918 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
59920 date.format('Y-m-')+dd
59923 if(typeof(_this.tdata[d]) != 'undefined'){
59924 Roo.each(_this.tdata[d], function(r){
59928 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
59929 if(r.parent_id*1>0){
59930 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
59933 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
59934 deactive = 'de-act-link';
59937 row['weekday'+w] += String.format(
59938 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
59940 r.product_id_name, //1
59941 r.when_dt.format('h:ia'), //2
59951 // only do this if something added..
59953 result.records.push(_this.grid.dataSource.reader.newRow(row));
59957 // push it twice. (second one with an hour..
59961 this.fireEvent("load", this, o, o.request.arg);
59962 o.request.callback.call(o.request.scope, result, o.request.arg, true);
59964 sortInfo : {field: 'when_dt', direction : 'ASC' },
59966 xtype: 'HttpProxy',
59969 url : baseURL + '/Roo/Shop_course.php'
59972 xtype: 'JsonReader',
59989 'name': 'parent_id',
59993 'name': 'product_id',
59997 'name': 'productitem_id',
60015 click : function (_self, e)
60017 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60018 sd.setMonth(sd.getMonth()-1);
60019 _this.monthField.setValue(sd.format('Y-m-d'));
60020 _this.grid.ds.load({});
60026 xtype: 'Separator',
60030 xtype: 'MonthField',
60033 render : function (_self)
60035 _this.monthField = _self;
60036 // _this.monthField.set today
60038 select : function (combo, date)
60040 _this.grid.ds.load({});
60043 value : (function() { return new Date(); })()
60046 xtype: 'Separator',
60052 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60062 click : function (_self, e)
60064 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60065 sd.setMonth(sd.getMonth()+1);
60066 _this.monthField.setValue(sd.format('Y-m-d'));
60067 _this.grid.ds.load({});
60080 * Ext JS Library 1.1.1
60081 * Copyright(c) 2006-2007, Ext JS, LLC.
60083 * Originally Released Under LGPL - original licence link has changed is not relivant.
60086 * <script type="text/javascript">
60090 * @class Roo.LoadMask
60091 * A simple utility class for generically masking elements while loading data. If the element being masked has
60092 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60093 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60094 * element's UpdateManager load indicator and will be destroyed after the initial load.
60096 * Create a new LoadMask
60097 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60098 * @param {Object} config The config object
60100 Roo.LoadMask = function(el, config){
60101 this.el = Roo.get(el);
60102 Roo.apply(this, config);
60104 this.store.on('beforeload', this.onBeforeLoad, this);
60105 this.store.on('load', this.onLoad, this);
60106 this.store.on('loadexception', this.onLoadException, this);
60107 this.removeMask = false;
60109 var um = this.el.getUpdateManager();
60110 um.showLoadIndicator = false; // disable the default indicator
60111 um.on('beforeupdate', this.onBeforeLoad, this);
60112 um.on('update', this.onLoad, this);
60113 um.on('failure', this.onLoad, this);
60114 this.removeMask = true;
60118 Roo.LoadMask.prototype = {
60120 * @cfg {Boolean} removeMask
60121 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60122 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60125 * @cfg {String} msg
60126 * The text to display in a centered loading message box (defaults to 'Loading...')
60128 msg : 'Loading...',
60130 * @cfg {String} msgCls
60131 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60133 msgCls : 'x-mask-loading',
60136 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60142 * Disables the mask to prevent it from being displayed
60144 disable : function(){
60145 this.disabled = true;
60149 * Enables the mask so that it can be displayed
60151 enable : function(){
60152 this.disabled = false;
60155 onLoadException : function()
60157 Roo.log(arguments);
60159 if (typeof(arguments[3]) != 'undefined') {
60160 Roo.MessageBox.alert("Error loading",arguments[3]);
60164 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60165 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60174 this.el.unmask(this.removeMask);
60177 onLoad : function()
60179 this.el.unmask(this.removeMask);
60183 onBeforeLoad : function(){
60184 if(!this.disabled){
60185 this.el.mask(this.msg, this.msgCls);
60190 destroy : function(){
60192 this.store.un('beforeload', this.onBeforeLoad, this);
60193 this.store.un('load', this.onLoad, this);
60194 this.store.un('loadexception', this.onLoadException, this);
60196 var um = this.el.getUpdateManager();
60197 um.un('beforeupdate', this.onBeforeLoad, this);
60198 um.un('update', this.onLoad, this);
60199 um.un('failure', this.onLoad, this);
60204 * Ext JS Library 1.1.1
60205 * Copyright(c) 2006-2007, Ext JS, LLC.
60207 * Originally Released Under LGPL - original licence link has changed is not relivant.
60210 * <script type="text/javascript">
60215 * @class Roo.XTemplate
60216 * @extends Roo.Template
60217 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60219 var t = new Roo.XTemplate(
60220 '<select name="{name}">',
60221 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60225 // then append, applying the master template values
60228 * Supported features:
60233 {a_variable} - output encoded.
60234 {a_variable.format:("Y-m-d")} - call a method on the variable
60235 {a_variable:raw} - unencoded output
60236 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60237 {a_variable:this.method_on_template(...)} - call a method on the template object.
60242 <tpl for="a_variable or condition.."></tpl>
60243 <tpl if="a_variable or condition"></tpl>
60244 <tpl exec="some javascript"></tpl>
60245 <tpl name="named_template"></tpl> (experimental)
60247 <tpl for="."></tpl> - just iterate the property..
60248 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60252 Roo.XTemplate = function()
60254 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60261 Roo.extend(Roo.XTemplate, Roo.Template, {
60264 * The various sub templates
60269 * basic tag replacing syntax
60272 * // you can fake an object call by doing this
60276 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60279 * compile the template
60281 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60284 compile: function()
60288 s = ['<tpl>', s, '</tpl>'].join('');
60290 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60291 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60292 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60293 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60294 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60299 while(true == !!(m = s.match(re))){
60300 var forMatch = m[0].match(nameRe),
60301 ifMatch = m[0].match(ifRe),
60302 execMatch = m[0].match(execRe),
60303 namedMatch = m[0].match(namedRe),
60308 name = forMatch && forMatch[1] ? forMatch[1] : '';
60311 // if - puts fn into test..
60312 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60314 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60319 // exec - calls a function... returns empty if true is returned.
60320 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60322 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60330 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60331 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60332 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60335 var uid = namedMatch ? namedMatch[1] : id;
60339 id: namedMatch ? namedMatch[1] : id,
60346 s = s.replace(m[0], '');
60348 s = s.replace(m[0], '{xtpl'+ id + '}');
60353 for(var i = tpls.length-1; i >= 0; --i){
60354 this.compileTpl(tpls[i]);
60355 this.tpls[tpls[i].id] = tpls[i];
60357 this.master = tpls[tpls.length-1];
60361 * same as applyTemplate, except it's done to one of the subTemplates
60362 * when using named templates, you can do:
60364 * var str = pl.applySubTemplate('your-name', values);
60367 * @param {Number} id of the template
60368 * @param {Object} values to apply to template
60369 * @param {Object} parent (normaly the instance of this object)
60371 applySubTemplate : function(id, values, parent)
60375 var t = this.tpls[id];
60379 if(t.test && !t.test.call(this, values, parent)){
60383 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60384 Roo.log(e.toString());
60390 if(t.exec && t.exec.call(this, values, parent)){
60394 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60395 Roo.log(e.toString());
60400 var vs = t.target ? t.target.call(this, values, parent) : values;
60401 parent = t.target ? values : parent;
60402 if(t.target && vs instanceof Array){
60404 for(var i = 0, len = vs.length; i < len; i++){
60405 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60407 return buf.join('');
60409 return t.compiled.call(this, vs, parent);
60411 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60412 Roo.log(e.toString());
60413 Roo.log(t.compiled);
60418 compileTpl : function(tpl)
60420 var fm = Roo.util.Format;
60421 var useF = this.disableFormats !== true;
60422 var sep = Roo.isGecko ? "+" : ",";
60423 var undef = function(str) {
60424 Roo.log("Property not found :" + str);
60428 var fn = function(m, name, format, args)
60430 //Roo.log(arguments);
60431 args = args ? args.replace(/\\'/g,"'") : args;
60432 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60433 if (typeof(format) == 'undefined') {
60434 format= 'htmlEncode';
60436 if (format == 'raw' ) {
60440 if(name.substr(0, 4) == 'xtpl'){
60441 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60444 // build an array of options to determine if value is undefined..
60446 // basically get 'xxxx.yyyy' then do
60447 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60448 // (function () { Roo.log("Property not found"); return ''; })() :
60453 Roo.each(name.split('.'), function(st) {
60454 lookfor += (lookfor.length ? '.': '') + st;
60455 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60458 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60461 if(format && useF){
60463 args = args ? ',' + args : "";
60465 if(format.substr(0, 5) != "this."){
60466 format = "fm." + format + '(';
60468 format = 'this.call("'+ format.substr(5) + '", ';
60472 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60476 // called with xxyx.yuu:(test,test)
60478 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60480 // raw.. - :raw modifier..
60481 return "'"+ sep + udef_st + name + ")"+sep+"'";
60485 // branched to use + in gecko and [].join() in others
60487 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60488 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60491 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60492 body.push(tpl.body.replace(/(\r\n|\n)/g,
60493 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60494 body.push("'].join('');};};");
60495 body = body.join('');
60498 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60500 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60506 applyTemplate : function(values){
60507 return this.master.compiled.call(this, values, {});
60508 //var s = this.subs;
60511 apply : function(){
60512 return this.applyTemplate.apply(this, arguments);
60517 Roo.XTemplate.from = function(el){
60518 el = Roo.getDom(el);
60519 return new Roo.XTemplate(el.value || el.innerHTML);