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 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7168 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7169 * @param {String} selector The simple selector to test
7170 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7171 search as a number or element (defaults to 10 || document.body)
7172 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7174 up : function(simpleSelector, maxDepth){
7175 return this.findParentNode(simpleSelector, maxDepth, true);
7181 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7182 * @param {String} selector The simple selector to test
7183 * @return {Boolean} True if this element matches the selector, else false
7185 is : function(simpleSelector){
7186 return Roo.DomQuery.is(this.dom, simpleSelector);
7190 * Perform animation on this element.
7191 * @param {Object} args The YUI animation control args
7192 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7193 * @param {Function} onComplete (optional) Function to call when animation completes
7194 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7195 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7196 * @return {Roo.Element} this
7198 animate : function(args, duration, onComplete, easing, animType){
7199 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7204 * @private Internal animation call
7206 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7207 animType = animType || 'run';
7209 var anim = Roo.lib.Anim[animType](
7211 (opt.duration || defaultDur) || .35,
7212 (opt.easing || defaultEase) || 'easeOut',
7214 Roo.callback(cb, this);
7215 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7223 // private legacy anim prep
7224 preanim : function(a, i){
7225 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7229 * Removes worthless text nodes
7230 * @param {Boolean} forceReclean (optional) By default the element
7231 * keeps track if it has been cleaned already so
7232 * you can call this over and over. However, if you update the element and
7233 * need to force a reclean, you can pass true.
7235 clean : function(forceReclean){
7236 if(this.isCleaned && forceReclean !== true){
7240 var d = this.dom, n = d.firstChild, ni = -1;
7242 var nx = n.nextSibling;
7243 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7250 this.isCleaned = true;
7255 calcOffsetsTo : function(el){
7258 var restorePos = false;
7259 if(el.getStyle('position') == 'static'){
7260 el.position('relative');
7265 while(op && op != d && op.tagName != 'HTML'){
7268 op = op.offsetParent;
7271 el.position('static');
7277 * Scrolls this element into view within the passed container.
7278 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7279 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7280 * @return {Roo.Element} this
7282 scrollIntoView : function(container, hscroll){
7283 var c = Roo.getDom(container) || document.body;
7286 var o = this.calcOffsetsTo(c),
7289 b = t+el.offsetHeight,
7290 r = l+el.offsetWidth;
7292 var ch = c.clientHeight;
7293 var ct = parseInt(c.scrollTop, 10);
7294 var cl = parseInt(c.scrollLeft, 10);
7296 var cr = cl + c.clientWidth;
7304 if(hscroll !== false){
7308 c.scrollLeft = r-c.clientWidth;
7315 scrollChildIntoView : function(child, hscroll){
7316 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7320 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7321 * the new height may not be available immediately.
7322 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7323 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7324 * @param {Function} onComplete (optional) Function to call when animation completes
7325 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7326 * @return {Roo.Element} this
7328 autoHeight : function(animate, duration, onComplete, easing){
7329 var oldHeight = this.getHeight();
7331 this.setHeight(1); // force clipping
7332 setTimeout(function(){
7333 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7335 this.setHeight(height);
7337 if(typeof onComplete == "function"){
7341 this.setHeight(oldHeight); // restore original height
7342 this.setHeight(height, animate, duration, function(){
7344 if(typeof onComplete == "function") { onComplete(); }
7345 }.createDelegate(this), easing);
7347 }.createDelegate(this), 0);
7352 * Returns true if this element is an ancestor of the passed element
7353 * @param {HTMLElement/String} el The element to check
7354 * @return {Boolean} True if this element is an ancestor of el, else false
7356 contains : function(el){
7357 if(!el){return false;}
7358 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7362 * Checks whether the element is currently visible using both visibility and display properties.
7363 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7364 * @return {Boolean} True if the element is currently visible, else false
7366 isVisible : function(deep) {
7367 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7368 if(deep !== true || !vis){
7371 var p = this.dom.parentNode;
7372 while(p && p.tagName.toLowerCase() != "body"){
7373 if(!Roo.fly(p, '_isVisible').isVisible()){
7382 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7383 * @param {String} selector The CSS selector
7384 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7385 * @return {CompositeElement/CompositeElementLite} The composite element
7387 select : function(selector, unique){
7388 return El.select(selector, unique, this.dom);
7392 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7393 * @param {String} selector The CSS selector
7394 * @return {Array} An array of the matched nodes
7396 query : function(selector, unique){
7397 return Roo.DomQuery.select(selector, this.dom);
7401 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7402 * @param {String} selector The CSS selector
7403 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7404 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7406 child : function(selector, returnDom){
7407 var n = Roo.DomQuery.selectNode(selector, this.dom);
7408 return returnDom ? n : Roo.get(n);
7412 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7413 * @param {String} selector The CSS selector
7414 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7415 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7417 down : function(selector, returnDom){
7418 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7419 return returnDom ? n : Roo.get(n);
7423 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7424 * @param {String} group The group the DD object is member of
7425 * @param {Object} config The DD config object
7426 * @param {Object} overrides An object containing methods to override/implement on the DD object
7427 * @return {Roo.dd.DD} The DD object
7429 initDD : function(group, config, overrides){
7430 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7431 return Roo.apply(dd, overrides);
7435 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7436 * @param {String} group The group the DDProxy object is member of
7437 * @param {Object} config The DDProxy config object
7438 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7439 * @return {Roo.dd.DDProxy} The DDProxy object
7441 initDDProxy : function(group, config, overrides){
7442 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7443 return Roo.apply(dd, overrides);
7447 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7448 * @param {String} group The group the DDTarget object is member of
7449 * @param {Object} config The DDTarget config object
7450 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7451 * @return {Roo.dd.DDTarget} The DDTarget object
7453 initDDTarget : function(group, config, overrides){
7454 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7455 return Roo.apply(dd, overrides);
7459 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7460 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7461 * @param {Boolean} visible Whether the element is visible
7462 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7463 * @return {Roo.Element} this
7465 setVisible : function(visible, animate){
7467 if(this.visibilityMode == El.DISPLAY){
7468 this.setDisplayed(visible);
7471 this.dom.style.visibility = visible ? "visible" : "hidden";
7474 // closure for composites
7476 var visMode = this.visibilityMode;
7478 this.setOpacity(.01);
7479 this.setVisible(true);
7481 this.anim({opacity: { to: (visible?1:0) }},
7482 this.preanim(arguments, 1),
7483 null, .35, 'easeIn', function(){
7485 if(visMode == El.DISPLAY){
7486 dom.style.display = "none";
7488 dom.style.visibility = "hidden";
7490 Roo.get(dom).setOpacity(1);
7498 * Returns true if display is not "none"
7501 isDisplayed : function() {
7502 return this.getStyle("display") != "none";
7506 * Toggles the element's visibility or display, depending on visibility mode.
7507 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7508 * @return {Roo.Element} this
7510 toggle : function(animate){
7511 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7516 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7517 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7518 * @return {Roo.Element} this
7520 setDisplayed : function(value) {
7521 if(typeof value == "boolean"){
7522 value = value ? this.originalDisplay : "none";
7524 this.setStyle("display", value);
7529 * Tries to focus the element. Any exceptions are caught and ignored.
7530 * @return {Roo.Element} this
7532 focus : function() {
7540 * Tries to blur the element. Any exceptions are caught and ignored.
7541 * @return {Roo.Element} this
7551 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7552 * @param {String/Array} className The CSS class to add, or an array of classes
7553 * @return {Roo.Element} this
7555 addClass : function(className){
7556 if(className instanceof Array){
7557 for(var i = 0, len = className.length; i < len; i++) {
7558 this.addClass(className[i]);
7561 if(className && !this.hasClass(className)){
7562 this.dom.className = this.dom.className + " " + className;
7569 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7570 * @param {String/Array} className The CSS class to add, or an array of classes
7571 * @return {Roo.Element} this
7573 radioClass : function(className){
7574 var siblings = this.dom.parentNode.childNodes;
7575 for(var i = 0; i < siblings.length; i++) {
7576 var s = siblings[i];
7577 if(s.nodeType == 1){
7578 Roo.get(s).removeClass(className);
7581 this.addClass(className);
7586 * Removes one or more CSS classes from the element.
7587 * @param {String/Array} className The CSS class to remove, or an array of classes
7588 * @return {Roo.Element} this
7590 removeClass : function(className){
7591 if(!className || !this.dom.className){
7594 if(className instanceof Array){
7595 for(var i = 0, len = className.length; i < len; i++) {
7596 this.removeClass(className[i]);
7599 if(this.hasClass(className)){
7600 var re = this.classReCache[className];
7602 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7603 this.classReCache[className] = re;
7605 this.dom.className =
7606 this.dom.className.replace(re, " ");
7616 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7617 * @param {String} className The CSS class to toggle
7618 * @return {Roo.Element} this
7620 toggleClass : function(className){
7621 if(this.hasClass(className)){
7622 this.removeClass(className);
7624 this.addClass(className);
7630 * Checks if the specified CSS class exists on this element's DOM node.
7631 * @param {String} className The CSS class to check for
7632 * @return {Boolean} True if the class exists, else false
7634 hasClass : function(className){
7635 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7639 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7640 * @param {String} oldClassName The CSS class to replace
7641 * @param {String} newClassName The replacement CSS class
7642 * @return {Roo.Element} this
7644 replaceClass : function(oldClassName, newClassName){
7645 this.removeClass(oldClassName);
7646 this.addClass(newClassName);
7651 * Returns an object with properties matching the styles requested.
7652 * For example, el.getStyles('color', 'font-size', 'width') might return
7653 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7654 * @param {String} style1 A style name
7655 * @param {String} style2 A style name
7656 * @param {String} etc.
7657 * @return {Object} The style object
7659 getStyles : function(){
7660 var a = arguments, len = a.length, r = {};
7661 for(var i = 0; i < len; i++){
7662 r[a[i]] = this.getStyle(a[i]);
7668 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7669 * @param {String} property The style property whose value is returned.
7670 * @return {String} The current value of the style property for this element.
7672 getStyle : function(){
7673 return view && view.getComputedStyle ?
7675 var el = this.dom, v, cs, camel;
7676 if(prop == 'float'){
7679 if(el.style && (v = el.style[prop])){
7682 if(cs = view.getComputedStyle(el, "")){
7683 if(!(camel = propCache[prop])){
7684 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7691 var el = this.dom, v, cs, camel;
7692 if(prop == 'opacity'){
7693 if(typeof el.style.filter == 'string'){
7694 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7696 var fv = parseFloat(m[1]);
7698 return fv ? fv / 100 : 0;
7703 }else if(prop == 'float'){
7704 prop = "styleFloat";
7706 if(!(camel = propCache[prop])){
7707 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7709 if(v = el.style[camel]){
7712 if(cs = el.currentStyle){
7720 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7721 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7722 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7723 * @return {Roo.Element} this
7725 setStyle : function(prop, value){
7726 if(typeof prop == "string"){
7728 if (prop == 'float') {
7729 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7734 if(!(camel = propCache[prop])){
7735 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7738 if(camel == 'opacity') {
7739 this.setOpacity(value);
7741 this.dom.style[camel] = value;
7744 for(var style in prop){
7745 if(typeof prop[style] != "function"){
7746 this.setStyle(style, prop[style]);
7754 * More flexible version of {@link #setStyle} for setting style properties.
7755 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7756 * a function which returns such a specification.
7757 * @return {Roo.Element} this
7759 applyStyles : function(style){
7760 Roo.DomHelper.applyStyles(this.dom, style);
7765 * 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).
7766 * @return {Number} The X position of the element
7769 return D.getX(this.dom);
7773 * 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).
7774 * @return {Number} The Y position of the element
7777 return D.getY(this.dom);
7781 * 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).
7782 * @return {Array} The XY position of the element
7785 return D.getXY(this.dom);
7789 * 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).
7790 * @param {Number} The X position of the element
7791 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7792 * @return {Roo.Element} this
7794 setX : function(x, animate){
7796 D.setX(this.dom, x);
7798 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7804 * 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).
7805 * @param {Number} The Y position of the element
7806 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7807 * @return {Roo.Element} this
7809 setY : function(y, animate){
7811 D.setY(this.dom, y);
7813 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7819 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7820 * @param {String} left The left CSS property value
7821 * @return {Roo.Element} this
7823 setLeft : function(left){
7824 this.setStyle("left", this.addUnits(left));
7829 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7830 * @param {String} top The top CSS property value
7831 * @return {Roo.Element} this
7833 setTop : function(top){
7834 this.setStyle("top", this.addUnits(top));
7839 * Sets the element's CSS right style.
7840 * @param {String} right The right CSS property value
7841 * @return {Roo.Element} this
7843 setRight : function(right){
7844 this.setStyle("right", this.addUnits(right));
7849 * Sets the element's CSS bottom style.
7850 * @param {String} bottom The bottom CSS property value
7851 * @return {Roo.Element} this
7853 setBottom : function(bottom){
7854 this.setStyle("bottom", this.addUnits(bottom));
7859 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7860 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7861 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7862 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7863 * @return {Roo.Element} this
7865 setXY : function(pos, animate){
7867 D.setXY(this.dom, pos);
7869 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7875 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7876 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7877 * @param {Number} x X value for new position (coordinates are page-based)
7878 * @param {Number} y Y value for new position (coordinates are page-based)
7879 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7880 * @return {Roo.Element} this
7882 setLocation : function(x, y, animate){
7883 this.setXY([x, y], this.preanim(arguments, 2));
7888 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7889 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7890 * @param {Number} x X value for new position (coordinates are page-based)
7891 * @param {Number} y Y value for new position (coordinates are page-based)
7892 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7893 * @return {Roo.Element} this
7895 moveTo : function(x, y, animate){
7896 this.setXY([x, y], this.preanim(arguments, 2));
7901 * Returns the region of the given element.
7902 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7903 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7905 getRegion : function(){
7906 return D.getRegion(this.dom);
7910 * Returns the offset height of the element
7911 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7912 * @return {Number} The element's height
7914 getHeight : function(contentHeight){
7915 var h = this.dom.offsetHeight || 0;
7916 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7920 * Returns the offset width of the element
7921 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7922 * @return {Number} The element's width
7924 getWidth : function(contentWidth){
7925 var w = this.dom.offsetWidth || 0;
7926 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7930 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7931 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7932 * if a height has not been set using CSS.
7935 getComputedHeight : function(){
7936 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7938 h = parseInt(this.getStyle('height'), 10) || 0;
7939 if(!this.isBorderBox()){
7940 h += this.getFrameWidth('tb');
7947 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7948 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7949 * if a width has not been set using CSS.
7952 getComputedWidth : function(){
7953 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7955 w = parseInt(this.getStyle('width'), 10) || 0;
7956 if(!this.isBorderBox()){
7957 w += this.getFrameWidth('lr');
7964 * Returns the size of the element.
7965 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7966 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7968 getSize : function(contentSize){
7969 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7973 * Returns the width and height of the viewport.
7974 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7976 getViewSize : function(){
7977 var d = this.dom, doc = document, aw = 0, ah = 0;
7978 if(d == doc || d == doc.body){
7979 return {width : D.getViewWidth(), height: D.getViewHeight()};
7982 width : d.clientWidth,
7983 height: d.clientHeight
7989 * Returns the value of the "value" attribute
7990 * @param {Boolean} asNumber true to parse the value as a number
7991 * @return {String/Number}
7993 getValue : function(asNumber){
7994 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7998 adjustWidth : function(width){
7999 if(typeof width == "number"){
8000 if(this.autoBoxAdjust && !this.isBorderBox()){
8001 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8011 adjustHeight : function(height){
8012 if(typeof height == "number"){
8013 if(this.autoBoxAdjust && !this.isBorderBox()){
8014 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8024 * Set the width of the element
8025 * @param {Number} width The new width
8026 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8027 * @return {Roo.Element} this
8029 setWidth : function(width, animate){
8030 width = this.adjustWidth(width);
8032 this.dom.style.width = this.addUnits(width);
8034 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8040 * Set the height of the element
8041 * @param {Number} height The new height
8042 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8043 * @return {Roo.Element} this
8045 setHeight : function(height, animate){
8046 height = this.adjustHeight(height);
8048 this.dom.style.height = this.addUnits(height);
8050 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8056 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8057 * @param {Number} width The new width
8058 * @param {Number} height The new height
8059 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8060 * @return {Roo.Element} this
8062 setSize : function(width, height, animate){
8063 if(typeof width == "object"){ // in case of object from getSize()
8064 height = width.height; width = width.width;
8066 width = this.adjustWidth(width); height = this.adjustHeight(height);
8068 this.dom.style.width = this.addUnits(width);
8069 this.dom.style.height = this.addUnits(height);
8071 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8077 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8078 * @param {Number} x X value for new position (coordinates are page-based)
8079 * @param {Number} y Y value for new position (coordinates are page-based)
8080 * @param {Number} width The new width
8081 * @param {Number} height The new height
8082 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8083 * @return {Roo.Element} this
8085 setBounds : function(x, y, width, height, animate){
8087 this.setSize(width, height);
8088 this.setLocation(x, y);
8090 width = this.adjustWidth(width); height = this.adjustHeight(height);
8091 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8092 this.preanim(arguments, 4), 'motion');
8098 * 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.
8099 * @param {Roo.lib.Region} region The region to fill
8100 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8101 * @return {Roo.Element} this
8103 setRegion : function(region, animate){
8104 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8109 * Appends an event handler
8111 * @param {String} eventName The type of event to append
8112 * @param {Function} fn The method the event invokes
8113 * @param {Object} scope (optional) The scope (this object) of the fn
8114 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8116 addListener : function(eventName, fn, scope, options){
8118 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8123 * Removes an event handler from this element
8124 * @param {String} eventName the type of event to remove
8125 * @param {Function} fn the method the event invokes
8126 * @return {Roo.Element} this
8128 removeListener : function(eventName, fn){
8129 Roo.EventManager.removeListener(this.dom, eventName, fn);
8134 * Removes all previous added listeners from this element
8135 * @return {Roo.Element} this
8137 removeAllListeners : function(){
8138 E.purgeElement(this.dom);
8142 relayEvent : function(eventName, observable){
8143 this.on(eventName, function(e){
8144 observable.fireEvent(eventName, e);
8149 * Set the opacity of the element
8150 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8151 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8152 * @return {Roo.Element} this
8154 setOpacity : function(opacity, animate){
8156 var s = this.dom.style;
8159 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8160 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8162 s.opacity = opacity;
8165 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8171 * Gets the left X coordinate
8172 * @param {Boolean} local True to get the local css position instead of page coordinate
8175 getLeft : function(local){
8179 return parseInt(this.getStyle("left"), 10) || 0;
8184 * Gets the right X coordinate of the element (element X position + element width)
8185 * @param {Boolean} local True to get the local css position instead of page coordinate
8188 getRight : function(local){
8190 return this.getX() + this.getWidth();
8192 return (this.getLeft(true) + this.getWidth()) || 0;
8197 * Gets the top Y coordinate
8198 * @param {Boolean} local True to get the local css position instead of page coordinate
8201 getTop : function(local) {
8205 return parseInt(this.getStyle("top"), 10) || 0;
8210 * Gets the bottom Y coordinate of the element (element Y position + element height)
8211 * @param {Boolean} local True to get the local css position instead of page coordinate
8214 getBottom : function(local){
8216 return this.getY() + this.getHeight();
8218 return (this.getTop(true) + this.getHeight()) || 0;
8223 * Initializes positioning on this element. If a desired position is not passed, it will make the
8224 * the element positioned relative IF it is not already positioned.
8225 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8226 * @param {Number} zIndex (optional) The zIndex to apply
8227 * @param {Number} x (optional) Set the page X position
8228 * @param {Number} y (optional) Set the page Y position
8230 position : function(pos, zIndex, x, y){
8232 if(this.getStyle('position') == 'static'){
8233 this.setStyle('position', 'relative');
8236 this.setStyle("position", pos);
8239 this.setStyle("z-index", zIndex);
8241 if(x !== undefined && y !== undefined){
8243 }else if(x !== undefined){
8245 }else if(y !== undefined){
8251 * Clear positioning back to the default when the document was loaded
8252 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8253 * @return {Roo.Element} this
8255 clearPositioning : function(value){
8263 "position" : "static"
8269 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8270 * snapshot before performing an update and then restoring the element.
8273 getPositioning : function(){
8274 var l = this.getStyle("left");
8275 var t = this.getStyle("top");
8277 "position" : this.getStyle("position"),
8279 "right" : l ? "" : this.getStyle("right"),
8281 "bottom" : t ? "" : this.getStyle("bottom"),
8282 "z-index" : this.getStyle("z-index")
8287 * Gets the width of the border(s) for the specified side(s)
8288 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8289 * passing lr would get the border (l)eft width + the border (r)ight width.
8290 * @return {Number} The width of the sides passed added together
8292 getBorderWidth : function(side){
8293 return this.addStyles(side, El.borders);
8297 * Gets the width of the padding(s) for the specified side(s)
8298 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8299 * passing lr would get the padding (l)eft + the padding (r)ight.
8300 * @return {Number} The padding of the sides passed added together
8302 getPadding : function(side){
8303 return this.addStyles(side, El.paddings);
8307 * Set positioning with an object returned by getPositioning().
8308 * @param {Object} posCfg
8309 * @return {Roo.Element} this
8311 setPositioning : function(pc){
8312 this.applyStyles(pc);
8313 if(pc.right == "auto"){
8314 this.dom.style.right = "";
8316 if(pc.bottom == "auto"){
8317 this.dom.style.bottom = "";
8323 fixDisplay : function(){
8324 if(this.getStyle("display") == "none"){
8325 this.setStyle("visibility", "hidden");
8326 this.setStyle("display", this.originalDisplay); // first try reverting to default
8327 if(this.getStyle("display") == "none"){ // if that fails, default to block
8328 this.setStyle("display", "block");
8334 * Quick set left and top adding default units
8335 * @param {String} left The left CSS property value
8336 * @param {String} top The top CSS property value
8337 * @return {Roo.Element} this
8339 setLeftTop : function(left, top){
8340 this.dom.style.left = this.addUnits(left);
8341 this.dom.style.top = this.addUnits(top);
8346 * Move this element relative to its current position.
8347 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8348 * @param {Number} distance How far to move the element in pixels
8349 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8350 * @return {Roo.Element} this
8352 move : function(direction, distance, animate){
8353 var xy = this.getXY();
8354 direction = direction.toLowerCase();
8358 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8362 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8367 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8372 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8379 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8380 * @return {Roo.Element} this
8383 if(!this.isClipped){
8384 this.isClipped = true;
8385 this.originalClip = {
8386 "o": this.getStyle("overflow"),
8387 "x": this.getStyle("overflow-x"),
8388 "y": this.getStyle("overflow-y")
8390 this.setStyle("overflow", "hidden");
8391 this.setStyle("overflow-x", "hidden");
8392 this.setStyle("overflow-y", "hidden");
8398 * Return clipping (overflow) to original clipping before clip() was called
8399 * @return {Roo.Element} this
8401 unclip : function(){
8403 this.isClipped = false;
8404 var o = this.originalClip;
8405 if(o.o){this.setStyle("overflow", o.o);}
8406 if(o.x){this.setStyle("overflow-x", o.x);}
8407 if(o.y){this.setStyle("overflow-y", o.y);}
8414 * Gets the x,y coordinates specified by the anchor position on the element.
8415 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8416 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8417 * {width: (target width), height: (target height)} (defaults to the element's current size)
8418 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8419 * @return {Array} [x, y] An array containing the element's x and y coordinates
8421 getAnchorXY : function(anchor, local, s){
8422 //Passing a different size is useful for pre-calculating anchors,
8423 //especially for anchored animations that change the el size.
8425 var w, h, vp = false;
8428 if(d == document.body || d == document){
8430 w = D.getViewWidth(); h = D.getViewHeight();
8432 w = this.getWidth(); h = this.getHeight();
8435 w = s.width; h = s.height;
8437 var x = 0, y = 0, r = Math.round;
8438 switch((anchor || "tl").toLowerCase()){
8480 var sc = this.getScroll();
8481 return [x + sc.left, y + sc.top];
8483 //Add the element's offset xy
8484 var o = this.getXY();
8485 return [x+o[0], y+o[1]];
8489 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8490 * supported position values.
8491 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8492 * @param {String} position The position to align to.
8493 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8494 * @return {Array} [x, y]
8496 getAlignToXY : function(el, p, o){
8500 throw "Element.alignTo with an element that doesn't exist";
8502 var c = false; //constrain to viewport
8503 var p1 = "", p2 = "";
8510 }else if(p.indexOf("-") == -1){
8513 p = p.toLowerCase();
8514 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8516 throw "Element.alignTo with an invalid alignment " + p;
8518 p1 = m[1]; p2 = m[2]; c = !!m[3];
8520 //Subtract the aligned el's internal xy from the target's offset xy
8521 //plus custom offset to get the aligned el's new offset xy
8522 var a1 = this.getAnchorXY(p1, true);
8523 var a2 = el.getAnchorXY(p2, false);
8524 var x = a2[0] - a1[0] + o[0];
8525 var y = a2[1] - a1[1] + o[1];
8527 //constrain the aligned el to viewport if necessary
8528 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8529 // 5px of margin for ie
8530 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8532 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8533 //perpendicular to the vp border, allow the aligned el to slide on that border,
8534 //otherwise swap the aligned el to the opposite border of the target.
8535 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8536 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8537 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8538 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8541 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8542 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8544 if((x+w) > dw + scrollX){
8545 x = swapX ? r.left-w : dw+scrollX-w;
8548 x = swapX ? r.right : scrollX;
8550 if((y+h) > dh + scrollY){
8551 y = swapY ? r.top-h : dh+scrollY-h;
8554 y = swapY ? r.bottom : scrollY;
8561 getConstrainToXY : function(){
8562 var os = {top:0, left:0, bottom:0, right: 0};
8564 return function(el, local, offsets, proposedXY){
8566 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8568 var vw, vh, vx = 0, vy = 0;
8569 if(el.dom == document.body || el.dom == document){
8570 vw = Roo.lib.Dom.getViewWidth();
8571 vh = Roo.lib.Dom.getViewHeight();
8573 vw = el.dom.clientWidth;
8574 vh = el.dom.clientHeight;
8576 var vxy = el.getXY();
8582 var s = el.getScroll();
8584 vx += offsets.left + s.left;
8585 vy += offsets.top + s.top;
8587 vw -= offsets.right;
8588 vh -= offsets.bottom;
8593 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8594 var x = xy[0], y = xy[1];
8595 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8597 // only move it if it needs it
8600 // first validate right/bottom
8609 // then make sure top/left isn't negative
8618 return moved ? [x, y] : false;
8623 adjustForConstraints : function(xy, parent, offsets){
8624 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8628 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8629 * document it aligns it to the viewport.
8630 * The position parameter is optional, and can be specified in any one of the following formats:
8632 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8633 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8634 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8635 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8636 * <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
8637 * element's anchor point, and the second value is used as the target's anchor point.</li>
8639 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8640 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8641 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8642 * that specified in order to enforce the viewport constraints.
8643 * Following are all of the supported anchor positions:
8646 ----- -----------------------------
8647 tl The top left corner (default)
8648 t The center of the top edge
8649 tr The top right corner
8650 l The center of the left edge
8651 c In the center of the element
8652 r The center of the right edge
8653 bl The bottom left corner
8654 b The center of the bottom edge
8655 br The bottom right corner
8659 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8660 el.alignTo("other-el");
8662 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8663 el.alignTo("other-el", "tr?");
8665 // align the bottom right corner of el with the center left edge of other-el
8666 el.alignTo("other-el", "br-l?");
8668 // align the center of el with the bottom left corner of other-el and
8669 // adjust the x position by -6 pixels (and the y position by 0)
8670 el.alignTo("other-el", "c-bl", [-6, 0]);
8672 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8673 * @param {String} position The position to align to.
8674 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8675 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8676 * @return {Roo.Element} this
8678 alignTo : function(element, position, offsets, animate){
8679 var xy = this.getAlignToXY(element, position, offsets);
8680 this.setXY(xy, this.preanim(arguments, 3));
8685 * Anchors an element to another element and realigns it when the window is resized.
8686 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8687 * @param {String} position The position to align to.
8688 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8689 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8690 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8691 * is a number, it is used as the buffer delay (defaults to 50ms).
8692 * @param {Function} callback The function to call after the animation finishes
8693 * @return {Roo.Element} this
8695 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8696 var action = function(){
8697 this.alignTo(el, alignment, offsets, animate);
8698 Roo.callback(callback, this);
8700 Roo.EventManager.onWindowResize(action, this);
8701 var tm = typeof monitorScroll;
8702 if(tm != 'undefined'){
8703 Roo.EventManager.on(window, 'scroll', action, this,
8704 {buffer: tm == 'number' ? monitorScroll : 50});
8706 action.call(this); // align immediately
8710 * Clears any opacity settings from this element. Required in some cases for IE.
8711 * @return {Roo.Element} this
8713 clearOpacity : function(){
8714 if (window.ActiveXObject) {
8715 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8716 this.dom.style.filter = "";
8719 this.dom.style.opacity = "";
8720 this.dom.style["-moz-opacity"] = "";
8721 this.dom.style["-khtml-opacity"] = "";
8727 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8728 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8729 * @return {Roo.Element} this
8731 hide : function(animate){
8732 this.setVisible(false, this.preanim(arguments, 0));
8737 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8738 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8739 * @return {Roo.Element} this
8741 show : function(animate){
8742 this.setVisible(true, this.preanim(arguments, 0));
8747 * @private Test if size has a unit, otherwise appends the default
8749 addUnits : function(size){
8750 return Roo.Element.addUnits(size, this.defaultUnit);
8754 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8755 * @return {Roo.Element} this
8757 beginMeasure : function(){
8759 if(el.offsetWidth || el.offsetHeight){
8760 return this; // offsets work already
8763 var p = this.dom, b = document.body; // start with this element
8764 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8765 var pe = Roo.get(p);
8766 if(pe.getStyle('display') == 'none'){
8767 changed.push({el: p, visibility: pe.getStyle("visibility")});
8768 p.style.visibility = "hidden";
8769 p.style.display = "block";
8773 this._measureChanged = changed;
8779 * Restores displays to before beginMeasure was called
8780 * @return {Roo.Element} this
8782 endMeasure : function(){
8783 var changed = this._measureChanged;
8785 for(var i = 0, len = changed.length; i < len; i++) {
8787 r.el.style.visibility = r.visibility;
8788 r.el.style.display = "none";
8790 this._measureChanged = null;
8796 * Update the innerHTML of this element, optionally searching for and processing scripts
8797 * @param {String} html The new HTML
8798 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8799 * @param {Function} callback For async script loading you can be noticed when the update completes
8800 * @return {Roo.Element} this
8802 update : function(html, loadScripts, callback){
8803 if(typeof html == "undefined"){
8806 if(loadScripts !== true){
8807 this.dom.innerHTML = html;
8808 if(typeof callback == "function"){
8816 html += '<span id="' + id + '"></span>';
8818 E.onAvailable(id, function(){
8819 var hd = document.getElementsByTagName("head")[0];
8820 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8821 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8822 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8825 while(match = re.exec(html)){
8826 var attrs = match[1];
8827 var srcMatch = attrs ? attrs.match(srcRe) : false;
8828 if(srcMatch && srcMatch[2]){
8829 var s = document.createElement("script");
8830 s.src = srcMatch[2];
8831 var typeMatch = attrs.match(typeRe);
8832 if(typeMatch && typeMatch[2]){
8833 s.type = typeMatch[2];
8836 }else if(match[2] && match[2].length > 0){
8837 if(window.execScript) {
8838 window.execScript(match[2]);
8846 window.eval(match[2]);
8850 var el = document.getElementById(id);
8851 if(el){el.parentNode.removeChild(el);}
8852 if(typeof callback == "function"){
8856 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8861 * Direct access to the UpdateManager update() method (takes the same parameters).
8862 * @param {String/Function} url The url for this request or a function to call to get the url
8863 * @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}
8864 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8865 * @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.
8866 * @return {Roo.Element} this
8869 var um = this.getUpdateManager();
8870 um.update.apply(um, arguments);
8875 * Gets this element's UpdateManager
8876 * @return {Roo.UpdateManager} The UpdateManager
8878 getUpdateManager : function(){
8879 if(!this.updateManager){
8880 this.updateManager = new Roo.UpdateManager(this);
8882 return this.updateManager;
8886 * Disables text selection for this element (normalized across browsers)
8887 * @return {Roo.Element} this
8889 unselectable : function(){
8890 this.dom.unselectable = "on";
8891 this.swallowEvent("selectstart", true);
8892 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8893 this.addClass("x-unselectable");
8898 * Calculates the x, y to center this element on the screen
8899 * @return {Array} The x, y values [x, y]
8901 getCenterXY : function(){
8902 return this.getAlignToXY(document, 'c-c');
8906 * Centers the Element in either the viewport, or another Element.
8907 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8909 center : function(centerIn){
8910 this.alignTo(centerIn || document, 'c-c');
8915 * Tests various css rules/browsers to determine if this element uses a border box
8918 isBorderBox : function(){
8919 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8923 * Return a box {x, y, width, height} that can be used to set another elements
8924 * size/location to match this element.
8925 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8926 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8927 * @return {Object} box An object in the format {x, y, width, height}
8929 getBox : function(contentBox, local){
8934 var left = parseInt(this.getStyle("left"), 10) || 0;
8935 var top = parseInt(this.getStyle("top"), 10) || 0;
8938 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8940 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8942 var l = this.getBorderWidth("l")+this.getPadding("l");
8943 var r = this.getBorderWidth("r")+this.getPadding("r");
8944 var t = this.getBorderWidth("t")+this.getPadding("t");
8945 var b = this.getBorderWidth("b")+this.getPadding("b");
8946 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)};
8948 bx.right = bx.x + bx.width;
8949 bx.bottom = bx.y + bx.height;
8954 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8955 for more information about the sides.
8956 * @param {String} sides
8959 getFrameWidth : function(sides, onlyContentBox){
8960 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8964 * 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.
8965 * @param {Object} box The box to fill {x, y, width, height}
8966 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8967 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8968 * @return {Roo.Element} this
8970 setBox : function(box, adjust, animate){
8971 var w = box.width, h = box.height;
8972 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8973 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8974 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8976 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8981 * Forces the browser to repaint this element
8982 * @return {Roo.Element} this
8984 repaint : function(){
8986 this.addClass("x-repaint");
8987 setTimeout(function(){
8988 Roo.get(dom).removeClass("x-repaint");
8994 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8995 * then it returns the calculated width of the sides (see getPadding)
8996 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8997 * @return {Object/Number}
8999 getMargins : function(side){
9002 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9003 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9004 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9005 right: parseInt(this.getStyle("margin-right"), 10) || 0
9008 return this.addStyles(side, El.margins);
9013 addStyles : function(sides, styles){
9015 for(var i = 0, len = sides.length; i < len; i++){
9016 v = this.getStyle(styles[sides.charAt(i)]);
9018 w = parseInt(v, 10);
9026 * Creates a proxy element of this element
9027 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9028 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9029 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9030 * @return {Roo.Element} The new proxy element
9032 createProxy : function(config, renderTo, matchBox){
9034 renderTo = Roo.getDom(renderTo);
9036 renderTo = document.body;
9038 config = typeof config == "object" ?
9039 config : {tag : "div", cls: config};
9040 var proxy = Roo.DomHelper.append(renderTo, config, true);
9042 proxy.setBox(this.getBox());
9048 * Puts a mask over this element to disable user interaction. Requires core.css.
9049 * This method can only be applied to elements which accept child nodes.
9050 * @param {String} msg (optional) A message to display in the mask
9051 * @param {String} msgCls (optional) A css class to apply to the msg element
9052 * @return {Element} The mask element
9054 mask : function(msg, msgCls)
9056 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9057 this.setStyle("position", "relative");
9060 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9062 this.addClass("x-masked");
9063 this._mask.setDisplayed(true);
9068 while (dom && dom.style) {
9069 if (!isNaN(parseInt(dom.style.zIndex))) {
9070 z = Math.max(z, parseInt(dom.style.zIndex));
9072 dom = dom.parentNode;
9074 // if we are masking the body - then it hides everything..
9075 if (this.dom == document.body) {
9077 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9078 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9081 if(typeof msg == 'string'){
9083 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9085 var mm = this._maskMsg;
9086 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9087 if (mm.dom.firstChild) { // weird IE issue?
9088 mm.dom.firstChild.innerHTML = msg;
9090 mm.setDisplayed(true);
9092 mm.setStyle('z-index', z + 102);
9094 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9095 this._mask.setHeight(this.getHeight());
9097 this._mask.setStyle('z-index', z + 100);
9103 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9104 * it is cached for reuse.
9106 unmask : function(removeEl){
9108 if(removeEl === true){
9109 this._mask.remove();
9112 this._maskMsg.remove();
9113 delete this._maskMsg;
9116 this._mask.setDisplayed(false);
9118 this._maskMsg.setDisplayed(false);
9122 this.removeClass("x-masked");
9126 * Returns true if this element is masked
9129 isMasked : function(){
9130 return this._mask && this._mask.isVisible();
9134 * Creates an iframe shim for this element to keep selects and other windowed objects from
9136 * @return {Roo.Element} The new shim element
9138 createShim : function(){
9139 var el = document.createElement('iframe');
9140 el.frameBorder = 'no';
9141 el.className = 'roo-shim';
9142 if(Roo.isIE && Roo.isSecure){
9143 el.src = Roo.SSL_SECURE_URL;
9145 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9146 shim.autoBoxAdjust = false;
9151 * Removes this element from the DOM and deletes it from the cache
9153 remove : function(){
9154 if(this.dom.parentNode){
9155 this.dom.parentNode.removeChild(this.dom);
9157 delete El.cache[this.dom.id];
9161 * Sets up event handlers to add and remove a css class when the mouse is over this element
9162 * @param {String} className
9163 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9164 * mouseout events for children elements
9165 * @return {Roo.Element} this
9167 addClassOnOver : function(className, preventFlicker){
9168 this.on("mouseover", function(){
9169 Roo.fly(this, '_internal').addClass(className);
9171 var removeFn = function(e){
9172 if(preventFlicker !== true || !e.within(this, true)){
9173 Roo.fly(this, '_internal').removeClass(className);
9176 this.on("mouseout", removeFn, this.dom);
9181 * Sets up event handlers to add and remove a css class when this element has the focus
9182 * @param {String} className
9183 * @return {Roo.Element} this
9185 addClassOnFocus : function(className){
9186 this.on("focus", function(){
9187 Roo.fly(this, '_internal').addClass(className);
9189 this.on("blur", function(){
9190 Roo.fly(this, '_internal').removeClass(className);
9195 * 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)
9196 * @param {String} className
9197 * @return {Roo.Element} this
9199 addClassOnClick : function(className){
9201 this.on("mousedown", function(){
9202 Roo.fly(dom, '_internal').addClass(className);
9203 var d = Roo.get(document);
9204 var fn = function(){
9205 Roo.fly(dom, '_internal').removeClass(className);
9206 d.removeListener("mouseup", fn);
9208 d.on("mouseup", fn);
9214 * Stops the specified event from bubbling and optionally prevents the default action
9215 * @param {String} eventName
9216 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9217 * @return {Roo.Element} this
9219 swallowEvent : function(eventName, preventDefault){
9220 var fn = function(e){
9221 e.stopPropagation();
9226 if(eventName instanceof Array){
9227 for(var i = 0, len = eventName.length; i < len; i++){
9228 this.on(eventName[i], fn);
9232 this.on(eventName, fn);
9239 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9242 * Sizes this element to its parent element's dimensions performing
9243 * neccessary box adjustments.
9244 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9245 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9246 * @return {Roo.Element} this
9248 fitToParent : function(monitorResize, targetParent) {
9249 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9250 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9251 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9254 var p = Roo.get(targetParent || this.dom.parentNode);
9255 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9256 if (monitorResize === true) {
9257 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9258 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9264 * Gets the next sibling, skipping text nodes
9265 * @return {HTMLElement} The next sibling or null
9267 getNextSibling : function(){
9268 var n = this.dom.nextSibling;
9269 while(n && n.nodeType != 1){
9276 * Gets the previous sibling, skipping text nodes
9277 * @return {HTMLElement} The previous sibling or null
9279 getPrevSibling : function(){
9280 var n = this.dom.previousSibling;
9281 while(n && n.nodeType != 1){
9282 n = n.previousSibling;
9289 * Appends the passed element(s) to this element
9290 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9291 * @return {Roo.Element} this
9293 appendChild: function(el){
9300 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9301 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9302 * automatically generated with the specified attributes.
9303 * @param {HTMLElement} insertBefore (optional) a child element of this element
9304 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9305 * @return {Roo.Element} The new child element
9307 createChild: function(config, insertBefore, returnDom){
9308 config = config || {tag:'div'};
9310 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9312 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9316 * Appends this element to the passed element
9317 * @param {String/HTMLElement/Element} el The new parent element
9318 * @return {Roo.Element} this
9320 appendTo: function(el){
9321 el = Roo.getDom(el);
9322 el.appendChild(this.dom);
9327 * Inserts this element before the passed element in the DOM
9328 * @param {String/HTMLElement/Element} el The element to insert before
9329 * @return {Roo.Element} this
9331 insertBefore: function(el){
9332 el = Roo.getDom(el);
9333 el.parentNode.insertBefore(this.dom, el);
9338 * Inserts this element after the passed element in the DOM
9339 * @param {String/HTMLElement/Element} el The element to insert after
9340 * @return {Roo.Element} this
9342 insertAfter: function(el){
9343 el = Roo.getDom(el);
9344 el.parentNode.insertBefore(this.dom, el.nextSibling);
9349 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9350 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9351 * @return {Roo.Element} The new child
9353 insertFirst: function(el, returnDom){
9355 if(typeof el == 'object' && !el.nodeType){ // dh config
9356 return this.createChild(el, this.dom.firstChild, returnDom);
9358 el = Roo.getDom(el);
9359 this.dom.insertBefore(el, this.dom.firstChild);
9360 return !returnDom ? Roo.get(el) : el;
9365 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9366 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9367 * @param {String} where (optional) 'before' or 'after' defaults to before
9368 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9369 * @return {Roo.Element} the inserted Element
9371 insertSibling: function(el, where, returnDom){
9372 where = where ? where.toLowerCase() : 'before';
9374 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9376 if(typeof el == 'object' && !el.nodeType){ // dh config
9377 if(where == 'after' && !this.dom.nextSibling){
9378 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9380 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9384 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9385 where == 'before' ? this.dom : this.dom.nextSibling);
9394 * Creates and wraps this element with another element
9395 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9396 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9397 * @return {HTMLElement/Element} The newly created wrapper element
9399 wrap: function(config, returnDom){
9401 config = {tag: "div"};
9403 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9404 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9409 * Replaces the passed element with this element
9410 * @param {String/HTMLElement/Element} el The element to replace
9411 * @return {Roo.Element} this
9413 replace: function(el){
9415 this.insertBefore(el);
9421 * Inserts an html fragment into this element
9422 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9423 * @param {String} html The HTML fragment
9424 * @param {Boolean} returnEl True to return an Roo.Element
9425 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9427 insertHtml : function(where, html, returnEl){
9428 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9429 return returnEl ? Roo.get(el) : el;
9433 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9434 * @param {Object} o The object with the attributes
9435 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9436 * @return {Roo.Element} this
9438 set : function(o, useSet){
9440 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9442 if(attr == "style" || typeof o[attr] == "function") { continue; }
9444 el.className = o["cls"];
9447 el.setAttribute(attr, o[attr]);
9454 Roo.DomHelper.applyStyles(el, o.style);
9460 * Convenience method for constructing a KeyMap
9461 * @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:
9462 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9463 * @param {Function} fn The function to call
9464 * @param {Object} scope (optional) The scope of the function
9465 * @return {Roo.KeyMap} The KeyMap created
9467 addKeyListener : function(key, fn, scope){
9469 if(typeof key != "object" || key instanceof Array){
9485 return new Roo.KeyMap(this, config);
9489 * Creates a KeyMap for this element
9490 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9491 * @return {Roo.KeyMap} The KeyMap created
9493 addKeyMap : function(config){
9494 return new Roo.KeyMap(this, config);
9498 * Returns true if this element is scrollable.
9501 isScrollable : function(){
9503 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9507 * 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().
9508 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9509 * @param {Number} value The new scroll value
9510 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9511 * @return {Element} this
9514 scrollTo : function(side, value, animate){
9515 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9517 this.dom[prop] = value;
9519 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9520 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9526 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9527 * within this element's scrollable range.
9528 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9529 * @param {Number} distance How far to scroll the element in pixels
9530 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9531 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9532 * was scrolled as far as it could go.
9534 scroll : function(direction, distance, animate){
9535 if(!this.isScrollable()){
9539 var l = el.scrollLeft, t = el.scrollTop;
9540 var w = el.scrollWidth, h = el.scrollHeight;
9541 var cw = el.clientWidth, ch = el.clientHeight;
9542 direction = direction.toLowerCase();
9543 var scrolled = false;
9544 var a = this.preanim(arguments, 2);
9549 var v = Math.min(l + distance, w-cw);
9550 this.scrollTo("left", v, a);
9557 var v = Math.max(l - distance, 0);
9558 this.scrollTo("left", v, a);
9566 var v = Math.max(t - distance, 0);
9567 this.scrollTo("top", v, a);
9575 var v = Math.min(t + distance, h-ch);
9576 this.scrollTo("top", v, a);
9585 * Translates the passed page coordinates into left/top css values for this element
9586 * @param {Number/Array} x The page x or an array containing [x, y]
9587 * @param {Number} y The page y
9588 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9590 translatePoints : function(x, y){
9591 if(typeof x == 'object' || x instanceof Array){
9594 var p = this.getStyle('position');
9595 var o = this.getXY();
9597 var l = parseInt(this.getStyle('left'), 10);
9598 var t = parseInt(this.getStyle('top'), 10);
9601 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9604 t = (p == "relative") ? 0 : this.dom.offsetTop;
9607 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9611 * Returns the current scroll position of the element.
9612 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9614 getScroll : function(){
9615 var d = this.dom, doc = document;
9616 if(d == doc || d == doc.body){
9617 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9618 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9619 return {left: l, top: t};
9621 return {left: d.scrollLeft, top: d.scrollTop};
9626 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9627 * are convert to standard 6 digit hex color.
9628 * @param {String} attr The css attribute
9629 * @param {String} defaultValue The default value to use when a valid color isn't found
9630 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9633 getColor : function(attr, defaultValue, prefix){
9634 var v = this.getStyle(attr);
9635 if(!v || v == "transparent" || v == "inherit") {
9636 return defaultValue;
9638 var color = typeof prefix == "undefined" ? "#" : prefix;
9639 if(v.substr(0, 4) == "rgb("){
9640 var rvs = v.slice(4, v.length -1).split(",");
9641 for(var i = 0; i < 3; i++){
9642 var h = parseInt(rvs[i]).toString(16);
9649 if(v.substr(0, 1) == "#"){
9651 for(var i = 1; i < 4; i++){
9652 var c = v.charAt(i);
9655 }else if(v.length == 7){
9656 color += v.substr(1);
9660 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9664 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9665 * gradient background, rounded corners and a 4-way shadow.
9666 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9667 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9668 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9669 * @return {Roo.Element} this
9671 boxWrap : function(cls){
9672 cls = cls || 'x-box';
9673 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9674 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9679 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9680 * @param {String} namespace The namespace in which to look for the attribute
9681 * @param {String} name The attribute name
9682 * @return {String} The attribute value
9684 getAttributeNS : Roo.isIE ? function(ns, name){
9686 var type = typeof d[ns+":"+name];
9687 if(type != 'undefined' && type != 'unknown'){
9688 return d[ns+":"+name];
9691 } : function(ns, name){
9693 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9698 * Sets or Returns the value the dom attribute value
9699 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9700 * @param {String} value (optional) The value to set the attribute to
9701 * @return {String} The attribute value
9703 attr : function(name){
9704 if (arguments.length > 1) {
9705 this.dom.setAttribute(name, arguments[1]);
9706 return arguments[1];
9708 if (typeof(name) == 'object') {
9709 for(var i in name) {
9710 this.attr(i, name[i]);
9716 if (!this.dom.hasAttribute(name)) {
9719 return this.dom.getAttribute(name);
9726 var ep = El.prototype;
9729 * Appends an event handler (Shorthand for addListener)
9730 * @param {String} eventName The type of event to append
9731 * @param {Function} fn The method the event invokes
9732 * @param {Object} scope (optional) The scope (this object) of the fn
9733 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9736 ep.on = ep.addListener;
9738 ep.mon = ep.addListener;
9741 * Removes an event handler from this element (shorthand for removeListener)
9742 * @param {String} eventName the type of event to remove
9743 * @param {Function} fn the method the event invokes
9744 * @return {Roo.Element} this
9747 ep.un = ep.removeListener;
9750 * true to automatically adjust width and height settings for box-model issues (default to true)
9752 ep.autoBoxAdjust = true;
9755 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9758 El.addUnits = function(v, defaultUnit){
9759 if(v === "" || v == "auto"){
9762 if(v === undefined){
9765 if(typeof v == "number" || !El.unitPattern.test(v)){
9766 return v + (defaultUnit || 'px');
9771 // special markup used throughout Roo when box wrapping elements
9772 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>';
9774 * Visibility mode constant - Use visibility to hide element
9780 * Visibility mode constant - Use display to hide element
9786 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9787 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9788 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9800 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9801 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9802 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9803 * @return {Element} The Element object
9806 El.get = function(el){
9808 if(!el){ return null; }
9809 if(typeof el == "string"){ // element id
9810 if(!(elm = document.getElementById(el))){
9813 if(ex = El.cache[el]){
9816 ex = El.cache[el] = new El(elm);
9819 }else if(el.tagName){ // dom element
9823 if(ex = El.cache[id]){
9826 ex = El.cache[id] = new El(el);
9829 }else if(el instanceof El){
9831 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9832 // catch case where it hasn't been appended
9833 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9836 }else if(el.isComposite){
9838 }else if(el instanceof Array){
9839 return El.select(el);
9840 }else if(el == document){
9841 // create a bogus element object representing the document object
9843 var f = function(){};
9844 f.prototype = El.prototype;
9846 docEl.dom = document;
9854 El.uncache = function(el){
9855 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9857 delete El.cache[a[i].id || a[i]];
9863 // Garbage collection - uncache elements/purge listeners on orphaned elements
9864 // so we don't hold a reference and cause the browser to retain them
9865 El.garbageCollect = function(){
9866 if(!Roo.enableGarbageCollector){
9867 clearInterval(El.collectorThread);
9870 for(var eid in El.cache){
9871 var el = El.cache[eid], d = el.dom;
9872 // -------------------------------------------------------
9873 // Determining what is garbage:
9874 // -------------------------------------------------------
9876 // dom node is null, definitely garbage
9877 // -------------------------------------------------------
9879 // no parentNode == direct orphan, definitely garbage
9880 // -------------------------------------------------------
9881 // !d.offsetParent && !document.getElementById(eid)
9882 // display none elements have no offsetParent so we will
9883 // also try to look it up by it's id. However, check
9884 // offsetParent first so we don't do unneeded lookups.
9885 // This enables collection of elements that are not orphans
9886 // directly, but somewhere up the line they have an orphan
9888 // -------------------------------------------------------
9889 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9890 delete El.cache[eid];
9891 if(d && Roo.enableListenerCollection){
9897 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9901 El.Flyweight = function(dom){
9904 El.Flyweight.prototype = El.prototype;
9906 El._flyweights = {};
9908 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9909 * the dom node can be overwritten by other code.
9910 * @param {String/HTMLElement} el The dom node or id
9911 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9912 * prevent conflicts (e.g. internally Roo uses "_internal")
9914 * @return {Element} The shared Element object
9916 El.fly = function(el, named){
9917 named = named || '_global';
9918 el = Roo.getDom(el);
9922 if(!El._flyweights[named]){
9923 El._flyweights[named] = new El.Flyweight();
9925 El._flyweights[named].dom = el;
9926 return El._flyweights[named];
9930 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9931 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9932 * Shorthand of {@link Roo.Element#get}
9933 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9934 * @return {Element} The Element object
9940 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9941 * the dom node can be overwritten by other code.
9942 * Shorthand of {@link Roo.Element#fly}
9943 * @param {String/HTMLElement} el The dom node or id
9944 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9945 * prevent conflicts (e.g. internally Roo uses "_internal")
9947 * @return {Element} The shared Element object
9953 // speedy lookup for elements never to box adjust
9954 var noBoxAdjust = Roo.isStrict ? {
9957 input:1, select:1, textarea:1
9959 if(Roo.isIE || Roo.isGecko){
9960 noBoxAdjust['button'] = 1;
9964 Roo.EventManager.on(window, 'unload', function(){
9966 delete El._flyweights;
9974 Roo.Element.selectorFunction = Roo.DomQuery.select;
9977 Roo.Element.select = function(selector, unique, root){
9979 if(typeof selector == "string"){
9980 els = Roo.Element.selectorFunction(selector, root);
9981 }else if(selector.length !== undefined){
9984 throw "Invalid selector";
9986 if(unique === true){
9987 return new Roo.CompositeElement(els);
9989 return new Roo.CompositeElementLite(els);
9993 * Selects elements based on the passed CSS selector to enable working on them as 1.
9994 * @param {String/Array} selector The CSS selector or an array of elements
9995 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9996 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9997 * @return {CompositeElementLite/CompositeElement}
10001 Roo.select = Roo.Element.select;
10018 * Ext JS Library 1.1.1
10019 * Copyright(c) 2006-2007, Ext JS, LLC.
10021 * Originally Released Under LGPL - original licence link has changed is not relivant.
10024 * <script type="text/javascript">
10029 //Notifies Element that fx methods are available
10030 Roo.enableFx = true;
10034 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10035 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10036 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10037 * Element effects to work.</p><br/>
10039 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10040 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10041 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10042 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10043 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10044 * expected results and should be done with care.</p><br/>
10046 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10047 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10050 ----- -----------------------------
10051 tl The top left corner
10052 t The center of the top edge
10053 tr The top right corner
10054 l The center of the left edge
10055 r The center of the right edge
10056 bl The bottom left corner
10057 b The center of the bottom edge
10058 br The bottom right corner
10060 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10061 * below are common options that can be passed to any Fx method.</b>
10062 * @cfg {Function} callback A function called when the effect is finished
10063 * @cfg {Object} scope The scope of the effect function
10064 * @cfg {String} easing A valid Easing value for the effect
10065 * @cfg {String} afterCls A css class to apply after the effect
10066 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10067 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10068 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10069 * effects that end with the element being visually hidden, ignored otherwise)
10070 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10071 * a function which returns such a specification that will be applied to the Element after the effect finishes
10072 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10073 * @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
10074 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10078 * Slides the element into view. An anchor point can be optionally passed to set the point of
10079 * origin for the slide effect. This function automatically handles wrapping the element with
10080 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10083 // default: slide the element in from the top
10086 // custom: slide the element in from the right with a 2-second duration
10087 el.slideIn('r', { duration: 2 });
10089 // common config options shown with default values
10095 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10096 * @param {Object} options (optional) Object literal with any of the Fx config options
10097 * @return {Roo.Element} The Element
10099 slideIn : function(anchor, o){
10100 var el = this.getFxEl();
10103 el.queueFx(o, function(){
10105 anchor = anchor || "t";
10107 // fix display to visibility
10110 // restore values after effect
10111 var r = this.getFxRestore();
10112 var b = this.getBox();
10113 // fixed size for slide
10117 var wrap = this.fxWrap(r.pos, o, "hidden");
10119 var st = this.dom.style;
10120 st.visibility = "visible";
10121 st.position = "absolute";
10123 // clear out temp styles after slide and unwrap
10124 var after = function(){
10125 el.fxUnwrap(wrap, r.pos, o);
10126 st.width = r.width;
10127 st.height = r.height;
10130 // time to calc the positions
10131 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10133 switch(anchor.toLowerCase()){
10135 wrap.setSize(b.width, 0);
10136 st.left = st.bottom = "0";
10140 wrap.setSize(0, b.height);
10141 st.right = st.top = "0";
10145 wrap.setSize(0, b.height);
10146 wrap.setX(b.right);
10147 st.left = st.top = "0";
10148 a = {width: bw, points: pt};
10151 wrap.setSize(b.width, 0);
10152 wrap.setY(b.bottom);
10153 st.left = st.top = "0";
10154 a = {height: bh, points: pt};
10157 wrap.setSize(0, 0);
10158 st.right = st.bottom = "0";
10159 a = {width: bw, height: bh};
10162 wrap.setSize(0, 0);
10163 wrap.setY(b.y+b.height);
10164 st.right = st.top = "0";
10165 a = {width: bw, height: bh, points: pt};
10168 wrap.setSize(0, 0);
10169 wrap.setXY([b.right, b.bottom]);
10170 st.left = st.top = "0";
10171 a = {width: bw, height: bh, points: pt};
10174 wrap.setSize(0, 0);
10175 wrap.setX(b.x+b.width);
10176 st.left = st.bottom = "0";
10177 a = {width: bw, height: bh, points: pt};
10180 this.dom.style.visibility = "visible";
10183 arguments.callee.anim = wrap.fxanim(a,
10193 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10194 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10195 * 'hidden') but block elements will still take up space in the document. The element must be removed
10196 * from the DOM using the 'remove' config option if desired. This function automatically handles
10197 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10200 // default: slide the element out to the top
10203 // custom: slide the element out to the right with a 2-second duration
10204 el.slideOut('r', { duration: 2 });
10206 // common config options shown with default values
10214 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10215 * @param {Object} options (optional) Object literal with any of the Fx config options
10216 * @return {Roo.Element} The Element
10218 slideOut : function(anchor, o){
10219 var el = this.getFxEl();
10222 el.queueFx(o, function(){
10224 anchor = anchor || "t";
10226 // restore values after effect
10227 var r = this.getFxRestore();
10229 var b = this.getBox();
10230 // fixed size for slide
10234 var wrap = this.fxWrap(r.pos, o, "visible");
10236 var st = this.dom.style;
10237 st.visibility = "visible";
10238 st.position = "absolute";
10242 var after = function(){
10244 el.setDisplayed(false);
10249 el.fxUnwrap(wrap, r.pos, o);
10251 st.width = r.width;
10252 st.height = r.height;
10257 var a, zero = {to: 0};
10258 switch(anchor.toLowerCase()){
10260 st.left = st.bottom = "0";
10261 a = {height: zero};
10264 st.right = st.top = "0";
10268 st.left = st.top = "0";
10269 a = {width: zero, points: {to:[b.right, b.y]}};
10272 st.left = st.top = "0";
10273 a = {height: zero, points: {to:[b.x, b.bottom]}};
10276 st.right = st.bottom = "0";
10277 a = {width: zero, height: zero};
10280 st.right = st.top = "0";
10281 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10284 st.left = st.top = "0";
10285 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10288 st.left = st.bottom = "0";
10289 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10293 arguments.callee.anim = wrap.fxanim(a,
10303 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10304 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10305 * The element must be removed from the DOM using the 'remove' config option if desired.
10311 // common config options shown with default values
10319 * @param {Object} options (optional) Object literal with any of the Fx config options
10320 * @return {Roo.Element} The Element
10322 puff : function(o){
10323 var el = this.getFxEl();
10326 el.queueFx(o, function(){
10327 this.clearOpacity();
10330 // restore values after effect
10331 var r = this.getFxRestore();
10332 var st = this.dom.style;
10334 var after = function(){
10336 el.setDisplayed(false);
10343 el.setPositioning(r.pos);
10344 st.width = r.width;
10345 st.height = r.height;
10350 var width = this.getWidth();
10351 var height = this.getHeight();
10353 arguments.callee.anim = this.fxanim({
10354 width : {to: this.adjustWidth(width * 2)},
10355 height : {to: this.adjustHeight(height * 2)},
10356 points : {by: [-(width * .5), -(height * .5)]},
10358 fontSize: {to:200, unit: "%"}
10369 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10370 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10371 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10377 // all config options shown with default values
10385 * @param {Object} options (optional) Object literal with any of the Fx config options
10386 * @return {Roo.Element} The Element
10388 switchOff : function(o){
10389 var el = this.getFxEl();
10392 el.queueFx(o, function(){
10393 this.clearOpacity();
10396 // restore values after effect
10397 var r = this.getFxRestore();
10398 var st = this.dom.style;
10400 var after = function(){
10402 el.setDisplayed(false);
10408 el.setPositioning(r.pos);
10409 st.width = r.width;
10410 st.height = r.height;
10415 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10416 this.clearOpacity();
10420 points:{by:[0, this.getHeight() * .5]}
10421 }, o, 'motion', 0.3, 'easeIn', after);
10422 }).defer(100, this);
10429 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10430 * changed using the "attr" config option) and then fading back to the original color. If no original
10431 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10434 // default: highlight background to yellow
10437 // custom: highlight foreground text to blue for 2 seconds
10438 el.highlight("0000ff", { attr: 'color', duration: 2 });
10440 // common config options shown with default values
10441 el.highlight("ffff9c", {
10442 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10443 endColor: (current color) or "ffffff",
10448 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10449 * @param {Object} options (optional) Object literal with any of the Fx config options
10450 * @return {Roo.Element} The Element
10452 highlight : function(color, o){
10453 var el = this.getFxEl();
10456 el.queueFx(o, function(){
10457 color = color || "ffff9c";
10458 attr = o.attr || "backgroundColor";
10460 this.clearOpacity();
10463 var origColor = this.getColor(attr);
10464 var restoreColor = this.dom.style[attr];
10465 endColor = (o.endColor || origColor) || "ffffff";
10467 var after = function(){
10468 el.dom.style[attr] = restoreColor;
10473 a[attr] = {from: color, to: endColor};
10474 arguments.callee.anim = this.fxanim(a,
10484 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10487 // default: a single light blue ripple
10490 // custom: 3 red ripples lasting 3 seconds total
10491 el.frame("ff0000", 3, { duration: 3 });
10493 // common config options shown with default values
10494 el.frame("C3DAF9", 1, {
10495 duration: 1 //duration of entire animation (not each individual ripple)
10496 // Note: Easing is not configurable and will be ignored if included
10499 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10500 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10501 * @param {Object} options (optional) Object literal with any of the Fx config options
10502 * @return {Roo.Element} The Element
10504 frame : function(color, count, o){
10505 var el = this.getFxEl();
10508 el.queueFx(o, function(){
10509 color = color || "#C3DAF9";
10510 if(color.length == 6){
10511 color = "#" + color;
10513 count = count || 1;
10514 duration = o.duration || 1;
10517 var b = this.getBox();
10518 var animFn = function(){
10519 var proxy = this.createProxy({
10522 visbility:"hidden",
10523 position:"absolute",
10524 "z-index":"35000", // yee haw
10525 border:"0px solid " + color
10528 var scale = Roo.isBorderBox ? 2 : 1;
10530 top:{from:b.y, to:b.y - 20},
10531 left:{from:b.x, to:b.x - 20},
10532 borderWidth:{from:0, to:10},
10533 opacity:{from:1, to:0},
10534 height:{from:b.height, to:(b.height + (20*scale))},
10535 width:{from:b.width, to:(b.width + (20*scale))}
10536 }, duration, function(){
10540 animFn.defer((duration/2)*1000, this);
10551 * Creates a pause before any subsequent queued effects begin. If there are
10552 * no effects queued after the pause it will have no effect.
10557 * @param {Number} seconds The length of time to pause (in seconds)
10558 * @return {Roo.Element} The Element
10560 pause : function(seconds){
10561 var el = this.getFxEl();
10564 el.queueFx(o, function(){
10565 setTimeout(function(){
10567 }, seconds * 1000);
10573 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10574 * using the "endOpacity" config option.
10577 // default: fade in from opacity 0 to 100%
10580 // custom: fade in from opacity 0 to 75% over 2 seconds
10581 el.fadeIn({ endOpacity: .75, duration: 2});
10583 // common config options shown with default values
10585 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10590 * @param {Object} options (optional) Object literal with any of the Fx config options
10591 * @return {Roo.Element} The Element
10593 fadeIn : function(o){
10594 var el = this.getFxEl();
10596 el.queueFx(o, function(){
10597 this.setOpacity(0);
10599 this.dom.style.visibility = 'visible';
10600 var to = o.endOpacity || 1;
10601 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10602 o, null, .5, "easeOut", function(){
10604 this.clearOpacity();
10613 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10614 * using the "endOpacity" config option.
10617 // default: fade out from the element's current opacity to 0
10620 // custom: fade out from the element's current opacity to 25% over 2 seconds
10621 el.fadeOut({ endOpacity: .25, duration: 2});
10623 // common config options shown with default values
10625 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10632 * @param {Object} options (optional) Object literal with any of the Fx config options
10633 * @return {Roo.Element} The Element
10635 fadeOut : function(o){
10636 var el = this.getFxEl();
10638 el.queueFx(o, function(){
10639 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10640 o, null, .5, "easeOut", function(){
10641 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10642 this.dom.style.display = "none";
10644 this.dom.style.visibility = "hidden";
10646 this.clearOpacity();
10654 * Animates the transition of an element's dimensions from a starting height/width
10655 * to an ending height/width.
10658 // change height and width to 100x100 pixels
10659 el.scale(100, 100);
10661 // common config options shown with default values. The height and width will default to
10662 // the element's existing values if passed as null.
10665 [element's height], {
10670 * @param {Number} width The new width (pass undefined to keep the original width)
10671 * @param {Number} height The new height (pass undefined to keep the original height)
10672 * @param {Object} options (optional) Object literal with any of the Fx config options
10673 * @return {Roo.Element} The Element
10675 scale : function(w, h, o){
10676 this.shift(Roo.apply({}, o, {
10684 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10685 * Any of these properties not specified in the config object will not be changed. This effect
10686 * requires that at least one new dimension, position or opacity setting must be passed in on
10687 * the config object in order for the function to have any effect.
10690 // slide the element horizontally to x position 200 while changing the height and opacity
10691 el.shift({ x: 200, height: 50, opacity: .8 });
10693 // common config options shown with default values.
10695 width: [element's width],
10696 height: [element's height],
10697 x: [element's x position],
10698 y: [element's y position],
10699 opacity: [element's opacity],
10704 * @param {Object} options Object literal with any of the Fx config options
10705 * @return {Roo.Element} The Element
10707 shift : function(o){
10708 var el = this.getFxEl();
10710 el.queueFx(o, function(){
10711 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10712 if(w !== undefined){
10713 a.width = {to: this.adjustWidth(w)};
10715 if(h !== undefined){
10716 a.height = {to: this.adjustHeight(h)};
10718 if(x !== undefined || y !== undefined){
10720 x !== undefined ? x : this.getX(),
10721 y !== undefined ? y : this.getY()
10724 if(op !== undefined){
10725 a.opacity = {to: op};
10727 if(o.xy !== undefined){
10728 a.points = {to: o.xy};
10730 arguments.callee.anim = this.fxanim(a,
10731 o, 'motion', .35, "easeOut", function(){
10739 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10740 * ending point of the effect.
10743 // default: slide the element downward while fading out
10746 // custom: slide the element out to the right with a 2-second duration
10747 el.ghost('r', { duration: 2 });
10749 // common config options shown with default values
10757 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10758 * @param {Object} options (optional) Object literal with any of the Fx config options
10759 * @return {Roo.Element} The Element
10761 ghost : function(anchor, o){
10762 var el = this.getFxEl();
10765 el.queueFx(o, function(){
10766 anchor = anchor || "b";
10768 // restore values after effect
10769 var r = this.getFxRestore();
10770 var w = this.getWidth(),
10771 h = this.getHeight();
10773 var st = this.dom.style;
10775 var after = function(){
10777 el.setDisplayed(false);
10783 el.setPositioning(r.pos);
10784 st.width = r.width;
10785 st.height = r.height;
10790 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10791 switch(anchor.toLowerCase()){
10818 arguments.callee.anim = this.fxanim(a,
10828 * Ensures that all effects queued after syncFx is called on the element are
10829 * run concurrently. This is the opposite of {@link #sequenceFx}.
10830 * @return {Roo.Element} The Element
10832 syncFx : function(){
10833 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10842 * Ensures that all effects queued after sequenceFx is called on the element are
10843 * run in sequence. This is the opposite of {@link #syncFx}.
10844 * @return {Roo.Element} The Element
10846 sequenceFx : function(){
10847 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10849 concurrent : false,
10856 nextFx : function(){
10857 var ef = this.fxQueue[0];
10864 * Returns true if the element has any effects actively running or queued, else returns false.
10865 * @return {Boolean} True if element has active effects, else false
10867 hasActiveFx : function(){
10868 return this.fxQueue && this.fxQueue[0];
10872 * Stops any running effects and clears the element's internal effects queue if it contains
10873 * any additional effects that haven't started yet.
10874 * @return {Roo.Element} The Element
10876 stopFx : function(){
10877 if(this.hasActiveFx()){
10878 var cur = this.fxQueue[0];
10879 if(cur && cur.anim && cur.anim.isAnimated()){
10880 this.fxQueue = [cur]; // clear out others
10881 cur.anim.stop(true);
10888 beforeFx : function(o){
10889 if(this.hasActiveFx() && !o.concurrent){
10900 * Returns true if the element is currently blocking so that no other effect can be queued
10901 * until this effect is finished, else returns false if blocking is not set. This is commonly
10902 * used to ensure that an effect initiated by a user action runs to completion prior to the
10903 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10904 * @return {Boolean} True if blocking, else false
10906 hasFxBlock : function(){
10907 var q = this.fxQueue;
10908 return q && q[0] && q[0].block;
10912 queueFx : function(o, fn){
10916 if(!this.hasFxBlock()){
10917 Roo.applyIf(o, this.fxDefaults);
10919 var run = this.beforeFx(o);
10920 fn.block = o.block;
10921 this.fxQueue.push(fn);
10933 fxWrap : function(pos, o, vis){
10935 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10938 wrapXY = this.getXY();
10940 var div = document.createElement("div");
10941 div.style.visibility = vis;
10942 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10943 wrap.setPositioning(pos);
10944 if(wrap.getStyle("position") == "static"){
10945 wrap.position("relative");
10947 this.clearPositioning('auto');
10949 wrap.dom.appendChild(this.dom);
10951 wrap.setXY(wrapXY);
10958 fxUnwrap : function(wrap, pos, o){
10959 this.clearPositioning();
10960 this.setPositioning(pos);
10962 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10968 getFxRestore : function(){
10969 var st = this.dom.style;
10970 return {pos: this.getPositioning(), width: st.width, height : st.height};
10974 afterFx : function(o){
10976 this.applyStyles(o.afterStyle);
10979 this.addClass(o.afterCls);
10981 if(o.remove === true){
10984 Roo.callback(o.callback, o.scope, [this]);
10986 this.fxQueue.shift();
10992 getFxEl : function(){ // support for composite element fx
10993 return Roo.get(this.dom);
10997 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10998 animType = animType || 'run';
11000 var anim = Roo.lib.Anim[animType](
11002 (opt.duration || defaultDur) || .35,
11003 (opt.easing || defaultEase) || 'easeOut',
11005 Roo.callback(cb, this);
11014 // backwords compat
11015 Roo.Fx.resize = Roo.Fx.scale;
11017 //When included, Roo.Fx is automatically applied to Element so that all basic
11018 //effects are available directly via the Element API
11019 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11021 * Ext JS Library 1.1.1
11022 * Copyright(c) 2006-2007, Ext JS, LLC.
11024 * Originally Released Under LGPL - original licence link has changed is not relivant.
11027 * <script type="text/javascript">
11032 * @class Roo.CompositeElement
11033 * Standard composite class. Creates a Roo.Element for every element in the collection.
11035 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11036 * actions will be performed on all the elements in this collection.</b>
11038 * All methods return <i>this</i> and can be chained.
11040 var els = Roo.select("#some-el div.some-class", true);
11041 // or select directly from an existing element
11042 var el = Roo.get('some-el');
11043 el.select('div.some-class', true);
11045 els.setWidth(100); // all elements become 100 width
11046 els.hide(true); // all elements fade out and hide
11048 els.setWidth(100).hide(true);
11051 Roo.CompositeElement = function(els){
11052 this.elements = [];
11053 this.addElements(els);
11055 Roo.CompositeElement.prototype = {
11057 addElements : function(els){
11061 if(typeof els == "string"){
11062 els = Roo.Element.selectorFunction(els);
11064 var yels = this.elements;
11065 var index = yels.length-1;
11066 for(var i = 0, len = els.length; i < len; i++) {
11067 yels[++index] = Roo.get(els[i]);
11073 * Clears this composite and adds the elements returned by the passed selector.
11074 * @param {String/Array} els A string CSS selector, an array of elements or an element
11075 * @return {CompositeElement} this
11077 fill : function(els){
11078 this.elements = [];
11084 * Filters this composite to only elements that match the passed selector.
11085 * @param {String} selector A string CSS selector
11086 * @param {Boolean} inverse return inverse filter (not matches)
11087 * @return {CompositeElement} this
11089 filter : function(selector, inverse){
11091 inverse = inverse || false;
11092 this.each(function(el){
11093 var match = inverse ? !el.is(selector) : el.is(selector);
11095 els[els.length] = el.dom;
11102 invoke : function(fn, args){
11103 var els = this.elements;
11104 for(var i = 0, len = els.length; i < len; i++) {
11105 Roo.Element.prototype[fn].apply(els[i], args);
11110 * Adds elements to this composite.
11111 * @param {String/Array} els A string CSS selector, an array of elements or an element
11112 * @return {CompositeElement} this
11114 add : function(els){
11115 if(typeof els == "string"){
11116 this.addElements(Roo.Element.selectorFunction(els));
11117 }else if(els.length !== undefined){
11118 this.addElements(els);
11120 this.addElements([els]);
11125 * Calls the passed function passing (el, this, index) for each element in this composite.
11126 * @param {Function} fn The function to call
11127 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11128 * @return {CompositeElement} this
11130 each : function(fn, scope){
11131 var els = this.elements;
11132 for(var i = 0, len = els.length; i < len; i++){
11133 if(fn.call(scope || els[i], els[i], this, i) === false) {
11141 * Returns the Element object at the specified index
11142 * @param {Number} index
11143 * @return {Roo.Element}
11145 item : function(index){
11146 return this.elements[index] || null;
11150 * Returns the first Element
11151 * @return {Roo.Element}
11153 first : function(){
11154 return this.item(0);
11158 * Returns the last Element
11159 * @return {Roo.Element}
11162 return this.item(this.elements.length-1);
11166 * Returns the number of elements in this composite
11169 getCount : function(){
11170 return this.elements.length;
11174 * Returns true if this composite contains the passed element
11177 contains : function(el){
11178 return this.indexOf(el) !== -1;
11182 * Returns true if this composite contains the passed element
11185 indexOf : function(el){
11186 return this.elements.indexOf(Roo.get(el));
11191 * Removes the specified element(s).
11192 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11193 * or an array of any of those.
11194 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11195 * @return {CompositeElement} this
11197 removeElement : function(el, removeDom){
11198 if(el instanceof Array){
11199 for(var i = 0, len = el.length; i < len; i++){
11200 this.removeElement(el[i]);
11204 var index = typeof el == 'number' ? el : this.indexOf(el);
11207 var d = this.elements[index];
11211 d.parentNode.removeChild(d);
11214 this.elements.splice(index, 1);
11220 * Replaces the specified element with the passed element.
11221 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11223 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11224 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11225 * @return {CompositeElement} this
11227 replaceElement : function(el, replacement, domReplace){
11228 var index = typeof el == 'number' ? el : this.indexOf(el);
11231 this.elements[index].replaceWith(replacement);
11233 this.elements.splice(index, 1, Roo.get(replacement))
11240 * Removes all elements.
11242 clear : function(){
11243 this.elements = [];
11247 Roo.CompositeElement.createCall = function(proto, fnName){
11248 if(!proto[fnName]){
11249 proto[fnName] = function(){
11250 return this.invoke(fnName, arguments);
11254 for(var fnName in Roo.Element.prototype){
11255 if(typeof Roo.Element.prototype[fnName] == "function"){
11256 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11262 * Ext JS Library 1.1.1
11263 * Copyright(c) 2006-2007, Ext JS, LLC.
11265 * Originally Released Under LGPL - original licence link has changed is not relivant.
11268 * <script type="text/javascript">
11272 * @class Roo.CompositeElementLite
11273 * @extends Roo.CompositeElement
11274 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11276 var els = Roo.select("#some-el div.some-class");
11277 // or select directly from an existing element
11278 var el = Roo.get('some-el');
11279 el.select('div.some-class');
11281 els.setWidth(100); // all elements become 100 width
11282 els.hide(true); // all elements fade out and hide
11284 els.setWidth(100).hide(true);
11285 </code></pre><br><br>
11286 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11287 * actions will be performed on all the elements in this collection.</b>
11289 Roo.CompositeElementLite = function(els){
11290 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11291 this.el = new Roo.Element.Flyweight();
11293 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11294 addElements : function(els){
11296 if(els instanceof Array){
11297 this.elements = this.elements.concat(els);
11299 var yels = this.elements;
11300 var index = yels.length-1;
11301 for(var i = 0, len = els.length; i < len; i++) {
11302 yels[++index] = els[i];
11308 invoke : function(fn, args){
11309 var els = this.elements;
11311 for(var i = 0, len = els.length; i < len; i++) {
11313 Roo.Element.prototype[fn].apply(el, args);
11318 * Returns a flyweight Element of the dom element object at the specified index
11319 * @param {Number} index
11320 * @return {Roo.Element}
11322 item : function(index){
11323 if(!this.elements[index]){
11326 this.el.dom = this.elements[index];
11330 // fixes scope with flyweight
11331 addListener : function(eventName, handler, scope, opt){
11332 var els = this.elements;
11333 for(var i = 0, len = els.length; i < len; i++) {
11334 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11340 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11341 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11342 * a reference to the dom node, use el.dom.</b>
11343 * @param {Function} fn The function to call
11344 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11345 * @return {CompositeElement} this
11347 each : function(fn, scope){
11348 var els = this.elements;
11350 for(var i = 0, len = els.length; i < len; i++){
11352 if(fn.call(scope || el, el, this, i) === false){
11359 indexOf : function(el){
11360 return this.elements.indexOf(Roo.getDom(el));
11363 replaceElement : function(el, replacement, domReplace){
11364 var index = typeof el == 'number' ? el : this.indexOf(el);
11366 replacement = Roo.getDom(replacement);
11368 var d = this.elements[index];
11369 d.parentNode.insertBefore(replacement, d);
11370 d.parentNode.removeChild(d);
11372 this.elements.splice(index, 1, replacement);
11377 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11381 * Ext JS Library 1.1.1
11382 * Copyright(c) 2006-2007, Ext JS, LLC.
11384 * Originally Released Under LGPL - original licence link has changed is not relivant.
11387 * <script type="text/javascript">
11393 * @class Roo.data.Connection
11394 * @extends Roo.util.Observable
11395 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11396 * either to a configured URL, or to a URL specified at request time.<br><br>
11398 * Requests made by this class are asynchronous, and will return immediately. No data from
11399 * the server will be available to the statement immediately following the {@link #request} call.
11400 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11402 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11403 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11404 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11405 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11406 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11407 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11408 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11409 * standard DOM methods.
11411 * @param {Object} config a configuration object.
11413 Roo.data.Connection = function(config){
11414 Roo.apply(this, config);
11417 * @event beforerequest
11418 * Fires before a network request is made to retrieve a data object.
11419 * @param {Connection} conn This Connection object.
11420 * @param {Object} options The options config object passed to the {@link #request} method.
11422 "beforerequest" : true,
11424 * @event requestcomplete
11425 * Fires if the request was successfully completed.
11426 * @param {Connection} conn This Connection object.
11427 * @param {Object} response The XHR object containing the response data.
11428 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11429 * @param {Object} options The options config object passed to the {@link #request} method.
11431 "requestcomplete" : true,
11433 * @event requestexception
11434 * Fires if an error HTTP status was returned from the server.
11435 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11436 * @param {Connection} conn This Connection object.
11437 * @param {Object} response The XHR object containing the response data.
11438 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11439 * @param {Object} options The options config object passed to the {@link #request} method.
11441 "requestexception" : true
11443 Roo.data.Connection.superclass.constructor.call(this);
11446 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11448 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11451 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11452 * extra parameters to each request made by this object. (defaults to undefined)
11455 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11456 * to each request made by this object. (defaults to undefined)
11459 * @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)
11462 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11466 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11472 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11475 disableCaching: true,
11478 * Sends an HTTP request to a remote server.
11479 * @param {Object} options An object which may contain the following properties:<ul>
11480 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11481 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11482 * request, a url encoded string or a function to call to get either.</li>
11483 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11484 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11485 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11486 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11487 * <li>options {Object} The parameter to the request call.</li>
11488 * <li>success {Boolean} True if the request succeeded.</li>
11489 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11491 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11492 * The callback is passed the following parameters:<ul>
11493 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11494 * <li>options {Object} The parameter to the request call.</li>
11496 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11497 * The callback is passed the following parameters:<ul>
11498 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11499 * <li>options {Object} The parameter to the request call.</li>
11501 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11502 * for the callback function. Defaults to the browser window.</li>
11503 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11504 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11505 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11506 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11507 * params for the post data. Any params will be appended to the URL.</li>
11508 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11510 * @return {Number} transactionId
11512 request : function(o){
11513 if(this.fireEvent("beforerequest", this, o) !== false){
11516 if(typeof p == "function"){
11517 p = p.call(o.scope||window, o);
11519 if(typeof p == "object"){
11520 p = Roo.urlEncode(o.params);
11522 if(this.extraParams){
11523 var extras = Roo.urlEncode(this.extraParams);
11524 p = p ? (p + '&' + extras) : extras;
11527 var url = o.url || this.url;
11528 if(typeof url == 'function'){
11529 url = url.call(o.scope||window, o);
11533 var form = Roo.getDom(o.form);
11534 url = url || form.action;
11536 var enctype = form.getAttribute("enctype");
11537 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11538 return this.doFormUpload(o, p, url);
11540 var f = Roo.lib.Ajax.serializeForm(form);
11541 p = p ? (p + '&' + f) : f;
11544 var hs = o.headers;
11545 if(this.defaultHeaders){
11546 hs = Roo.apply(hs || {}, this.defaultHeaders);
11553 success: this.handleResponse,
11554 failure: this.handleFailure,
11556 argument: {options: o},
11557 timeout : o.timeout || this.timeout
11560 var method = o.method||this.method||(p ? "POST" : "GET");
11562 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11563 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11566 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11570 }else if(this.autoAbort !== false){
11574 if((method == 'GET' && p) || o.xmlData){
11575 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11578 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11579 return this.transId;
11581 Roo.callback(o.callback, o.scope, [o, null, null]);
11587 * Determine whether this object has a request outstanding.
11588 * @param {Number} transactionId (Optional) defaults to the last transaction
11589 * @return {Boolean} True if there is an outstanding request.
11591 isLoading : function(transId){
11593 return Roo.lib.Ajax.isCallInProgress(transId);
11595 return this.transId ? true : false;
11600 * Aborts any outstanding request.
11601 * @param {Number} transactionId (Optional) defaults to the last transaction
11603 abort : function(transId){
11604 if(transId || this.isLoading()){
11605 Roo.lib.Ajax.abort(transId || this.transId);
11610 handleResponse : function(response){
11611 this.transId = false;
11612 var options = response.argument.options;
11613 response.argument = options ? options.argument : null;
11614 this.fireEvent("requestcomplete", this, response, options);
11615 Roo.callback(options.success, options.scope, [response, options]);
11616 Roo.callback(options.callback, options.scope, [options, true, response]);
11620 handleFailure : function(response, e){
11621 this.transId = false;
11622 var options = response.argument.options;
11623 response.argument = options ? options.argument : null;
11624 this.fireEvent("requestexception", this, response, options, e);
11625 Roo.callback(options.failure, options.scope, [response, options]);
11626 Roo.callback(options.callback, options.scope, [options, false, response]);
11630 doFormUpload : function(o, ps, url){
11632 var frame = document.createElement('iframe');
11635 frame.className = 'x-hidden';
11637 frame.src = Roo.SSL_SECURE_URL;
11639 document.body.appendChild(frame);
11642 document.frames[id].name = id;
11645 var form = Roo.getDom(o.form);
11647 form.method = 'POST';
11648 form.enctype = form.encoding = 'multipart/form-data';
11654 if(ps){ // add dynamic params
11656 ps = Roo.urlDecode(ps, false);
11658 if(ps.hasOwnProperty(k)){
11659 hd = document.createElement('input');
11660 hd.type = 'hidden';
11663 form.appendChild(hd);
11670 var r = { // bogus response object
11675 r.argument = o ? o.argument : null;
11680 doc = frame.contentWindow.document;
11682 doc = (frame.contentDocument || window.frames[id].document);
11684 if(doc && doc.body){
11685 r.responseText = doc.body.innerHTML;
11687 if(doc && doc.XMLDocument){
11688 r.responseXML = doc.XMLDocument;
11690 r.responseXML = doc;
11697 Roo.EventManager.removeListener(frame, 'load', cb, this);
11699 this.fireEvent("requestcomplete", this, r, o);
11700 Roo.callback(o.success, o.scope, [r, o]);
11701 Roo.callback(o.callback, o.scope, [o, true, r]);
11703 setTimeout(function(){document.body.removeChild(frame);}, 100);
11706 Roo.EventManager.on(frame, 'load', cb, this);
11709 if(hiddens){ // remove dynamic params
11710 for(var i = 0, len = hiddens.length; i < len; i++){
11711 form.removeChild(hiddens[i]);
11718 * Ext JS Library 1.1.1
11719 * Copyright(c) 2006-2007, Ext JS, LLC.
11721 * Originally Released Under LGPL - original licence link has changed is not relivant.
11724 * <script type="text/javascript">
11728 * Global Ajax request class.
11731 * @extends Roo.data.Connection
11734 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11735 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11736 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11737 * @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)
11738 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11739 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11740 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11742 Roo.Ajax = new Roo.data.Connection({
11751 * Serialize the passed form into a url encoded string
11753 * @param {String/HTMLElement} form
11756 serializeForm : function(form){
11757 return Roo.lib.Ajax.serializeForm(form);
11761 * Ext JS Library 1.1.1
11762 * Copyright(c) 2006-2007, Ext JS, LLC.
11764 * Originally Released Under LGPL - original licence link has changed is not relivant.
11767 * <script type="text/javascript">
11772 * @class Roo.UpdateManager
11773 * @extends Roo.util.Observable
11774 * Provides AJAX-style update for Element object.<br><br>
11777 * // Get it from a Roo.Element object
11778 * var el = Roo.get("foo");
11779 * var mgr = el.getUpdateManager();
11780 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11782 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11784 * // or directly (returns the same UpdateManager instance)
11785 * var mgr = new Roo.UpdateManager("myElementId");
11786 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11787 * mgr.on("update", myFcnNeedsToKnow);
11789 // short handed call directly from the element object
11790 Roo.get("foo").load({
11794 text: "Loading Foo..."
11798 * Create new UpdateManager directly.
11799 * @param {String/HTMLElement/Roo.Element} el The element to update
11800 * @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).
11802 Roo.UpdateManager = function(el, forceNew){
11804 if(!forceNew && el.updateManager){
11805 return el.updateManager;
11808 * The Element object
11809 * @type Roo.Element
11813 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11816 this.defaultUrl = null;
11820 * @event beforeupdate
11821 * Fired before an update is made, return false from your handler and the update is cancelled.
11822 * @param {Roo.Element} el
11823 * @param {String/Object/Function} url
11824 * @param {String/Object} params
11826 "beforeupdate": true,
11829 * Fired after successful update is made.
11830 * @param {Roo.Element} el
11831 * @param {Object} oResponseObject The response Object
11836 * Fired on update failure.
11837 * @param {Roo.Element} el
11838 * @param {Object} oResponseObject The response Object
11842 var d = Roo.UpdateManager.defaults;
11844 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11847 this.sslBlankUrl = d.sslBlankUrl;
11849 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11852 this.disableCaching = d.disableCaching;
11854 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11857 this.indicatorText = d.indicatorText;
11859 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11862 this.showLoadIndicator = d.showLoadIndicator;
11864 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11867 this.timeout = d.timeout;
11870 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11873 this.loadScripts = d.loadScripts;
11876 * Transaction object of current executing transaction
11878 this.transaction = null;
11883 this.autoRefreshProcId = null;
11885 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11888 this.refreshDelegate = this.refresh.createDelegate(this);
11890 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11893 this.updateDelegate = this.update.createDelegate(this);
11895 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11898 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11902 this.successDelegate = this.processSuccess.createDelegate(this);
11906 this.failureDelegate = this.processFailure.createDelegate(this);
11908 if(!this.renderer){
11910 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11912 this.renderer = new Roo.UpdateManager.BasicRenderer();
11915 Roo.UpdateManager.superclass.constructor.call(this);
11918 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11920 * Get the Element this UpdateManager is bound to
11921 * @return {Roo.Element} The element
11923 getEl : function(){
11927 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11928 * @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:
11931 url: "your-url.php",<br/>
11932 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11933 callback: yourFunction,<br/>
11934 scope: yourObject, //(optional scope) <br/>
11935 discardUrl: false, <br/>
11936 nocache: false,<br/>
11937 text: "Loading...",<br/>
11939 scripts: false<br/>
11942 * The only required property is url. The optional properties nocache, text and scripts
11943 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11944 * @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}
11945 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11946 * @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.
11948 update : function(url, params, callback, discardUrl){
11949 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11950 var method = this.method,
11952 if(typeof url == "object"){ // must be config object
11955 params = params || cfg.params;
11956 callback = callback || cfg.callback;
11957 discardUrl = discardUrl || cfg.discardUrl;
11958 if(callback && cfg.scope){
11959 callback = callback.createDelegate(cfg.scope);
11961 if(typeof cfg.method != "undefined"){method = cfg.method;};
11962 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11963 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11964 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11965 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11967 this.showLoading();
11969 this.defaultUrl = url;
11971 if(typeof url == "function"){
11972 url = url.call(this);
11975 method = method || (params ? "POST" : "GET");
11976 if(method == "GET"){
11977 url = this.prepareUrl(url);
11980 var o = Roo.apply(cfg ||{}, {
11983 success: this.successDelegate,
11984 failure: this.failureDelegate,
11985 callback: undefined,
11986 timeout: (this.timeout*1000),
11987 argument: {"url": url, "form": null, "callback": callback, "params": params}
11989 Roo.log("updated manager called with timeout of " + o.timeout);
11990 this.transaction = Roo.Ajax.request(o);
11995 * 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.
11996 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11997 * @param {String/HTMLElement} form The form Id or form element
11998 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11999 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12000 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12002 formUpdate : function(form, url, reset, callback){
12003 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12004 if(typeof url == "function"){
12005 url = url.call(this);
12007 form = Roo.getDom(form);
12008 this.transaction = Roo.Ajax.request({
12011 success: this.successDelegate,
12012 failure: this.failureDelegate,
12013 timeout: (this.timeout*1000),
12014 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12016 this.showLoading.defer(1, this);
12021 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12022 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12024 refresh : function(callback){
12025 if(this.defaultUrl == null){
12028 this.update(this.defaultUrl, null, callback, true);
12032 * Set this element to auto refresh.
12033 * @param {Number} interval How often to update (in seconds).
12034 * @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)
12035 * @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}
12036 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12037 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12039 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12041 this.update(url || this.defaultUrl, params, callback, true);
12043 if(this.autoRefreshProcId){
12044 clearInterval(this.autoRefreshProcId);
12046 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12050 * Stop auto refresh on this element.
12052 stopAutoRefresh : function(){
12053 if(this.autoRefreshProcId){
12054 clearInterval(this.autoRefreshProcId);
12055 delete this.autoRefreshProcId;
12059 isAutoRefreshing : function(){
12060 return this.autoRefreshProcId ? true : false;
12063 * Called to update the element to "Loading" state. Override to perform custom action.
12065 showLoading : function(){
12066 if(this.showLoadIndicator){
12067 this.el.update(this.indicatorText);
12072 * Adds unique parameter to query string if disableCaching = true
12075 prepareUrl : function(url){
12076 if(this.disableCaching){
12077 var append = "_dc=" + (new Date().getTime());
12078 if(url.indexOf("?") !== -1){
12079 url += "&" + append;
12081 url += "?" + append;
12090 processSuccess : function(response){
12091 this.transaction = null;
12092 if(response.argument.form && response.argument.reset){
12093 try{ // put in try/catch since some older FF releases had problems with this
12094 response.argument.form.reset();
12097 if(this.loadScripts){
12098 this.renderer.render(this.el, response, this,
12099 this.updateComplete.createDelegate(this, [response]));
12101 this.renderer.render(this.el, response, this);
12102 this.updateComplete(response);
12106 updateComplete : function(response){
12107 this.fireEvent("update", this.el, response);
12108 if(typeof response.argument.callback == "function"){
12109 response.argument.callback(this.el, true, response);
12116 processFailure : function(response){
12117 this.transaction = null;
12118 this.fireEvent("failure", this.el, response);
12119 if(typeof response.argument.callback == "function"){
12120 response.argument.callback(this.el, false, response);
12125 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12126 * @param {Object} renderer The object implementing the render() method
12128 setRenderer : function(renderer){
12129 this.renderer = renderer;
12132 getRenderer : function(){
12133 return this.renderer;
12137 * Set the defaultUrl used for updates
12138 * @param {String/Function} defaultUrl The url or a function to call to get the url
12140 setDefaultUrl : function(defaultUrl){
12141 this.defaultUrl = defaultUrl;
12145 * Aborts the executing transaction
12147 abort : function(){
12148 if(this.transaction){
12149 Roo.Ajax.abort(this.transaction);
12154 * Returns true if an update is in progress
12155 * @return {Boolean}
12157 isUpdating : function(){
12158 if(this.transaction){
12159 return Roo.Ajax.isLoading(this.transaction);
12166 * @class Roo.UpdateManager.defaults
12167 * @static (not really - but it helps the doc tool)
12168 * The defaults collection enables customizing the default properties of UpdateManager
12170 Roo.UpdateManager.defaults = {
12172 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12178 * True to process scripts by default (Defaults to false).
12181 loadScripts : false,
12184 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12187 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12189 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12192 disableCaching : false,
12194 * Whether to show indicatorText when loading (Defaults to true).
12197 showLoadIndicator : true,
12199 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12202 indicatorText : '<div class="loading-indicator">Loading...</div>'
12206 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12208 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12209 * @param {String/HTMLElement/Roo.Element} el The element to update
12210 * @param {String} url The url
12211 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12212 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12215 * @member Roo.UpdateManager
12217 Roo.UpdateManager.updateElement = function(el, url, params, options){
12218 var um = Roo.get(el, true).getUpdateManager();
12219 Roo.apply(um, options);
12220 um.update(url, params, options ? options.callback : null);
12222 // alias for backwards compat
12223 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12225 * @class Roo.UpdateManager.BasicRenderer
12226 * Default Content renderer. Updates the elements innerHTML with the responseText.
12228 Roo.UpdateManager.BasicRenderer = function(){};
12230 Roo.UpdateManager.BasicRenderer.prototype = {
12232 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12233 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12234 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12235 * @param {Roo.Element} el The element being rendered
12236 * @param {Object} response The YUI Connect response object
12237 * @param {UpdateManager} updateManager The calling update manager
12238 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12240 render : function(el, response, updateManager, callback){
12241 el.update(response.responseText, updateManager.loadScripts, callback);
12247 * (c)) Alan Knowles
12253 * @class Roo.DomTemplate
12254 * @extends Roo.Template
12255 * An effort at a dom based template engine..
12257 * Similar to XTemplate, except it uses dom parsing to create the template..
12259 * Supported features:
12264 {a_variable} - output encoded.
12265 {a_variable.format:("Y-m-d")} - call a method on the variable
12266 {a_variable:raw} - unencoded output
12267 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12268 {a_variable:this.method_on_template(...)} - call a method on the template object.
12273 <div roo-for="a_variable or condition.."></div>
12274 <div roo-if="a_variable or condition"></div>
12275 <div roo-exec="some javascript"></div>
12276 <div roo-name="named_template"></div>
12281 Roo.DomTemplate = function()
12283 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12290 Roo.extend(Roo.DomTemplate, Roo.Template, {
12292 * id counter for sub templates.
12296 * flag to indicate if dom parser is inside a pre,
12297 * it will strip whitespace if not.
12302 * The various sub templates
12310 * basic tag replacing syntax
12313 * // you can fake an object call by doing this
12317 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12318 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12320 iterChild : function (node, method) {
12322 var oldPre = this.inPre;
12323 if (node.tagName == 'PRE') {
12326 for( var i = 0; i < node.childNodes.length; i++) {
12327 method.call(this, node.childNodes[i]);
12329 this.inPre = oldPre;
12335 * compile the template
12337 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12340 compile: function()
12344 // covert the html into DOM...
12348 doc = document.implementation.createHTMLDocument("");
12349 doc.documentElement.innerHTML = this.html ;
12350 div = doc.documentElement;
12352 // old IE... - nasty -- it causes all sorts of issues.. with
12353 // images getting pulled from server..
12354 div = document.createElement('div');
12355 div.innerHTML = this.html;
12357 //doc.documentElement.innerHTML = htmlBody
12363 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12365 var tpls = this.tpls;
12367 // create a top level template from the snippet..
12369 //Roo.log(div.innerHTML);
12376 body : div.innerHTML,
12389 Roo.each(tpls, function(tp){
12390 this.compileTpl(tp);
12391 this.tpls[tp.id] = tp;
12394 this.master = tpls[0];
12400 compileNode : function(node, istop) {
12405 // skip anything not a tag..
12406 if (node.nodeType != 1) {
12407 if (node.nodeType == 3 && !this.inPre) {
12408 // reduce white space..
12409 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12432 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12433 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12434 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12435 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12441 // just itterate children..
12442 this.iterChild(node,this.compileNode);
12445 tpl.uid = this.id++;
12446 tpl.value = node.getAttribute('roo-' + tpl.attr);
12447 node.removeAttribute('roo-'+ tpl.attr);
12448 if (tpl.attr != 'name') {
12449 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12450 node.parentNode.replaceChild(placeholder, node);
12453 var placeholder = document.createElement('span');
12454 placeholder.className = 'roo-tpl-' + tpl.value;
12455 node.parentNode.replaceChild(placeholder, node);
12458 // parent now sees '{domtplXXXX}
12459 this.iterChild(node,this.compileNode);
12461 // we should now have node body...
12462 var div = document.createElement('div');
12463 div.appendChild(node);
12465 // this has the unfortunate side effect of converting tagged attributes
12466 // eg. href="{...}" into %7C...%7D
12467 // this has been fixed by searching for those combo's although it's a bit hacky..
12470 tpl.body = div.innerHTML;
12477 switch (tpl.value) {
12478 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12479 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12480 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12485 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12489 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12493 tpl.id = tpl.value; // replace non characters???
12499 this.tpls.push(tpl);
12509 * Compile a segment of the template into a 'sub-template'
12515 compileTpl : function(tpl)
12517 var fm = Roo.util.Format;
12518 var useF = this.disableFormats !== true;
12520 var sep = Roo.isGecko ? "+\n" : ",\n";
12522 var undef = function(str) {
12523 Roo.debug && Roo.log("Property not found :" + str);
12527 //Roo.log(tpl.body);
12531 var fn = function(m, lbrace, name, format, args)
12534 //Roo.log(arguments);
12535 args = args ? args.replace(/\\'/g,"'") : args;
12536 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12537 if (typeof(format) == 'undefined') {
12538 format = 'htmlEncode';
12540 if (format == 'raw' ) {
12544 if(name.substr(0, 6) == 'domtpl'){
12545 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12548 // build an array of options to determine if value is undefined..
12550 // basically get 'xxxx.yyyy' then do
12551 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12552 // (function () { Roo.log("Property not found"); return ''; })() :
12557 Roo.each(name.split('.'), function(st) {
12558 lookfor += (lookfor.length ? '.': '') + st;
12559 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12562 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12565 if(format && useF){
12567 args = args ? ',' + args : "";
12569 if(format.substr(0, 5) != "this."){
12570 format = "fm." + format + '(';
12572 format = 'this.call("'+ format.substr(5) + '", ';
12576 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12579 if (args && args.length) {
12580 // called with xxyx.yuu:(test,test)
12582 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12584 // raw.. - :raw modifier..
12585 return "'"+ sep + udef_st + name + ")"+sep+"'";
12589 // branched to use + in gecko and [].join() in others
12591 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12592 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12595 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12596 body.push(tpl.body.replace(/(\r\n|\n)/g,
12597 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12598 body.push("'].join('');};};");
12599 body = body.join('');
12602 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12604 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12611 * same as applyTemplate, except it's done to one of the subTemplates
12612 * when using named templates, you can do:
12614 * var str = pl.applySubTemplate('your-name', values);
12617 * @param {Number} id of the template
12618 * @param {Object} values to apply to template
12619 * @param {Object} parent (normaly the instance of this object)
12621 applySubTemplate : function(id, values, parent)
12625 var t = this.tpls[id];
12629 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12630 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12634 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12641 if(t.execCall && t.execCall.call(this, values, parent)){
12645 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12651 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12652 parent = t.target ? values : parent;
12653 if(t.forCall && vs instanceof Array){
12655 for(var i = 0, len = vs.length; i < len; i++){
12657 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12659 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12661 //Roo.log(t.compiled);
12665 return buf.join('');
12668 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12673 return t.compiled.call(this, vs, parent);
12675 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12677 //Roo.log(t.compiled);
12685 applyTemplate : function(values){
12686 return this.master.compiled.call(this, values, {});
12687 //var s = this.subs;
12690 apply : function(){
12691 return this.applyTemplate.apply(this, arguments);
12696 Roo.DomTemplate.from = function(el){
12697 el = Roo.getDom(el);
12698 return new Roo.Domtemplate(el.value || el.innerHTML);
12701 * Ext JS Library 1.1.1
12702 * Copyright(c) 2006-2007, Ext JS, LLC.
12704 * Originally Released Under LGPL - original licence link has changed is not relivant.
12707 * <script type="text/javascript">
12711 * @class Roo.util.DelayedTask
12712 * Provides a convenient method of performing setTimeout where a new
12713 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12714 * You can use this class to buffer
12715 * the keypress events for a certain number of milliseconds, and perform only if they stop
12716 * for that amount of time.
12717 * @constructor The parameters to this constructor serve as defaults and are not required.
12718 * @param {Function} fn (optional) The default function to timeout
12719 * @param {Object} scope (optional) The default scope of that timeout
12720 * @param {Array} args (optional) The default Array of arguments
12722 Roo.util.DelayedTask = function(fn, scope, args){
12723 var id = null, d, t;
12725 var call = function(){
12726 var now = new Date().getTime();
12730 fn.apply(scope, args || []);
12734 * Cancels any pending timeout and queues a new one
12735 * @param {Number} delay The milliseconds to delay
12736 * @param {Function} newFn (optional) Overrides function passed to constructor
12737 * @param {Object} newScope (optional) Overrides scope passed to constructor
12738 * @param {Array} newArgs (optional) Overrides args passed to constructor
12740 this.delay = function(delay, newFn, newScope, newArgs){
12741 if(id && delay != d){
12745 t = new Date().getTime();
12747 scope = newScope || scope;
12748 args = newArgs || args;
12750 id = setInterval(call, d);
12755 * Cancel the last queued timeout
12757 this.cancel = function(){
12765 * Ext JS Library 1.1.1
12766 * Copyright(c) 2006-2007, Ext JS, LLC.
12768 * Originally Released Under LGPL - original licence link has changed is not relivant.
12771 * <script type="text/javascript">
12775 Roo.util.TaskRunner = function(interval){
12776 interval = interval || 10;
12777 var tasks = [], removeQueue = [];
12779 var running = false;
12781 var stopThread = function(){
12787 var startThread = function(){
12790 id = setInterval(runTasks, interval);
12794 var removeTask = function(task){
12795 removeQueue.push(task);
12801 var runTasks = function(){
12802 if(removeQueue.length > 0){
12803 for(var i = 0, len = removeQueue.length; i < len; i++){
12804 tasks.remove(removeQueue[i]);
12807 if(tasks.length < 1){
12812 var now = new Date().getTime();
12813 for(var i = 0, len = tasks.length; i < len; ++i){
12815 var itime = now - t.taskRunTime;
12816 if(t.interval <= itime){
12817 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12818 t.taskRunTime = now;
12819 if(rt === false || t.taskRunCount === t.repeat){
12824 if(t.duration && t.duration <= (now - t.taskStartTime)){
12831 * Queues a new task.
12832 * @param {Object} task
12834 this.start = function(task){
12836 task.taskStartTime = new Date().getTime();
12837 task.taskRunTime = 0;
12838 task.taskRunCount = 0;
12843 this.stop = function(task){
12848 this.stopAll = function(){
12850 for(var i = 0, len = tasks.length; i < len; i++){
12851 if(tasks[i].onStop){
12860 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12862 * Ext JS Library 1.1.1
12863 * Copyright(c) 2006-2007, Ext JS, LLC.
12865 * Originally Released Under LGPL - original licence link has changed is not relivant.
12868 * <script type="text/javascript">
12873 * @class Roo.util.MixedCollection
12874 * @extends Roo.util.Observable
12875 * A Collection class that maintains both numeric indexes and keys and exposes events.
12877 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12878 * collection (defaults to false)
12879 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12880 * and return the key value for that item. This is used when available to look up the key on items that
12881 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12882 * equivalent to providing an implementation for the {@link #getKey} method.
12884 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12892 * Fires when the collection is cleared.
12897 * Fires when an item is added to the collection.
12898 * @param {Number} index The index at which the item was added.
12899 * @param {Object} o The item added.
12900 * @param {String} key The key associated with the added item.
12905 * Fires when an item is replaced in the collection.
12906 * @param {String} key he key associated with the new added.
12907 * @param {Object} old The item being replaced.
12908 * @param {Object} new The new item.
12913 * Fires when an item is removed from the collection.
12914 * @param {Object} o The item being removed.
12915 * @param {String} key (optional) The key associated with the removed item.
12920 this.allowFunctions = allowFunctions === true;
12922 this.getKey = keyFn;
12924 Roo.util.MixedCollection.superclass.constructor.call(this);
12927 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12928 allowFunctions : false,
12931 * Adds an item to the collection.
12932 * @param {String} key The key to associate with the item
12933 * @param {Object} o The item to add.
12934 * @return {Object} The item added.
12936 add : function(key, o){
12937 if(arguments.length == 1){
12939 key = this.getKey(o);
12941 if(typeof key == "undefined" || key === null){
12943 this.items.push(o);
12944 this.keys.push(null);
12946 var old = this.map[key];
12948 return this.replace(key, o);
12951 this.items.push(o);
12953 this.keys.push(key);
12955 this.fireEvent("add", this.length-1, o, key);
12960 * MixedCollection has a generic way to fetch keys if you implement getKey.
12963 var mc = new Roo.util.MixedCollection();
12964 mc.add(someEl.dom.id, someEl);
12965 mc.add(otherEl.dom.id, otherEl);
12969 var mc = new Roo.util.MixedCollection();
12970 mc.getKey = function(el){
12976 // or via the constructor
12977 var mc = new Roo.util.MixedCollection(false, function(el){
12983 * @param o {Object} The item for which to find the key.
12984 * @return {Object} The key for the passed item.
12986 getKey : function(o){
12991 * Replaces an item in the collection.
12992 * @param {String} key The key associated with the item to replace, or the item to replace.
12993 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12994 * @return {Object} The new item.
12996 replace : function(key, o){
12997 if(arguments.length == 1){
12999 key = this.getKey(o);
13001 var old = this.item(key);
13002 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13003 return this.add(key, o);
13005 var index = this.indexOfKey(key);
13006 this.items[index] = o;
13008 this.fireEvent("replace", key, old, o);
13013 * Adds all elements of an Array or an Object to the collection.
13014 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13015 * an Array of values, each of which are added to the collection.
13017 addAll : function(objs){
13018 if(arguments.length > 1 || objs instanceof Array){
13019 var args = arguments.length > 1 ? arguments : objs;
13020 for(var i = 0, len = args.length; i < len; i++){
13024 for(var key in objs){
13025 if(this.allowFunctions || typeof objs[key] != "function"){
13026 this.add(key, objs[key]);
13033 * Executes the specified function once for every item in the collection, passing each
13034 * item as the first and only parameter. returning false from the function will stop the iteration.
13035 * @param {Function} fn The function to execute for each item.
13036 * @param {Object} scope (optional) The scope in which to execute the function.
13038 each : function(fn, scope){
13039 var items = [].concat(this.items); // each safe for removal
13040 for(var i = 0, len = items.length; i < len; i++){
13041 if(fn.call(scope || items[i], items[i], i, len) === false){
13048 * Executes the specified function once for every key in the collection, passing each
13049 * key, and its associated item as the first two parameters.
13050 * @param {Function} fn The function to execute for each item.
13051 * @param {Object} scope (optional) The scope in which to execute the function.
13053 eachKey : function(fn, scope){
13054 for(var i = 0, len = this.keys.length; i < len; i++){
13055 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13060 * Returns the first item in the collection which elicits a true return value from the
13061 * passed selection function.
13062 * @param {Function} fn The selection function to execute for each item.
13063 * @param {Object} scope (optional) The scope in which to execute the function.
13064 * @return {Object} The first item in the collection which returned true from the selection function.
13066 find : function(fn, scope){
13067 for(var i = 0, len = this.items.length; i < len; i++){
13068 if(fn.call(scope || window, this.items[i], this.keys[i])){
13069 return this.items[i];
13076 * Inserts an item at the specified index in the collection.
13077 * @param {Number} index The index to insert the item at.
13078 * @param {String} key The key to associate with the new item, or the item itself.
13079 * @param {Object} o (optional) If the second parameter was a key, the new item.
13080 * @return {Object} The item inserted.
13082 insert : function(index, key, o){
13083 if(arguments.length == 2){
13085 key = this.getKey(o);
13087 if(index >= this.length){
13088 return this.add(key, o);
13091 this.items.splice(index, 0, o);
13092 if(typeof key != "undefined" && key != null){
13095 this.keys.splice(index, 0, key);
13096 this.fireEvent("add", index, o, key);
13101 * Removed an item from the collection.
13102 * @param {Object} o The item to remove.
13103 * @return {Object} The item removed.
13105 remove : function(o){
13106 return this.removeAt(this.indexOf(o));
13110 * Remove an item from a specified index in the collection.
13111 * @param {Number} index The index within the collection of the item to remove.
13113 removeAt : function(index){
13114 if(index < this.length && index >= 0){
13116 var o = this.items[index];
13117 this.items.splice(index, 1);
13118 var key = this.keys[index];
13119 if(typeof key != "undefined"){
13120 delete this.map[key];
13122 this.keys.splice(index, 1);
13123 this.fireEvent("remove", o, key);
13128 * Removed an item associated with the passed key fom the collection.
13129 * @param {String} key The key of the item to remove.
13131 removeKey : function(key){
13132 return this.removeAt(this.indexOfKey(key));
13136 * Returns the number of items in the collection.
13137 * @return {Number} the number of items in the collection.
13139 getCount : function(){
13140 return this.length;
13144 * Returns index within the collection of the passed Object.
13145 * @param {Object} o The item to find the index of.
13146 * @return {Number} index of the item.
13148 indexOf : function(o){
13149 if(!this.items.indexOf){
13150 for(var i = 0, len = this.items.length; i < len; i++){
13151 if(this.items[i] == o) {
13157 return this.items.indexOf(o);
13162 * Returns index within the collection of the passed key.
13163 * @param {String} key The key to find the index of.
13164 * @return {Number} index of the key.
13166 indexOfKey : function(key){
13167 if(!this.keys.indexOf){
13168 for(var i = 0, len = this.keys.length; i < len; i++){
13169 if(this.keys[i] == key) {
13175 return this.keys.indexOf(key);
13180 * Returns the item associated with the passed key OR index. Key has priority over index.
13181 * @param {String/Number} key The key or index of the item.
13182 * @return {Object} The item associated with the passed key.
13184 item : function(key){
13185 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13186 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13190 * Returns the item at the specified index.
13191 * @param {Number} index The index of the item.
13194 itemAt : function(index){
13195 return this.items[index];
13199 * Returns the item associated with the passed key.
13200 * @param {String/Number} key The key of the item.
13201 * @return {Object} The item associated with the passed key.
13203 key : function(key){
13204 return this.map[key];
13208 * Returns true if the collection contains the passed Object as an item.
13209 * @param {Object} o The Object to look for in the collection.
13210 * @return {Boolean} True if the collection contains the Object as an item.
13212 contains : function(o){
13213 return this.indexOf(o) != -1;
13217 * Returns true if the collection contains the passed Object as a key.
13218 * @param {String} key The key to look for in the collection.
13219 * @return {Boolean} True if the collection contains the Object as a key.
13221 containsKey : function(key){
13222 return typeof this.map[key] != "undefined";
13226 * Removes all items from the collection.
13228 clear : function(){
13233 this.fireEvent("clear");
13237 * Returns the first item in the collection.
13238 * @return {Object} the first item in the collection..
13240 first : function(){
13241 return this.items[0];
13245 * Returns the last item in the collection.
13246 * @return {Object} the last item in the collection..
13249 return this.items[this.length-1];
13252 _sort : function(property, dir, fn){
13253 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13254 fn = fn || function(a, b){
13257 var c = [], k = this.keys, items = this.items;
13258 for(var i = 0, len = items.length; i < len; i++){
13259 c[c.length] = {key: k[i], value: items[i], index: i};
13261 c.sort(function(a, b){
13262 var v = fn(a[property], b[property]) * dsc;
13264 v = (a.index < b.index ? -1 : 1);
13268 for(var i = 0, len = c.length; i < len; i++){
13269 items[i] = c[i].value;
13272 this.fireEvent("sort", this);
13276 * Sorts this collection with the passed comparison function
13277 * @param {String} direction (optional) "ASC" or "DESC"
13278 * @param {Function} fn (optional) comparison function
13280 sort : function(dir, fn){
13281 this._sort("value", dir, fn);
13285 * Sorts this collection by keys
13286 * @param {String} direction (optional) "ASC" or "DESC"
13287 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13289 keySort : function(dir, fn){
13290 this._sort("key", dir, fn || function(a, b){
13291 return String(a).toUpperCase()-String(b).toUpperCase();
13296 * Returns a range of items in this collection
13297 * @param {Number} startIndex (optional) defaults to 0
13298 * @param {Number} endIndex (optional) default to the last item
13299 * @return {Array} An array of items
13301 getRange : function(start, end){
13302 var items = this.items;
13303 if(items.length < 1){
13306 start = start || 0;
13307 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13310 for(var i = start; i <= end; i++) {
13311 r[r.length] = items[i];
13314 for(var i = start; i >= end; i--) {
13315 r[r.length] = items[i];
13322 * Filter the <i>objects</i> in this collection by a specific property.
13323 * Returns a new collection that has been filtered.
13324 * @param {String} property A property on your objects
13325 * @param {String/RegExp} value Either string that the property values
13326 * should start with or a RegExp to test against the property
13327 * @return {MixedCollection} The new filtered collection
13329 filter : function(property, value){
13330 if(!value.exec){ // not a regex
13331 value = String(value);
13332 if(value.length == 0){
13333 return this.clone();
13335 value = new RegExp("^" + Roo.escapeRe(value), "i");
13337 return this.filterBy(function(o){
13338 return o && value.test(o[property]);
13343 * Filter by a function. * Returns a new collection that has been filtered.
13344 * The passed function will be called with each
13345 * object in the collection. If the function returns true, the value is included
13346 * otherwise it is filtered.
13347 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13348 * @param {Object} scope (optional) The scope of the function (defaults to this)
13349 * @return {MixedCollection} The new filtered collection
13351 filterBy : function(fn, scope){
13352 var r = new Roo.util.MixedCollection();
13353 r.getKey = this.getKey;
13354 var k = this.keys, it = this.items;
13355 for(var i = 0, len = it.length; i < len; i++){
13356 if(fn.call(scope||this, it[i], k[i])){
13357 r.add(k[i], it[i]);
13364 * Creates a duplicate of this collection
13365 * @return {MixedCollection}
13367 clone : function(){
13368 var r = new Roo.util.MixedCollection();
13369 var k = this.keys, it = this.items;
13370 for(var i = 0, len = it.length; i < len; i++){
13371 r.add(k[i], it[i]);
13373 r.getKey = this.getKey;
13378 * Returns the item associated with the passed key or index.
13380 * @param {String/Number} key The key or index of the item.
13381 * @return {Object} The item associated with the passed key.
13383 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13385 * Ext JS Library 1.1.1
13386 * Copyright(c) 2006-2007, Ext JS, LLC.
13388 * Originally Released Under LGPL - original licence link has changed is not relivant.
13391 * <script type="text/javascript">
13394 * @class Roo.util.JSON
13395 * Modified version of Douglas Crockford"s json.js that doesn"t
13396 * mess with the Object prototype
13397 * http://www.json.org/js.html
13400 Roo.util.JSON = new (function(){
13401 var useHasOwn = {}.hasOwnProperty ? true : false;
13403 // crashes Safari in some instances
13404 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13406 var pad = function(n) {
13407 return n < 10 ? "0" + n : n;
13420 var encodeString = function(s){
13421 if (/["\\\x00-\x1f]/.test(s)) {
13422 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13427 c = b.charCodeAt();
13429 Math.floor(c / 16).toString(16) +
13430 (c % 16).toString(16);
13433 return '"' + s + '"';
13436 var encodeArray = function(o){
13437 var a = ["["], b, i, l = o.length, v;
13438 for (i = 0; i < l; i += 1) {
13440 switch (typeof v) {
13449 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13457 var encodeDate = function(o){
13458 return '"' + o.getFullYear() + "-" +
13459 pad(o.getMonth() + 1) + "-" +
13460 pad(o.getDate()) + "T" +
13461 pad(o.getHours()) + ":" +
13462 pad(o.getMinutes()) + ":" +
13463 pad(o.getSeconds()) + '"';
13467 * Encodes an Object, Array or other value
13468 * @param {Mixed} o The variable to encode
13469 * @return {String} The JSON string
13471 this.encode = function(o)
13473 // should this be extended to fully wrap stringify..
13475 if(typeof o == "undefined" || o === null){
13477 }else if(o instanceof Array){
13478 return encodeArray(o);
13479 }else if(o instanceof Date){
13480 return encodeDate(o);
13481 }else if(typeof o == "string"){
13482 return encodeString(o);
13483 }else if(typeof o == "number"){
13484 return isFinite(o) ? String(o) : "null";
13485 }else if(typeof o == "boolean"){
13488 var a = ["{"], b, i, v;
13490 if(!useHasOwn || o.hasOwnProperty(i)) {
13492 switch (typeof v) {
13501 a.push(this.encode(i), ":",
13502 v === null ? "null" : this.encode(v));
13513 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13514 * @param {String} json The JSON string
13515 * @return {Object} The resulting object
13517 this.decode = function(json){
13519 return /** eval:var:json */ eval("(" + json + ')');
13523 * Shorthand for {@link Roo.util.JSON#encode}
13524 * @member Roo encode
13526 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13528 * Shorthand for {@link Roo.util.JSON#decode}
13529 * @member Roo decode
13531 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13534 * Ext JS Library 1.1.1
13535 * Copyright(c) 2006-2007, Ext JS, LLC.
13537 * Originally Released Under LGPL - original licence link has changed is not relivant.
13540 * <script type="text/javascript">
13544 * @class Roo.util.Format
13545 * Reusable data formatting functions
13548 Roo.util.Format = function(){
13549 var trimRe = /^\s+|\s+$/g;
13552 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13553 * @param {String} value The string to truncate
13554 * @param {Number} length The maximum length to allow before truncating
13555 * @return {String} The converted text
13557 ellipsis : function(value, len){
13558 if(value && value.length > len){
13559 return value.substr(0, len-3)+"...";
13565 * Checks a reference and converts it to empty string if it is undefined
13566 * @param {Mixed} value Reference to check
13567 * @return {Mixed} Empty string if converted, otherwise the original value
13569 undef : function(value){
13570 return typeof value != "undefined" ? value : "";
13574 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13575 * @param {String} value The string to encode
13576 * @return {String} The encoded text
13578 htmlEncode : function(value){
13579 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13583 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13584 * @param {String} value The string to decode
13585 * @return {String} The decoded text
13587 htmlDecode : function(value){
13588 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13592 * Trims any whitespace from either side of a string
13593 * @param {String} value The text to trim
13594 * @return {String} The trimmed text
13596 trim : function(value){
13597 return String(value).replace(trimRe, "");
13601 * Returns a substring from within an original string
13602 * @param {String} value The original text
13603 * @param {Number} start The start index of the substring
13604 * @param {Number} length The length of the substring
13605 * @return {String} The substring
13607 substr : function(value, start, length){
13608 return String(value).substr(start, length);
13612 * Converts a string to all lower case letters
13613 * @param {String} value The text to convert
13614 * @return {String} The converted text
13616 lowercase : function(value){
13617 return String(value).toLowerCase();
13621 * Converts a string to all upper case letters
13622 * @param {String} value The text to convert
13623 * @return {String} The converted text
13625 uppercase : function(value){
13626 return String(value).toUpperCase();
13630 * Converts the first character only of a string to upper case
13631 * @param {String} value The text to convert
13632 * @return {String} The converted text
13634 capitalize : function(value){
13635 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13639 call : function(value, fn){
13640 if(arguments.length > 2){
13641 var args = Array.prototype.slice.call(arguments, 2);
13642 args.unshift(value);
13644 return /** eval:var:value */ eval(fn).apply(window, args);
13646 /** eval:var:value */
13647 return /** eval:var:value */ eval(fn).call(window, value);
13653 * safer version of Math.toFixed..??/
13654 * @param {Number/String} value The numeric value to format
13655 * @param {Number/String} value Decimal places
13656 * @return {String} The formatted currency string
13658 toFixed : function(v, n)
13660 // why not use to fixed - precision is buggered???
13662 return Math.round(v-0);
13664 var fact = Math.pow(10,n+1);
13665 v = (Math.round((v-0)*fact))/fact;
13666 var z = (''+fact).substring(2);
13667 if (v == Math.floor(v)) {
13668 return Math.floor(v) + '.' + z;
13671 // now just padd decimals..
13672 var ps = String(v).split('.');
13673 var fd = (ps[1] + z);
13674 var r = fd.substring(0,n);
13675 var rm = fd.substring(n);
13677 return ps[0] + '.' + r;
13679 r*=1; // turn it into a number;
13681 if (String(r).length != n) {
13684 r = String(r).substring(1); // chop the end off.
13687 return ps[0] + '.' + r;
13692 * Format a number as US currency
13693 * @param {Number/String} value The numeric value to format
13694 * @return {String} The formatted currency string
13696 usMoney : function(v){
13697 return '$' + Roo.util.Format.number(v);
13702 * eventually this should probably emulate php's number_format
13703 * @param {Number/String} value The numeric value to format
13704 * @param {Number} decimals number of decimal places
13705 * @return {String} The formatted currency string
13707 number : function(v,decimals)
13709 // multiply and round.
13710 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13711 var mul = Math.pow(10, decimals);
13712 var zero = String(mul).substring(1);
13713 v = (Math.round((v-0)*mul))/mul;
13715 // if it's '0' number.. then
13717 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13719 var ps = v.split('.');
13723 var r = /(\d+)(\d{3})/;
13725 while (r.test(whole)) {
13726 whole = whole.replace(r, '$1' + ',' + '$2');
13732 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13733 // does not have decimals
13734 (decimals ? ('.' + zero) : '');
13737 return whole + sub ;
13741 * Parse a value into a formatted date using the specified format pattern.
13742 * @param {Mixed} value The value to format
13743 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13744 * @return {String} The formatted date string
13746 date : function(v, format){
13750 if(!(v instanceof Date)){
13751 v = new Date(Date.parse(v));
13753 return v.dateFormat(format || Roo.util.Format.defaults.date);
13757 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13758 * @param {String} format Any valid date format string
13759 * @return {Function} The date formatting function
13761 dateRenderer : function(format){
13762 return function(v){
13763 return Roo.util.Format.date(v, format);
13768 stripTagsRE : /<\/?[^>]+>/gi,
13771 * Strips all HTML tags
13772 * @param {Mixed} value The text from which to strip tags
13773 * @return {String} The stripped text
13775 stripTags : function(v){
13776 return !v ? v : String(v).replace(this.stripTagsRE, "");
13780 Roo.util.Format.defaults = {
13784 * Ext JS Library 1.1.1
13785 * Copyright(c) 2006-2007, Ext JS, LLC.
13787 * Originally Released Under LGPL - original licence link has changed is not relivant.
13790 * <script type="text/javascript">
13797 * @class Roo.MasterTemplate
13798 * @extends Roo.Template
13799 * Provides a template that can have child templates. The syntax is:
13801 var t = new Roo.MasterTemplate(
13802 '<select name="{name}">',
13803 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13806 t.add('options', {value: 'foo', text: 'bar'});
13807 // or you can add multiple child elements in one shot
13808 t.addAll('options', [
13809 {value: 'foo', text: 'bar'},
13810 {value: 'foo2', text: 'bar2'},
13811 {value: 'foo3', text: 'bar3'}
13813 // then append, applying the master template values
13814 t.append('my-form', {name: 'my-select'});
13816 * A name attribute for the child template is not required if you have only one child
13817 * template or you want to refer to them by index.
13819 Roo.MasterTemplate = function(){
13820 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13821 this.originalHtml = this.html;
13823 var m, re = this.subTemplateRe;
13826 while(m = re.exec(this.html)){
13827 var name = m[1], content = m[2];
13832 tpl : new Roo.Template(content)
13835 st[name] = st[subIndex];
13837 st[subIndex].tpl.compile();
13838 st[subIndex].tpl.call = this.call.createDelegate(this);
13841 this.subCount = subIndex;
13844 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13846 * The regular expression used to match sub templates
13850 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13853 * Applies the passed values to a child template.
13854 * @param {String/Number} name (optional) The name or index of the child template
13855 * @param {Array/Object} values The values to be applied to the template
13856 * @return {MasterTemplate} this
13858 add : function(name, values){
13859 if(arguments.length == 1){
13860 values = arguments[0];
13863 var s = this.subs[name];
13864 s.buffer[s.buffer.length] = s.tpl.apply(values);
13869 * Applies all the passed values to a child template.
13870 * @param {String/Number} name (optional) The name or index of the child template
13871 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13872 * @param {Boolean} reset (optional) True to reset the template first
13873 * @return {MasterTemplate} this
13875 fill : function(name, values, reset){
13877 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13885 for(var i = 0, len = values.length; i < len; i++){
13886 this.add(name, values[i]);
13892 * Resets the template for reuse
13893 * @return {MasterTemplate} this
13895 reset : function(){
13897 for(var i = 0; i < this.subCount; i++){
13903 applyTemplate : function(values){
13905 var replaceIndex = -1;
13906 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13907 return s[++replaceIndex].buffer.join("");
13909 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13912 apply : function(){
13913 return this.applyTemplate.apply(this, arguments);
13916 compile : function(){return this;}
13920 * Alias for fill().
13923 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13925 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13926 * var tpl = Roo.MasterTemplate.from('element-id');
13927 * @param {String/HTMLElement} el
13928 * @param {Object} config
13931 Roo.MasterTemplate.from = function(el, config){
13932 el = Roo.getDom(el);
13933 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13936 * Ext JS Library 1.1.1
13937 * Copyright(c) 2006-2007, Ext JS, LLC.
13939 * Originally Released Under LGPL - original licence link has changed is not relivant.
13942 * <script type="text/javascript">
13947 * @class Roo.util.CSS
13948 * Utility class for manipulating CSS rules
13951 Roo.util.CSS = function(){
13953 var doc = document;
13955 var camelRe = /(-[a-z])/gi;
13956 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13960 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13961 * tag and appended to the HEAD of the document.
13962 * @param {String|Object} cssText The text containing the css rules
13963 * @param {String} id An id to add to the stylesheet for later removal
13964 * @return {StyleSheet}
13966 createStyleSheet : function(cssText, id){
13968 var head = doc.getElementsByTagName("head")[0];
13969 var nrules = doc.createElement("style");
13970 nrules.setAttribute("type", "text/css");
13972 nrules.setAttribute("id", id);
13974 if (typeof(cssText) != 'string') {
13975 // support object maps..
13976 // not sure if this a good idea..
13977 // perhaps it should be merged with the general css handling
13978 // and handle js style props.
13979 var cssTextNew = [];
13980 for(var n in cssText) {
13982 for(var k in cssText[n]) {
13983 citems.push( k + ' : ' +cssText[n][k] + ';' );
13985 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13988 cssText = cssTextNew.join("\n");
13994 head.appendChild(nrules);
13995 ss = nrules.styleSheet;
13996 ss.cssText = cssText;
13999 nrules.appendChild(doc.createTextNode(cssText));
14001 nrules.cssText = cssText;
14003 head.appendChild(nrules);
14004 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14006 this.cacheStyleSheet(ss);
14011 * Removes a style or link tag by id
14012 * @param {String} id The id of the tag
14014 removeStyleSheet : function(id){
14015 var existing = doc.getElementById(id);
14017 existing.parentNode.removeChild(existing);
14022 * Dynamically swaps an existing stylesheet reference for a new one
14023 * @param {String} id The id of an existing link tag to remove
14024 * @param {String} url The href of the new stylesheet to include
14026 swapStyleSheet : function(id, url){
14027 this.removeStyleSheet(id);
14028 var ss = doc.createElement("link");
14029 ss.setAttribute("rel", "stylesheet");
14030 ss.setAttribute("type", "text/css");
14031 ss.setAttribute("id", id);
14032 ss.setAttribute("href", url);
14033 doc.getElementsByTagName("head")[0].appendChild(ss);
14037 * Refresh the rule cache if you have dynamically added stylesheets
14038 * @return {Object} An object (hash) of rules indexed by selector
14040 refreshCache : function(){
14041 return this.getRules(true);
14045 cacheStyleSheet : function(stylesheet){
14049 try{// try catch for cross domain access issue
14050 var ssRules = stylesheet.cssRules || stylesheet.rules;
14051 for(var j = ssRules.length-1; j >= 0; --j){
14052 rules[ssRules[j].selectorText] = ssRules[j];
14058 * Gets all css rules for the document
14059 * @param {Boolean} refreshCache true to refresh the internal cache
14060 * @return {Object} An object (hash) of rules indexed by selector
14062 getRules : function(refreshCache){
14063 if(rules == null || refreshCache){
14065 var ds = doc.styleSheets;
14066 for(var i =0, len = ds.length; i < len; i++){
14068 this.cacheStyleSheet(ds[i]);
14076 * Gets an an individual CSS rule by selector(s)
14077 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14078 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14079 * @return {CSSRule} The CSS rule or null if one is not found
14081 getRule : function(selector, refreshCache){
14082 var rs = this.getRules(refreshCache);
14083 if(!(selector instanceof Array)){
14084 return rs[selector];
14086 for(var i = 0; i < selector.length; i++){
14087 if(rs[selector[i]]){
14088 return rs[selector[i]];
14096 * Updates a rule property
14097 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14098 * @param {String} property The css property
14099 * @param {String} value The new value for the property
14100 * @return {Boolean} true If a rule was found and updated
14102 updateRule : function(selector, property, value){
14103 if(!(selector instanceof Array)){
14104 var rule = this.getRule(selector);
14106 rule.style[property.replace(camelRe, camelFn)] = value;
14110 for(var i = 0; i < selector.length; i++){
14111 if(this.updateRule(selector[i], property, value)){
14121 * Ext JS Library 1.1.1
14122 * Copyright(c) 2006-2007, Ext JS, LLC.
14124 * Originally Released Under LGPL - original licence link has changed is not relivant.
14127 * <script type="text/javascript">
14133 * @class Roo.util.ClickRepeater
14134 * @extends Roo.util.Observable
14136 * A wrapper class which can be applied to any element. Fires a "click" event while the
14137 * mouse is pressed. The interval between firings may be specified in the config but
14138 * defaults to 10 milliseconds.
14140 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14142 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14143 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14144 * Similar to an autorepeat key delay.
14145 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14146 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14147 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14148 * "interval" and "delay" are ignored. "immediate" is honored.
14149 * @cfg {Boolean} preventDefault True to prevent the default click event
14150 * @cfg {Boolean} stopDefault True to stop the default click event
14153 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14154 * 2007-02-02 jvs Renamed to ClickRepeater
14155 * 2007-02-03 jvs Modifications for FF Mac and Safari
14158 * @param {String/HTMLElement/Element} el The element to listen on
14159 * @param {Object} config
14161 Roo.util.ClickRepeater = function(el, config)
14163 this.el = Roo.get(el);
14164 this.el.unselectable();
14166 Roo.apply(this, config);
14171 * Fires when the mouse button is depressed.
14172 * @param {Roo.util.ClickRepeater} this
14174 "mousedown" : true,
14177 * Fires on a specified interval during the time the element is pressed.
14178 * @param {Roo.util.ClickRepeater} this
14183 * Fires when the mouse key is released.
14184 * @param {Roo.util.ClickRepeater} this
14189 this.el.on("mousedown", this.handleMouseDown, this);
14190 if(this.preventDefault || this.stopDefault){
14191 this.el.on("click", function(e){
14192 if(this.preventDefault){
14193 e.preventDefault();
14195 if(this.stopDefault){
14201 // allow inline handler
14203 this.on("click", this.handler, this.scope || this);
14206 Roo.util.ClickRepeater.superclass.constructor.call(this);
14209 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14212 preventDefault : true,
14213 stopDefault : false,
14217 handleMouseDown : function(){
14218 clearTimeout(this.timer);
14220 if(this.pressClass){
14221 this.el.addClass(this.pressClass);
14223 this.mousedownTime = new Date();
14225 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14226 this.el.on("mouseout", this.handleMouseOut, this);
14228 this.fireEvent("mousedown", this);
14229 this.fireEvent("click", this);
14231 this.timer = this.click.defer(this.delay || this.interval, this);
14235 click : function(){
14236 this.fireEvent("click", this);
14237 this.timer = this.click.defer(this.getInterval(), this);
14241 getInterval: function(){
14242 if(!this.accelerate){
14243 return this.interval;
14245 var pressTime = this.mousedownTime.getElapsed();
14246 if(pressTime < 500){
14248 }else if(pressTime < 1700){
14250 }else if(pressTime < 2600){
14252 }else if(pressTime < 3500){
14254 }else if(pressTime < 4400){
14256 }else if(pressTime < 5300){
14258 }else if(pressTime < 6200){
14266 handleMouseOut : function(){
14267 clearTimeout(this.timer);
14268 if(this.pressClass){
14269 this.el.removeClass(this.pressClass);
14271 this.el.on("mouseover", this.handleMouseReturn, this);
14275 handleMouseReturn : function(){
14276 this.el.un("mouseover", this.handleMouseReturn);
14277 if(this.pressClass){
14278 this.el.addClass(this.pressClass);
14284 handleMouseUp : function(){
14285 clearTimeout(this.timer);
14286 this.el.un("mouseover", this.handleMouseReturn);
14287 this.el.un("mouseout", this.handleMouseOut);
14288 Roo.get(document).un("mouseup", this.handleMouseUp);
14289 this.el.removeClass(this.pressClass);
14290 this.fireEvent("mouseup", this);
14294 * Ext JS Library 1.1.1
14295 * Copyright(c) 2006-2007, Ext JS, LLC.
14297 * Originally Released Under LGPL - original licence link has changed is not relivant.
14300 * <script type="text/javascript">
14305 * @class Roo.KeyNav
14306 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14307 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14308 * way to implement custom navigation schemes for any UI component.</p>
14309 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14310 * pageUp, pageDown, del, home, end. Usage:</p>
14312 var nav = new Roo.KeyNav("my-element", {
14313 "left" : function(e){
14314 this.moveLeft(e.ctrlKey);
14316 "right" : function(e){
14317 this.moveRight(e.ctrlKey);
14319 "enter" : function(e){
14326 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14327 * @param {Object} config The config
14329 Roo.KeyNav = function(el, config){
14330 this.el = Roo.get(el);
14331 Roo.apply(this, config);
14332 if(!this.disabled){
14333 this.disabled = true;
14338 Roo.KeyNav.prototype = {
14340 * @cfg {Boolean} disabled
14341 * True to disable this KeyNav instance (defaults to false)
14345 * @cfg {String} defaultEventAction
14346 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14347 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14348 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14350 defaultEventAction: "stopEvent",
14352 * @cfg {Boolean} forceKeyDown
14353 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14354 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14355 * handle keydown instead of keypress.
14357 forceKeyDown : false,
14360 prepareEvent : function(e){
14361 var k = e.getKey();
14362 var h = this.keyToHandler[k];
14363 //if(h && this[h]){
14364 // e.stopPropagation();
14366 if(Roo.isSafari && h && k >= 37 && k <= 40){
14372 relay : function(e){
14373 var k = e.getKey();
14374 var h = this.keyToHandler[k];
14376 if(this.doRelay(e, this[h], h) !== true){
14377 e[this.defaultEventAction]();
14383 doRelay : function(e, h, hname){
14384 return h.call(this.scope || this, e);
14387 // possible handlers
14401 // quick lookup hash
14418 * Enable this KeyNav
14420 enable: function(){
14422 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14423 // the EventObject will normalize Safari automatically
14424 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14425 this.el.on("keydown", this.relay, this);
14427 this.el.on("keydown", this.prepareEvent, this);
14428 this.el.on("keypress", this.relay, this);
14430 this.disabled = false;
14435 * Disable this KeyNav
14437 disable: function(){
14438 if(!this.disabled){
14439 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14440 this.el.un("keydown", this.relay);
14442 this.el.un("keydown", this.prepareEvent);
14443 this.el.un("keypress", this.relay);
14445 this.disabled = true;
14450 * Ext JS Library 1.1.1
14451 * Copyright(c) 2006-2007, Ext JS, LLC.
14453 * Originally Released Under LGPL - original licence link has changed is not relivant.
14456 * <script type="text/javascript">
14461 * @class Roo.KeyMap
14462 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14463 * The constructor accepts the same config object as defined by {@link #addBinding}.
14464 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14465 * combination it will call the function with this signature (if the match is a multi-key
14466 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14467 * A KeyMap can also handle a string representation of keys.<br />
14470 // map one key by key code
14471 var map = new Roo.KeyMap("my-element", {
14472 key: 13, // or Roo.EventObject.ENTER
14477 // map multiple keys to one action by string
14478 var map = new Roo.KeyMap("my-element", {
14484 // map multiple keys to multiple actions by strings and array of codes
14485 var map = new Roo.KeyMap("my-element", [
14488 fn: function(){ alert("Return was pressed"); }
14491 fn: function(){ alert('a, b or c was pressed'); }
14496 fn: function(){ alert('Control + shift + tab was pressed.'); }
14500 * <b>Note: A KeyMap starts enabled</b>
14502 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14503 * @param {Object} config The config (see {@link #addBinding})
14504 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14506 Roo.KeyMap = function(el, config, eventName){
14507 this.el = Roo.get(el);
14508 this.eventName = eventName || "keydown";
14509 this.bindings = [];
14511 this.addBinding(config);
14516 Roo.KeyMap.prototype = {
14518 * True to stop the event from bubbling and prevent the default browser action if the
14519 * key was handled by the KeyMap (defaults to false)
14525 * Add a new binding to this KeyMap. The following config object properties are supported:
14527 Property Type Description
14528 ---------- --------------- ----------------------------------------------------------------------
14529 key String/Array A single keycode or an array of keycodes to handle
14530 shift Boolean True to handle key only when shift is pressed (defaults to false)
14531 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14532 alt Boolean True to handle key only when alt is pressed (defaults to false)
14533 fn Function The function to call when KeyMap finds the expected key combination
14534 scope Object The scope of the callback function
14540 var map = new Roo.KeyMap(document, {
14541 key: Roo.EventObject.ENTER,
14546 //Add a new binding to the existing KeyMap later
14554 * @param {Object/Array} config A single KeyMap config or an array of configs
14556 addBinding : function(config){
14557 if(config instanceof Array){
14558 for(var i = 0, len = config.length; i < len; i++){
14559 this.addBinding(config[i]);
14563 var keyCode = config.key,
14564 shift = config.shift,
14565 ctrl = config.ctrl,
14568 scope = config.scope;
14569 if(typeof keyCode == "string"){
14571 var keyString = keyCode.toUpperCase();
14572 for(var j = 0, len = keyString.length; j < len; j++){
14573 ks.push(keyString.charCodeAt(j));
14577 var keyArray = keyCode instanceof Array;
14578 var handler = function(e){
14579 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14580 var k = e.getKey();
14582 for(var i = 0, len = keyCode.length; i < len; i++){
14583 if(keyCode[i] == k){
14584 if(this.stopEvent){
14587 fn.call(scope || window, k, e);
14593 if(this.stopEvent){
14596 fn.call(scope || window, k, e);
14601 this.bindings.push(handler);
14605 * Shorthand for adding a single key listener
14606 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14607 * following options:
14608 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14609 * @param {Function} fn The function to call
14610 * @param {Object} scope (optional) The scope of the function
14612 on : function(key, fn, scope){
14613 var keyCode, shift, ctrl, alt;
14614 if(typeof key == "object" && !(key instanceof Array)){
14633 handleKeyDown : function(e){
14634 if(this.enabled){ //just in case
14635 var b = this.bindings;
14636 for(var i = 0, len = b.length; i < len; i++){
14637 b[i].call(this, e);
14643 * Returns true if this KeyMap is enabled
14644 * @return {Boolean}
14646 isEnabled : function(){
14647 return this.enabled;
14651 * Enables this KeyMap
14653 enable: function(){
14655 this.el.on(this.eventName, this.handleKeyDown, this);
14656 this.enabled = true;
14661 * Disable this KeyMap
14663 disable: function(){
14665 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14666 this.enabled = false;
14671 * Ext JS Library 1.1.1
14672 * Copyright(c) 2006-2007, Ext JS, LLC.
14674 * Originally Released Under LGPL - original licence link has changed is not relivant.
14677 * <script type="text/javascript">
14682 * @class Roo.util.TextMetrics
14683 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14684 * wide, in pixels, a given block of text will be.
14687 Roo.util.TextMetrics = function(){
14691 * Measures the size of the specified text
14692 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14693 * that can affect the size of the rendered text
14694 * @param {String} text The text to measure
14695 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14696 * in order to accurately measure the text height
14697 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14699 measure : function(el, text, fixedWidth){
14701 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14704 shared.setFixedWidth(fixedWidth || 'auto');
14705 return shared.getSize(text);
14709 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14710 * the overhead of multiple calls to initialize the style properties on each measurement.
14711 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14712 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14713 * in order to accurately measure the text height
14714 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14716 createInstance : function(el, fixedWidth){
14717 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14724 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14725 var ml = new Roo.Element(document.createElement('div'));
14726 document.body.appendChild(ml.dom);
14727 ml.position('absolute');
14728 ml.setLeftTop(-1000, -1000);
14732 ml.setWidth(fixedWidth);
14737 * Returns the size of the specified text based on the internal element's style and width properties
14738 * @memberOf Roo.util.TextMetrics.Instance#
14739 * @param {String} text The text to measure
14740 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14742 getSize : function(text){
14744 var s = ml.getSize();
14750 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14751 * that can affect the size of the rendered text
14752 * @memberOf Roo.util.TextMetrics.Instance#
14753 * @param {String/HTMLElement} el The element, dom node or id
14755 bind : function(el){
14757 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14762 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14763 * to set a fixed width in order to accurately measure the text height.
14764 * @memberOf Roo.util.TextMetrics.Instance#
14765 * @param {Number} width The width to set on the element
14767 setFixedWidth : function(width){
14768 ml.setWidth(width);
14772 * Returns the measured width of the specified text
14773 * @memberOf Roo.util.TextMetrics.Instance#
14774 * @param {String} text The text to measure
14775 * @return {Number} width The width in pixels
14777 getWidth : function(text){
14778 ml.dom.style.width = 'auto';
14779 return this.getSize(text).width;
14783 * Returns the measured height of the specified text. For multiline text, be sure to call
14784 * {@link #setFixedWidth} if necessary.
14785 * @memberOf Roo.util.TextMetrics.Instance#
14786 * @param {String} text The text to measure
14787 * @return {Number} height The height in pixels
14789 getHeight : function(text){
14790 return this.getSize(text).height;
14794 instance.bind(bindTo);
14799 // backwards compat
14800 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14802 * Ext JS Library 1.1.1
14803 * Copyright(c) 2006-2007, Ext JS, LLC.
14805 * Originally Released Under LGPL - original licence link has changed is not relivant.
14808 * <script type="text/javascript">
14812 * @class Roo.state.Provider
14813 * Abstract base class for state provider implementations. This class provides methods
14814 * for encoding and decoding <b>typed</b> variables including dates and defines the
14815 * Provider interface.
14817 Roo.state.Provider = function(){
14819 * @event statechange
14820 * Fires when a state change occurs.
14821 * @param {Provider} this This state provider
14822 * @param {String} key The state key which was changed
14823 * @param {String} value The encoded value for the state
14826 "statechange": true
14829 Roo.state.Provider.superclass.constructor.call(this);
14831 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14833 * Returns the current value for a key
14834 * @param {String} name The key name
14835 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14836 * @return {Mixed} The state data
14838 get : function(name, defaultValue){
14839 return typeof this.state[name] == "undefined" ?
14840 defaultValue : this.state[name];
14844 * Clears a value from the state
14845 * @param {String} name The key name
14847 clear : function(name){
14848 delete this.state[name];
14849 this.fireEvent("statechange", this, name, null);
14853 * Sets the value for a key
14854 * @param {String} name The key name
14855 * @param {Mixed} value The value to set
14857 set : function(name, value){
14858 this.state[name] = value;
14859 this.fireEvent("statechange", this, name, value);
14863 * Decodes a string previously encoded with {@link #encodeValue}.
14864 * @param {String} value The value to decode
14865 * @return {Mixed} The decoded value
14867 decodeValue : function(cookie){
14868 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14869 var matches = re.exec(unescape(cookie));
14870 if(!matches || !matches[1]) {
14871 return; // non state cookie
14873 var type = matches[1];
14874 var v = matches[2];
14877 return parseFloat(v);
14879 return new Date(Date.parse(v));
14884 var values = v.split("^");
14885 for(var i = 0, len = values.length; i < len; i++){
14886 all.push(this.decodeValue(values[i]));
14891 var values = v.split("^");
14892 for(var i = 0, len = values.length; i < len; i++){
14893 var kv = values[i].split("=");
14894 all[kv[0]] = this.decodeValue(kv[1]);
14903 * Encodes a value including type information. Decode with {@link #decodeValue}.
14904 * @param {Mixed} value The value to encode
14905 * @return {String} The encoded value
14907 encodeValue : function(v){
14909 if(typeof v == "number"){
14911 }else if(typeof v == "boolean"){
14912 enc = "b:" + (v ? "1" : "0");
14913 }else if(v instanceof Date){
14914 enc = "d:" + v.toGMTString();
14915 }else if(v instanceof Array){
14917 for(var i = 0, len = v.length; i < len; i++){
14918 flat += this.encodeValue(v[i]);
14924 }else if(typeof v == "object"){
14927 if(typeof v[key] != "function"){
14928 flat += key + "=" + this.encodeValue(v[key]) + "^";
14931 enc = "o:" + flat.substring(0, flat.length-1);
14935 return escape(enc);
14941 * Ext JS Library 1.1.1
14942 * Copyright(c) 2006-2007, Ext JS, LLC.
14944 * Originally Released Under LGPL - original licence link has changed is not relivant.
14947 * <script type="text/javascript">
14950 * @class Roo.state.Manager
14951 * This is the global state manager. By default all components that are "state aware" check this class
14952 * for state information if you don't pass them a custom state provider. In order for this class
14953 * to be useful, it must be initialized with a provider when your application initializes.
14955 // in your initialization function
14957 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14959 // supposed you have a {@link Roo.BorderLayout}
14960 var layout = new Roo.BorderLayout(...);
14961 layout.restoreState();
14962 // or a {Roo.BasicDialog}
14963 var dialog = new Roo.BasicDialog(...);
14964 dialog.restoreState();
14968 Roo.state.Manager = function(){
14969 var provider = new Roo.state.Provider();
14973 * Configures the default state provider for your application
14974 * @param {Provider} stateProvider The state provider to set
14976 setProvider : function(stateProvider){
14977 provider = stateProvider;
14981 * Returns the current value for a key
14982 * @param {String} name The key name
14983 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14984 * @return {Mixed} The state data
14986 get : function(key, defaultValue){
14987 return provider.get(key, defaultValue);
14991 * Sets the value for a key
14992 * @param {String} name The key name
14993 * @param {Mixed} value The state data
14995 set : function(key, value){
14996 provider.set(key, value);
15000 * Clears a value from the state
15001 * @param {String} name The key name
15003 clear : function(key){
15004 provider.clear(key);
15008 * Gets the currently configured state provider
15009 * @return {Provider} The state provider
15011 getProvider : function(){
15018 * Ext JS Library 1.1.1
15019 * Copyright(c) 2006-2007, Ext JS, LLC.
15021 * Originally Released Under LGPL - original licence link has changed is not relivant.
15024 * <script type="text/javascript">
15027 * @class Roo.state.CookieProvider
15028 * @extends Roo.state.Provider
15029 * The default Provider implementation which saves state via cookies.
15032 var cp = new Roo.state.CookieProvider({
15034 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15035 domain: "roojs.com"
15037 Roo.state.Manager.setProvider(cp);
15039 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15040 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15041 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15042 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15043 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15044 * domain the page is running on including the 'www' like 'www.roojs.com')
15045 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15047 * Create a new CookieProvider
15048 * @param {Object} config The configuration object
15050 Roo.state.CookieProvider = function(config){
15051 Roo.state.CookieProvider.superclass.constructor.call(this);
15053 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15054 this.domain = null;
15055 this.secure = false;
15056 Roo.apply(this, config);
15057 this.state = this.readCookies();
15060 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15062 set : function(name, value){
15063 if(typeof value == "undefined" || value === null){
15067 this.setCookie(name, value);
15068 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15072 clear : function(name){
15073 this.clearCookie(name);
15074 Roo.state.CookieProvider.superclass.clear.call(this, name);
15078 readCookies : function(){
15080 var c = document.cookie + ";";
15081 var re = /\s?(.*?)=(.*?);/g;
15083 while((matches = re.exec(c)) != null){
15084 var name = matches[1];
15085 var value = matches[2];
15086 if(name && name.substring(0,3) == "ys-"){
15087 cookies[name.substr(3)] = this.decodeValue(value);
15094 setCookie : function(name, value){
15095 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15096 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15097 ((this.path == null) ? "" : ("; path=" + this.path)) +
15098 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15099 ((this.secure == true) ? "; secure" : "");
15103 clearCookie : function(name){
15104 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15105 ((this.path == null) ? "" : ("; path=" + this.path)) +
15106 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15107 ((this.secure == true) ? "; secure" : "");
15111 * Ext JS Library 1.1.1
15112 * Copyright(c) 2006-2007, Ext JS, LLC.
15114 * Originally Released Under LGPL - original licence link has changed is not relivant.
15117 * <script type="text/javascript">
15122 * @class Roo.ComponentMgr
15123 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15126 Roo.ComponentMgr = function(){
15127 var all = new Roo.util.MixedCollection();
15131 * Registers a component.
15132 * @param {Roo.Component} c The component
15134 register : function(c){
15139 * Unregisters a component.
15140 * @param {Roo.Component} c The component
15142 unregister : function(c){
15147 * Returns a component by id
15148 * @param {String} id The component id
15150 get : function(id){
15151 return all.get(id);
15155 * Registers a function that will be called when a specified component is added to ComponentMgr
15156 * @param {String} id The component id
15157 * @param {Funtction} fn The callback function
15158 * @param {Object} scope The scope of the callback
15160 onAvailable : function(id, fn, scope){
15161 all.on("add", function(index, o){
15163 fn.call(scope || o, o);
15164 all.un("add", fn, scope);
15171 * Ext JS Library 1.1.1
15172 * Copyright(c) 2006-2007, Ext JS, LLC.
15174 * Originally Released Under LGPL - original licence link has changed is not relivant.
15177 * <script type="text/javascript">
15181 * @class Roo.Component
15182 * @extends Roo.util.Observable
15183 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15184 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15185 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15186 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15187 * All visual components (widgets) that require rendering into a layout should subclass Component.
15189 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15190 * 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
15191 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15193 Roo.Component = function(config){
15194 config = config || {};
15195 if(config.tagName || config.dom || typeof config == "string"){ // element object
15196 config = {el: config, id: config.id || config};
15198 this.initialConfig = config;
15200 Roo.apply(this, config);
15204 * Fires after the component is disabled.
15205 * @param {Roo.Component} this
15210 * Fires after the component is enabled.
15211 * @param {Roo.Component} this
15215 * @event beforeshow
15216 * Fires before the component is shown. Return false to stop the show.
15217 * @param {Roo.Component} this
15222 * Fires after the component is shown.
15223 * @param {Roo.Component} this
15227 * @event beforehide
15228 * Fires before the component is hidden. Return false to stop the hide.
15229 * @param {Roo.Component} this
15234 * Fires after the component is hidden.
15235 * @param {Roo.Component} this
15239 * @event beforerender
15240 * Fires before the component is rendered. Return false to stop the render.
15241 * @param {Roo.Component} this
15243 beforerender : true,
15246 * Fires after the component is rendered.
15247 * @param {Roo.Component} this
15251 * @event beforedestroy
15252 * Fires before the component is destroyed. Return false to stop the destroy.
15253 * @param {Roo.Component} this
15255 beforedestroy : true,
15258 * Fires after the component is destroyed.
15259 * @param {Roo.Component} this
15264 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15266 Roo.ComponentMgr.register(this);
15267 Roo.Component.superclass.constructor.call(this);
15268 this.initComponent();
15269 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15270 this.render(this.renderTo);
15271 delete this.renderTo;
15276 Roo.Component.AUTO_ID = 1000;
15278 Roo.extend(Roo.Component, Roo.util.Observable, {
15280 * @scope Roo.Component.prototype
15282 * true if this component is hidden. Read-only.
15287 * true if this component is disabled. Read-only.
15292 * true if this component has been rendered. Read-only.
15296 /** @cfg {String} disableClass
15297 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15299 disabledClass : "x-item-disabled",
15300 /** @cfg {Boolean} allowDomMove
15301 * Whether the component can move the Dom node when rendering (defaults to true).
15303 allowDomMove : true,
15304 /** @cfg {String} hideMode (display|visibility)
15305 * How this component should hidden. Supported values are
15306 * "visibility" (css visibility), "offsets" (negative offset position) and
15307 * "display" (css display) - defaults to "display".
15309 hideMode: 'display',
15312 ctype : "Roo.Component",
15315 * @cfg {String} actionMode
15316 * which property holds the element that used for hide() / show() / disable() / enable()
15322 getActionEl : function(){
15323 return this[this.actionMode];
15326 initComponent : Roo.emptyFn,
15328 * If this is a lazy rendering component, render it to its container element.
15329 * @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.
15331 render : function(container, position){
15332 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15333 if(!container && this.el){
15334 this.el = Roo.get(this.el);
15335 container = this.el.dom.parentNode;
15336 this.allowDomMove = false;
15338 this.container = Roo.get(container);
15339 this.rendered = true;
15340 if(position !== undefined){
15341 if(typeof position == 'number'){
15342 position = this.container.dom.childNodes[position];
15344 position = Roo.getDom(position);
15347 this.onRender(this.container, position || null);
15349 this.el.addClass(this.cls);
15353 this.el.applyStyles(this.style);
15356 this.fireEvent("render", this);
15357 this.afterRender(this.container);
15369 // default function is not really useful
15370 onRender : function(ct, position){
15372 this.el = Roo.get(this.el);
15373 if(this.allowDomMove !== false){
15374 ct.dom.insertBefore(this.el.dom, position);
15380 getAutoCreate : function(){
15381 var cfg = typeof this.autoCreate == "object" ?
15382 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15383 if(this.id && !cfg.id){
15390 afterRender : Roo.emptyFn,
15393 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15394 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15396 destroy : function(){
15397 if(this.fireEvent("beforedestroy", this) !== false){
15398 this.purgeListeners();
15399 this.beforeDestroy();
15401 this.el.removeAllListeners();
15403 if(this.actionMode == "container"){
15404 this.container.remove();
15408 Roo.ComponentMgr.unregister(this);
15409 this.fireEvent("destroy", this);
15414 beforeDestroy : function(){
15419 onDestroy : function(){
15424 * Returns the underlying {@link Roo.Element}.
15425 * @return {Roo.Element} The element
15427 getEl : function(){
15432 * Returns the id of this component.
15435 getId : function(){
15440 * Try to focus this component.
15441 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15442 * @return {Roo.Component} this
15444 focus : function(selectText){
15447 if(selectText === true){
15448 this.el.dom.select();
15463 * Disable this component.
15464 * @return {Roo.Component} this
15466 disable : function(){
15470 this.disabled = true;
15471 this.fireEvent("disable", this);
15476 onDisable : function(){
15477 this.getActionEl().addClass(this.disabledClass);
15478 this.el.dom.disabled = true;
15482 * Enable this component.
15483 * @return {Roo.Component} this
15485 enable : function(){
15489 this.disabled = false;
15490 this.fireEvent("enable", this);
15495 onEnable : function(){
15496 this.getActionEl().removeClass(this.disabledClass);
15497 this.el.dom.disabled = false;
15501 * Convenience function for setting disabled/enabled by boolean.
15502 * @param {Boolean} disabled
15504 setDisabled : function(disabled){
15505 this[disabled ? "disable" : "enable"]();
15509 * Show this component.
15510 * @return {Roo.Component} this
15513 if(this.fireEvent("beforeshow", this) !== false){
15514 this.hidden = false;
15518 this.fireEvent("show", this);
15524 onShow : function(){
15525 var ae = this.getActionEl();
15526 if(this.hideMode == 'visibility'){
15527 ae.dom.style.visibility = "visible";
15528 }else if(this.hideMode == 'offsets'){
15529 ae.removeClass('x-hidden');
15531 ae.dom.style.display = "";
15536 * Hide this component.
15537 * @return {Roo.Component} this
15540 if(this.fireEvent("beforehide", this) !== false){
15541 this.hidden = true;
15545 this.fireEvent("hide", this);
15551 onHide : function(){
15552 var ae = this.getActionEl();
15553 if(this.hideMode == 'visibility'){
15554 ae.dom.style.visibility = "hidden";
15555 }else if(this.hideMode == 'offsets'){
15556 ae.addClass('x-hidden');
15558 ae.dom.style.display = "none";
15563 * Convenience function to hide or show this component by boolean.
15564 * @param {Boolean} visible True to show, false to hide
15565 * @return {Roo.Component} this
15567 setVisible: function(visible){
15577 * Returns true if this component is visible.
15579 isVisible : function(){
15580 return this.getActionEl().isVisible();
15583 cloneConfig : function(overrides){
15584 overrides = overrides || {};
15585 var id = overrides.id || Roo.id();
15586 var cfg = Roo.applyIf(overrides, this.initialConfig);
15587 cfg.id = id; // prevent dup id
15588 return new this.constructor(cfg);
15592 * Ext JS Library 1.1.1
15593 * Copyright(c) 2006-2007, Ext JS, LLC.
15595 * Originally Released Under LGPL - original licence link has changed is not relivant.
15598 * <script type="text/javascript">
15602 * @class Roo.BoxComponent
15603 * @extends Roo.Component
15604 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15605 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15606 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15607 * layout containers.
15609 * @param {Roo.Element/String/Object} config The configuration options.
15611 Roo.BoxComponent = function(config){
15612 Roo.Component.call(this, config);
15616 * Fires after the component is resized.
15617 * @param {Roo.Component} this
15618 * @param {Number} adjWidth The box-adjusted width that was set
15619 * @param {Number} adjHeight The box-adjusted height that was set
15620 * @param {Number} rawWidth The width that was originally specified
15621 * @param {Number} rawHeight The height that was originally specified
15626 * Fires after the component is moved.
15627 * @param {Roo.Component} this
15628 * @param {Number} x The new x position
15629 * @param {Number} y The new y position
15635 Roo.extend(Roo.BoxComponent, Roo.Component, {
15636 // private, set in afterRender to signify that the component has been rendered
15638 // private, used to defer height settings to subclasses
15639 deferHeight: false,
15640 /** @cfg {Number} width
15641 * width (optional) size of component
15643 /** @cfg {Number} height
15644 * height (optional) size of component
15648 * Sets the width and height of the component. This method fires the resize event. This method can accept
15649 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15650 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15651 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15652 * @return {Roo.BoxComponent} this
15654 setSize : function(w, h){
15655 // support for standard size objects
15656 if(typeof w == 'object'){
15661 if(!this.boxReady){
15667 // prevent recalcs when not needed
15668 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15671 this.lastSize = {width: w, height: h};
15673 var adj = this.adjustSize(w, h);
15674 var aw = adj.width, ah = adj.height;
15675 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15676 var rz = this.getResizeEl();
15677 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15678 rz.setSize(aw, ah);
15679 }else if(!this.deferHeight && ah !== undefined){
15681 }else if(aw !== undefined){
15684 this.onResize(aw, ah, w, h);
15685 this.fireEvent('resize', this, aw, ah, w, h);
15691 * Gets the current size of the component's underlying element.
15692 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15694 getSize : function(){
15695 return this.el.getSize();
15699 * Gets the current XY position of the component's underlying element.
15700 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15701 * @return {Array} The XY position of the element (e.g., [100, 200])
15703 getPosition : function(local){
15704 if(local === true){
15705 return [this.el.getLeft(true), this.el.getTop(true)];
15707 return this.xy || this.el.getXY();
15711 * Gets the current box measurements of the component's underlying element.
15712 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15713 * @returns {Object} box An object in the format {x, y, width, height}
15715 getBox : function(local){
15716 var s = this.el.getSize();
15718 s.x = this.el.getLeft(true);
15719 s.y = this.el.getTop(true);
15721 var xy = this.xy || this.el.getXY();
15729 * Sets the current box measurements of the component's underlying element.
15730 * @param {Object} box An object in the format {x, y, width, height}
15731 * @returns {Roo.BoxComponent} this
15733 updateBox : function(box){
15734 this.setSize(box.width, box.height);
15735 this.setPagePosition(box.x, box.y);
15740 getResizeEl : function(){
15741 return this.resizeEl || this.el;
15745 getPositionEl : function(){
15746 return this.positionEl || this.el;
15750 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15751 * This method fires the move event.
15752 * @param {Number} left The new left
15753 * @param {Number} top The new top
15754 * @returns {Roo.BoxComponent} this
15756 setPosition : function(x, y){
15759 if(!this.boxReady){
15762 var adj = this.adjustPosition(x, y);
15763 var ax = adj.x, ay = adj.y;
15765 var el = this.getPositionEl();
15766 if(ax !== undefined || ay !== undefined){
15767 if(ax !== undefined && ay !== undefined){
15768 el.setLeftTop(ax, ay);
15769 }else if(ax !== undefined){
15771 }else if(ay !== undefined){
15774 this.onPosition(ax, ay);
15775 this.fireEvent('move', this, ax, ay);
15781 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15782 * This method fires the move event.
15783 * @param {Number} x The new x position
15784 * @param {Number} y The new y position
15785 * @returns {Roo.BoxComponent} this
15787 setPagePosition : function(x, y){
15790 if(!this.boxReady){
15793 if(x === undefined || y === undefined){ // cannot translate undefined points
15796 var p = this.el.translatePoints(x, y);
15797 this.setPosition(p.left, p.top);
15802 onRender : function(ct, position){
15803 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15805 this.resizeEl = Roo.get(this.resizeEl);
15807 if(this.positionEl){
15808 this.positionEl = Roo.get(this.positionEl);
15813 afterRender : function(){
15814 Roo.BoxComponent.superclass.afterRender.call(this);
15815 this.boxReady = true;
15816 this.setSize(this.width, this.height);
15817 if(this.x || this.y){
15818 this.setPosition(this.x, this.y);
15820 if(this.pageX || this.pageY){
15821 this.setPagePosition(this.pageX, this.pageY);
15826 * Force the component's size to recalculate based on the underlying element's current height and width.
15827 * @returns {Roo.BoxComponent} this
15829 syncSize : function(){
15830 delete this.lastSize;
15831 this.setSize(this.el.getWidth(), this.el.getHeight());
15836 * Called after the component is resized, this method is empty by default but can be implemented by any
15837 * subclass that needs to perform custom logic after a resize occurs.
15838 * @param {Number} adjWidth The box-adjusted width that was set
15839 * @param {Number} adjHeight The box-adjusted height that was set
15840 * @param {Number} rawWidth The width that was originally specified
15841 * @param {Number} rawHeight The height that was originally specified
15843 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15848 * Called after the component is moved, this method is empty by default but can be implemented by any
15849 * subclass that needs to perform custom logic after a move occurs.
15850 * @param {Number} x The new x position
15851 * @param {Number} y The new y position
15853 onPosition : function(x, y){
15858 adjustSize : function(w, h){
15859 if(this.autoWidth){
15862 if(this.autoHeight){
15865 return {width : w, height: h};
15869 adjustPosition : function(x, y){
15870 return {x : x, y: y};
15873 * Original code for Roojs - LGPL
15874 * <script type="text/javascript">
15878 * @class Roo.XComponent
15879 * A delayed Element creator...
15880 * Or a way to group chunks of interface together.
15881 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15882 * used in conjunction with XComponent.build() it will create an instance of each element,
15883 * then call addxtype() to build the User interface.
15885 * Mypart.xyx = new Roo.XComponent({
15887 parent : 'Mypart.xyz', // empty == document.element.!!
15891 disabled : function() {}
15893 tree : function() { // return an tree of xtype declared components
15897 xtype : 'NestedLayoutPanel',
15904 * It can be used to build a big heiracy, with parent etc.
15905 * or you can just use this to render a single compoent to a dom element
15906 * MYPART.render(Roo.Element | String(id) | dom_element )
15913 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15914 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15916 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15918 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15919 * - if mulitple topModules exist, the last one is defined as the top module.
15923 * When the top level or multiple modules are to embedded into a existing HTML page,
15924 * the parent element can container '#id' of the element where the module will be drawn.
15928 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15929 * it relies more on a include mechanism, where sub modules are included into an outer page.
15930 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15932 * Bootstrap Roo Included elements
15934 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15935 * hence confusing the component builder as it thinks there are multiple top level elements.
15939 * @extends Roo.util.Observable
15941 * @param cfg {Object} configuration of component
15944 Roo.XComponent = function(cfg) {
15945 Roo.apply(this, cfg);
15949 * Fires when this the componnt is built
15950 * @param {Roo.XComponent} c the component
15955 this.region = this.region || 'center'; // default..
15956 Roo.XComponent.register(this);
15957 this.modules = false;
15958 this.el = false; // where the layout goes..
15962 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15965 * The created element (with Roo.factory())
15966 * @type {Roo.Layout}
15972 * for BC - use el in new code
15973 * @type {Roo.Layout}
15979 * for BC - use el in new code
15980 * @type {Roo.Layout}
15985 * @cfg {Function|boolean} disabled
15986 * If this module is disabled by some rule, return true from the funtion
15991 * @cfg {String} parent
15992 * Name of parent element which it get xtype added to..
15997 * @cfg {String} order
15998 * Used to set the order in which elements are created (usefull for multiple tabs)
16003 * @cfg {String} name
16004 * String to display while loading.
16008 * @cfg {String} region
16009 * Region to render component to (defaults to center)
16014 * @cfg {Array} items
16015 * A single item array - the first element is the root of the tree..
16016 * It's done this way to stay compatible with the Xtype system...
16022 * The method that retuns the tree of parts that make up this compoennt
16029 * render element to dom or tree
16030 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16033 render : function(el)
16037 var hp = this.parent ? 1 : 0;
16038 Roo.debug && Roo.log(this);
16040 var tree = this._tree ? this._tree() : this.tree();
16043 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16044 // if parent is a '#.....' string, then let's use that..
16045 var ename = this.parent.substr(1);
16046 this.parent = false;
16047 Roo.debug && Roo.log(ename);
16049 case 'bootstrap-body':
16050 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16051 // this is the BorderLayout standard?
16052 this.parent = { el : true };
16055 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16056 // need to insert stuff...
16058 el : new Roo.bootstrap.layout.Border({
16059 el : document.body,
16065 tabPosition: 'top',
16066 //resizeTabs: true,
16067 alwaysShowTabs: true,
16077 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16078 this.parent = { el : new Roo.bootstrap.Body() };
16079 Roo.debug && Roo.log("setting el to doc body");
16082 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16086 this.parent = { el : true};
16089 el = Roo.get(ename);
16090 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16091 this.parent = { el : true};
16098 if (!el && !this.parent) {
16099 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16104 Roo.debug && Roo.log("EL:");
16105 Roo.debug && Roo.log(el);
16106 Roo.debug && Roo.log("this.parent.el:");
16107 Roo.debug && Roo.log(this.parent.el);
16110 // altertive root elements ??? - we need a better way to indicate these.
16111 var is_alt = Roo.XComponent.is_alt ||
16112 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16113 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16114 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16118 if (!this.parent && is_alt) {
16119 //el = Roo.get(document.body);
16120 this.parent = { el : true };
16125 if (!this.parent) {
16127 Roo.debug && Roo.log("no parent - creating one");
16129 el = el ? Roo.get(el) : false;
16131 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16134 el : new Roo.bootstrap.layout.Border({
16135 el: el || document.body,
16141 tabPosition: 'top',
16142 //resizeTabs: true,
16143 alwaysShowTabs: false,
16146 overflow: 'visible'
16152 // it's a top level one..
16154 el : new Roo.BorderLayout(el || document.body, {
16159 tabPosition: 'top',
16160 //resizeTabs: true,
16161 alwaysShowTabs: el && hp? false : true,
16162 hideTabs: el || !hp ? true : false,
16170 if (!this.parent.el) {
16171 // probably an old style ctor, which has been disabled.
16175 // The 'tree' method is '_tree now'
16177 tree.region = tree.region || this.region;
16178 var is_body = false;
16179 if (this.parent.el === true) {
16180 // bootstrap... - body..
16184 this.parent.el = Roo.factory(tree);
16188 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16189 this.fireEvent('built', this);
16191 this.panel = this.el;
16192 this.layout = this.panel.layout;
16193 this.parentLayout = this.parent.layout || false;
16199 Roo.apply(Roo.XComponent, {
16201 * @property hideProgress
16202 * true to disable the building progress bar.. usefull on single page renders.
16205 hideProgress : false,
16207 * @property buildCompleted
16208 * True when the builder has completed building the interface.
16211 buildCompleted : false,
16214 * @property topModule
16215 * the upper most module - uses document.element as it's constructor.
16222 * @property modules
16223 * array of modules to be created by registration system.
16224 * @type {Array} of Roo.XComponent
16229 * @property elmodules
16230 * array of modules to be created by which use #ID
16231 * @type {Array} of Roo.XComponent
16238 * Is an alternative Root - normally used by bootstrap or other systems,
16239 * where the top element in the tree can wrap 'body'
16240 * @type {boolean} (default false)
16245 * @property build_from_html
16246 * Build elements from html - used by bootstrap HTML stuff
16247 * - this is cleared after build is completed
16248 * @type {boolean} (default false)
16251 build_from_html : false,
16253 * Register components to be built later.
16255 * This solves the following issues
16256 * - Building is not done on page load, but after an authentication process has occured.
16257 * - Interface elements are registered on page load
16258 * - Parent Interface elements may not be loaded before child, so this handles that..
16265 module : 'Pman.Tab.projectMgr',
16267 parent : 'Pman.layout',
16268 disabled : false, // or use a function..
16271 * * @param {Object} details about module
16273 register : function(obj) {
16275 Roo.XComponent.event.fireEvent('register', obj);
16276 switch(typeof(obj.disabled) ) {
16282 if ( obj.disabled() ) {
16288 if (obj.disabled) {
16294 this.modules.push(obj);
16298 * convert a string to an object..
16299 * eg. 'AAA.BBB' -> finds AAA.BBB
16303 toObject : function(str)
16305 if (!str || typeof(str) == 'object') {
16308 if (str.substring(0,1) == '#') {
16312 var ar = str.split('.');
16317 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16319 throw "Module not found : " + str;
16323 throw "Module not found : " + str;
16325 Roo.each(ar, function(e) {
16326 if (typeof(o[e]) == 'undefined') {
16327 throw "Module not found : " + str;
16338 * move modules into their correct place in the tree..
16341 preBuild : function ()
16344 Roo.each(this.modules , function (obj)
16346 Roo.XComponent.event.fireEvent('beforebuild', obj);
16348 var opar = obj.parent;
16350 obj.parent = this.toObject(opar);
16352 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16357 Roo.debug && Roo.log("GOT top level module");
16358 Roo.debug && Roo.log(obj);
16359 obj.modules = new Roo.util.MixedCollection(false,
16360 function(o) { return o.order + '' }
16362 this.topModule = obj;
16365 // parent is a string (usually a dom element name..)
16366 if (typeof(obj.parent) == 'string') {
16367 this.elmodules.push(obj);
16370 if (obj.parent.constructor != Roo.XComponent) {
16371 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16373 if (!obj.parent.modules) {
16374 obj.parent.modules = new Roo.util.MixedCollection(false,
16375 function(o) { return o.order + '' }
16378 if (obj.parent.disabled) {
16379 obj.disabled = true;
16381 obj.parent.modules.add(obj);
16386 * make a list of modules to build.
16387 * @return {Array} list of modules.
16390 buildOrder : function()
16393 var cmp = function(a,b) {
16394 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16396 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16397 throw "No top level modules to build";
16400 // make a flat list in order of modules to build.
16401 var mods = this.topModule ? [ this.topModule ] : [];
16404 // elmodules (is a list of DOM based modules )
16405 Roo.each(this.elmodules, function(e) {
16407 if (!this.topModule &&
16408 typeof(e.parent) == 'string' &&
16409 e.parent.substring(0,1) == '#' &&
16410 Roo.get(e.parent.substr(1))
16413 _this.topModule = e;
16419 // add modules to their parents..
16420 var addMod = function(m) {
16421 Roo.debug && Roo.log("build Order: add: " + m.name);
16424 if (m.modules && !m.disabled) {
16425 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16426 m.modules.keySort('ASC', cmp );
16427 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16429 m.modules.each(addMod);
16431 Roo.debug && Roo.log("build Order: no child modules");
16433 // not sure if this is used any more..
16435 m.finalize.name = m.name + " (clean up) ";
16436 mods.push(m.finalize);
16440 if (this.topModule && this.topModule.modules) {
16441 this.topModule.modules.keySort('ASC', cmp );
16442 this.topModule.modules.each(addMod);
16448 * Build the registered modules.
16449 * @param {Object} parent element.
16450 * @param {Function} optional method to call after module has been added.
16454 build : function(opts)
16457 if (typeof(opts) != 'undefined') {
16458 Roo.apply(this,opts);
16462 var mods = this.buildOrder();
16464 //this.allmods = mods;
16465 //Roo.debug && Roo.log(mods);
16467 if (!mods.length) { // should not happen
16468 throw "NO modules!!!";
16472 var msg = "Building Interface...";
16473 // flash it up as modal - so we store the mask!?
16474 if (!this.hideProgress && Roo.MessageBox) {
16475 Roo.MessageBox.show({ title: 'loading' });
16476 Roo.MessageBox.show({
16477 title: "Please wait...",
16486 var total = mods.length;
16489 var progressRun = function() {
16490 if (!mods.length) {
16491 Roo.debug && Roo.log('hide?');
16492 if (!this.hideProgress && Roo.MessageBox) {
16493 Roo.MessageBox.hide();
16495 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16497 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16503 var m = mods.shift();
16506 Roo.debug && Roo.log(m);
16507 // not sure if this is supported any more.. - modules that are are just function
16508 if (typeof(m) == 'function') {
16510 return progressRun.defer(10, _this);
16514 msg = "Building Interface " + (total - mods.length) +
16516 (m.name ? (' - ' + m.name) : '');
16517 Roo.debug && Roo.log(msg);
16518 if (!this.hideProgress && Roo.MessageBox) {
16519 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16523 // is the module disabled?
16524 var disabled = (typeof(m.disabled) == 'function') ?
16525 m.disabled.call(m.module.disabled) : m.disabled;
16529 return progressRun(); // we do not update the display!
16537 // it's 10 on top level, and 1 on others??? why...
16538 return progressRun.defer(10, _this);
16541 progressRun.defer(1, _this);
16555 * wrapper for event.on - aliased later..
16556 * Typically use to register a event handler for register:
16558 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16567 Roo.XComponent.event = new Roo.util.Observable({
16571 * Fires when an Component is registered,
16572 * set the disable property on the Component to stop registration.
16573 * @param {Roo.XComponent} c the component being registerd.
16578 * @event beforebuild
16579 * Fires before each Component is built
16580 * can be used to apply permissions.
16581 * @param {Roo.XComponent} c the component being registerd.
16584 'beforebuild' : true,
16586 * @event buildcomplete
16587 * Fires on the top level element when all elements have been built
16588 * @param {Roo.XComponent} the top level component.
16590 'buildcomplete' : true
16595 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16598 * marked - a markdown parser
16599 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16600 * https://github.com/chjj/marked
16606 * Roo.Markdown - is a very crude wrapper around marked..
16610 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16612 * Note: move the sample code to the bottom of this
16613 * file before uncommenting it.
16618 Roo.Markdown.toHtml = function(text) {
16620 var c = new Roo.Markdown.marked.setOptions({
16621 renderer: new Roo.Markdown.marked.Renderer(),
16632 text = text.replace(/\\\n/g,' ');
16633 return Roo.Markdown.marked(text);
16638 // Wraps all "globals" so that the only thing
16639 // exposed is makeHtml().
16644 * Block-Level Grammar
16649 code: /^( {4}[^\n]+\n*)+/,
16651 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16652 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16654 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16655 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16656 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16657 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16658 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16660 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16664 block.bullet = /(?:[*+-]|\d+\.)/;
16665 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16666 block.item = replace(block.item, 'gm')
16667 (/bull/g, block.bullet)
16670 block.list = replace(block.list)
16671 (/bull/g, block.bullet)
16672 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16673 ('def', '\\n+(?=' + block.def.source + ')')
16676 block.blockquote = replace(block.blockquote)
16680 block._tag = '(?!(?:'
16681 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16682 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16683 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16685 block.html = replace(block.html)
16686 ('comment', /<!--[\s\S]*?-->/)
16687 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16688 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16689 (/tag/g, block._tag)
16692 block.paragraph = replace(block.paragraph)
16694 ('heading', block.heading)
16695 ('lheading', block.lheading)
16696 ('blockquote', block.blockquote)
16697 ('tag', '<' + block._tag)
16702 * Normal Block Grammar
16705 block.normal = merge({}, block);
16708 * GFM Block Grammar
16711 block.gfm = merge({}, block.normal, {
16712 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16714 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16717 block.gfm.paragraph = replace(block.paragraph)
16719 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16720 + block.list.source.replace('\\1', '\\3') + '|')
16724 * GFM + Tables Block Grammar
16727 block.tables = merge({}, block.gfm, {
16728 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16729 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16736 function Lexer(options) {
16738 this.tokens.links = {};
16739 this.options = options || marked.defaults;
16740 this.rules = block.normal;
16742 if (this.options.gfm) {
16743 if (this.options.tables) {
16744 this.rules = block.tables;
16746 this.rules = block.gfm;
16752 * Expose Block Rules
16755 Lexer.rules = block;
16758 * Static Lex Method
16761 Lexer.lex = function(src, options) {
16762 var lexer = new Lexer(options);
16763 return lexer.lex(src);
16770 Lexer.prototype.lex = function(src) {
16772 .replace(/\r\n|\r/g, '\n')
16773 .replace(/\t/g, ' ')
16774 .replace(/\u00a0/g, ' ')
16775 .replace(/\u2424/g, '\n');
16777 return this.token(src, true);
16784 Lexer.prototype.token = function(src, top, bq) {
16785 var src = src.replace(/^ +$/gm, '')
16798 if (cap = this.rules.newline.exec(src)) {
16799 src = src.substring(cap[0].length);
16800 if (cap[0].length > 1) {
16808 if (cap = this.rules.code.exec(src)) {
16809 src = src.substring(cap[0].length);
16810 cap = cap[0].replace(/^ {4}/gm, '');
16813 text: !this.options.pedantic
16814 ? cap.replace(/\n+$/, '')
16821 if (cap = this.rules.fences.exec(src)) {
16822 src = src.substring(cap[0].length);
16832 if (cap = this.rules.heading.exec(src)) {
16833 src = src.substring(cap[0].length);
16836 depth: cap[1].length,
16842 // table no leading pipe (gfm)
16843 if (top && (cap = this.rules.nptable.exec(src))) {
16844 src = src.substring(cap[0].length);
16848 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16849 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16850 cells: cap[3].replace(/\n$/, '').split('\n')
16853 for (i = 0; i < item.align.length; i++) {
16854 if (/^ *-+: *$/.test(item.align[i])) {
16855 item.align[i] = 'right';
16856 } else if (/^ *:-+: *$/.test(item.align[i])) {
16857 item.align[i] = 'center';
16858 } else if (/^ *:-+ *$/.test(item.align[i])) {
16859 item.align[i] = 'left';
16861 item.align[i] = null;
16865 for (i = 0; i < item.cells.length; i++) {
16866 item.cells[i] = item.cells[i].split(/ *\| */);
16869 this.tokens.push(item);
16875 if (cap = this.rules.lheading.exec(src)) {
16876 src = src.substring(cap[0].length);
16879 depth: cap[2] === '=' ? 1 : 2,
16886 if (cap = this.rules.hr.exec(src)) {
16887 src = src.substring(cap[0].length);
16895 if (cap = this.rules.blockquote.exec(src)) {
16896 src = src.substring(cap[0].length);
16899 type: 'blockquote_start'
16902 cap = cap[0].replace(/^ *> ?/gm, '');
16904 // Pass `top` to keep the current
16905 // "toplevel" state. This is exactly
16906 // how markdown.pl works.
16907 this.token(cap, top, true);
16910 type: 'blockquote_end'
16917 if (cap = this.rules.list.exec(src)) {
16918 src = src.substring(cap[0].length);
16922 type: 'list_start',
16923 ordered: bull.length > 1
16926 // Get each top-level item.
16927 cap = cap[0].match(this.rules.item);
16933 for (; i < l; i++) {
16936 // Remove the list item's bullet
16937 // so it is seen as the next token.
16938 space = item.length;
16939 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16941 // Outdent whatever the
16942 // list item contains. Hacky.
16943 if (~item.indexOf('\n ')) {
16944 space -= item.length;
16945 item = !this.options.pedantic
16946 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16947 : item.replace(/^ {1,4}/gm, '');
16950 // Determine whether the next list item belongs here.
16951 // Backpedal if it does not belong in this list.
16952 if (this.options.smartLists && i !== l - 1) {
16953 b = block.bullet.exec(cap[i + 1])[0];
16954 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16955 src = cap.slice(i + 1).join('\n') + src;
16960 // Determine whether item is loose or not.
16961 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16962 // for discount behavior.
16963 loose = next || /\n\n(?!\s*$)/.test(item);
16965 next = item.charAt(item.length - 1) === '\n';
16966 if (!loose) { loose = next; }
16971 ? 'loose_item_start'
16972 : 'list_item_start'
16976 this.token(item, false, bq);
16979 type: 'list_item_end'
16991 if (cap = this.rules.html.exec(src)) {
16992 src = src.substring(cap[0].length);
16994 type: this.options.sanitize
16997 pre: !this.options.sanitizer
16998 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17005 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17006 src = src.substring(cap[0].length);
17007 this.tokens.links[cap[1].toLowerCase()] = {
17015 if (top && (cap = this.rules.table.exec(src))) {
17016 src = src.substring(cap[0].length);
17020 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17021 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17022 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17025 for (i = 0; i < item.align.length; i++) {
17026 if (/^ *-+: *$/.test(item.align[i])) {
17027 item.align[i] = 'right';
17028 } else if (/^ *:-+: *$/.test(item.align[i])) {
17029 item.align[i] = 'center';
17030 } else if (/^ *:-+ *$/.test(item.align[i])) {
17031 item.align[i] = 'left';
17033 item.align[i] = null;
17037 for (i = 0; i < item.cells.length; i++) {
17038 item.cells[i] = item.cells[i]
17039 .replace(/^ *\| *| *\| *$/g, '')
17043 this.tokens.push(item);
17048 // top-level paragraph
17049 if (top && (cap = this.rules.paragraph.exec(src))) {
17050 src = src.substring(cap[0].length);
17053 text: cap[1].charAt(cap[1].length - 1) === '\n'
17054 ? cap[1].slice(0, -1)
17061 if (cap = this.rules.text.exec(src)) {
17062 // Top-level should never reach here.
17063 src = src.substring(cap[0].length);
17073 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17077 return this.tokens;
17081 * Inline-Level Grammar
17085 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17086 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17088 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17089 link: /^!?\[(inside)\]\(href\)/,
17090 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17091 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17092 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17093 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17094 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17095 br: /^ {2,}\n(?!\s*$)/,
17097 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17100 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17101 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17103 inline.link = replace(inline.link)
17104 ('inside', inline._inside)
17105 ('href', inline._href)
17108 inline.reflink = replace(inline.reflink)
17109 ('inside', inline._inside)
17113 * Normal Inline Grammar
17116 inline.normal = merge({}, inline);
17119 * Pedantic Inline Grammar
17122 inline.pedantic = merge({}, inline.normal, {
17123 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17124 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17128 * GFM Inline Grammar
17131 inline.gfm = merge({}, inline.normal, {
17132 escape: replace(inline.escape)('])', '~|])')(),
17133 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17134 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17135 text: replace(inline.text)
17137 ('|', '|https?://|')
17142 * GFM + Line Breaks Inline Grammar
17145 inline.breaks = merge({}, inline.gfm, {
17146 br: replace(inline.br)('{2,}', '*')(),
17147 text: replace(inline.gfm.text)('{2,}', '*')()
17151 * Inline Lexer & Compiler
17154 function InlineLexer(links, options) {
17155 this.options = options || marked.defaults;
17156 this.links = links;
17157 this.rules = inline.normal;
17158 this.renderer = this.options.renderer || new Renderer;
17159 this.renderer.options = this.options;
17163 Error('Tokens array requires a `links` property.');
17166 if (this.options.gfm) {
17167 if (this.options.breaks) {
17168 this.rules = inline.breaks;
17170 this.rules = inline.gfm;
17172 } else if (this.options.pedantic) {
17173 this.rules = inline.pedantic;
17178 * Expose Inline Rules
17181 InlineLexer.rules = inline;
17184 * Static Lexing/Compiling Method
17187 InlineLexer.output = function(src, links, options) {
17188 var inline = new InlineLexer(links, options);
17189 return inline.output(src);
17196 InlineLexer.prototype.output = function(src) {
17205 if (cap = this.rules.escape.exec(src)) {
17206 src = src.substring(cap[0].length);
17212 if (cap = this.rules.autolink.exec(src)) {
17213 src = src.substring(cap[0].length);
17214 if (cap[2] === '@') {
17215 text = cap[1].charAt(6) === ':'
17216 ? this.mangle(cap[1].substring(7))
17217 : this.mangle(cap[1]);
17218 href = this.mangle('mailto:') + text;
17220 text = escape(cap[1]);
17223 out += this.renderer.link(href, null, text);
17228 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17229 src = src.substring(cap[0].length);
17230 text = escape(cap[1]);
17232 out += this.renderer.link(href, null, text);
17237 if (cap = this.rules.tag.exec(src)) {
17238 if (!this.inLink && /^<a /i.test(cap[0])) {
17239 this.inLink = true;
17240 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17241 this.inLink = false;
17243 src = src.substring(cap[0].length);
17244 out += this.options.sanitize
17245 ? this.options.sanitizer
17246 ? this.options.sanitizer(cap[0])
17253 if (cap = this.rules.link.exec(src)) {
17254 src = src.substring(cap[0].length);
17255 this.inLink = true;
17256 out += this.outputLink(cap, {
17260 this.inLink = false;
17265 if ((cap = this.rules.reflink.exec(src))
17266 || (cap = this.rules.nolink.exec(src))) {
17267 src = src.substring(cap[0].length);
17268 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17269 link = this.links[link.toLowerCase()];
17270 if (!link || !link.href) {
17271 out += cap[0].charAt(0);
17272 src = cap[0].substring(1) + src;
17275 this.inLink = true;
17276 out += this.outputLink(cap, link);
17277 this.inLink = false;
17282 if (cap = this.rules.strong.exec(src)) {
17283 src = src.substring(cap[0].length);
17284 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17289 if (cap = this.rules.em.exec(src)) {
17290 src = src.substring(cap[0].length);
17291 out += this.renderer.em(this.output(cap[2] || cap[1]));
17296 if (cap = this.rules.code.exec(src)) {
17297 src = src.substring(cap[0].length);
17298 out += this.renderer.codespan(escape(cap[2], true));
17303 if (cap = this.rules.br.exec(src)) {
17304 src = src.substring(cap[0].length);
17305 out += this.renderer.br();
17310 if (cap = this.rules.del.exec(src)) {
17311 src = src.substring(cap[0].length);
17312 out += this.renderer.del(this.output(cap[1]));
17317 if (cap = this.rules.text.exec(src)) {
17318 src = src.substring(cap[0].length);
17319 out += this.renderer.text(escape(this.smartypants(cap[0])));
17325 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17336 InlineLexer.prototype.outputLink = function(cap, link) {
17337 var href = escape(link.href)
17338 , title = link.title ? escape(link.title) : null;
17340 return cap[0].charAt(0) !== '!'
17341 ? this.renderer.link(href, title, this.output(cap[1]))
17342 : this.renderer.image(href, title, escape(cap[1]));
17346 * Smartypants Transformations
17349 InlineLexer.prototype.smartypants = function(text) {
17350 if (!this.options.smartypants) { return text; }
17353 .replace(/---/g, '\u2014')
17355 .replace(/--/g, '\u2013')
17357 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17358 // closing singles & apostrophes
17359 .replace(/'/g, '\u2019')
17361 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17363 .replace(/"/g, '\u201d')
17365 .replace(/\.{3}/g, '\u2026');
17372 InlineLexer.prototype.mangle = function(text) {
17373 if (!this.options.mangle) { return text; }
17379 for (; i < l; i++) {
17380 ch = text.charCodeAt(i);
17381 if (Math.random() > 0.5) {
17382 ch = 'x' + ch.toString(16);
17384 out += '&#' + ch + ';';
17394 function Renderer(options) {
17395 this.options = options || {};
17398 Renderer.prototype.code = function(code, lang, escaped) {
17399 if (this.options.highlight) {
17400 var out = this.options.highlight(code, lang);
17401 if (out != null && out !== code) {
17406 // hack!!! - it's already escapeD?
17411 return '<pre><code>'
17412 + (escaped ? code : escape(code, true))
17413 + '\n</code></pre>';
17416 return '<pre><code class="'
17417 + this.options.langPrefix
17418 + escape(lang, true)
17420 + (escaped ? code : escape(code, true))
17421 + '\n</code></pre>\n';
17424 Renderer.prototype.blockquote = function(quote) {
17425 return '<blockquote>\n' + quote + '</blockquote>\n';
17428 Renderer.prototype.html = function(html) {
17432 Renderer.prototype.heading = function(text, level, raw) {
17436 + this.options.headerPrefix
17437 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17445 Renderer.prototype.hr = function() {
17446 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17449 Renderer.prototype.list = function(body, ordered) {
17450 var type = ordered ? 'ol' : 'ul';
17451 return '<' + type + '>\n' + body + '</' + type + '>\n';
17454 Renderer.prototype.listitem = function(text) {
17455 return '<li>' + text + '</li>\n';
17458 Renderer.prototype.paragraph = function(text) {
17459 return '<p>' + text + '</p>\n';
17462 Renderer.prototype.table = function(header, body) {
17463 return '<table class="table table-striped">\n'
17473 Renderer.prototype.tablerow = function(content) {
17474 return '<tr>\n' + content + '</tr>\n';
17477 Renderer.prototype.tablecell = function(content, flags) {
17478 var type = flags.header ? 'th' : 'td';
17479 var tag = flags.align
17480 ? '<' + type + ' style="text-align:' + flags.align + '">'
17481 : '<' + type + '>';
17482 return tag + content + '</' + type + '>\n';
17485 // span level renderer
17486 Renderer.prototype.strong = function(text) {
17487 return '<strong>' + text + '</strong>';
17490 Renderer.prototype.em = function(text) {
17491 return '<em>' + text + '</em>';
17494 Renderer.prototype.codespan = function(text) {
17495 return '<code>' + text + '</code>';
17498 Renderer.prototype.br = function() {
17499 return this.options.xhtml ? '<br/>' : '<br>';
17502 Renderer.prototype.del = function(text) {
17503 return '<del>' + text + '</del>';
17506 Renderer.prototype.link = function(href, title, text) {
17507 if (this.options.sanitize) {
17509 var prot = decodeURIComponent(unescape(href))
17510 .replace(/[^\w:]/g, '')
17515 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17519 var out = '<a href="' + href + '"';
17521 out += ' title="' + title + '"';
17523 out += '>' + text + '</a>';
17527 Renderer.prototype.image = function(href, title, text) {
17528 var out = '<img src="' + href + '" alt="' + text + '"';
17530 out += ' title="' + title + '"';
17532 out += this.options.xhtml ? '/>' : '>';
17536 Renderer.prototype.text = function(text) {
17541 * Parsing & Compiling
17544 function Parser(options) {
17547 this.options = options || marked.defaults;
17548 this.options.renderer = this.options.renderer || new Renderer;
17549 this.renderer = this.options.renderer;
17550 this.renderer.options = this.options;
17554 * Static Parse Method
17557 Parser.parse = function(src, options, renderer) {
17558 var parser = new Parser(options, renderer);
17559 return parser.parse(src);
17566 Parser.prototype.parse = function(src) {
17567 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17568 this.tokens = src.reverse();
17571 while (this.next()) {
17582 Parser.prototype.next = function() {
17583 return this.token = this.tokens.pop();
17587 * Preview Next Token
17590 Parser.prototype.peek = function() {
17591 return this.tokens[this.tokens.length - 1] || 0;
17595 * Parse Text Tokens
17598 Parser.prototype.parseText = function() {
17599 var body = this.token.text;
17601 while (this.peek().type === 'text') {
17602 body += '\n' + this.next().text;
17605 return this.inline.output(body);
17609 * Parse Current Token
17612 Parser.prototype.tok = function() {
17613 switch (this.token.type) {
17618 return this.renderer.hr();
17621 return this.renderer.heading(
17622 this.inline.output(this.token.text),
17627 return this.renderer.code(this.token.text,
17629 this.token.escaped);
17642 for (i = 0; i < this.token.header.length; i++) {
17643 flags = { header: true, align: this.token.align[i] };
17644 cell += this.renderer.tablecell(
17645 this.inline.output(this.token.header[i]),
17646 { header: true, align: this.token.align[i] }
17649 header += this.renderer.tablerow(cell);
17651 for (i = 0; i < this.token.cells.length; i++) {
17652 row = this.token.cells[i];
17655 for (j = 0; j < row.length; j++) {
17656 cell += this.renderer.tablecell(
17657 this.inline.output(row[j]),
17658 { header: false, align: this.token.align[j] }
17662 body += this.renderer.tablerow(cell);
17664 return this.renderer.table(header, body);
17666 case 'blockquote_start': {
17669 while (this.next().type !== 'blockquote_end') {
17670 body += this.tok();
17673 return this.renderer.blockquote(body);
17675 case 'list_start': {
17677 , ordered = this.token.ordered;
17679 while (this.next().type !== 'list_end') {
17680 body += this.tok();
17683 return this.renderer.list(body, ordered);
17685 case 'list_item_start': {
17688 while (this.next().type !== 'list_item_end') {
17689 body += this.token.type === 'text'
17694 return this.renderer.listitem(body);
17696 case 'loose_item_start': {
17699 while (this.next().type !== 'list_item_end') {
17700 body += this.tok();
17703 return this.renderer.listitem(body);
17706 var html = !this.token.pre && !this.options.pedantic
17707 ? this.inline.output(this.token.text)
17709 return this.renderer.html(html);
17711 case 'paragraph': {
17712 return this.renderer.paragraph(this.inline.output(this.token.text));
17715 return this.renderer.paragraph(this.parseText());
17724 function escape(html, encode) {
17726 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17727 .replace(/</g, '<')
17728 .replace(/>/g, '>')
17729 .replace(/"/g, '"')
17730 .replace(/'/g, ''');
17733 function unescape(html) {
17734 // explicitly match decimal, hex, and named HTML entities
17735 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17736 n = n.toLowerCase();
17737 if (n === 'colon') { return ':'; }
17738 if (n.charAt(0) === '#') {
17739 return n.charAt(1) === 'x'
17740 ? String.fromCharCode(parseInt(n.substring(2), 16))
17741 : String.fromCharCode(+n.substring(1));
17747 function replace(regex, opt) {
17748 regex = regex.source;
17750 return function self(name, val) {
17751 if (!name) { return new RegExp(regex, opt); }
17752 val = val.source || val;
17753 val = val.replace(/(^|[^\[])\^/g, '$1');
17754 regex = regex.replace(name, val);
17762 function merge(obj) {
17767 for (; i < arguments.length; i++) {
17768 target = arguments[i];
17769 for (key in target) {
17770 if (Object.prototype.hasOwnProperty.call(target, key)) {
17771 obj[key] = target[key];
17784 function marked(src, opt, callback) {
17785 if (callback || typeof opt === 'function') {
17791 opt = merge({}, marked.defaults, opt || {});
17793 var highlight = opt.highlight
17799 tokens = Lexer.lex(src, opt)
17801 return callback(e);
17804 pending = tokens.length;
17806 var done = function(err) {
17808 opt.highlight = highlight;
17809 return callback(err);
17815 out = Parser.parse(tokens, opt);
17820 opt.highlight = highlight;
17824 : callback(null, out);
17827 if (!highlight || highlight.length < 3) {
17831 delete opt.highlight;
17833 if (!pending) { return done(); }
17835 for (; i < tokens.length; i++) {
17837 if (token.type !== 'code') {
17838 return --pending || done();
17840 return highlight(token.text, token.lang, function(err, code) {
17841 if (err) { return done(err); }
17842 if (code == null || code === token.text) {
17843 return --pending || done();
17846 token.escaped = true;
17847 --pending || done();
17855 if (opt) { opt = merge({}, marked.defaults, opt); }
17856 return Parser.parse(Lexer.lex(src, opt), opt);
17858 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17859 if ((opt || marked.defaults).silent) {
17860 return '<p>An error occured:</p><pre>'
17861 + escape(e.message + '', true)
17873 marked.setOptions = function(opt) {
17874 merge(marked.defaults, opt);
17878 marked.defaults = {
17889 langPrefix: 'lang-',
17890 smartypants: false,
17892 renderer: new Renderer,
17900 marked.Parser = Parser;
17901 marked.parser = Parser.parse;
17903 marked.Renderer = Renderer;
17905 marked.Lexer = Lexer;
17906 marked.lexer = Lexer.lex;
17908 marked.InlineLexer = InlineLexer;
17909 marked.inlineLexer = InlineLexer.output;
17911 marked.parse = marked;
17913 Roo.Markdown.marked = marked;
17917 * Ext JS Library 1.1.1
17918 * Copyright(c) 2006-2007, Ext JS, LLC.
17920 * Originally Released Under LGPL - original licence link has changed is not relivant.
17923 * <script type="text/javascript">
17929 * These classes are derivatives of the similarly named classes in the YUI Library.
17930 * The original license:
17931 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17932 * Code licensed under the BSD License:
17933 * http://developer.yahoo.net/yui/license.txt
17938 var Event=Roo.EventManager;
17939 var Dom=Roo.lib.Dom;
17942 * @class Roo.dd.DragDrop
17943 * @extends Roo.util.Observable
17944 * Defines the interface and base operation of items that that can be
17945 * dragged or can be drop targets. It was designed to be extended, overriding
17946 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17947 * Up to three html elements can be associated with a DragDrop instance:
17949 * <li>linked element: the element that is passed into the constructor.
17950 * This is the element which defines the boundaries for interaction with
17951 * other DragDrop objects.</li>
17952 * <li>handle element(s): The drag operation only occurs if the element that
17953 * was clicked matches a handle element. By default this is the linked
17954 * element, but there are times that you will want only a portion of the
17955 * linked element to initiate the drag operation, and the setHandleElId()
17956 * method provides a way to define this.</li>
17957 * <li>drag element: this represents the element that would be moved along
17958 * with the cursor during a drag operation. By default, this is the linked
17959 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
17960 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17963 * This class should not be instantiated until the onload event to ensure that
17964 * the associated elements are available.
17965 * The following would define a DragDrop obj that would interact with any
17966 * other DragDrop obj in the "group1" group:
17968 * dd = new Roo.dd.DragDrop("div1", "group1");
17970 * Since none of the event handlers have been implemented, nothing would
17971 * actually happen if you were to run the code above. Normally you would
17972 * override this class or one of the default implementations, but you can
17973 * also override the methods you want on an instance of the class...
17975 * dd.onDragDrop = function(e, id) {
17976 * alert("dd was dropped on " + id);
17980 * @param {String} id of the element that is linked to this instance
17981 * @param {String} sGroup the group of related DragDrop objects
17982 * @param {object} config an object containing configurable attributes
17983 * Valid properties for DragDrop:
17984 * padding, isTarget, maintainOffset, primaryButtonOnly
17986 Roo.dd.DragDrop = function(id, sGroup, config) {
17988 this.init(id, sGroup, config);
17993 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
17996 * The id of the element associated with this object. This is what we
17997 * refer to as the "linked element" because the size and position of
17998 * this element is used to determine when the drag and drop objects have
18006 * Configuration attributes passed into the constructor
18013 * The id of the element that will be dragged. By default this is same
18014 * as the linked element , but could be changed to another element. Ex:
18016 * @property dragElId
18023 * the id of the element that initiates the drag operation. By default
18024 * this is the linked element, but could be changed to be a child of this
18025 * element. This lets us do things like only starting the drag when the
18026 * header element within the linked html element is clicked.
18027 * @property handleElId
18034 * An associative array of HTML tags that will be ignored if clicked.
18035 * @property invalidHandleTypes
18036 * @type {string: string}
18038 invalidHandleTypes: null,
18041 * An associative array of ids for elements that will be ignored if clicked
18042 * @property invalidHandleIds
18043 * @type {string: string}
18045 invalidHandleIds: null,
18048 * An indexted array of css class names for elements that will be ignored
18050 * @property invalidHandleClasses
18053 invalidHandleClasses: null,
18056 * The linked element's absolute X position at the time the drag was
18058 * @property startPageX
18065 * The linked element's absolute X position at the time the drag was
18067 * @property startPageY
18074 * The group defines a logical collection of DragDrop objects that are
18075 * related. Instances only get events when interacting with other
18076 * DragDrop object in the same group. This lets us define multiple
18077 * groups using a single DragDrop subclass if we want.
18079 * @type {string: string}
18084 * Individual drag/drop instances can be locked. This will prevent
18085 * onmousedown start drag.
18093 * Lock this instance
18096 lock: function() { this.locked = true; },
18099 * Unlock this instace
18102 unlock: function() { this.locked = false; },
18105 * By default, all insances can be a drop target. This can be disabled by
18106 * setting isTarget to false.
18113 * The padding configured for this drag and drop object for calculating
18114 * the drop zone intersection with this object.
18121 * Cached reference to the linked element
18122 * @property _domRef
18128 * Internal typeof flag
18129 * @property __ygDragDrop
18132 __ygDragDrop: true,
18135 * Set to true when horizontal contraints are applied
18136 * @property constrainX
18143 * Set to true when vertical contraints are applied
18144 * @property constrainY
18151 * The left constraint
18159 * The right constraint
18167 * The up constraint
18176 * The down constraint
18184 * Maintain offsets when we resetconstraints. Set to true when you want
18185 * the position of the element relative to its parent to stay the same
18186 * when the page changes
18188 * @property maintainOffset
18191 maintainOffset: false,
18194 * Array of pixel locations the element will snap to if we specified a
18195 * horizontal graduation/interval. This array is generated automatically
18196 * when you define a tick interval.
18203 * Array of pixel locations the element will snap to if we specified a
18204 * vertical graduation/interval. This array is generated automatically
18205 * when you define a tick interval.
18212 * By default the drag and drop instance will only respond to the primary
18213 * button click (left button for a right-handed mouse). Set to true to
18214 * allow drag and drop to start with any mouse click that is propogated
18216 * @property primaryButtonOnly
18219 primaryButtonOnly: true,
18222 * The availabe property is false until the linked dom element is accessible.
18223 * @property available
18229 * By default, drags can only be initiated if the mousedown occurs in the
18230 * region the linked element is. This is done in part to work around a
18231 * bug in some browsers that mis-report the mousedown if the previous
18232 * mouseup happened outside of the window. This property is set to true
18233 * if outer handles are defined.
18235 * @property hasOuterHandles
18239 hasOuterHandles: false,
18242 * Code that executes immediately before the startDrag event
18243 * @method b4StartDrag
18246 b4StartDrag: function(x, y) { },
18249 * Abstract method called after a drag/drop object is clicked
18250 * and the drag or mousedown time thresholds have beeen met.
18251 * @method startDrag
18252 * @param {int} X click location
18253 * @param {int} Y click location
18255 startDrag: function(x, y) { /* override this */ },
18258 * Code that executes immediately before the onDrag event
18262 b4Drag: function(e) { },
18265 * Abstract method called during the onMouseMove event while dragging an
18268 * @param {Event} e the mousemove event
18270 onDrag: function(e) { /* override this */ },
18273 * Abstract method called when this element fist begins hovering over
18274 * another DragDrop obj
18275 * @method onDragEnter
18276 * @param {Event} e the mousemove event
18277 * @param {String|DragDrop[]} id In POINT mode, the element
18278 * id this is hovering over. In INTERSECT mode, an array of one or more
18279 * dragdrop items being hovered over.
18281 onDragEnter: function(e, id) { /* override this */ },
18284 * Code that executes immediately before the onDragOver event
18285 * @method b4DragOver
18288 b4DragOver: function(e) { },
18291 * Abstract method called when this element is hovering over another
18293 * @method onDragOver
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 dd items
18297 * being hovered over.
18299 onDragOver: function(e, id) { /* override this */ },
18302 * Code that executes immediately before the onDragOut event
18303 * @method b4DragOut
18306 b4DragOut: function(e) { },
18309 * Abstract method called when we are no longer hovering over an element
18310 * @method onDragOut
18311 * @param {Event} e the mousemove event
18312 * @param {String|DragDrop[]} id In POINT mode, the element
18313 * id this was hovering over. In INTERSECT mode, an array of dd items
18314 * that the mouse is no longer over.
18316 onDragOut: function(e, id) { /* override this */ },
18319 * Code that executes immediately before the onDragDrop event
18320 * @method b4DragDrop
18323 b4DragDrop: function(e) { },
18326 * Abstract method called when this item is dropped on another DragDrop
18328 * @method onDragDrop
18329 * @param {Event} e the mouseup event
18330 * @param {String|DragDrop[]} id In POINT mode, the element
18331 * id this was dropped on. In INTERSECT mode, an array of dd items this
18334 onDragDrop: function(e, id) { /* override this */ },
18337 * Abstract method called when this item is dropped on an area with no
18339 * @method onInvalidDrop
18340 * @param {Event} e the mouseup event
18342 onInvalidDrop: function(e) { /* override this */ },
18345 * Code that executes immediately before the endDrag event
18346 * @method b4EndDrag
18349 b4EndDrag: function(e) { },
18352 * Fired when we are done dragging the object
18354 * @param {Event} e the mouseup event
18356 endDrag: function(e) { /* override this */ },
18359 * Code executed immediately before the onMouseDown event
18360 * @method b4MouseDown
18361 * @param {Event} e the mousedown event
18364 b4MouseDown: function(e) { },
18367 * Event handler that fires when a drag/drop obj gets a mousedown
18368 * @method onMouseDown
18369 * @param {Event} e the mousedown event
18371 onMouseDown: function(e) { /* override this */ },
18374 * Event handler that fires when a drag/drop obj gets a mouseup
18375 * @method onMouseUp
18376 * @param {Event} e the mouseup event
18378 onMouseUp: function(e) { /* override this */ },
18381 * Override the onAvailable method to do what is needed after the initial
18382 * position was determined.
18383 * @method onAvailable
18385 onAvailable: function () {
18389 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18392 defaultPadding : {left:0, right:0, top:0, bottom:0},
18395 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18399 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18400 { dragElId: "existingProxyDiv" });
18401 dd.startDrag = function(){
18402 this.constrainTo("parent-id");
18405 * Or you can initalize it using the {@link Roo.Element} object:
18407 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18408 startDrag : function(){
18409 this.constrainTo("parent-id");
18413 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18414 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18415 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18416 * an object containing the sides to pad. For example: {right:10, bottom:10}
18417 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18419 constrainTo : function(constrainTo, pad, inContent){
18420 if(typeof pad == "number"){
18421 pad = {left: pad, right:pad, top:pad, bottom:pad};
18423 pad = pad || this.defaultPadding;
18424 var b = Roo.get(this.getEl()).getBox();
18425 var ce = Roo.get(constrainTo);
18426 var s = ce.getScroll();
18427 var c, cd = ce.dom;
18428 if(cd == document.body){
18429 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18432 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18436 var topSpace = b.y - c.y;
18437 var leftSpace = b.x - c.x;
18439 this.resetConstraints();
18440 this.setXConstraint(leftSpace - (pad.left||0), // left
18441 c.width - leftSpace - b.width - (pad.right||0) //right
18443 this.setYConstraint(topSpace - (pad.top||0), //top
18444 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18449 * Returns a reference to the linked element
18451 * @return {HTMLElement} the html element
18453 getEl: function() {
18454 if (!this._domRef) {
18455 this._domRef = Roo.getDom(this.id);
18458 return this._domRef;
18462 * Returns a reference to the actual element to drag. By default this is
18463 * the same as the html element, but it can be assigned to another
18464 * element. An example of this can be found in Roo.dd.DDProxy
18465 * @method getDragEl
18466 * @return {HTMLElement} the html element
18468 getDragEl: function() {
18469 return Roo.getDom(this.dragElId);
18473 * Sets up the DragDrop object. Must be called in the constructor of any
18474 * Roo.dd.DragDrop subclass
18476 * @param id the id of the linked element
18477 * @param {String} sGroup the group of related items
18478 * @param {object} config configuration attributes
18480 init: function(id, sGroup, config) {
18481 this.initTarget(id, sGroup, config);
18482 if (!Roo.isTouch) {
18483 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18485 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18486 // Event.on(this.id, "selectstart", Event.preventDefault);
18490 * Initializes Targeting functionality only... the object does not
18491 * get a mousedown handler.
18492 * @method initTarget
18493 * @param id the id of the linked element
18494 * @param {String} sGroup the group of related items
18495 * @param {object} config configuration attributes
18497 initTarget: function(id, sGroup, config) {
18499 // configuration attributes
18500 this.config = config || {};
18502 // create a local reference to the drag and drop manager
18503 this.DDM = Roo.dd.DDM;
18504 // initialize the groups array
18507 // assume that we have an element reference instead of an id if the
18508 // parameter is not a string
18509 if (typeof id !== "string") {
18516 // add to an interaction group
18517 this.addToGroup((sGroup) ? sGroup : "default");
18519 // We don't want to register this as the handle with the manager
18520 // so we just set the id rather than calling the setter.
18521 this.handleElId = id;
18523 // the linked element is the element that gets dragged by default
18524 this.setDragElId(id);
18526 // by default, clicked anchors will not start drag operations.
18527 this.invalidHandleTypes = { A: "A" };
18528 this.invalidHandleIds = {};
18529 this.invalidHandleClasses = [];
18531 this.applyConfig();
18533 this.handleOnAvailable();
18537 * Applies the configuration parameters that were passed into the constructor.
18538 * This is supposed to happen at each level through the inheritance chain. So
18539 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18540 * DragDrop in order to get all of the parameters that are available in
18542 * @method applyConfig
18544 applyConfig: function() {
18546 // configurable properties:
18547 // padding, isTarget, maintainOffset, primaryButtonOnly
18548 this.padding = this.config.padding || [0, 0, 0, 0];
18549 this.isTarget = (this.config.isTarget !== false);
18550 this.maintainOffset = (this.config.maintainOffset);
18551 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18556 * Executed when the linked element is available
18557 * @method handleOnAvailable
18560 handleOnAvailable: function() {
18561 this.available = true;
18562 this.resetConstraints();
18563 this.onAvailable();
18567 * Configures the padding for the target zone in px. Effectively expands
18568 * (or reduces) the virtual object size for targeting calculations.
18569 * Supports css-style shorthand; if only one parameter is passed, all sides
18570 * will have that padding, and if only two are passed, the top and bottom
18571 * will have the first param, the left and right the second.
18572 * @method setPadding
18573 * @param {int} iTop Top pad
18574 * @param {int} iRight Right pad
18575 * @param {int} iBot Bot pad
18576 * @param {int} iLeft Left pad
18578 setPadding: function(iTop, iRight, iBot, iLeft) {
18579 // this.padding = [iLeft, iRight, iTop, iBot];
18580 if (!iRight && 0 !== iRight) {
18581 this.padding = [iTop, iTop, iTop, iTop];
18582 } else if (!iBot && 0 !== iBot) {
18583 this.padding = [iTop, iRight, iTop, iRight];
18585 this.padding = [iTop, iRight, iBot, iLeft];
18590 * Stores the initial placement of the linked element.
18591 * @method setInitialPosition
18592 * @param {int} diffX the X offset, default 0
18593 * @param {int} diffY the Y offset, default 0
18595 setInitPosition: function(diffX, diffY) {
18596 var el = this.getEl();
18598 if (!this.DDM.verifyEl(el)) {
18602 var dx = diffX || 0;
18603 var dy = diffY || 0;
18605 var p = Dom.getXY( el );
18607 this.initPageX = p[0] - dx;
18608 this.initPageY = p[1] - dy;
18610 this.lastPageX = p[0];
18611 this.lastPageY = p[1];
18614 this.setStartPosition(p);
18618 * Sets the start position of the element. This is set when the obj
18619 * is initialized, the reset when a drag is started.
18620 * @method setStartPosition
18621 * @param pos current position (from previous lookup)
18624 setStartPosition: function(pos) {
18625 var p = pos || Dom.getXY( this.getEl() );
18626 this.deltaSetXY = null;
18628 this.startPageX = p[0];
18629 this.startPageY = p[1];
18633 * Add this instance to a group of related drag/drop objects. All
18634 * instances belong to at least one group, and can belong to as many
18635 * groups as needed.
18636 * @method addToGroup
18637 * @param sGroup {string} the name of the group
18639 addToGroup: function(sGroup) {
18640 this.groups[sGroup] = true;
18641 this.DDM.regDragDrop(this, sGroup);
18645 * Remove's this instance from the supplied interaction group
18646 * @method removeFromGroup
18647 * @param {string} sGroup The group to drop
18649 removeFromGroup: function(sGroup) {
18650 if (this.groups[sGroup]) {
18651 delete this.groups[sGroup];
18654 this.DDM.removeDDFromGroup(this, sGroup);
18658 * Allows you to specify that an element other than the linked element
18659 * will be moved with the cursor during a drag
18660 * @method setDragElId
18661 * @param id {string} the id of the element that will be used to initiate the drag
18663 setDragElId: function(id) {
18664 this.dragElId = id;
18668 * Allows you to specify a child of the linked element that should be
18669 * used to initiate the drag operation. An example of this would be if
18670 * you have a content div with text and links. Clicking anywhere in the
18671 * content area would normally start the drag operation. Use this method
18672 * to specify that an element inside of the content div is the element
18673 * that starts the drag operation.
18674 * @method setHandleElId
18675 * @param id {string} the id of the element that will be used to
18676 * initiate the drag.
18678 setHandleElId: function(id) {
18679 if (typeof id !== "string") {
18682 this.handleElId = id;
18683 this.DDM.regHandle(this.id, id);
18687 * Allows you to set an element outside of the linked element as a drag
18689 * @method setOuterHandleElId
18690 * @param id the id of the element that will be used to initiate the drag
18692 setOuterHandleElId: function(id) {
18693 if (typeof id !== "string") {
18696 Event.on(id, "mousedown",
18697 this.handleMouseDown, this);
18698 this.setHandleElId(id);
18700 this.hasOuterHandles = true;
18704 * Remove all drag and drop hooks for this element
18707 unreg: function() {
18708 Event.un(this.id, "mousedown",
18709 this.handleMouseDown);
18710 Event.un(this.id, "touchstart",
18711 this.handleMouseDown);
18712 this._domRef = null;
18713 this.DDM._remove(this);
18716 destroy : function(){
18721 * Returns true if this instance is locked, or the drag drop mgr is locked
18722 * (meaning that all drag/drop is disabled on the page.)
18724 * @return {boolean} true if this obj or all drag/drop is locked, else
18727 isLocked: function() {
18728 return (this.DDM.isLocked() || this.locked);
18732 * Fired when this object is clicked
18733 * @method handleMouseDown
18735 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18738 handleMouseDown: function(e, oDD){
18740 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18741 //Roo.log('not touch/ button !=0');
18744 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18745 return; // double touch..
18749 if (this.isLocked()) {
18750 //Roo.log('locked');
18754 this.DDM.refreshCache(this.groups);
18755 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18756 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18757 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18758 //Roo.log('no outer handes or not over target');
18761 // Roo.log('check validator');
18762 if (this.clickValidator(e)) {
18763 // Roo.log('validate success');
18764 // set the initial element position
18765 this.setStartPosition();
18768 this.b4MouseDown(e);
18769 this.onMouseDown(e);
18771 this.DDM.handleMouseDown(e, this);
18773 this.DDM.stopEvent(e);
18781 clickValidator: function(e) {
18782 var target = e.getTarget();
18783 return ( this.isValidHandleChild(target) &&
18784 (this.id == this.handleElId ||
18785 this.DDM.handleWasClicked(target, this.id)) );
18789 * Allows you to specify a tag name that should not start a drag operation
18790 * when clicked. This is designed to facilitate embedding links within a
18791 * drag handle that do something other than start the drag.
18792 * @method addInvalidHandleType
18793 * @param {string} tagName the type of element to exclude
18795 addInvalidHandleType: function(tagName) {
18796 var type = tagName.toUpperCase();
18797 this.invalidHandleTypes[type] = type;
18801 * Lets you to specify an element id for a child of a drag handle
18802 * that should not initiate a drag
18803 * @method addInvalidHandleId
18804 * @param {string} id the element id of the element you wish to ignore
18806 addInvalidHandleId: function(id) {
18807 if (typeof id !== "string") {
18810 this.invalidHandleIds[id] = id;
18814 * Lets you specify a css class of elements that will not initiate a drag
18815 * @method addInvalidHandleClass
18816 * @param {string} cssClass the class of the elements you wish to ignore
18818 addInvalidHandleClass: function(cssClass) {
18819 this.invalidHandleClasses.push(cssClass);
18823 * Unsets an excluded tag name set by addInvalidHandleType
18824 * @method removeInvalidHandleType
18825 * @param {string} tagName the type of element to unexclude
18827 removeInvalidHandleType: function(tagName) {
18828 var type = tagName.toUpperCase();
18829 // this.invalidHandleTypes[type] = null;
18830 delete this.invalidHandleTypes[type];
18834 * Unsets an invalid handle id
18835 * @method removeInvalidHandleId
18836 * @param {string} id the id of the element to re-enable
18838 removeInvalidHandleId: function(id) {
18839 if (typeof id !== "string") {
18842 delete this.invalidHandleIds[id];
18846 * Unsets an invalid css class
18847 * @method removeInvalidHandleClass
18848 * @param {string} cssClass the class of the element(s) you wish to
18851 removeInvalidHandleClass: function(cssClass) {
18852 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18853 if (this.invalidHandleClasses[i] == cssClass) {
18854 delete this.invalidHandleClasses[i];
18860 * Checks the tag exclusion list to see if this click should be ignored
18861 * @method isValidHandleChild
18862 * @param {HTMLElement} node the HTMLElement to evaluate
18863 * @return {boolean} true if this is a valid tag type, false if not
18865 isValidHandleChild: function(node) {
18868 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18871 nodeName = node.nodeName.toUpperCase();
18873 nodeName = node.nodeName;
18875 valid = valid && !this.invalidHandleTypes[nodeName];
18876 valid = valid && !this.invalidHandleIds[node.id];
18878 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18879 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18888 * Create the array of horizontal tick marks if an interval was specified
18889 * in setXConstraint().
18890 * @method setXTicks
18893 setXTicks: function(iStartX, iTickSize) {
18895 this.xTickSize = iTickSize;
18899 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18901 this.xTicks[this.xTicks.length] = i;
18906 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18908 this.xTicks[this.xTicks.length] = i;
18913 this.xTicks.sort(this.DDM.numericSort) ;
18917 * Create the array of vertical tick marks if an interval was specified in
18918 * setYConstraint().
18919 * @method setYTicks
18922 setYTicks: function(iStartY, iTickSize) {
18924 this.yTickSize = iTickSize;
18928 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18930 this.yTicks[this.yTicks.length] = i;
18935 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18937 this.yTicks[this.yTicks.length] = i;
18942 this.yTicks.sort(this.DDM.numericSort) ;
18946 * By default, the element can be dragged any place on the screen. Use
18947 * this method to limit the horizontal travel of the element. Pass in
18948 * 0,0 for the parameters if you want to lock the drag to the y axis.
18949 * @method setXConstraint
18950 * @param {int} iLeft the number of pixels the element can move to the left
18951 * @param {int} iRight the number of pixels the element can move to the
18953 * @param {int} iTickSize optional parameter for specifying that the
18955 * should move iTickSize pixels at a time.
18957 setXConstraint: function(iLeft, iRight, iTickSize) {
18958 this.leftConstraint = iLeft;
18959 this.rightConstraint = iRight;
18961 this.minX = this.initPageX - iLeft;
18962 this.maxX = this.initPageX + iRight;
18963 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18965 this.constrainX = true;
18969 * Clears any constraints applied to this instance. Also clears ticks
18970 * since they can't exist independent of a constraint at this time.
18971 * @method clearConstraints
18973 clearConstraints: function() {
18974 this.constrainX = false;
18975 this.constrainY = false;
18980 * Clears any tick interval defined for this instance
18981 * @method clearTicks
18983 clearTicks: function() {
18984 this.xTicks = null;
18985 this.yTicks = null;
18986 this.xTickSize = 0;
18987 this.yTickSize = 0;
18991 * By default, the element can be dragged any place on the screen. Set
18992 * this to limit the vertical travel of the element. Pass in 0,0 for the
18993 * parameters if you want to lock the drag to the x axis.
18994 * @method setYConstraint
18995 * @param {int} iUp the number of pixels the element can move up
18996 * @param {int} iDown the number of pixels the element can move down
18997 * @param {int} iTickSize optional parameter for specifying that the
18998 * element should move iTickSize pixels at a time.
19000 setYConstraint: function(iUp, iDown, iTickSize) {
19001 this.topConstraint = iUp;
19002 this.bottomConstraint = iDown;
19004 this.minY = this.initPageY - iUp;
19005 this.maxY = this.initPageY + iDown;
19006 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19008 this.constrainY = true;
19013 * resetConstraints must be called if you manually reposition a dd element.
19014 * @method resetConstraints
19015 * @param {boolean} maintainOffset
19017 resetConstraints: function() {
19020 // Maintain offsets if necessary
19021 if (this.initPageX || this.initPageX === 0) {
19022 // figure out how much this thing has moved
19023 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19024 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19026 this.setInitPosition(dx, dy);
19028 // This is the first time we have detected the element's position
19030 this.setInitPosition();
19033 if (this.constrainX) {
19034 this.setXConstraint( this.leftConstraint,
19035 this.rightConstraint,
19039 if (this.constrainY) {
19040 this.setYConstraint( this.topConstraint,
19041 this.bottomConstraint,
19047 * Normally the drag element is moved pixel by pixel, but we can specify
19048 * that it move a number of pixels at a time. This method resolves the
19049 * location when we have it set up like this.
19051 * @param {int} val where we want to place the object
19052 * @param {int[]} tickArray sorted array of valid points
19053 * @return {int} the closest tick
19056 getTick: function(val, tickArray) {
19059 // If tick interval is not defined, it is effectively 1 pixel,
19060 // so we return the value passed to us.
19062 } else if (tickArray[0] >= val) {
19063 // The value is lower than the first tick, so we return the first
19065 return tickArray[0];
19067 for (var i=0, len=tickArray.length; i<len; ++i) {
19069 if (tickArray[next] && tickArray[next] >= val) {
19070 var diff1 = val - tickArray[i];
19071 var diff2 = tickArray[next] - val;
19072 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19076 // The value is larger than the last tick, so we return the last
19078 return tickArray[tickArray.length - 1];
19085 * @return {string} string representation of the dd obj
19087 toString: function() {
19088 return ("DragDrop " + this.id);
19096 * Ext JS Library 1.1.1
19097 * Copyright(c) 2006-2007, Ext JS, LLC.
19099 * Originally Released Under LGPL - original licence link has changed is not relivant.
19102 * <script type="text/javascript">
19107 * The drag and drop utility provides a framework for building drag and drop
19108 * applications. In addition to enabling drag and drop for specific elements,
19109 * the drag and drop elements are tracked by the manager class, and the
19110 * interactions between the various elements are tracked during the drag and
19111 * the implementing code is notified about these important moments.
19114 // Only load the library once. Rewriting the manager class would orphan
19115 // existing drag and drop instances.
19116 if (!Roo.dd.DragDropMgr) {
19119 * @class Roo.dd.DragDropMgr
19120 * DragDropMgr is a singleton that tracks the element interaction for
19121 * all DragDrop items in the window. Generally, you will not call
19122 * this class directly, but it does have helper methods that could
19123 * be useful in your DragDrop implementations.
19126 Roo.dd.DragDropMgr = function() {
19128 var Event = Roo.EventManager;
19133 * Two dimensional Array of registered DragDrop objects. The first
19134 * dimension is the DragDrop item group, the second the DragDrop
19137 * @type {string: string}
19144 * Array of element ids defined as drag handles. Used to determine
19145 * if the element that generated the mousedown event is actually the
19146 * handle and not the html element itself.
19147 * @property handleIds
19148 * @type {string: string}
19155 * the DragDrop object that is currently being dragged
19156 * @property dragCurrent
19164 * the DragDrop object(s) that are being hovered over
19165 * @property dragOvers
19173 * the X distance between the cursor and the object being dragged
19182 * the Y distance between the cursor and the object being dragged
19191 * Flag to determine if we should prevent the default behavior of the
19192 * events we define. By default this is true, but this can be set to
19193 * false if you need the default behavior (not recommended)
19194 * @property preventDefault
19198 preventDefault: true,
19201 * Flag to determine if we should stop the propagation of the events
19202 * we generate. This is true by default but you may want to set it to
19203 * false if the html element contains other features that require the
19205 * @property stopPropagation
19209 stopPropagation: true,
19212 * Internal flag that is set to true when drag and drop has been
19214 * @property initialized
19221 * All drag and drop can be disabled.
19229 * Called the first time an element is registered.
19235 this.initialized = true;
19239 * In point mode, drag and drop interaction is defined by the
19240 * location of the cursor during the drag/drop
19248 * In intersect mode, drag and drop interactio nis defined by the
19249 * overlap of two or more drag and drop objects.
19250 * @property INTERSECT
19257 * The current drag and drop mode. Default: POINT
19265 * Runs method on all drag and drop objects
19266 * @method _execOnAll
19270 _execOnAll: function(sMethod, args) {
19271 for (var i in this.ids) {
19272 for (var j in this.ids[i]) {
19273 var oDD = this.ids[i][j];
19274 if (! this.isTypeOfDD(oDD)) {
19277 oDD[sMethod].apply(oDD, args);
19283 * Drag and drop initialization. Sets up the global event handlers
19288 _onLoad: function() {
19292 if (!Roo.isTouch) {
19293 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19294 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19296 Event.on(document, "touchend", this.handleMouseUp, this, true);
19297 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19299 Event.on(window, "unload", this._onUnload, this, true);
19300 Event.on(window, "resize", this._onResize, this, true);
19301 // Event.on(window, "mouseout", this._test);
19306 * Reset constraints on all drag and drop objs
19307 * @method _onResize
19311 _onResize: function(e) {
19312 this._execOnAll("resetConstraints", []);
19316 * Lock all drag and drop functionality
19320 lock: function() { this.locked = true; },
19323 * Unlock all drag and drop functionality
19327 unlock: function() { this.locked = false; },
19330 * Is drag and drop locked?
19332 * @return {boolean} True if drag and drop is locked, false otherwise.
19335 isLocked: function() { return this.locked; },
19338 * Location cache that is set for all drag drop objects when a drag is
19339 * initiated, cleared when the drag is finished.
19340 * @property locationCache
19347 * Set useCache to false if you want to force object the lookup of each
19348 * drag and drop linked element constantly during a drag.
19349 * @property useCache
19356 * The number of pixels that the mouse needs to move after the
19357 * mousedown before the drag is initiated. Default=3;
19358 * @property clickPixelThresh
19362 clickPixelThresh: 3,
19365 * The number of milliseconds after the mousedown event to initiate the
19366 * drag if we don't get a mouseup event. Default=1000
19367 * @property clickTimeThresh
19371 clickTimeThresh: 350,
19374 * Flag that indicates that either the drag pixel threshold or the
19375 * mousdown time threshold has been met
19376 * @property dragThreshMet
19381 dragThreshMet: false,
19384 * Timeout used for the click time threshold
19385 * @property clickTimeout
19390 clickTimeout: null,
19393 * The X position of the mousedown event stored for later use when a
19394 * drag threshold is met.
19403 * The Y position of the mousedown event stored for later use when a
19404 * drag threshold is met.
19413 * Each DragDrop instance must be registered with the DragDropMgr.
19414 * This is executed in DragDrop.init()
19415 * @method regDragDrop
19416 * @param {DragDrop} oDD the DragDrop object to register
19417 * @param {String} sGroup the name of the group this element belongs to
19420 regDragDrop: function(oDD, sGroup) {
19421 if (!this.initialized) { this.init(); }
19423 if (!this.ids[sGroup]) {
19424 this.ids[sGroup] = {};
19426 this.ids[sGroup][oDD.id] = oDD;
19430 * Removes the supplied dd instance from the supplied group. Executed
19431 * by DragDrop.removeFromGroup, so don't call this function directly.
19432 * @method removeDDFromGroup
19436 removeDDFromGroup: function(oDD, sGroup) {
19437 if (!this.ids[sGroup]) {
19438 this.ids[sGroup] = {};
19441 var obj = this.ids[sGroup];
19442 if (obj && obj[oDD.id]) {
19443 delete obj[oDD.id];
19448 * Unregisters a drag and drop item. This is executed in
19449 * DragDrop.unreg, use that method instead of calling this directly.
19454 _remove: function(oDD) {
19455 for (var g in oDD.groups) {
19456 if (g && this.ids[g][oDD.id]) {
19457 delete this.ids[g][oDD.id];
19460 delete this.handleIds[oDD.id];
19464 * Each DragDrop handle element must be registered. This is done
19465 * automatically when executing DragDrop.setHandleElId()
19466 * @method regHandle
19467 * @param {String} sDDId the DragDrop id this element is a handle for
19468 * @param {String} sHandleId the id of the element that is the drag
19472 regHandle: function(sDDId, sHandleId) {
19473 if (!this.handleIds[sDDId]) {
19474 this.handleIds[sDDId] = {};
19476 this.handleIds[sDDId][sHandleId] = sHandleId;
19480 * Utility function to determine if a given element has been
19481 * registered as a drag drop item.
19482 * @method isDragDrop
19483 * @param {String} id the element id to check
19484 * @return {boolean} true if this element is a DragDrop item,
19488 isDragDrop: function(id) {
19489 return ( this.getDDById(id) ) ? true : false;
19493 * Returns the drag and drop instances that are in all groups the
19494 * passed in instance belongs to.
19495 * @method getRelated
19496 * @param {DragDrop} p_oDD the obj to get related data for
19497 * @param {boolean} bTargetsOnly if true, only return targetable objs
19498 * @return {DragDrop[]} the related instances
19501 getRelated: function(p_oDD, bTargetsOnly) {
19503 for (var i in p_oDD.groups) {
19504 for (j in this.ids[i]) {
19505 var dd = this.ids[i][j];
19506 if (! this.isTypeOfDD(dd)) {
19509 if (!bTargetsOnly || dd.isTarget) {
19510 oDDs[oDDs.length] = dd;
19519 * Returns true if the specified dd target is a legal target for
19520 * the specifice drag obj
19521 * @method isLegalTarget
19522 * @param {DragDrop} the drag obj
19523 * @param {DragDrop} the target
19524 * @return {boolean} true if the target is a legal target for the
19528 isLegalTarget: function (oDD, oTargetDD) {
19529 var targets = this.getRelated(oDD, true);
19530 for (var i=0, len=targets.length;i<len;++i) {
19531 if (targets[i].id == oTargetDD.id) {
19540 * My goal is to be able to transparently determine if an object is
19541 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19542 * returns "object", oDD.constructor.toString() always returns
19543 * "DragDrop" and not the name of the subclass. So for now it just
19544 * evaluates a well-known variable in DragDrop.
19545 * @method isTypeOfDD
19546 * @param {Object} the object to evaluate
19547 * @return {boolean} true if typeof oDD = DragDrop
19550 isTypeOfDD: function (oDD) {
19551 return (oDD && oDD.__ygDragDrop);
19555 * Utility function to determine if a given element has been
19556 * registered as a drag drop handle for the given Drag Drop object.
19558 * @param {String} id the element id to check
19559 * @return {boolean} true if this element is a DragDrop handle, false
19563 isHandle: function(sDDId, sHandleId) {
19564 return ( this.handleIds[sDDId] &&
19565 this.handleIds[sDDId][sHandleId] );
19569 * Returns the DragDrop instance for a given id
19570 * @method getDDById
19571 * @param {String} id the id of the DragDrop object
19572 * @return {DragDrop} the drag drop object, null if it is not found
19575 getDDById: function(id) {
19576 for (var i in this.ids) {
19577 if (this.ids[i][id]) {
19578 return this.ids[i][id];
19585 * Fired after a registered DragDrop object gets the mousedown event.
19586 * Sets up the events required to track the object being dragged
19587 * @method handleMouseDown
19588 * @param {Event} e the event
19589 * @param oDD the DragDrop object being dragged
19593 handleMouseDown: function(e, oDD) {
19595 Roo.QuickTips.disable();
19597 this.currentTarget = e.getTarget();
19599 this.dragCurrent = oDD;
19601 var el = oDD.getEl();
19603 // track start position
19604 this.startX = e.getPageX();
19605 this.startY = e.getPageY();
19607 this.deltaX = this.startX - el.offsetLeft;
19608 this.deltaY = this.startY - el.offsetTop;
19610 this.dragThreshMet = false;
19612 this.clickTimeout = setTimeout(
19614 var DDM = Roo.dd.DDM;
19615 DDM.startDrag(DDM.startX, DDM.startY);
19617 this.clickTimeThresh );
19621 * Fired when either the drag pixel threshol or the mousedown hold
19622 * time threshold has been met.
19623 * @method startDrag
19624 * @param x {int} the X position of the original mousedown
19625 * @param y {int} the Y position of the original mousedown
19628 startDrag: function(x, y) {
19629 clearTimeout(this.clickTimeout);
19630 if (this.dragCurrent) {
19631 this.dragCurrent.b4StartDrag(x, y);
19632 this.dragCurrent.startDrag(x, y);
19634 this.dragThreshMet = true;
19638 * Internal function to handle the mouseup event. Will be invoked
19639 * from the context of the document.
19640 * @method handleMouseUp
19641 * @param {Event} e the event
19645 handleMouseUp: function(e) {
19648 Roo.QuickTips.enable();
19650 if (! this.dragCurrent) {
19654 clearTimeout(this.clickTimeout);
19656 if (this.dragThreshMet) {
19657 this.fireEvents(e, true);
19667 * Utility to stop event propagation and event default, if these
19668 * features are turned on.
19669 * @method stopEvent
19670 * @param {Event} e the event as returned by this.getEvent()
19673 stopEvent: function(e){
19674 if(this.stopPropagation) {
19675 e.stopPropagation();
19678 if (this.preventDefault) {
19679 e.preventDefault();
19684 * Internal function to clean up event handlers after the drag
19685 * operation is complete
19687 * @param {Event} e the event
19691 stopDrag: function(e) {
19692 // Fire the drag end event for the item that was dragged
19693 if (this.dragCurrent) {
19694 if (this.dragThreshMet) {
19695 this.dragCurrent.b4EndDrag(e);
19696 this.dragCurrent.endDrag(e);
19699 this.dragCurrent.onMouseUp(e);
19702 this.dragCurrent = null;
19703 this.dragOvers = {};
19707 * Internal function to handle the mousemove event. Will be invoked
19708 * from the context of the html element.
19710 * @TODO figure out what we can do about mouse events lost when the
19711 * user drags objects beyond the window boundary. Currently we can
19712 * detect this in internet explorer by verifying that the mouse is
19713 * down during the mousemove event. Firefox doesn't give us the
19714 * button state on the mousemove event.
19715 * @method handleMouseMove
19716 * @param {Event} e the event
19720 handleMouseMove: function(e) {
19721 if (! this.dragCurrent) {
19725 // var button = e.which || e.button;
19727 // check for IE mouseup outside of page boundary
19728 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19730 return this.handleMouseUp(e);
19733 if (!this.dragThreshMet) {
19734 var diffX = Math.abs(this.startX - e.getPageX());
19735 var diffY = Math.abs(this.startY - e.getPageY());
19736 if (diffX > this.clickPixelThresh ||
19737 diffY > this.clickPixelThresh) {
19738 this.startDrag(this.startX, this.startY);
19742 if (this.dragThreshMet) {
19743 this.dragCurrent.b4Drag(e);
19744 this.dragCurrent.onDrag(e);
19745 if(!this.dragCurrent.moveOnly){
19746 this.fireEvents(e, false);
19756 * Iterates over all of the DragDrop elements to find ones we are
19757 * hovering over or dropping on
19758 * @method fireEvents
19759 * @param {Event} e the event
19760 * @param {boolean} isDrop is this a drop op or a mouseover op?
19764 fireEvents: function(e, isDrop) {
19765 var dc = this.dragCurrent;
19767 // If the user did the mouse up outside of the window, we could
19768 // get here even though we have ended the drag.
19769 if (!dc || dc.isLocked()) {
19773 var pt = e.getPoint();
19775 // cache the previous dragOver array
19781 var enterEvts = [];
19783 // Check to see if the object(s) we were hovering over is no longer
19784 // being hovered over so we can fire the onDragOut event
19785 for (var i in this.dragOvers) {
19787 var ddo = this.dragOvers[i];
19789 if (! this.isTypeOfDD(ddo)) {
19793 if (! this.isOverTarget(pt, ddo, this.mode)) {
19794 outEvts.push( ddo );
19797 oldOvers[i] = true;
19798 delete this.dragOvers[i];
19801 for (var sGroup in dc.groups) {
19803 if ("string" != typeof sGroup) {
19807 for (i in this.ids[sGroup]) {
19808 var oDD = this.ids[sGroup][i];
19809 if (! this.isTypeOfDD(oDD)) {
19813 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19814 if (this.isOverTarget(pt, oDD, this.mode)) {
19815 // look for drop interactions
19817 dropEvts.push( oDD );
19818 // look for drag enter and drag over interactions
19821 // initial drag over: dragEnter fires
19822 if (!oldOvers[oDD.id]) {
19823 enterEvts.push( oDD );
19824 // subsequent drag overs: dragOver fires
19826 overEvts.push( oDD );
19829 this.dragOvers[oDD.id] = oDD;
19837 if (outEvts.length) {
19838 dc.b4DragOut(e, outEvts);
19839 dc.onDragOut(e, outEvts);
19842 if (enterEvts.length) {
19843 dc.onDragEnter(e, enterEvts);
19846 if (overEvts.length) {
19847 dc.b4DragOver(e, overEvts);
19848 dc.onDragOver(e, overEvts);
19851 if (dropEvts.length) {
19852 dc.b4DragDrop(e, dropEvts);
19853 dc.onDragDrop(e, dropEvts);
19857 // fire dragout events
19859 for (i=0, len=outEvts.length; i<len; ++i) {
19860 dc.b4DragOut(e, outEvts[i].id);
19861 dc.onDragOut(e, outEvts[i].id);
19864 // fire enter events
19865 for (i=0,len=enterEvts.length; i<len; ++i) {
19866 // dc.b4DragEnter(e, oDD.id);
19867 dc.onDragEnter(e, enterEvts[i].id);
19870 // fire over events
19871 for (i=0,len=overEvts.length; i<len; ++i) {
19872 dc.b4DragOver(e, overEvts[i].id);
19873 dc.onDragOver(e, overEvts[i].id);
19876 // fire drop events
19877 for (i=0, len=dropEvts.length; i<len; ++i) {
19878 dc.b4DragDrop(e, dropEvts[i].id);
19879 dc.onDragDrop(e, dropEvts[i].id);
19884 // notify about a drop that did not find a target
19885 if (isDrop && !dropEvts.length) {
19886 dc.onInvalidDrop(e);
19892 * Helper function for getting the best match from the list of drag
19893 * and drop objects returned by the drag and drop events when we are
19894 * in INTERSECT mode. It returns either the first object that the
19895 * cursor is over, or the object that has the greatest overlap with
19896 * the dragged element.
19897 * @method getBestMatch
19898 * @param {DragDrop[]} dds The array of drag and drop objects
19900 * @return {DragDrop} The best single match
19903 getBestMatch: function(dds) {
19905 // Return null if the input is not what we expect
19906 //if (!dds || !dds.length || dds.length == 0) {
19908 // If there is only one item, it wins
19909 //} else if (dds.length == 1) {
19911 var len = dds.length;
19916 // Loop through the targeted items
19917 for (var i=0; i<len; ++i) {
19919 // If the cursor is over the object, it wins. If the
19920 // cursor is over multiple matches, the first one we come
19922 if (dd.cursorIsOver) {
19925 // Otherwise the object with the most overlap wins
19928 winner.overlap.getArea() < dd.overlap.getArea()) {
19939 * Refreshes the cache of the top-left and bottom-right points of the
19940 * drag and drop objects in the specified group(s). This is in the
19941 * format that is stored in the drag and drop instance, so typical
19944 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19948 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19950 * @TODO this really should be an indexed array. Alternatively this
19951 * method could accept both.
19952 * @method refreshCache
19953 * @param {Object} groups an associative array of groups to refresh
19956 refreshCache: function(groups) {
19957 for (var sGroup in groups) {
19958 if ("string" != typeof sGroup) {
19961 for (var i in this.ids[sGroup]) {
19962 var oDD = this.ids[sGroup][i];
19964 if (this.isTypeOfDD(oDD)) {
19965 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19966 var loc = this.getLocation(oDD);
19968 this.locationCache[oDD.id] = loc;
19970 delete this.locationCache[oDD.id];
19971 // this will unregister the drag and drop object if
19972 // the element is not in a usable state
19981 * This checks to make sure an element exists and is in the DOM. The
19982 * main purpose is to handle cases where innerHTML is used to remove
19983 * drag and drop objects from the DOM. IE provides an 'unspecified
19984 * error' when trying to access the offsetParent of such an element
19986 * @param {HTMLElement} el the element to check
19987 * @return {boolean} true if the element looks usable
19990 verifyEl: function(el) {
19995 parent = el.offsetParent;
19998 parent = el.offsetParent;
20009 * Returns a Region object containing the drag and drop element's position
20010 * and size, including the padding configured for it
20011 * @method getLocation
20012 * @param {DragDrop} oDD the drag and drop object to get the
20014 * @return {Roo.lib.Region} a Region object representing the total area
20015 * the element occupies, including any padding
20016 * the instance is configured for.
20019 getLocation: function(oDD) {
20020 if (! this.isTypeOfDD(oDD)) {
20024 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20027 pos= Roo.lib.Dom.getXY(el);
20035 x2 = x1 + el.offsetWidth;
20037 y2 = y1 + el.offsetHeight;
20039 t = y1 - oDD.padding[0];
20040 r = x2 + oDD.padding[1];
20041 b = y2 + oDD.padding[2];
20042 l = x1 - oDD.padding[3];
20044 return new Roo.lib.Region( t, r, b, l );
20048 * Checks the cursor location to see if it over the target
20049 * @method isOverTarget
20050 * @param {Roo.lib.Point} pt The point to evaluate
20051 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20052 * @return {boolean} true if the mouse is over the target
20056 isOverTarget: function(pt, oTarget, intersect) {
20057 // use cache if available
20058 var loc = this.locationCache[oTarget.id];
20059 if (!loc || !this.useCache) {
20060 loc = this.getLocation(oTarget);
20061 this.locationCache[oTarget.id] = loc;
20069 oTarget.cursorIsOver = loc.contains( pt );
20071 // DragDrop is using this as a sanity check for the initial mousedown
20072 // in this case we are done. In POINT mode, if the drag obj has no
20073 // contraints, we are also done. Otherwise we need to evaluate the
20074 // location of the target as related to the actual location of the
20075 // dragged element.
20076 var dc = this.dragCurrent;
20077 if (!dc || !dc.getTargetCoord ||
20078 (!intersect && !dc.constrainX && !dc.constrainY)) {
20079 return oTarget.cursorIsOver;
20082 oTarget.overlap = null;
20084 // Get the current location of the drag element, this is the
20085 // location of the mouse event less the delta that represents
20086 // where the original mousedown happened on the element. We
20087 // need to consider constraints and ticks as well.
20088 var pos = dc.getTargetCoord(pt.x, pt.y);
20090 var el = dc.getDragEl();
20091 var curRegion = new Roo.lib.Region( pos.y,
20092 pos.x + el.offsetWidth,
20093 pos.y + el.offsetHeight,
20096 var overlap = curRegion.intersect(loc);
20099 oTarget.overlap = overlap;
20100 return (intersect) ? true : oTarget.cursorIsOver;
20107 * unload event handler
20108 * @method _onUnload
20112 _onUnload: function(e, me) {
20113 Roo.dd.DragDropMgr.unregAll();
20117 * Cleans up the drag and drop events and objects.
20122 unregAll: function() {
20124 if (this.dragCurrent) {
20126 this.dragCurrent = null;
20129 this._execOnAll("unreg", []);
20131 for (i in this.elementCache) {
20132 delete this.elementCache[i];
20135 this.elementCache = {};
20140 * A cache of DOM elements
20141 * @property elementCache
20148 * Get the wrapper for the DOM element specified
20149 * @method getElWrapper
20150 * @param {String} id the id of the element to get
20151 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20153 * @deprecated This wrapper isn't that useful
20156 getElWrapper: function(id) {
20157 var oWrapper = this.elementCache[id];
20158 if (!oWrapper || !oWrapper.el) {
20159 oWrapper = this.elementCache[id] =
20160 new this.ElementWrapper(Roo.getDom(id));
20166 * Returns the actual DOM element
20167 * @method getElement
20168 * @param {String} id the id of the elment to get
20169 * @return {Object} The element
20170 * @deprecated use Roo.getDom instead
20173 getElement: function(id) {
20174 return Roo.getDom(id);
20178 * Returns the style property for the DOM element (i.e.,
20179 * document.getElById(id).style)
20181 * @param {String} id the id of the elment to get
20182 * @return {Object} The style property of the element
20183 * @deprecated use Roo.getDom instead
20186 getCss: function(id) {
20187 var el = Roo.getDom(id);
20188 return (el) ? el.style : null;
20192 * Inner class for cached elements
20193 * @class DragDropMgr.ElementWrapper
20198 ElementWrapper: function(el) {
20203 this.el = el || null;
20208 this.id = this.el && el.id;
20210 * A reference to the style property
20213 this.css = this.el && el.style;
20217 * Returns the X position of an html element
20219 * @param el the element for which to get the position
20220 * @return {int} the X coordinate
20222 * @deprecated use Roo.lib.Dom.getX instead
20225 getPosX: function(el) {
20226 return Roo.lib.Dom.getX(el);
20230 * Returns the Y position of an html element
20232 * @param el the element for which to get the position
20233 * @return {int} the Y coordinate
20234 * @deprecated use Roo.lib.Dom.getY instead
20237 getPosY: function(el) {
20238 return Roo.lib.Dom.getY(el);
20242 * Swap two nodes. In IE, we use the native method, for others we
20243 * emulate the IE behavior
20245 * @param n1 the first node to swap
20246 * @param n2 the other node to swap
20249 swapNode: function(n1, n2) {
20253 var p = n2.parentNode;
20254 var s = n2.nextSibling;
20257 p.insertBefore(n1, n2);
20258 } else if (n2 == n1.nextSibling) {
20259 p.insertBefore(n2, n1);
20261 n1.parentNode.replaceChild(n2, n1);
20262 p.insertBefore(n1, s);
20268 * Returns the current scroll position
20269 * @method getScroll
20273 getScroll: function () {
20274 var t, l, dde=document.documentElement, db=document.body;
20275 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20277 l = dde.scrollLeft;
20284 return { top: t, left: l };
20288 * Returns the specified element style property
20290 * @param {HTMLElement} el the element
20291 * @param {string} styleProp the style property
20292 * @return {string} The value of the style property
20293 * @deprecated use Roo.lib.Dom.getStyle
20296 getStyle: function(el, styleProp) {
20297 return Roo.fly(el).getStyle(styleProp);
20301 * Gets the scrollTop
20302 * @method getScrollTop
20303 * @return {int} the document's scrollTop
20306 getScrollTop: function () { return this.getScroll().top; },
20309 * Gets the scrollLeft
20310 * @method getScrollLeft
20311 * @return {int} the document's scrollTop
20314 getScrollLeft: function () { return this.getScroll().left; },
20317 * Sets the x/y position of an element to the location of the
20320 * @param {HTMLElement} moveEl The element to move
20321 * @param {HTMLElement} targetEl The position reference element
20324 moveToEl: function (moveEl, targetEl) {
20325 var aCoord = Roo.lib.Dom.getXY(targetEl);
20326 Roo.lib.Dom.setXY(moveEl, aCoord);
20330 * Numeric array sort function
20331 * @method numericSort
20334 numericSort: function(a, b) { return (a - b); },
20338 * @property _timeoutCount
20345 * Trying to make the load order less important. Without this we get
20346 * an error if this file is loaded before the Event Utility.
20347 * @method _addListeners
20351 _addListeners: function() {
20352 var DDM = Roo.dd.DDM;
20353 if ( Roo.lib.Event && document ) {
20356 if (DDM._timeoutCount > 2000) {
20358 setTimeout(DDM._addListeners, 10);
20359 if (document && document.body) {
20360 DDM._timeoutCount += 1;
20367 * Recursively searches the immediate parent and all child nodes for
20368 * the handle element in order to determine wheter or not it was
20370 * @method handleWasClicked
20371 * @param node the html element to inspect
20374 handleWasClicked: function(node, id) {
20375 if (this.isHandle(id, node.id)) {
20378 // check to see if this is a text node child of the one we want
20379 var p = node.parentNode;
20382 if (this.isHandle(id, p.id)) {
20397 // shorter alias, save a few bytes
20398 Roo.dd.DDM = Roo.dd.DragDropMgr;
20399 Roo.dd.DDM._addListeners();
20403 * Ext JS Library 1.1.1
20404 * Copyright(c) 2006-2007, Ext JS, LLC.
20406 * Originally Released Under LGPL - original licence link has changed is not relivant.
20409 * <script type="text/javascript">
20414 * A DragDrop implementation where the linked element follows the
20415 * mouse cursor during a drag.
20416 * @extends Roo.dd.DragDrop
20418 * @param {String} id the id of the linked element
20419 * @param {String} sGroup the group of related DragDrop items
20420 * @param {object} config an object containing configurable attributes
20421 * Valid properties for DD:
20424 Roo.dd.DD = function(id, sGroup, config) {
20426 this.init(id, sGroup, config);
20430 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20433 * When set to true, the utility automatically tries to scroll the browser
20434 * window wehn a drag and drop element is dragged near the viewport boundary.
20435 * Defaults to true.
20442 * Sets the pointer offset to the distance between the linked element's top
20443 * left corner and the location the element was clicked
20444 * @method autoOffset
20445 * @param {int} iPageX the X coordinate of the click
20446 * @param {int} iPageY the Y coordinate of the click
20448 autoOffset: function(iPageX, iPageY) {
20449 var x = iPageX - this.startPageX;
20450 var y = iPageY - this.startPageY;
20451 this.setDelta(x, y);
20455 * Sets the pointer offset. You can call this directly to force the
20456 * offset to be in a particular location (e.g., pass in 0,0 to set it
20457 * to the center of the object)
20459 * @param {int} iDeltaX the distance from the left
20460 * @param {int} iDeltaY the distance from the top
20462 setDelta: function(iDeltaX, iDeltaY) {
20463 this.deltaX = iDeltaX;
20464 this.deltaY = iDeltaY;
20468 * Sets the drag element to the location of the mousedown or click event,
20469 * maintaining the cursor location relative to the location on the element
20470 * that was clicked. Override this if you want to place the element in a
20471 * location other than where the cursor is.
20472 * @method setDragElPos
20473 * @param {int} iPageX the X coordinate of the mousedown or drag event
20474 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20476 setDragElPos: function(iPageX, iPageY) {
20477 // the first time we do this, we are going to check to make sure
20478 // the element has css positioning
20480 var el = this.getDragEl();
20481 this.alignElWithMouse(el, iPageX, iPageY);
20485 * Sets the element to the location of the mousedown or click event,
20486 * maintaining the cursor location relative to the location on the element
20487 * that was clicked. Override this if you want to place the element in a
20488 * location other than where the cursor is.
20489 * @method alignElWithMouse
20490 * @param {HTMLElement} el the element to move
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 alignElWithMouse: function(el, iPageX, iPageY) {
20495 var oCoord = this.getTargetCoord(iPageX, iPageY);
20496 var fly = el.dom ? el : Roo.fly(el);
20497 if (!this.deltaSetXY) {
20498 var aCoord = [oCoord.x, oCoord.y];
20500 var newLeft = fly.getLeft(true);
20501 var newTop = fly.getTop(true);
20502 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20504 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20507 this.cachePosition(oCoord.x, oCoord.y);
20508 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20513 * Saves the most recent position so that we can reset the constraints and
20514 * tick marks on-demand. We need to know this so that we can calculate the
20515 * number of pixels the element is offset from its original position.
20516 * @method cachePosition
20517 * @param iPageX the current x position (optional, this just makes it so we
20518 * don't have to look it up again)
20519 * @param iPageY the current y position (optional, this just makes it so we
20520 * don't have to look it up again)
20522 cachePosition: function(iPageX, iPageY) {
20524 this.lastPageX = iPageX;
20525 this.lastPageY = iPageY;
20527 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20528 this.lastPageX = aCoord[0];
20529 this.lastPageY = aCoord[1];
20534 * Auto-scroll the window if the dragged object has been moved beyond the
20535 * visible window boundary.
20536 * @method autoScroll
20537 * @param {int} x the drag element's x position
20538 * @param {int} y the drag element's y position
20539 * @param {int} h the height of the drag element
20540 * @param {int} w the width of the drag element
20543 autoScroll: function(x, y, h, w) {
20546 // The client height
20547 var clientH = Roo.lib.Dom.getViewWidth();
20549 // The client width
20550 var clientW = Roo.lib.Dom.getViewHeight();
20552 // The amt scrolled down
20553 var st = this.DDM.getScrollTop();
20555 // The amt scrolled right
20556 var sl = this.DDM.getScrollLeft();
20558 // Location of the bottom of the element
20561 // Location of the right of the element
20564 // The distance from the cursor to the bottom of the visible area,
20565 // adjusted so that we don't scroll if the cursor is beyond the
20566 // element drag constraints
20567 var toBot = (clientH + st - y - this.deltaY);
20569 // The distance from the cursor to the right of the visible area
20570 var toRight = (clientW + sl - x - this.deltaX);
20573 // How close to the edge the cursor must be before we scroll
20574 // var thresh = (document.all) ? 100 : 40;
20577 // How many pixels to scroll per autoscroll op. This helps to reduce
20578 // clunky scrolling. IE is more sensitive about this ... it needs this
20579 // value to be higher.
20580 var scrAmt = (document.all) ? 80 : 30;
20582 // Scroll down if we are near the bottom of the visible page and the
20583 // obj extends below the crease
20584 if ( bot > clientH && toBot < thresh ) {
20585 window.scrollTo(sl, st + scrAmt);
20588 // Scroll up if the window is scrolled down and the top of the object
20589 // goes above the top border
20590 if ( y < st && st > 0 && y - st < thresh ) {
20591 window.scrollTo(sl, st - scrAmt);
20594 // Scroll right if the obj is beyond the right border and the cursor is
20595 // near the border.
20596 if ( right > clientW && toRight < thresh ) {
20597 window.scrollTo(sl + scrAmt, st);
20600 // Scroll left if the window has been scrolled to the right and the obj
20601 // extends past the left border
20602 if ( x < sl && sl > 0 && x - sl < thresh ) {
20603 window.scrollTo(sl - scrAmt, st);
20609 * Finds the location the element should be placed if we want to move
20610 * it to where the mouse location less the click offset would place us.
20611 * @method getTargetCoord
20612 * @param {int} iPageX the X coordinate of the click
20613 * @param {int} iPageY the Y coordinate of the click
20614 * @return an object that contains the coordinates (Object.x and Object.y)
20617 getTargetCoord: function(iPageX, iPageY) {
20620 var x = iPageX - this.deltaX;
20621 var y = iPageY - this.deltaY;
20623 if (this.constrainX) {
20624 if (x < this.minX) { x = this.minX; }
20625 if (x > this.maxX) { x = this.maxX; }
20628 if (this.constrainY) {
20629 if (y < this.minY) { y = this.minY; }
20630 if (y > this.maxY) { y = this.maxY; }
20633 x = this.getTick(x, this.xTicks);
20634 y = this.getTick(y, this.yTicks);
20641 * Sets up config options specific to this class. Overrides
20642 * Roo.dd.DragDrop, but all versions of this method through the
20643 * inheritance chain are called
20645 applyConfig: function() {
20646 Roo.dd.DD.superclass.applyConfig.call(this);
20647 this.scroll = (this.config.scroll !== false);
20651 * Event that fires prior to the onMouseDown event. Overrides
20654 b4MouseDown: function(e) {
20655 // this.resetConstraints();
20656 this.autoOffset(e.getPageX(),
20661 * Event that fires prior to the onDrag event. Overrides
20664 b4Drag: function(e) {
20665 this.setDragElPos(e.getPageX(),
20669 toString: function() {
20670 return ("DD " + this.id);
20673 //////////////////////////////////////////////////////////////////////////
20674 // Debugging ygDragDrop events that can be overridden
20675 //////////////////////////////////////////////////////////////////////////
20677 startDrag: function(x, y) {
20680 onDrag: function(e) {
20683 onDragEnter: function(e, id) {
20686 onDragOver: function(e, id) {
20689 onDragOut: function(e, id) {
20692 onDragDrop: function(e, id) {
20695 endDrag: function(e) {
20702 * Ext JS Library 1.1.1
20703 * Copyright(c) 2006-2007, Ext JS, LLC.
20705 * Originally Released Under LGPL - original licence link has changed is not relivant.
20708 * <script type="text/javascript">
20712 * @class Roo.dd.DDProxy
20713 * A DragDrop implementation that inserts an empty, bordered div into
20714 * the document that follows the cursor during drag operations. At the time of
20715 * the click, the frame div is resized to the dimensions of the linked html
20716 * element, and moved to the exact location of the linked element.
20718 * References to the "frame" element refer to the single proxy element that
20719 * was created to be dragged in place of all DDProxy elements on the
20722 * @extends Roo.dd.DD
20724 * @param {String} id the id of the linked html element
20725 * @param {String} sGroup the group of related DragDrop objects
20726 * @param {object} config an object containing configurable attributes
20727 * Valid properties for DDProxy in addition to those in DragDrop:
20728 * resizeFrame, centerFrame, dragElId
20730 Roo.dd.DDProxy = function(id, sGroup, config) {
20732 this.init(id, sGroup, config);
20738 * The default drag frame div id
20739 * @property Roo.dd.DDProxy.dragElId
20743 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20745 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20748 * By default we resize the drag frame to be the same size as the element
20749 * we want to drag (this is to get the frame effect). We can turn it off
20750 * if we want a different behavior.
20751 * @property resizeFrame
20757 * By default the frame is positioned exactly where the drag element is, so
20758 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20759 * you do not have constraints on the obj is to have the drag frame centered
20760 * around the cursor. Set centerFrame to true for this effect.
20761 * @property centerFrame
20764 centerFrame: false,
20767 * Creates the proxy element if it does not yet exist
20768 * @method createFrame
20770 createFrame: function() {
20772 var body = document.body;
20774 if (!body || !body.firstChild) {
20775 setTimeout( function() { self.createFrame(); }, 50 );
20779 var div = this.getDragEl();
20782 div = document.createElement("div");
20783 div.id = this.dragElId;
20786 s.position = "absolute";
20787 s.visibility = "hidden";
20789 s.border = "2px solid #aaa";
20792 // appendChild can blow up IE if invoked prior to the window load event
20793 // while rendering a table. It is possible there are other scenarios
20794 // that would cause this to happen as well.
20795 body.insertBefore(div, body.firstChild);
20800 * Initialization for the drag frame element. Must be called in the
20801 * constructor of all subclasses
20802 * @method initFrame
20804 initFrame: function() {
20805 this.createFrame();
20808 applyConfig: function() {
20809 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20811 this.resizeFrame = (this.config.resizeFrame !== false);
20812 this.centerFrame = (this.config.centerFrame);
20813 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20817 * Resizes the drag frame to the dimensions of the clicked object, positions
20818 * it over the object, and finally displays it
20819 * @method showFrame
20820 * @param {int} iPageX X click position
20821 * @param {int} iPageY Y click position
20824 showFrame: function(iPageX, iPageY) {
20825 var el = this.getEl();
20826 var dragEl = this.getDragEl();
20827 var s = dragEl.style;
20829 this._resizeProxy();
20831 if (this.centerFrame) {
20832 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20833 Math.round(parseInt(s.height, 10)/2) );
20836 this.setDragElPos(iPageX, iPageY);
20838 Roo.fly(dragEl).show();
20842 * The proxy is automatically resized to the dimensions of the linked
20843 * element when a drag is initiated, unless resizeFrame is set to false
20844 * @method _resizeProxy
20847 _resizeProxy: function() {
20848 if (this.resizeFrame) {
20849 var el = this.getEl();
20850 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20854 // overrides Roo.dd.DragDrop
20855 b4MouseDown: function(e) {
20856 var x = e.getPageX();
20857 var y = e.getPageY();
20858 this.autoOffset(x, y);
20859 this.setDragElPos(x, y);
20862 // overrides Roo.dd.DragDrop
20863 b4StartDrag: function(x, y) {
20864 // show the drag frame
20865 this.showFrame(x, y);
20868 // overrides Roo.dd.DragDrop
20869 b4EndDrag: function(e) {
20870 Roo.fly(this.getDragEl()).hide();
20873 // overrides Roo.dd.DragDrop
20874 // By default we try to move the element to the last location of the frame.
20875 // This is so that the default behavior mirrors that of Roo.dd.DD.
20876 endDrag: function(e) {
20878 var lel = this.getEl();
20879 var del = this.getDragEl();
20881 // Show the drag frame briefly so we can get its position
20882 del.style.visibility = "";
20885 // Hide the linked element before the move to get around a Safari
20887 lel.style.visibility = "hidden";
20888 Roo.dd.DDM.moveToEl(lel, del);
20889 del.style.visibility = "hidden";
20890 lel.style.visibility = "";
20895 beforeMove : function(){
20899 afterDrag : function(){
20903 toString: function() {
20904 return ("DDProxy " + this.id);
20910 * Ext JS Library 1.1.1
20911 * Copyright(c) 2006-2007, Ext JS, LLC.
20913 * Originally Released Under LGPL - original licence link has changed is not relivant.
20916 * <script type="text/javascript">
20920 * @class Roo.dd.DDTarget
20921 * A DragDrop implementation that does not move, but can be a drop
20922 * target. You would get the same result by simply omitting implementation
20923 * for the event callbacks, but this way we reduce the processing cost of the
20924 * event listener and the callbacks.
20925 * @extends Roo.dd.DragDrop
20927 * @param {String} id the id of the element that is a drop target
20928 * @param {String} sGroup the group of related DragDrop objects
20929 * @param {object} config an object containing configurable attributes
20930 * Valid properties for DDTarget in addition to those in
20934 Roo.dd.DDTarget = function(id, sGroup, config) {
20936 this.initTarget(id, sGroup, config);
20938 if (config.listeners || config.events) {
20939 Roo.dd.DragDrop.superclass.constructor.call(this, {
20940 listeners : config.listeners || {},
20941 events : config.events || {}
20946 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20947 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20948 toString: function() {
20949 return ("DDTarget " + this.id);
20954 * Ext JS Library 1.1.1
20955 * Copyright(c) 2006-2007, Ext JS, LLC.
20957 * Originally Released Under LGPL - original licence link has changed is not relivant.
20960 * <script type="text/javascript">
20965 * @class Roo.dd.ScrollManager
20966 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20967 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
20970 Roo.dd.ScrollManager = function(){
20971 var ddm = Roo.dd.DragDropMgr;
20978 var onStop = function(e){
20983 var triggerRefresh = function(){
20984 if(ddm.dragCurrent){
20985 ddm.refreshCache(ddm.dragCurrent.groups);
20989 var doScroll = function(){
20990 if(ddm.dragCurrent){
20991 var dds = Roo.dd.ScrollManager;
20993 if(proc.el.scroll(proc.dir, dds.increment)){
20997 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21002 var clearProc = function(){
21004 clearInterval(proc.id);
21011 var startProc = function(el, dir){
21012 Roo.log('scroll startproc');
21016 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21019 var onFire = function(e, isDrop){
21021 if(isDrop || !ddm.dragCurrent){ return; }
21022 var dds = Roo.dd.ScrollManager;
21023 if(!dragEl || dragEl != ddm.dragCurrent){
21024 dragEl = ddm.dragCurrent;
21025 // refresh regions on drag start
21026 dds.refreshCache();
21029 var xy = Roo.lib.Event.getXY(e);
21030 var pt = new Roo.lib.Point(xy[0], xy[1]);
21031 for(var id in els){
21032 var el = els[id], r = el._region;
21033 if(r && r.contains(pt) && el.isScrollable()){
21034 if(r.bottom - pt.y <= dds.thresh){
21036 startProc(el, "down");
21039 }else if(r.right - pt.x <= dds.thresh){
21041 startProc(el, "left");
21044 }else if(pt.y - r.top <= dds.thresh){
21046 startProc(el, "up");
21049 }else if(pt.x - r.left <= dds.thresh){
21051 startProc(el, "right");
21060 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21061 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21065 * Registers new overflow element(s) to auto scroll
21066 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21068 register : function(el){
21069 if(el instanceof Array){
21070 for(var i = 0, len = el.length; i < len; i++) {
21071 this.register(el[i]);
21077 Roo.dd.ScrollManager.els = els;
21081 * Unregisters overflow element(s) so they are no longer scrolled
21082 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21084 unregister : function(el){
21085 if(el instanceof Array){
21086 for(var i = 0, len = el.length; i < len; i++) {
21087 this.unregister(el[i]);
21096 * The number of pixels from the edge of a container the pointer needs to be to
21097 * trigger scrolling (defaults to 25)
21103 * The number of pixels to scroll in each scroll increment (defaults to 50)
21109 * The frequency of scrolls in milliseconds (defaults to 500)
21115 * True to animate the scroll (defaults to true)
21121 * The animation duration in seconds -
21122 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21128 * Manually trigger a cache refresh.
21130 refreshCache : function(){
21131 for(var id in els){
21132 if(typeof els[id] == 'object'){ // for people extending the object prototype
21133 els[id]._region = els[id].getRegion();
21140 * Ext JS Library 1.1.1
21141 * Copyright(c) 2006-2007, Ext JS, LLC.
21143 * Originally Released Under LGPL - original licence link has changed is not relivant.
21146 * <script type="text/javascript">
21151 * @class Roo.dd.Registry
21152 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21153 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21156 Roo.dd.Registry = function(){
21159 var autoIdSeed = 0;
21161 var getId = function(el, autogen){
21162 if(typeof el == "string"){
21166 if(!id && autogen !== false){
21167 id = "roodd-" + (++autoIdSeed);
21175 * Register a drag drop element
21176 * @param {String|HTMLElement} element The id or DOM node to register
21177 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21178 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21179 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21180 * populated in the data object (if applicable):
21182 Value Description<br />
21183 --------- ------------------------------------------<br />
21184 handles Array of DOM nodes that trigger dragging<br />
21185 for the element being registered<br />
21186 isHandle True if the element passed in triggers<br />
21187 dragging itself, else false
21190 register : function(el, data){
21192 if(typeof el == "string"){
21193 el = document.getElementById(el);
21196 elements[getId(el)] = data;
21197 if(data.isHandle !== false){
21198 handles[data.ddel.id] = data;
21201 var hs = data.handles;
21202 for(var i = 0, len = hs.length; i < len; i++){
21203 handles[getId(hs[i])] = data;
21209 * Unregister a drag drop element
21210 * @param {String|HTMLElement} element The id or DOM node to unregister
21212 unregister : function(el){
21213 var id = getId(el, false);
21214 var data = elements[id];
21216 delete elements[id];
21218 var hs = data.handles;
21219 for(var i = 0, len = hs.length; i < len; i++){
21220 delete handles[getId(hs[i], false)];
21227 * Returns the handle registered for a DOM Node by id
21228 * @param {String|HTMLElement} id The DOM node or id to look up
21229 * @return {Object} handle The custom handle data
21231 getHandle : function(id){
21232 if(typeof id != "string"){ // must be element?
21235 return handles[id];
21239 * Returns the handle that is registered for the DOM node that is the target of the event
21240 * @param {Event} e The event
21241 * @return {Object} handle The custom handle data
21243 getHandleFromEvent : function(e){
21244 var t = Roo.lib.Event.getTarget(e);
21245 return t ? handles[t.id] : null;
21249 * Returns a custom data object that is registered for a DOM node by id
21250 * @param {String|HTMLElement} id The DOM node or id to look up
21251 * @return {Object} data The custom data
21253 getTarget : function(id){
21254 if(typeof id != "string"){ // must be element?
21257 return elements[id];
21261 * Returns a custom data object that is registered for the DOM node that is the target of the event
21262 * @param {Event} e The event
21263 * @return {Object} data The custom data
21265 getTargetFromEvent : function(e){
21266 var t = Roo.lib.Event.getTarget(e);
21267 return t ? elements[t.id] || handles[t.id] : null;
21272 * Ext JS Library 1.1.1
21273 * Copyright(c) 2006-2007, Ext JS, LLC.
21275 * Originally Released Under LGPL - original licence link has changed is not relivant.
21278 * <script type="text/javascript">
21283 * @class Roo.dd.StatusProxy
21284 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21285 * default drag proxy used by all Roo.dd components.
21287 * @param {Object} config
21289 Roo.dd.StatusProxy = function(config){
21290 Roo.apply(this, config);
21291 this.id = this.id || Roo.id();
21292 this.el = new Roo.Layer({
21294 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21295 {tag: "div", cls: "x-dd-drop-icon"},
21296 {tag: "div", cls: "x-dd-drag-ghost"}
21299 shadow: !config || config.shadow !== false
21301 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21302 this.dropStatus = this.dropNotAllowed;
21305 Roo.dd.StatusProxy.prototype = {
21307 * @cfg {String} dropAllowed
21308 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21310 dropAllowed : "x-dd-drop-ok",
21312 * @cfg {String} dropNotAllowed
21313 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21315 dropNotAllowed : "x-dd-drop-nodrop",
21318 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21319 * over the current target element.
21320 * @param {String} cssClass The css class for the new drop status indicator image
21322 setStatus : function(cssClass){
21323 cssClass = cssClass || this.dropNotAllowed;
21324 if(this.dropStatus != cssClass){
21325 this.el.replaceClass(this.dropStatus, cssClass);
21326 this.dropStatus = cssClass;
21331 * Resets the status indicator to the default dropNotAllowed value
21332 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21334 reset : function(clearGhost){
21335 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21336 this.dropStatus = this.dropNotAllowed;
21338 this.ghost.update("");
21343 * Updates the contents of the ghost element
21344 * @param {String} html The html that will replace the current innerHTML of the ghost element
21346 update : function(html){
21347 if(typeof html == "string"){
21348 this.ghost.update(html);
21350 this.ghost.update("");
21351 html.style.margin = "0";
21352 this.ghost.dom.appendChild(html);
21354 // ensure float = none set?? cant remember why though.
21355 var el = this.ghost.dom.firstChild;
21357 Roo.fly(el).setStyle('float', 'none');
21362 * Returns the underlying proxy {@link Roo.Layer}
21363 * @return {Roo.Layer} el
21365 getEl : function(){
21370 * Returns the ghost element
21371 * @return {Roo.Element} el
21373 getGhost : function(){
21379 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21381 hide : function(clear){
21389 * Stops the repair animation if it's currently running
21392 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21398 * Displays this proxy
21405 * Force the Layer to sync its shadow and shim positions to the element
21412 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21413 * invalid drop operation by the item being dragged.
21414 * @param {Array} xy The XY position of the element ([x, y])
21415 * @param {Function} callback The function to call after the repair is complete
21416 * @param {Object} scope The scope in which to execute the callback
21418 repair : function(xy, callback, scope){
21419 this.callback = callback;
21420 this.scope = scope;
21421 if(xy && this.animRepair !== false){
21422 this.el.addClass("x-dd-drag-repair");
21423 this.el.hideUnders(true);
21424 this.anim = this.el.shift({
21425 duration: this.repairDuration || .5,
21429 callback: this.afterRepair,
21433 this.afterRepair();
21438 afterRepair : function(){
21440 if(typeof this.callback == "function"){
21441 this.callback.call(this.scope || this);
21443 this.callback = null;
21448 * Ext JS Library 1.1.1
21449 * Copyright(c) 2006-2007, Ext JS, LLC.
21451 * Originally Released Under LGPL - original licence link has changed is not relivant.
21454 * <script type="text/javascript">
21458 * @class Roo.dd.DragSource
21459 * @extends Roo.dd.DDProxy
21460 * A simple class that provides the basic implementation needed to make any element draggable.
21462 * @param {String/HTMLElement/Element} el The container element
21463 * @param {Object} config
21465 Roo.dd.DragSource = function(el, config){
21466 this.el = Roo.get(el);
21467 this.dragData = {};
21469 Roo.apply(this, config);
21472 this.proxy = new Roo.dd.StatusProxy();
21475 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21476 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21478 this.dragging = false;
21481 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21483 * @cfg {String} dropAllowed
21484 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21486 dropAllowed : "x-dd-drop-ok",
21488 * @cfg {String} dropNotAllowed
21489 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21491 dropNotAllowed : "x-dd-drop-nodrop",
21494 * Returns the data object associated with this drag source
21495 * @return {Object} data An object containing arbitrary data
21497 getDragData : function(e){
21498 return this.dragData;
21502 onDragEnter : function(e, id){
21503 var target = Roo.dd.DragDropMgr.getDDById(id);
21504 this.cachedTarget = target;
21505 if(this.beforeDragEnter(target, e, id) !== false){
21506 if(target.isNotifyTarget){
21507 var status = target.notifyEnter(this, e, this.dragData);
21508 this.proxy.setStatus(status);
21510 this.proxy.setStatus(this.dropAllowed);
21513 if(this.afterDragEnter){
21515 * An empty function by default, but provided so that you can perform a custom action
21516 * when the dragged item enters the drop target by providing an implementation.
21517 * @param {Roo.dd.DragDrop} target The drop target
21518 * @param {Event} e The event object
21519 * @param {String} id The id of the dragged element
21520 * @method afterDragEnter
21522 this.afterDragEnter(target, e, id);
21528 * An empty function by default, but provided so that you can perform a custom action
21529 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21530 * @param {Roo.dd.DragDrop} target The drop target
21531 * @param {Event} e The event object
21532 * @param {String} id The id of the dragged element
21533 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21535 beforeDragEnter : function(target, e, id){
21540 alignElWithMouse: function() {
21541 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21546 onDragOver : function(e, id){
21547 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21548 if(this.beforeDragOver(target, e, id) !== false){
21549 if(target.isNotifyTarget){
21550 var status = target.notifyOver(this, e, this.dragData);
21551 this.proxy.setStatus(status);
21554 if(this.afterDragOver){
21556 * An empty function by default, but provided so that you can perform a custom action
21557 * while the dragged item is over the drop target by providing an implementation.
21558 * @param {Roo.dd.DragDrop} target The drop target
21559 * @param {Event} e The event object
21560 * @param {String} id The id of the dragged element
21561 * @method afterDragOver
21563 this.afterDragOver(target, e, id);
21569 * An empty function by default, but provided so that you can perform a custom action
21570 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21571 * @param {Roo.dd.DragDrop} target The drop target
21572 * @param {Event} e The event object
21573 * @param {String} id The id of the dragged element
21574 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21576 beforeDragOver : function(target, e, id){
21581 onDragOut : function(e, id){
21582 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21583 if(this.beforeDragOut(target, e, id) !== false){
21584 if(target.isNotifyTarget){
21585 target.notifyOut(this, e, this.dragData);
21587 this.proxy.reset();
21588 if(this.afterDragOut){
21590 * An empty function by default, but provided so that you can perform a custom action
21591 * after the dragged item is dragged out of the target without dropping.
21592 * @param {Roo.dd.DragDrop} target The drop target
21593 * @param {Event} e The event object
21594 * @param {String} id The id of the dragged element
21595 * @method afterDragOut
21597 this.afterDragOut(target, e, id);
21600 this.cachedTarget = null;
21604 * An empty function by default, but provided so that you can perform a custom action before the dragged
21605 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21606 * @param {Roo.dd.DragDrop} target The drop target
21607 * @param {Event} e The event object
21608 * @param {String} id The id of the dragged element
21609 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21611 beforeDragOut : function(target, e, id){
21616 onDragDrop : function(e, id){
21617 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21618 if(this.beforeDragDrop(target, e, id) !== false){
21619 if(target.isNotifyTarget){
21620 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21621 this.onValidDrop(target, e, id);
21623 this.onInvalidDrop(target, e, id);
21626 this.onValidDrop(target, e, id);
21629 if(this.afterDragDrop){
21631 * An empty function by default, but provided so that you can perform a custom action
21632 * after a valid drag drop has occurred by providing an implementation.
21633 * @param {Roo.dd.DragDrop} target The drop target
21634 * @param {Event} e The event object
21635 * @param {String} id The id of the dropped element
21636 * @method afterDragDrop
21638 this.afterDragDrop(target, e, id);
21641 delete this.cachedTarget;
21645 * An empty function by default, but provided so that you can perform a custom action before the dragged
21646 * item is dropped onto the target and optionally cancel the onDragDrop.
21647 * @param {Roo.dd.DragDrop} target The drop target
21648 * @param {Event} e The event object
21649 * @param {String} id The id of the dragged element
21650 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21652 beforeDragDrop : function(target, e, id){
21657 onValidDrop : function(target, e, id){
21659 if(this.afterValidDrop){
21661 * An empty function by default, but provided so that you can perform a custom action
21662 * after a valid drop has occurred by providing an implementation.
21663 * @param {Object} target The target DD
21664 * @param {Event} e The event object
21665 * @param {String} id The id of the dropped element
21666 * @method afterInvalidDrop
21668 this.afterValidDrop(target, e, id);
21673 getRepairXY : function(e, data){
21674 return this.el.getXY();
21678 onInvalidDrop : function(target, e, id){
21679 this.beforeInvalidDrop(target, e, id);
21680 if(this.cachedTarget){
21681 if(this.cachedTarget.isNotifyTarget){
21682 this.cachedTarget.notifyOut(this, e, this.dragData);
21684 this.cacheTarget = null;
21686 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21688 if(this.afterInvalidDrop){
21690 * An empty function by default, but provided so that you can perform a custom action
21691 * after an invalid drop has occurred by providing an implementation.
21692 * @param {Event} e The event object
21693 * @param {String} id The id of the dropped element
21694 * @method afterInvalidDrop
21696 this.afterInvalidDrop(e, id);
21701 afterRepair : function(){
21703 this.el.highlight(this.hlColor || "c3daf9");
21705 this.dragging = false;
21709 * An empty function by default, but provided so that you can perform a custom action after an invalid
21710 * drop has occurred.
21711 * @param {Roo.dd.DragDrop} target The drop target
21712 * @param {Event} e The event object
21713 * @param {String} id The id of the dragged element
21714 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21716 beforeInvalidDrop : function(target, e, id){
21721 handleMouseDown : function(e){
21722 if(this.dragging) {
21725 var data = this.getDragData(e);
21726 if(data && this.onBeforeDrag(data, e) !== false){
21727 this.dragData = data;
21729 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21734 * An empty function by default, but provided so that you can perform a custom action before the initial
21735 * drag event begins and optionally cancel it.
21736 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21737 * @param {Event} e The event object
21738 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21740 onBeforeDrag : function(data, e){
21745 * An empty function by default, but provided so that you can perform a custom action once the initial
21746 * drag event has begun. The drag cannot be canceled from this function.
21747 * @param {Number} x The x position of the click on the dragged object
21748 * @param {Number} y The y position of the click on the dragged object
21750 onStartDrag : Roo.emptyFn,
21752 // private - YUI override
21753 startDrag : function(x, y){
21754 this.proxy.reset();
21755 this.dragging = true;
21756 this.proxy.update("");
21757 this.onInitDrag(x, y);
21762 onInitDrag : function(x, y){
21763 var clone = this.el.dom.cloneNode(true);
21764 clone.id = Roo.id(); // prevent duplicate ids
21765 this.proxy.update(clone);
21766 this.onStartDrag(x, y);
21771 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21772 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21774 getProxy : function(){
21779 * Hides the drag source's {@link Roo.dd.StatusProxy}
21781 hideProxy : function(){
21783 this.proxy.reset(true);
21784 this.dragging = false;
21788 triggerCacheRefresh : function(){
21789 Roo.dd.DDM.refreshCache(this.groups);
21792 // private - override to prevent hiding
21793 b4EndDrag: function(e) {
21796 // private - override to prevent moving
21797 endDrag : function(e){
21798 this.onEndDrag(this.dragData, e);
21802 onEndDrag : function(data, e){
21805 // private - pin to cursor
21806 autoOffset : function(x, y) {
21807 this.setDelta(-12, -20);
21811 * Ext JS Library 1.1.1
21812 * Copyright(c) 2006-2007, Ext JS, LLC.
21814 * Originally Released Under LGPL - original licence link has changed is not relivant.
21817 * <script type="text/javascript">
21822 * @class Roo.dd.DropTarget
21823 * @extends Roo.dd.DDTarget
21824 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21825 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21827 * @param {String/HTMLElement/Element} el The container element
21828 * @param {Object} config
21830 Roo.dd.DropTarget = function(el, config){
21831 this.el = Roo.get(el);
21833 var listeners = false; ;
21834 if (config && config.listeners) {
21835 listeners= config.listeners;
21836 delete config.listeners;
21838 Roo.apply(this, config);
21840 if(this.containerScroll){
21841 Roo.dd.ScrollManager.register(this.el);
21845 * @scope Roo.dd.DropTarget
21850 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21851 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21852 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21854 * IMPORTANT : it should set this.overClass and this.dropAllowed
21856 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21857 * @param {Event} e The event
21858 * @param {Object} data An object containing arbitrary data supplied by the drag source
21864 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21865 * This method will be called on every mouse movement while the drag source is over the drop target.
21866 * This default implementation simply returns the dropAllowed config value.
21868 * IMPORTANT : it should set this.dropAllowed
21870 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21871 * @param {Event} e The event
21872 * @param {Object} data An object containing arbitrary data supplied by the drag source
21878 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21879 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21880 * overClass (if any) from the drop element.
21882 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21883 * @param {Event} e The event
21884 * @param {Object} data An object containing arbitrary data supplied by the drag source
21890 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21891 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21892 * implementation that does something to process the drop event and returns true so that the drag source's
21893 * repair action does not run.
21895 * IMPORTANT : it should set this.success
21897 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21898 * @param {Event} e The event
21899 * @param {Object} data An object containing arbitrary data supplied by the drag source
21905 Roo.dd.DropTarget.superclass.constructor.call( this,
21907 this.ddGroup || this.group,
21910 listeners : listeners || {}
21918 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21920 * @cfg {String} overClass
21921 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21924 * @cfg {String} ddGroup
21925 * The drag drop group to handle drop events for
21929 * @cfg {String} dropAllowed
21930 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21932 dropAllowed : "x-dd-drop-ok",
21934 * @cfg {String} dropNotAllowed
21935 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21937 dropNotAllowed : "x-dd-drop-nodrop",
21939 * @cfg {boolean} success
21940 * set this after drop listener..
21944 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21945 * if the drop point is valid for over/enter..
21952 isNotifyTarget : true,
21957 notifyEnter : function(dd, e, data)
21960 this.fireEvent('enter', dd, e, data);
21961 if(this.overClass){
21962 this.el.addClass(this.overClass);
21964 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21965 this.valid ? this.dropAllowed : this.dropNotAllowed
21972 notifyOver : function(dd, e, data)
21975 this.fireEvent('over', dd, e, data);
21976 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21977 this.valid ? this.dropAllowed : this.dropNotAllowed
21984 notifyOut : function(dd, e, data)
21986 this.fireEvent('out', dd, e, data);
21987 if(this.overClass){
21988 this.el.removeClass(this.overClass);
21995 notifyDrop : function(dd, e, data)
21997 this.success = false;
21998 this.fireEvent('drop', dd, e, data);
21999 return this.success;
22003 * Ext JS Library 1.1.1
22004 * Copyright(c) 2006-2007, Ext JS, LLC.
22006 * Originally Released Under LGPL - original licence link has changed is not relivant.
22009 * <script type="text/javascript">
22014 * @class Roo.dd.DragZone
22015 * @extends Roo.dd.DragSource
22016 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22017 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22019 * @param {String/HTMLElement/Element} el The container element
22020 * @param {Object} config
22022 Roo.dd.DragZone = function(el, config){
22023 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22024 if(this.containerScroll){
22025 Roo.dd.ScrollManager.register(this.el);
22029 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22031 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22032 * for auto scrolling during drag operations.
22035 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22036 * method after a failed drop (defaults to "c3daf9" - light blue)
22040 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22041 * for a valid target to drag based on the mouse down. Override this method
22042 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22043 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22044 * @param {EventObject} e The mouse down event
22045 * @return {Object} The dragData
22047 getDragData : function(e){
22048 return Roo.dd.Registry.getHandleFromEvent(e);
22052 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22053 * this.dragData.ddel
22054 * @param {Number} x The x position of the click on the dragged object
22055 * @param {Number} y The y position of the click on the dragged object
22056 * @return {Boolean} true to continue the drag, false to cancel
22058 onInitDrag : function(x, y){
22059 this.proxy.update(this.dragData.ddel.cloneNode(true));
22060 this.onStartDrag(x, y);
22065 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22067 afterRepair : function(){
22069 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22071 this.dragging = false;
22075 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22076 * the XY of this.dragData.ddel
22077 * @param {EventObject} e The mouse up event
22078 * @return {Array} The xy location (e.g. [100, 200])
22080 getRepairXY : function(e){
22081 return Roo.Element.fly(this.dragData.ddel).getXY();
22085 * Ext JS Library 1.1.1
22086 * Copyright(c) 2006-2007, Ext JS, LLC.
22088 * Originally Released Under LGPL - original licence link has changed is not relivant.
22091 * <script type="text/javascript">
22094 * @class Roo.dd.DropZone
22095 * @extends Roo.dd.DropTarget
22096 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22097 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22099 * @param {String/HTMLElement/Element} el The container element
22100 * @param {Object} config
22102 Roo.dd.DropZone = function(el, config){
22103 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22106 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22108 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22109 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22110 * provide your own custom lookup.
22111 * @param {Event} e The event
22112 * @return {Object} data The custom data
22114 getTargetFromEvent : function(e){
22115 return Roo.dd.Registry.getTargetFromEvent(e);
22119 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22120 * that it has registered. This method has no default implementation and should be overridden to provide
22121 * node-specific processing if necessary.
22122 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22123 * {@link #getTargetFromEvent} for this node)
22124 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22125 * @param {Event} e The event
22126 * @param {Object} data An object containing arbitrary data supplied by the drag source
22128 onNodeEnter : function(n, dd, e, data){
22133 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22134 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22135 * overridden to provide the proper feedback.
22136 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22137 * {@link #getTargetFromEvent} for this node)
22138 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22139 * @param {Event} e The event
22140 * @param {Object} data An object containing arbitrary data supplied by the drag source
22141 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22142 * underlying {@link Roo.dd.StatusProxy} can be updated
22144 onNodeOver : function(n, dd, e, data){
22145 return this.dropAllowed;
22149 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22150 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22151 * node-specific processing if necessary.
22152 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22153 * {@link #getTargetFromEvent} for this node)
22154 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22155 * @param {Event} e The event
22156 * @param {Object} data An object containing arbitrary data supplied by the drag source
22158 onNodeOut : function(n, dd, e, data){
22163 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22164 * the drop node. The default implementation returns false, so it should be overridden to provide the
22165 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22166 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22167 * {@link #getTargetFromEvent} for this node)
22168 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22169 * @param {Event} e The event
22170 * @param {Object} data An object containing arbitrary data supplied by the drag source
22171 * @return {Boolean} True if the drop was valid, else false
22173 onNodeDrop : function(n, dd, e, data){
22178 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22179 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22180 * it should be overridden to provide the proper feedback if necessary.
22181 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22182 * @param {Event} e The event
22183 * @param {Object} data An object containing arbitrary data supplied by the drag source
22184 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22185 * underlying {@link Roo.dd.StatusProxy} can be updated
22187 onContainerOver : function(dd, e, data){
22188 return this.dropNotAllowed;
22192 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22193 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22194 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22195 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22196 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22197 * @param {Event} e The event
22198 * @param {Object} data An object containing arbitrary data supplied by the drag source
22199 * @return {Boolean} True if the drop was valid, else false
22201 onContainerDrop : function(dd, e, data){
22206 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22207 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22208 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22209 * you should override this method and provide a custom implementation.
22210 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22211 * @param {Event} e The event
22212 * @param {Object} data An object containing arbitrary data supplied by the drag source
22213 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22214 * underlying {@link Roo.dd.StatusProxy} can be updated
22216 notifyEnter : function(dd, e, data){
22217 return this.dropNotAllowed;
22221 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22222 * This method will be called on every mouse movement while the drag source is over the drop zone.
22223 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22224 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22225 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22226 * registered node, it will call {@link #onContainerOver}.
22227 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22228 * @param {Event} e The event
22229 * @param {Object} data An object containing arbitrary data supplied by the drag source
22230 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22231 * underlying {@link Roo.dd.StatusProxy} can be updated
22233 notifyOver : function(dd, e, data){
22234 var n = this.getTargetFromEvent(e);
22235 if(!n){ // not over valid drop target
22236 if(this.lastOverNode){
22237 this.onNodeOut(this.lastOverNode, dd, e, data);
22238 this.lastOverNode = null;
22240 return this.onContainerOver(dd, e, data);
22242 if(this.lastOverNode != n){
22243 if(this.lastOverNode){
22244 this.onNodeOut(this.lastOverNode, dd, e, data);
22246 this.onNodeEnter(n, dd, e, data);
22247 this.lastOverNode = n;
22249 return this.onNodeOver(n, dd, e, data);
22253 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22254 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22255 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22256 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22257 * @param {Event} e The event
22258 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22260 notifyOut : function(dd, e, data){
22261 if(this.lastOverNode){
22262 this.onNodeOut(this.lastOverNode, dd, e, data);
22263 this.lastOverNode = null;
22268 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22269 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22270 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22271 * otherwise it will call {@link #onContainerDrop}.
22272 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22273 * @param {Event} e The event
22274 * @param {Object} data An object containing arbitrary data supplied by the drag source
22275 * @return {Boolean} True if the drop was valid, else false
22277 notifyDrop : function(dd, e, data){
22278 if(this.lastOverNode){
22279 this.onNodeOut(this.lastOverNode, dd, e, data);
22280 this.lastOverNode = null;
22282 var n = this.getTargetFromEvent(e);
22284 this.onNodeDrop(n, dd, e, data) :
22285 this.onContainerDrop(dd, e, data);
22289 triggerCacheRefresh : function(){
22290 Roo.dd.DDM.refreshCache(this.groups);
22294 * Ext JS Library 1.1.1
22295 * Copyright(c) 2006-2007, Ext JS, LLC.
22297 * Originally Released Under LGPL - original licence link has changed is not relivant.
22300 * <script type="text/javascript">
22305 * @class Roo.data.SortTypes
22307 * Defines the default sorting (casting?) comparison functions used when sorting data.
22309 Roo.data.SortTypes = {
22311 * Default sort that does nothing
22312 * @param {Mixed} s The value being converted
22313 * @return {Mixed} The comparison value
22315 none : function(s){
22320 * The regular expression used to strip tags
22324 stripTagsRE : /<\/?[^>]+>/gi,
22327 * Strips all HTML tags to sort on text only
22328 * @param {Mixed} s The value being converted
22329 * @return {String} The comparison value
22331 asText : function(s){
22332 return String(s).replace(this.stripTagsRE, "");
22336 * Strips all HTML tags to sort on text only - Case insensitive
22337 * @param {Mixed} s The value being converted
22338 * @return {String} The comparison value
22340 asUCText : function(s){
22341 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22345 * Case insensitive string
22346 * @param {Mixed} s The value being converted
22347 * @return {String} The comparison value
22349 asUCString : function(s) {
22350 return String(s).toUpperCase();
22355 * @param {Mixed} s The value being converted
22356 * @return {Number} The comparison value
22358 asDate : function(s) {
22362 if(s instanceof Date){
22363 return s.getTime();
22365 return Date.parse(String(s));
22370 * @param {Mixed} s The value being converted
22371 * @return {Float} The comparison value
22373 asFloat : function(s) {
22374 var val = parseFloat(String(s).replace(/,/g, ""));
22383 * @param {Mixed} s The value being converted
22384 * @return {Number} The comparison value
22386 asInt : function(s) {
22387 var val = parseInt(String(s).replace(/,/g, ""));
22395 * Ext JS Library 1.1.1
22396 * Copyright(c) 2006-2007, Ext JS, LLC.
22398 * Originally Released Under LGPL - original licence link has changed is not relivant.
22401 * <script type="text/javascript">
22405 * @class Roo.data.Record
22406 * Instances of this class encapsulate both record <em>definition</em> information, and record
22407 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22408 * to access Records cached in an {@link Roo.data.Store} object.<br>
22410 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22411 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22414 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22416 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22417 * {@link #create}. The parameters are the same.
22418 * @param {Array} data An associative Array of data values keyed by the field name.
22419 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22420 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22421 * not specified an integer id is generated.
22423 Roo.data.Record = function(data, id){
22424 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22429 * Generate a constructor for a specific record layout.
22430 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22431 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22432 * Each field definition object may contain the following properties: <ul>
22433 * <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,
22434 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22435 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22436 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22437 * is being used, then this is a string containing the javascript expression to reference the data relative to
22438 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22439 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22440 * this may be omitted.</p></li>
22441 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22442 * <ul><li>auto (Default, implies no conversion)</li>
22447 * <li>date</li></ul></p></li>
22448 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22449 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22450 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22451 * by the Reader into an object that will be stored in the Record. It is passed the
22452 * following parameters:<ul>
22453 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22455 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22457 * <br>usage:<br><pre><code>
22458 var TopicRecord = Roo.data.Record.create(
22459 {name: 'title', mapping: 'topic_title'},
22460 {name: 'author', mapping: 'username'},
22461 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22462 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22463 {name: 'lastPoster', mapping: 'user2'},
22464 {name: 'excerpt', mapping: 'post_text'}
22467 var myNewRecord = new TopicRecord({
22468 title: 'Do my job please',
22471 lastPost: new Date(),
22472 lastPoster: 'Animal',
22473 excerpt: 'No way dude!'
22475 myStore.add(myNewRecord);
22480 Roo.data.Record.create = function(o){
22481 var f = function(){
22482 f.superclass.constructor.apply(this, arguments);
22484 Roo.extend(f, Roo.data.Record);
22485 var p = f.prototype;
22486 p.fields = new Roo.util.MixedCollection(false, function(field){
22489 for(var i = 0, len = o.length; i < len; i++){
22490 p.fields.add(new Roo.data.Field(o[i]));
22492 f.getField = function(name){
22493 return p.fields.get(name);
22498 Roo.data.Record.AUTO_ID = 1000;
22499 Roo.data.Record.EDIT = 'edit';
22500 Roo.data.Record.REJECT = 'reject';
22501 Roo.data.Record.COMMIT = 'commit';
22503 Roo.data.Record.prototype = {
22505 * Readonly flag - true if this record has been modified.
22514 join : function(store){
22515 this.store = store;
22519 * Set the named field to the specified value.
22520 * @param {String} name The name of the field to set.
22521 * @param {Object} value The value to set the field to.
22523 set : function(name, value){
22524 if(this.data[name] == value){
22528 if(!this.modified){
22529 this.modified = {};
22531 if(typeof this.modified[name] == 'undefined'){
22532 this.modified[name] = this.data[name];
22534 this.data[name] = value;
22535 if(!this.editing && this.store){
22536 this.store.afterEdit(this);
22541 * Get the value of the named field.
22542 * @param {String} name The name of the field to get the value of.
22543 * @return {Object} The value of the field.
22545 get : function(name){
22546 return this.data[name];
22550 beginEdit : function(){
22551 this.editing = true;
22552 this.modified = {};
22556 cancelEdit : function(){
22557 this.editing = false;
22558 delete this.modified;
22562 endEdit : function(){
22563 this.editing = false;
22564 if(this.dirty && this.store){
22565 this.store.afterEdit(this);
22570 * Usually called by the {@link Roo.data.Store} which owns the Record.
22571 * Rejects all changes made to the Record since either creation, or the last commit operation.
22572 * Modified fields are reverted to their original values.
22574 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22575 * of reject operations.
22577 reject : function(){
22578 var m = this.modified;
22580 if(typeof m[n] != "function"){
22581 this.data[n] = m[n];
22584 this.dirty = false;
22585 delete this.modified;
22586 this.editing = false;
22588 this.store.afterReject(this);
22593 * Usually called by the {@link Roo.data.Store} which owns the Record.
22594 * Commits all changes made to the Record since either creation, or the last commit operation.
22596 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22597 * of commit operations.
22599 commit : function(){
22600 this.dirty = false;
22601 delete this.modified;
22602 this.editing = false;
22604 this.store.afterCommit(this);
22609 hasError : function(){
22610 return this.error != null;
22614 clearError : function(){
22619 * Creates a copy of this record.
22620 * @param {String} id (optional) A new record id if you don't want to use this record's id
22623 copy : function(newId) {
22624 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22628 * Ext JS Library 1.1.1
22629 * Copyright(c) 2006-2007, Ext JS, LLC.
22631 * Originally Released Under LGPL - original licence link has changed is not relivant.
22634 * <script type="text/javascript">
22640 * @class Roo.data.Store
22641 * @extends Roo.util.Observable
22642 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22643 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22645 * 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
22646 * has no knowledge of the format of the data returned by the Proxy.<br>
22648 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22649 * instances from the data object. These records are cached and made available through accessor functions.
22651 * Creates a new Store.
22652 * @param {Object} config A config object containing the objects needed for the Store to access data,
22653 * and read the data into Records.
22655 Roo.data.Store = function(config){
22656 this.data = new Roo.util.MixedCollection(false);
22657 this.data.getKey = function(o){
22660 this.baseParams = {};
22662 this.paramNames = {
22667 "multisort" : "_multisort"
22670 if(config && config.data){
22671 this.inlineData = config.data;
22672 delete config.data;
22675 Roo.apply(this, config);
22677 if(this.reader){ // reader passed
22678 this.reader = Roo.factory(this.reader, Roo.data);
22679 this.reader.xmodule = this.xmodule || false;
22680 if(!this.recordType){
22681 this.recordType = this.reader.recordType;
22683 if(this.reader.onMetaChange){
22684 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22688 if(this.recordType){
22689 this.fields = this.recordType.prototype.fields;
22691 this.modified = [];
22695 * @event datachanged
22696 * Fires when the data cache has changed, and a widget which is using this Store
22697 * as a Record cache should refresh its view.
22698 * @param {Store} this
22700 datachanged : true,
22702 * @event metachange
22703 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22704 * @param {Store} this
22705 * @param {Object} meta The JSON metadata
22710 * Fires when Records have been added to the Store
22711 * @param {Store} this
22712 * @param {Roo.data.Record[]} records The array of Records added
22713 * @param {Number} index The index at which the record(s) were added
22718 * Fires when a Record has been removed from the Store
22719 * @param {Store} this
22720 * @param {Roo.data.Record} record The Record that was removed
22721 * @param {Number} index The index at which the record was removed
22726 * Fires when a Record has been updated
22727 * @param {Store} this
22728 * @param {Roo.data.Record} record The Record that was updated
22729 * @param {String} operation The update operation being performed. Value may be one of:
22731 Roo.data.Record.EDIT
22732 Roo.data.Record.REJECT
22733 Roo.data.Record.COMMIT
22739 * Fires when the data cache has been cleared.
22740 * @param {Store} this
22744 * @event beforeload
22745 * Fires before a request is made for a new data object. If the beforeload handler returns false
22746 * the load action will be canceled.
22747 * @param {Store} this
22748 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22752 * @event beforeloadadd
22753 * Fires after a new set of Records has been loaded.
22754 * @param {Store} this
22755 * @param {Roo.data.Record[]} records The Records that were loaded
22756 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22758 beforeloadadd : true,
22761 * Fires after a new set of Records has been loaded, before they are added to the store.
22762 * @param {Store} this
22763 * @param {Roo.data.Record[]} records The Records that were loaded
22764 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22765 * @params {Object} return from reader
22769 * @event loadexception
22770 * Fires if an exception occurs in the Proxy during loading.
22771 * Called with the signature of the Proxy's "loadexception" event.
22772 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22775 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22776 * @param {Object} load options
22777 * @param {Object} jsonData from your request (normally this contains the Exception)
22779 loadexception : true
22783 this.proxy = Roo.factory(this.proxy, Roo.data);
22784 this.proxy.xmodule = this.xmodule || false;
22785 this.relayEvents(this.proxy, ["loadexception"]);
22787 this.sortToggle = {};
22788 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22790 Roo.data.Store.superclass.constructor.call(this);
22792 if(this.inlineData){
22793 this.loadData(this.inlineData);
22794 delete this.inlineData;
22798 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22800 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22801 * without a remote query - used by combo/forms at present.
22805 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22808 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22811 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22812 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22815 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22816 * on any HTTP request
22819 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22822 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22826 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22827 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22829 remoteSort : false,
22832 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22833 * loaded or when a record is removed. (defaults to false).
22835 pruneModifiedRecords : false,
22838 lastOptions : null,
22841 * Add Records to the Store and fires the add event.
22842 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22844 add : function(records){
22845 records = [].concat(records);
22846 for(var i = 0, len = records.length; i < len; i++){
22847 records[i].join(this);
22849 var index = this.data.length;
22850 this.data.addAll(records);
22851 this.fireEvent("add", this, records, index);
22855 * Remove a Record from the Store and fires the remove event.
22856 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
22858 remove : function(record){
22859 var index = this.data.indexOf(record);
22860 this.data.removeAt(index);
22861 if(this.pruneModifiedRecords){
22862 this.modified.remove(record);
22864 this.fireEvent("remove", this, record, index);
22868 * Remove all Records from the Store and fires the clear event.
22870 removeAll : function(){
22872 if(this.pruneModifiedRecords){
22873 this.modified = [];
22875 this.fireEvent("clear", this);
22879 * Inserts Records to the Store at the given index and fires the add event.
22880 * @param {Number} index The start index at which to insert the passed Records.
22881 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22883 insert : function(index, records){
22884 records = [].concat(records);
22885 for(var i = 0, len = records.length; i < len; i++){
22886 this.data.insert(index, records[i]);
22887 records[i].join(this);
22889 this.fireEvent("add", this, records, index);
22893 * Get the index within the cache of the passed Record.
22894 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
22895 * @return {Number} The index of the passed Record. Returns -1 if not found.
22897 indexOf : function(record){
22898 return this.data.indexOf(record);
22902 * Get the index within the cache of the Record with the passed id.
22903 * @param {String} id The id of the Record to find.
22904 * @return {Number} The index of the Record. Returns -1 if not found.
22906 indexOfId : function(id){
22907 return this.data.indexOfKey(id);
22911 * Get the Record with the specified id.
22912 * @param {String} id The id of the Record to find.
22913 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
22915 getById : function(id){
22916 return this.data.key(id);
22920 * Get the Record at the specified index.
22921 * @param {Number} index The index of the Record to find.
22922 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
22924 getAt : function(index){
22925 return this.data.itemAt(index);
22929 * Returns a range of Records between specified indices.
22930 * @param {Number} startIndex (optional) The starting index (defaults to 0)
22931 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
22932 * @return {Roo.data.Record[]} An array of Records
22934 getRange : function(start, end){
22935 return this.data.getRange(start, end);
22939 storeOptions : function(o){
22940 o = Roo.apply({}, o);
22943 this.lastOptions = o;
22947 * Loads the Record cache from the configured Proxy using the configured Reader.
22949 * If using remote paging, then the first load call must specify the <em>start</em>
22950 * and <em>limit</em> properties in the options.params property to establish the initial
22951 * position within the dataset, and the number of Records to cache on each read from the Proxy.
22953 * <strong>It is important to note that for remote data sources, loading is asynchronous,
22954 * and this call will return before the new data has been loaded. Perform any post-processing
22955 * in a callback function, or in a "load" event handler.</strong>
22957 * @param {Object} options An object containing properties which control loading options:<ul>
22958 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
22959 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
22960 * passed the following arguments:<ul>
22961 * <li>r : Roo.data.Record[]</li>
22962 * <li>options: Options object from the load call</li>
22963 * <li>success: Boolean success indicator</li></ul></li>
22964 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
22965 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
22968 load : function(options){
22969 options = options || {};
22970 if(this.fireEvent("beforeload", this, options) !== false){
22971 this.storeOptions(options);
22972 var p = Roo.apply(options.params || {}, this.baseParams);
22973 // if meta was not loaded from remote source.. try requesting it.
22974 if (!this.reader.metaFromRemote) {
22975 p._requestMeta = 1;
22977 if(this.sortInfo && this.remoteSort){
22978 var pn = this.paramNames;
22979 p[pn["sort"]] = this.sortInfo.field;
22980 p[pn["dir"]] = this.sortInfo.direction;
22982 if (this.multiSort) {
22983 var pn = this.paramNames;
22984 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
22987 this.proxy.load(p, this.reader, this.loadRecords, this, options);
22992 * Reloads the Record cache from the configured Proxy using the configured Reader and
22993 * the options from the last load operation performed.
22994 * @param {Object} options (optional) An object containing properties which may override the options
22995 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
22996 * the most recently used options are reused).
22998 reload : function(options){
22999 this.load(Roo.applyIf(options||{}, this.lastOptions));
23003 // Called as a callback by the Reader during a load operation.
23004 loadRecords : function(o, options, success){
23005 if(!o || success === false){
23006 if(success !== false){
23007 this.fireEvent("load", this, [], options, o);
23009 if(options.callback){
23010 options.callback.call(options.scope || this, [], options, false);
23014 // if data returned failure - throw an exception.
23015 if (o.success === false) {
23016 // show a message if no listener is registered.
23017 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23018 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23020 // loadmask wil be hooked into this..
23021 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23024 var r = o.records, t = o.totalRecords || r.length;
23026 this.fireEvent("beforeloadadd", this, r, options, o);
23028 if(!options || options.add !== true){
23029 if(this.pruneModifiedRecords){
23030 this.modified = [];
23032 for(var i = 0, len = r.length; i < len; i++){
23036 this.data = this.snapshot;
23037 delete this.snapshot;
23040 this.data.addAll(r);
23041 this.totalLength = t;
23043 this.fireEvent("datachanged", this);
23045 this.totalLength = Math.max(t, this.data.length+r.length);
23048 this.fireEvent("load", this, r, options, o);
23049 if(options.callback){
23050 options.callback.call(options.scope || this, r, options, true);
23056 * Loads data from a passed data block. A Reader which understands the format of the data
23057 * must have been configured in the constructor.
23058 * @param {Object} data The data block from which to read the Records. The format of the data expected
23059 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23060 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23062 loadData : function(o, append){
23063 var r = this.reader.readRecords(o);
23064 this.loadRecords(r, {add: append}, true);
23068 * Gets the number of cached records.
23070 * <em>If using paging, this may not be the total size of the dataset. If the data object
23071 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23072 * the data set size</em>
23074 getCount : function(){
23075 return this.data.length || 0;
23079 * Gets the total number of records in the dataset as returned by the server.
23081 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23082 * the dataset size</em>
23084 getTotalCount : function(){
23085 return this.totalLength || 0;
23089 * Returns the sort state of the Store as an object with two properties:
23091 field {String} The name of the field by which the Records are sorted
23092 direction {String} The sort order, "ASC" or "DESC"
23095 getSortState : function(){
23096 return this.sortInfo;
23100 applySort : function(){
23101 if(this.sortInfo && !this.remoteSort){
23102 var s = this.sortInfo, f = s.field;
23103 var st = this.fields.get(f).sortType;
23104 var fn = function(r1, r2){
23105 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23106 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23108 this.data.sort(s.direction, fn);
23109 if(this.snapshot && this.snapshot != this.data){
23110 this.snapshot.sort(s.direction, fn);
23116 * Sets the default sort column and order to be used by the next load operation.
23117 * @param {String} fieldName The name of the field to sort by.
23118 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23120 setDefaultSort : function(field, dir){
23121 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23125 * Sort the Records.
23126 * If remote sorting is used, the sort is performed on the server, and the cache is
23127 * reloaded. If local sorting is used, the cache is sorted internally.
23128 * @param {String} fieldName The name of the field to sort by.
23129 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23131 sort : function(fieldName, dir){
23132 var f = this.fields.get(fieldName);
23134 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23136 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23137 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23142 this.sortToggle[f.name] = dir;
23143 this.sortInfo = {field: f.name, direction: dir};
23144 if(!this.remoteSort){
23146 this.fireEvent("datachanged", this);
23148 this.load(this.lastOptions);
23153 * Calls the specified function for each of the Records in the cache.
23154 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23155 * Returning <em>false</em> aborts and exits the iteration.
23156 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23158 each : function(fn, scope){
23159 this.data.each(fn, scope);
23163 * Gets all records modified since the last commit. Modified records are persisted across load operations
23164 * (e.g., during paging).
23165 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23167 getModifiedRecords : function(){
23168 return this.modified;
23172 createFilterFn : function(property, value, anyMatch){
23173 if(!value.exec){ // not a regex
23174 value = String(value);
23175 if(value.length == 0){
23178 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23180 return function(r){
23181 return value.test(r.data[property]);
23186 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23187 * @param {String} property A field on your records
23188 * @param {Number} start The record index to start at (defaults to 0)
23189 * @param {Number} end The last record index to include (defaults to length - 1)
23190 * @return {Number} The sum
23192 sum : function(property, start, end){
23193 var rs = this.data.items, v = 0;
23194 start = start || 0;
23195 end = (end || end === 0) ? end : rs.length-1;
23197 for(var i = start; i <= end; i++){
23198 v += (rs[i].data[property] || 0);
23204 * Filter the records by a specified property.
23205 * @param {String} field A field on your records
23206 * @param {String/RegExp} value Either a string that the field
23207 * should start with or a RegExp to test against the field
23208 * @param {Boolean} anyMatch True to match any part not just the beginning
23210 filter : function(property, value, anyMatch){
23211 var fn = this.createFilterFn(property, value, anyMatch);
23212 return fn ? this.filterBy(fn) : this.clearFilter();
23216 * Filter by a function. The specified function will be called with each
23217 * record in this data source. If the function returns true the record is included,
23218 * otherwise it is filtered.
23219 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23220 * @param {Object} scope (optional) The scope of the function (defaults to this)
23222 filterBy : function(fn, scope){
23223 this.snapshot = this.snapshot || this.data;
23224 this.data = this.queryBy(fn, scope||this);
23225 this.fireEvent("datachanged", this);
23229 * Query the records by a specified property.
23230 * @param {String} field A field on your records
23231 * @param {String/RegExp} value Either a string that the field
23232 * should start with or a RegExp to test against the field
23233 * @param {Boolean} anyMatch True to match any part not just the beginning
23234 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23236 query : function(property, value, anyMatch){
23237 var fn = this.createFilterFn(property, value, anyMatch);
23238 return fn ? this.queryBy(fn) : this.data.clone();
23242 * Query by a function. The specified function will be called with each
23243 * record in this data source. If the function returns true the record is included
23245 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23246 * @param {Object} scope (optional) The scope of the function (defaults to this)
23247 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23249 queryBy : function(fn, scope){
23250 var data = this.snapshot || this.data;
23251 return data.filterBy(fn, scope||this);
23255 * Collects unique values for a particular dataIndex from this store.
23256 * @param {String} dataIndex The property to collect
23257 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23258 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23259 * @return {Array} An array of the unique values
23261 collect : function(dataIndex, allowNull, bypassFilter){
23262 var d = (bypassFilter === true && this.snapshot) ?
23263 this.snapshot.items : this.data.items;
23264 var v, sv, r = [], l = {};
23265 for(var i = 0, len = d.length; i < len; i++){
23266 v = d[i].data[dataIndex];
23268 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23277 * Revert to a view of the Record cache with no filtering applied.
23278 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23280 clearFilter : function(suppressEvent){
23281 if(this.snapshot && this.snapshot != this.data){
23282 this.data = this.snapshot;
23283 delete this.snapshot;
23284 if(suppressEvent !== true){
23285 this.fireEvent("datachanged", this);
23291 afterEdit : function(record){
23292 if(this.modified.indexOf(record) == -1){
23293 this.modified.push(record);
23295 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23299 afterReject : function(record){
23300 this.modified.remove(record);
23301 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23305 afterCommit : function(record){
23306 this.modified.remove(record);
23307 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23311 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23312 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23314 commitChanges : function(){
23315 var m = this.modified.slice(0);
23316 this.modified = [];
23317 for(var i = 0, len = m.length; i < len; i++){
23323 * Cancel outstanding changes on all changed records.
23325 rejectChanges : function(){
23326 var m = this.modified.slice(0);
23327 this.modified = [];
23328 for(var i = 0, len = m.length; i < len; i++){
23333 onMetaChange : function(meta, rtype, o){
23334 this.recordType = rtype;
23335 this.fields = rtype.prototype.fields;
23336 delete this.snapshot;
23337 this.sortInfo = meta.sortInfo || this.sortInfo;
23338 this.modified = [];
23339 this.fireEvent('metachange', this, this.reader.meta);
23342 moveIndex : function(data, type)
23344 var index = this.indexOf(data);
23346 var newIndex = index + type;
23350 this.insert(newIndex, data);
23355 * Ext JS Library 1.1.1
23356 * Copyright(c) 2006-2007, Ext JS, LLC.
23358 * Originally Released Under LGPL - original licence link has changed is not relivant.
23361 * <script type="text/javascript">
23365 * @class Roo.data.SimpleStore
23366 * @extends Roo.data.Store
23367 * Small helper class to make creating Stores from Array data easier.
23368 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23369 * @cfg {Array} fields An array of field definition objects, or field name strings.
23370 * @cfg {Array} data The multi-dimensional array of data
23372 * @param {Object} config
23374 Roo.data.SimpleStore = function(config){
23375 Roo.data.SimpleStore.superclass.constructor.call(this, {
23377 reader: new Roo.data.ArrayReader({
23380 Roo.data.Record.create(config.fields)
23382 proxy : new Roo.data.MemoryProxy(config.data)
23386 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23388 * Ext JS Library 1.1.1
23389 * Copyright(c) 2006-2007, Ext JS, LLC.
23391 * Originally Released Under LGPL - original licence link has changed is not relivant.
23394 * <script type="text/javascript">
23399 * @extends Roo.data.Store
23400 * @class Roo.data.JsonStore
23401 * Small helper class to make creating Stores for JSON data easier. <br/>
23403 var store = new Roo.data.JsonStore({
23404 url: 'get-images.php',
23406 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23409 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23410 * JsonReader and HttpProxy (unless inline data is provided).</b>
23411 * @cfg {Array} fields An array of field definition objects, or field name strings.
23413 * @param {Object} config
23415 Roo.data.JsonStore = function(c){
23416 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23417 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23418 reader: new Roo.data.JsonReader(c, c.fields)
23421 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23423 * Ext JS Library 1.1.1
23424 * Copyright(c) 2006-2007, Ext JS, LLC.
23426 * Originally Released Under LGPL - original licence link has changed is not relivant.
23429 * <script type="text/javascript">
23433 Roo.data.Field = function(config){
23434 if(typeof config == "string"){
23435 config = {name: config};
23437 Roo.apply(this, config);
23440 this.type = "auto";
23443 var st = Roo.data.SortTypes;
23444 // named sortTypes are supported, here we look them up
23445 if(typeof this.sortType == "string"){
23446 this.sortType = st[this.sortType];
23449 // set default sortType for strings and dates
23450 if(!this.sortType){
23453 this.sortType = st.asUCString;
23456 this.sortType = st.asDate;
23459 this.sortType = st.none;
23464 var stripRe = /[\$,%]/g;
23466 // prebuilt conversion function for this field, instead of
23467 // switching every time we're reading a value
23469 var cv, dateFormat = this.dateFormat;
23474 cv = function(v){ return v; };
23477 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23481 return v !== undefined && v !== null && v !== '' ?
23482 parseInt(String(v).replace(stripRe, ""), 10) : '';
23487 return v !== undefined && v !== null && v !== '' ?
23488 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23493 cv = function(v){ return v === true || v === "true" || v == 1; };
23500 if(v instanceof Date){
23504 if(dateFormat == "timestamp"){
23505 return new Date(v*1000);
23507 return Date.parseDate(v, dateFormat);
23509 var parsed = Date.parse(v);
23510 return parsed ? new Date(parsed) : null;
23519 Roo.data.Field.prototype = {
23527 * Ext JS Library 1.1.1
23528 * Copyright(c) 2006-2007, Ext JS, LLC.
23530 * Originally Released Under LGPL - original licence link has changed is not relivant.
23533 * <script type="text/javascript">
23536 // Base class for reading structured data from a data source. This class is intended to be
23537 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23540 * @class Roo.data.DataReader
23541 * Base class for reading structured data from a data source. This class is intended to be
23542 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23545 Roo.data.DataReader = function(meta, recordType){
23549 this.recordType = recordType instanceof Array ?
23550 Roo.data.Record.create(recordType) : recordType;
23553 Roo.data.DataReader.prototype = {
23555 * Create an empty record
23556 * @param {Object} data (optional) - overlay some values
23557 * @return {Roo.data.Record} record created.
23559 newRow : function(d) {
23561 this.recordType.prototype.fields.each(function(c) {
23563 case 'int' : da[c.name] = 0; break;
23564 case 'date' : da[c.name] = new Date(); break;
23565 case 'float' : da[c.name] = 0.0; break;
23566 case 'boolean' : da[c.name] = false; break;
23567 default : da[c.name] = ""; break;
23571 return new this.recordType(Roo.apply(da, d));
23576 * Ext JS Library 1.1.1
23577 * Copyright(c) 2006-2007, Ext JS, LLC.
23579 * Originally Released Under LGPL - original licence link has changed is not relivant.
23582 * <script type="text/javascript">
23586 * @class Roo.data.DataProxy
23587 * @extends Roo.data.Observable
23588 * This class is an abstract base class for implementations which provide retrieval of
23589 * unformatted data objects.<br>
23591 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23592 * (of the appropriate type which knows how to parse the data object) to provide a block of
23593 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23595 * Custom implementations must implement the load method as described in
23596 * {@link Roo.data.HttpProxy#load}.
23598 Roo.data.DataProxy = function(){
23601 * @event beforeload
23602 * Fires before a network request is made to retrieve a data object.
23603 * @param {Object} This DataProxy object.
23604 * @param {Object} params The params parameter to the load function.
23609 * Fires before the load method's callback is called.
23610 * @param {Object} This DataProxy object.
23611 * @param {Object} o The data object.
23612 * @param {Object} arg The callback argument object passed to the load function.
23616 * @event loadexception
23617 * Fires if an Exception occurs during data retrieval.
23618 * @param {Object} This DataProxy object.
23619 * @param {Object} o The data object.
23620 * @param {Object} arg The callback argument object passed to the load function.
23621 * @param {Object} e The Exception.
23623 loadexception : true
23625 Roo.data.DataProxy.superclass.constructor.call(this);
23628 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23631 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23635 * Ext JS Library 1.1.1
23636 * Copyright(c) 2006-2007, Ext JS, LLC.
23638 * Originally Released Under LGPL - original licence link has changed is not relivant.
23641 * <script type="text/javascript">
23644 * @class Roo.data.MemoryProxy
23645 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23646 * to the Reader when its load method is called.
23648 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23650 Roo.data.MemoryProxy = function(data){
23654 Roo.data.MemoryProxy.superclass.constructor.call(this);
23658 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23661 * Load data from the requested source (in this case an in-memory
23662 * data object passed to the constructor), read the data object into
23663 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23664 * process that block using the passed callback.
23665 * @param {Object} params This parameter is not used by the MemoryProxy class.
23666 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23667 * object into a block of Roo.data.Records.
23668 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23669 * The function must be passed <ul>
23670 * <li>The Record block object</li>
23671 * <li>The "arg" argument from the load function</li>
23672 * <li>A boolean success indicator</li>
23674 * @param {Object} scope The scope in which to call the callback
23675 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23677 load : function(params, reader, callback, scope, arg){
23678 params = params || {};
23681 result = reader.readRecords(this.data);
23683 this.fireEvent("loadexception", this, arg, null, e);
23684 callback.call(scope, null, arg, false);
23687 callback.call(scope, result, arg, true);
23691 update : function(params, records){
23696 * Ext JS Library 1.1.1
23697 * Copyright(c) 2006-2007, Ext JS, LLC.
23699 * Originally Released Under LGPL - original licence link has changed is not relivant.
23702 * <script type="text/javascript">
23705 * @class Roo.data.HttpProxy
23706 * @extends Roo.data.DataProxy
23707 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23708 * configured to reference a certain URL.<br><br>
23710 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23711 * from which the running page was served.<br><br>
23713 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23715 * Be aware that to enable the browser to parse an XML document, the server must set
23716 * the Content-Type header in the HTTP response to "text/xml".
23718 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23719 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23720 * will be used to make the request.
23722 Roo.data.HttpProxy = function(conn){
23723 Roo.data.HttpProxy.superclass.constructor.call(this);
23724 // is conn a conn config or a real conn?
23726 this.useAjax = !conn || !conn.events;
23730 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23731 // thse are take from connection...
23734 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23737 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23738 * extra parameters to each request made by this object. (defaults to undefined)
23741 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23742 * to each request made by this object. (defaults to undefined)
23745 * @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)
23748 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23751 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23757 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23761 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23762 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23763 * a finer-grained basis than the DataProxy events.
23765 getConnection : function(){
23766 return this.useAjax ? Roo.Ajax : this.conn;
23770 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23771 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23772 * process that block using the passed callback.
23773 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23774 * for the request to the remote server.
23775 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23776 * object into a block of Roo.data.Records.
23777 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23778 * The function must be passed <ul>
23779 * <li>The Record block object</li>
23780 * <li>The "arg" argument from the load function</li>
23781 * <li>A boolean success indicator</li>
23783 * @param {Object} scope The scope in which to call the callback
23784 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23786 load : function(params, reader, callback, scope, arg){
23787 if(this.fireEvent("beforeload", this, params) !== false){
23789 params : params || {},
23791 callback : callback,
23796 callback : this.loadResponse,
23800 Roo.applyIf(o, this.conn);
23801 if(this.activeRequest){
23802 Roo.Ajax.abort(this.activeRequest);
23804 this.activeRequest = Roo.Ajax.request(o);
23806 this.conn.request(o);
23809 callback.call(scope||this, null, arg, false);
23814 loadResponse : function(o, success, response){
23815 delete this.activeRequest;
23817 this.fireEvent("loadexception", this, o, response);
23818 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23823 result = o.reader.read(response);
23825 this.fireEvent("loadexception", this, o, response, e);
23826 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23830 this.fireEvent("load", this, o, o.request.arg);
23831 o.request.callback.call(o.request.scope, result, o.request.arg, true);
23835 update : function(dataSet){
23840 updateResponse : function(dataSet){
23845 * Ext JS Library 1.1.1
23846 * Copyright(c) 2006-2007, Ext JS, LLC.
23848 * Originally Released Under LGPL - original licence link has changed is not relivant.
23851 * <script type="text/javascript">
23855 * @class Roo.data.ScriptTagProxy
23856 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
23857 * other than the originating domain of the running page.<br><br>
23859 * <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
23860 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
23862 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
23863 * source code that is used as the source inside a <script> tag.<br><br>
23865 * In order for the browser to process the returned data, the server must wrap the data object
23866 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
23867 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
23868 * depending on whether the callback name was passed:
23871 boolean scriptTag = false;
23872 String cb = request.getParameter("callback");
23875 response.setContentType("text/javascript");
23877 response.setContentType("application/x-json");
23879 Writer out = response.getWriter();
23881 out.write(cb + "(");
23883 out.print(dataBlock.toJsonString());
23890 * @param {Object} config A configuration object.
23892 Roo.data.ScriptTagProxy = function(config){
23893 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
23894 Roo.apply(this, config);
23895 this.head = document.getElementsByTagName("head")[0];
23898 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
23900 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
23902 * @cfg {String} url The URL from which to request the data object.
23905 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
23909 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
23910 * the server the name of the callback function set up by the load call to process the returned data object.
23911 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
23912 * javascript output which calls this named function passing the data object as its only parameter.
23914 callbackParam : "callback",
23916 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
23917 * name to the request.
23922 * Load data from the configured URL, read the data object into
23923 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23924 * process that block using the passed callback.
23925 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23926 * for the request to the remote server.
23927 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23928 * object into a block of Roo.data.Records.
23929 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23930 * The function must be passed <ul>
23931 * <li>The Record block object</li>
23932 * <li>The "arg" argument from the load function</li>
23933 * <li>A boolean success indicator</li>
23935 * @param {Object} scope The scope in which to call the callback
23936 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23938 load : function(params, reader, callback, scope, arg){
23939 if(this.fireEvent("beforeload", this, params) !== false){
23941 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
23943 var url = this.url;
23944 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
23946 url += "&_dc=" + (new Date().getTime());
23948 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
23951 cb : "stcCallback"+transId,
23952 scriptId : "stcScript"+transId,
23956 callback : callback,
23962 window[trans.cb] = function(o){
23963 conn.handleResponse(o, trans);
23966 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
23968 if(this.autoAbort !== false){
23972 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
23974 var script = document.createElement("script");
23975 script.setAttribute("src", url);
23976 script.setAttribute("type", "text/javascript");
23977 script.setAttribute("id", trans.scriptId);
23978 this.head.appendChild(script);
23980 this.trans = trans;
23982 callback.call(scope||this, null, arg, false);
23987 isLoading : function(){
23988 return this.trans ? true : false;
23992 * Abort the current server request.
23994 abort : function(){
23995 if(this.isLoading()){
23996 this.destroyTrans(this.trans);
24001 destroyTrans : function(trans, isLoaded){
24002 this.head.removeChild(document.getElementById(trans.scriptId));
24003 clearTimeout(trans.timeoutId);
24005 window[trans.cb] = undefined;
24007 delete window[trans.cb];
24010 // if hasn't been loaded, wait for load to remove it to prevent script error
24011 window[trans.cb] = function(){
24012 window[trans.cb] = undefined;
24014 delete window[trans.cb];
24021 handleResponse : function(o, trans){
24022 this.trans = false;
24023 this.destroyTrans(trans, true);
24026 result = trans.reader.readRecords(o);
24028 this.fireEvent("loadexception", this, o, trans.arg, e);
24029 trans.callback.call(trans.scope||window, null, trans.arg, false);
24032 this.fireEvent("load", this, o, trans.arg);
24033 trans.callback.call(trans.scope||window, result, trans.arg, true);
24037 handleFailure : function(trans){
24038 this.trans = false;
24039 this.destroyTrans(trans, false);
24040 this.fireEvent("loadexception", this, null, trans.arg);
24041 trans.callback.call(trans.scope||window, null, trans.arg, false);
24045 * Ext JS Library 1.1.1
24046 * Copyright(c) 2006-2007, Ext JS, LLC.
24048 * Originally Released Under LGPL - original licence link has changed is not relivant.
24051 * <script type="text/javascript">
24055 * @class Roo.data.JsonReader
24056 * @extends Roo.data.DataReader
24057 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24058 * based on mappings in a provided Roo.data.Record constructor.
24060 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24061 * in the reply previously.
24066 var RecordDef = Roo.data.Record.create([
24067 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24068 {name: 'occupation'} // This field will use "occupation" as the mapping.
24070 var myReader = new Roo.data.JsonReader({
24071 totalProperty: "results", // The property which contains the total dataset size (optional)
24072 root: "rows", // The property which contains an Array of row objects
24073 id: "id" // The property within each row object that provides an ID for the record (optional)
24077 * This would consume a JSON file like this:
24079 { 'results': 2, 'rows': [
24080 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24081 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24084 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24085 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24086 * paged from the remote server.
24087 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24088 * @cfg {String} root name of the property which contains the Array of row objects.
24089 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24090 * @cfg {Array} fields Array of field definition objects
24092 * Create a new JsonReader
24093 * @param {Object} meta Metadata configuration options
24094 * @param {Object} recordType Either an Array of field definition objects,
24095 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24097 Roo.data.JsonReader = function(meta, recordType){
24100 // set some defaults:
24101 Roo.applyIf(meta, {
24102 totalProperty: 'total',
24103 successProperty : 'success',
24108 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24110 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24113 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24114 * Used by Store query builder to append _requestMeta to params.
24117 metaFromRemote : false,
24119 * This method is only used by a DataProxy which has retrieved data from a remote server.
24120 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24121 * @return {Object} data A data block which is used by an Roo.data.Store object as
24122 * a cache of Roo.data.Records.
24124 read : function(response){
24125 var json = response.responseText;
24127 var o = /* eval:var:o */ eval("("+json+")");
24129 throw {message: "JsonReader.read: Json object not found"};
24135 this.metaFromRemote = true;
24136 this.meta = o.metaData;
24137 this.recordType = Roo.data.Record.create(o.metaData.fields);
24138 this.onMetaChange(this.meta, this.recordType, o);
24140 return this.readRecords(o);
24143 // private function a store will implement
24144 onMetaChange : function(meta, recordType, o){
24151 simpleAccess: function(obj, subsc) {
24158 getJsonAccessor: function(){
24160 return function(expr) {
24162 return(re.test(expr))
24163 ? new Function("obj", "return obj." + expr)
24168 return Roo.emptyFn;
24173 * Create a data block containing Roo.data.Records from an XML document.
24174 * @param {Object} o An object which contains an Array of row objects in the property specified
24175 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24176 * which contains the total size of the dataset.
24177 * @return {Object} data A data block which is used by an Roo.data.Store object as
24178 * a cache of Roo.data.Records.
24180 readRecords : function(o){
24182 * After any data loads, the raw JSON data is available for further custom processing.
24186 var s = this.meta, Record = this.recordType,
24187 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24189 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24191 if(s.totalProperty) {
24192 this.getTotal = this.getJsonAccessor(s.totalProperty);
24194 if(s.successProperty) {
24195 this.getSuccess = this.getJsonAccessor(s.successProperty);
24197 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24199 var g = this.getJsonAccessor(s.id);
24200 this.getId = function(rec) {
24202 return (r === undefined || r === "") ? null : r;
24205 this.getId = function(){return null;};
24208 for(var jj = 0; jj < fl; jj++){
24210 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24211 this.ef[jj] = this.getJsonAccessor(map);
24215 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24216 if(s.totalProperty){
24217 var vt = parseInt(this.getTotal(o), 10);
24222 if(s.successProperty){
24223 var vs = this.getSuccess(o);
24224 if(vs === false || vs === 'false'){
24229 for(var i = 0; i < c; i++){
24232 var id = this.getId(n);
24233 for(var j = 0; j < fl; j++){
24235 var v = this.ef[j](n);
24237 Roo.log('missing convert for ' + f.name);
24241 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24243 var record = new Record(values, id);
24245 records[i] = record;
24251 totalRecords : totalRecords
24256 * Ext JS Library 1.1.1
24257 * Copyright(c) 2006-2007, Ext JS, LLC.
24259 * Originally Released Under LGPL - original licence link has changed is not relivant.
24262 * <script type="text/javascript">
24266 * @class Roo.data.XmlReader
24267 * @extends Roo.data.DataReader
24268 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24269 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24271 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24272 * header in the HTTP response must be set to "text/xml".</em>
24276 var RecordDef = Roo.data.Record.create([
24277 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24278 {name: 'occupation'} // This field will use "occupation" as the mapping.
24280 var myReader = new Roo.data.XmlReader({
24281 totalRecords: "results", // The element which contains the total dataset size (optional)
24282 record: "row", // The repeated element which contains row information
24283 id: "id" // The element within the row that provides an ID for the record (optional)
24287 * This would consume an XML file like this:
24291 <results>2</results>
24294 <name>Bill</name>
24295 <occupation>Gardener</occupation>
24299 <name>Ben</name>
24300 <occupation>Horticulturalist</occupation>
24304 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24305 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24306 * paged from the remote server.
24307 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24308 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24309 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24310 * a record identifier value.
24312 * Create a new XmlReader
24313 * @param {Object} meta Metadata configuration options
24314 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24315 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24316 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24318 Roo.data.XmlReader = function(meta, recordType){
24320 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24322 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24324 * This method is only used by a DataProxy which has retrieved data from a remote server.
24325 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24326 * to contain a method called 'responseXML' that returns an XML document object.
24327 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24328 * a cache of Roo.data.Records.
24330 read : function(response){
24331 var doc = response.responseXML;
24333 throw {message: "XmlReader.read: XML Document not available"};
24335 return this.readRecords(doc);
24339 * Create a data block containing Roo.data.Records from an XML document.
24340 * @param {Object} doc A parsed XML document.
24341 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24342 * a cache of Roo.data.Records.
24344 readRecords : function(doc){
24346 * After any data loads/reads, the raw XML Document is available for further custom processing.
24347 * @type XMLDocument
24349 this.xmlData = doc;
24350 var root = doc.documentElement || doc;
24351 var q = Roo.DomQuery;
24352 var recordType = this.recordType, fields = recordType.prototype.fields;
24353 var sid = this.meta.id;
24354 var totalRecords = 0, success = true;
24355 if(this.meta.totalRecords){
24356 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24359 if(this.meta.success){
24360 var sv = q.selectValue(this.meta.success, root, true);
24361 success = sv !== false && sv !== 'false';
24364 var ns = q.select(this.meta.record, root);
24365 for(var i = 0, len = ns.length; i < len; i++) {
24368 var id = sid ? q.selectValue(sid, n) : undefined;
24369 for(var j = 0, jlen = fields.length; j < jlen; j++){
24370 var f = fields.items[j];
24371 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24373 values[f.name] = v;
24375 var record = new recordType(values, id);
24377 records[records.length] = record;
24383 totalRecords : totalRecords || records.length
24388 * Ext JS Library 1.1.1
24389 * Copyright(c) 2006-2007, Ext JS, LLC.
24391 * Originally Released Under LGPL - original licence link has changed is not relivant.
24394 * <script type="text/javascript">
24398 * @class Roo.data.ArrayReader
24399 * @extends Roo.data.DataReader
24400 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24401 * Each element of that Array represents a row of data fields. The
24402 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24403 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24407 var RecordDef = Roo.data.Record.create([
24408 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24409 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24411 var myReader = new Roo.data.ArrayReader({
24412 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24416 * This would consume an Array like this:
24418 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24420 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24422 * Create a new JsonReader
24423 * @param {Object} meta Metadata configuration options.
24424 * @param {Object} recordType Either an Array of field definition objects
24425 * as specified to {@link Roo.data.Record#create},
24426 * or an {@link Roo.data.Record} object
24427 * created using {@link Roo.data.Record#create}.
24429 Roo.data.ArrayReader = function(meta, recordType){
24430 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24433 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24435 * Create a data block containing Roo.data.Records from an XML document.
24436 * @param {Object} o An Array of row objects which represents the dataset.
24437 * @return {Object} data A data block which is used by an Roo.data.Store object as
24438 * a cache of Roo.data.Records.
24440 readRecords : function(o){
24441 var sid = this.meta ? this.meta.id : null;
24442 var recordType = this.recordType, fields = recordType.prototype.fields;
24445 for(var i = 0; i < root.length; i++){
24448 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24449 for(var j = 0, jlen = fields.length; j < jlen; j++){
24450 var f = fields.items[j];
24451 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24452 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24454 values[f.name] = v;
24456 var record = new recordType(values, id);
24458 records[records.length] = record;
24462 totalRecords : records.length
24467 * Ext JS Library 1.1.1
24468 * Copyright(c) 2006-2007, Ext JS, LLC.
24470 * Originally Released Under LGPL - original licence link has changed is not relivant.
24473 * <script type="text/javascript">
24478 * @class Roo.data.Tree
24479 * @extends Roo.util.Observable
24480 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24481 * in the tree have most standard DOM functionality.
24483 * @param {Node} root (optional) The root node
24485 Roo.data.Tree = function(root){
24486 this.nodeHash = {};
24488 * The root node for this tree
24493 this.setRootNode(root);
24498 * Fires when a new child node is appended to a node in this tree.
24499 * @param {Tree} tree The owner tree
24500 * @param {Node} parent The parent node
24501 * @param {Node} node The newly appended node
24502 * @param {Number} index The index of the newly appended node
24507 * Fires when a child node is removed from a node in this tree.
24508 * @param {Tree} tree The owner tree
24509 * @param {Node} parent The parent node
24510 * @param {Node} node The child node removed
24515 * Fires when a node is moved to a new location in the tree
24516 * @param {Tree} tree The owner tree
24517 * @param {Node} node The node moved
24518 * @param {Node} oldParent The old parent of this node
24519 * @param {Node} newParent The new parent of this node
24520 * @param {Number} index The index it was moved to
24525 * Fires when a new child node is inserted in 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 inserted
24529 * @param {Node} refNode The child node the node was inserted before
24533 * @event beforeappend
24534 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24535 * @param {Tree} tree The owner tree
24536 * @param {Node} parent The parent node
24537 * @param {Node} node The child node to be appended
24539 "beforeappend" : true,
24541 * @event beforeremove
24542 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24543 * @param {Tree} tree The owner tree
24544 * @param {Node} parent The parent node
24545 * @param {Node} node The child node to be removed
24547 "beforeremove" : true,
24549 * @event beforemove
24550 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24551 * @param {Tree} tree The owner tree
24552 * @param {Node} node The node being moved
24553 * @param {Node} oldParent The parent of the node
24554 * @param {Node} newParent The new parent the node is moving to
24555 * @param {Number} index The index it is being moved to
24557 "beforemove" : true,
24559 * @event beforeinsert
24560 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24561 * @param {Tree} tree The owner tree
24562 * @param {Node} parent The parent node
24563 * @param {Node} node The child node to be inserted
24564 * @param {Node} refNode The child node the node is being inserted before
24566 "beforeinsert" : true
24569 Roo.data.Tree.superclass.constructor.call(this);
24572 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24573 pathSeparator: "/",
24575 proxyNodeEvent : function(){
24576 return this.fireEvent.apply(this, arguments);
24580 * Returns the root node for this tree.
24583 getRootNode : function(){
24588 * Sets the root node for this tree.
24589 * @param {Node} node
24592 setRootNode : function(node){
24594 node.ownerTree = this;
24595 node.isRoot = true;
24596 this.registerNode(node);
24601 * Gets a node in this tree by its id.
24602 * @param {String} id
24605 getNodeById : function(id){
24606 return this.nodeHash[id];
24609 registerNode : function(node){
24610 this.nodeHash[node.id] = node;
24613 unregisterNode : function(node){
24614 delete this.nodeHash[node.id];
24617 toString : function(){
24618 return "[Tree"+(this.id?" "+this.id:"")+"]";
24623 * @class Roo.data.Node
24624 * @extends Roo.util.Observable
24625 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24626 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24628 * @param {Object} attributes The attributes/config for the node
24630 Roo.data.Node = function(attributes){
24632 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24635 this.attributes = attributes || {};
24636 this.leaf = this.attributes.leaf;
24638 * The node id. @type String
24640 this.id = this.attributes.id;
24642 this.id = Roo.id(null, "ynode-");
24643 this.attributes.id = this.id;
24648 * All child nodes of this node. @type Array
24650 this.childNodes = [];
24651 if(!this.childNodes.indexOf){ // indexOf is a must
24652 this.childNodes.indexOf = function(o){
24653 for(var i = 0, len = this.length; i < len; i++){
24662 * The parent node for this node. @type Node
24664 this.parentNode = null;
24666 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24668 this.firstChild = null;
24670 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24672 this.lastChild = null;
24674 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24676 this.previousSibling = null;
24678 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24680 this.nextSibling = null;
24685 * Fires when a new child node is appended
24686 * @param {Tree} tree The owner tree
24687 * @param {Node} this This node
24688 * @param {Node} node The newly appended node
24689 * @param {Number} index The index of the newly appended node
24694 * Fires when a child node is removed
24695 * @param {Tree} tree The owner tree
24696 * @param {Node} this This node
24697 * @param {Node} node The removed node
24702 * Fires when this node is moved to a new location in the tree
24703 * @param {Tree} tree The owner tree
24704 * @param {Node} this This node
24705 * @param {Node} oldParent The old parent of this node
24706 * @param {Node} newParent The new parent of this node
24707 * @param {Number} index The index it was moved to
24712 * Fires when a new child node is inserted.
24713 * @param {Tree} tree The owner tree
24714 * @param {Node} this This node
24715 * @param {Node} node The child node inserted
24716 * @param {Node} refNode The child node the node was inserted before
24720 * @event beforeappend
24721 * Fires before a new child is appended, return false to cancel the append.
24722 * @param {Tree} tree The owner tree
24723 * @param {Node} this This node
24724 * @param {Node} node The child node to be appended
24726 "beforeappend" : true,
24728 * @event beforeremove
24729 * Fires before a child is removed, return false to cancel the remove.
24730 * @param {Tree} tree The owner tree
24731 * @param {Node} this This node
24732 * @param {Node} node The child node to be removed
24734 "beforeremove" : true,
24736 * @event beforemove
24737 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24738 * @param {Tree} tree The owner tree
24739 * @param {Node} this This node
24740 * @param {Node} oldParent The parent of this node
24741 * @param {Node} newParent The new parent this node is moving to
24742 * @param {Number} index The index it is being moved to
24744 "beforemove" : true,
24746 * @event beforeinsert
24747 * Fires before a new child is inserted, return false to cancel the insert.
24748 * @param {Tree} tree The owner tree
24749 * @param {Node} this This node
24750 * @param {Node} node The child node to be inserted
24751 * @param {Node} refNode The child node the node is being inserted before
24753 "beforeinsert" : true
24755 this.listeners = this.attributes.listeners;
24756 Roo.data.Node.superclass.constructor.call(this);
24759 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24760 fireEvent : function(evtName){
24761 // first do standard event for this node
24762 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24765 // then bubble it up to the tree if the event wasn't cancelled
24766 var ot = this.getOwnerTree();
24768 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24776 * Returns true if this node is a leaf
24777 * @return {Boolean}
24779 isLeaf : function(){
24780 return this.leaf === true;
24784 setFirstChild : function(node){
24785 this.firstChild = node;
24789 setLastChild : function(node){
24790 this.lastChild = node;
24795 * Returns true if this node is the last child of its parent
24796 * @return {Boolean}
24798 isLast : function(){
24799 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24803 * Returns true if this node is the first child of its parent
24804 * @return {Boolean}
24806 isFirst : function(){
24807 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24810 hasChildNodes : function(){
24811 return !this.isLeaf() && this.childNodes.length > 0;
24815 * Insert node(s) as the last child node of this node.
24816 * @param {Node/Array} node The node or Array of nodes to append
24817 * @return {Node} The appended node if single append, or null if an array was passed
24819 appendChild : function(node){
24821 if(node instanceof Array){
24823 }else if(arguments.length > 1){
24826 // if passed an array or multiple args do them one by one
24828 for(var i = 0, len = multi.length; i < len; i++) {
24829 this.appendChild(multi[i]);
24832 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
24835 var index = this.childNodes.length;
24836 var oldParent = node.parentNode;
24837 // it's a move, make sure we move it cleanly
24839 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
24842 oldParent.removeChild(node);
24844 index = this.childNodes.length;
24846 this.setFirstChild(node);
24848 this.childNodes.push(node);
24849 node.parentNode = this;
24850 var ps = this.childNodes[index-1];
24852 node.previousSibling = ps;
24853 ps.nextSibling = node;
24855 node.previousSibling = null;
24857 node.nextSibling = null;
24858 this.setLastChild(node);
24859 node.setOwnerTree(this.getOwnerTree());
24860 this.fireEvent("append", this.ownerTree, this, node, index);
24862 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
24869 * Removes a child node from this node.
24870 * @param {Node} node The node to remove
24871 * @return {Node} The removed node
24873 removeChild : function(node){
24874 var index = this.childNodes.indexOf(node);
24878 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
24882 // remove it from childNodes collection
24883 this.childNodes.splice(index, 1);
24886 if(node.previousSibling){
24887 node.previousSibling.nextSibling = node.nextSibling;
24889 if(node.nextSibling){
24890 node.nextSibling.previousSibling = node.previousSibling;
24893 // update child refs
24894 if(this.firstChild == node){
24895 this.setFirstChild(node.nextSibling);
24897 if(this.lastChild == node){
24898 this.setLastChild(node.previousSibling);
24901 node.setOwnerTree(null);
24902 // clear any references from the node
24903 node.parentNode = null;
24904 node.previousSibling = null;
24905 node.nextSibling = null;
24906 this.fireEvent("remove", this.ownerTree, this, node);
24911 * Inserts the first node before the second node in this nodes childNodes collection.
24912 * @param {Node} node The node to insert
24913 * @param {Node} refNode The node to insert before (if null the node is appended)
24914 * @return {Node} The inserted node
24916 insertBefore : function(node, refNode){
24917 if(!refNode){ // like standard Dom, refNode can be null for append
24918 return this.appendChild(node);
24921 if(node == refNode){
24925 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
24928 var index = this.childNodes.indexOf(refNode);
24929 var oldParent = node.parentNode;
24930 var refIndex = index;
24932 // when moving internally, indexes will change after remove
24933 if(oldParent == this && this.childNodes.indexOf(node) < index){
24937 // it's a move, make sure we move it cleanly
24939 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
24942 oldParent.removeChild(node);
24945 this.setFirstChild(node);
24947 this.childNodes.splice(refIndex, 0, node);
24948 node.parentNode = this;
24949 var ps = this.childNodes[refIndex-1];
24951 node.previousSibling = ps;
24952 ps.nextSibling = node;
24954 node.previousSibling = null;
24956 node.nextSibling = refNode;
24957 refNode.previousSibling = node;
24958 node.setOwnerTree(this.getOwnerTree());
24959 this.fireEvent("insert", this.ownerTree, this, node, refNode);
24961 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
24967 * Returns the child node at the specified index.
24968 * @param {Number} index
24971 item : function(index){
24972 return this.childNodes[index];
24976 * Replaces one child node in this node with another.
24977 * @param {Node} newChild The replacement node
24978 * @param {Node} oldChild The node to replace
24979 * @return {Node} The replaced node
24981 replaceChild : function(newChild, oldChild){
24982 this.insertBefore(newChild, oldChild);
24983 this.removeChild(oldChild);
24988 * Returns the index of a child node
24989 * @param {Node} node
24990 * @return {Number} The index of the node or -1 if it was not found
24992 indexOf : function(child){
24993 return this.childNodes.indexOf(child);
24997 * Returns the tree this node is in.
25000 getOwnerTree : function(){
25001 // if it doesn't have one, look for one
25002 if(!this.ownerTree){
25006 this.ownerTree = p.ownerTree;
25012 return this.ownerTree;
25016 * Returns depth of this node (the root node has a depth of 0)
25019 getDepth : function(){
25022 while(p.parentNode){
25030 setOwnerTree : function(tree){
25031 // if it's move, we need to update everyone
25032 if(tree != this.ownerTree){
25033 if(this.ownerTree){
25034 this.ownerTree.unregisterNode(this);
25036 this.ownerTree = tree;
25037 var cs = this.childNodes;
25038 for(var i = 0, len = cs.length; i < len; i++) {
25039 cs[i].setOwnerTree(tree);
25042 tree.registerNode(this);
25048 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25049 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25050 * @return {String} The path
25052 getPath : function(attr){
25053 attr = attr || "id";
25054 var p = this.parentNode;
25055 var b = [this.attributes[attr]];
25057 b.unshift(p.attributes[attr]);
25060 var sep = this.getOwnerTree().pathSeparator;
25061 return sep + b.join(sep);
25065 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25066 * function call will be the scope provided or the current node. The arguments to the function
25067 * will be the args provided or the current node. If the function returns false at any point,
25068 * the bubble is stopped.
25069 * @param {Function} fn The function to call
25070 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25071 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25073 bubble : function(fn, scope, args){
25076 if(fn.call(scope || p, args || p) === false){
25084 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25085 * function call will be the scope provided or the current node. The arguments to the function
25086 * will be the args provided or the current node. If the function returns false at any point,
25087 * the cascade is stopped on that branch.
25088 * @param {Function} fn The function to call
25089 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25090 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25092 cascade : function(fn, scope, args){
25093 if(fn.call(scope || this, args || this) !== false){
25094 var cs = this.childNodes;
25095 for(var i = 0, len = cs.length; i < len; i++) {
25096 cs[i].cascade(fn, scope, args);
25102 * Interates the child nodes of 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 iteration stops.
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 eachChild : function(fn, scope, args){
25111 var cs = this.childNodes;
25112 for(var i = 0, len = cs.length; i < len; i++) {
25113 if(fn.call(scope || this, args || cs[i]) === false){
25120 * Finds the first child that has the attribute with the specified value.
25121 * @param {String} attribute The attribute name
25122 * @param {Mixed} value The value to search for
25123 * @return {Node} The found child or null if none was found
25125 findChild : function(attribute, value){
25126 var cs = this.childNodes;
25127 for(var i = 0, len = cs.length; i < len; i++) {
25128 if(cs[i].attributes[attribute] == value){
25136 * Finds the first child by a custom function. The child matches if the function passed
25138 * @param {Function} fn
25139 * @param {Object} scope (optional)
25140 * @return {Node} The found child or null if none was found
25142 findChildBy : function(fn, scope){
25143 var cs = this.childNodes;
25144 for(var i = 0, len = cs.length; i < len; i++) {
25145 if(fn.call(scope||cs[i], cs[i]) === true){
25153 * Sorts this nodes children using the supplied sort function
25154 * @param {Function} fn
25155 * @param {Object} scope (optional)
25157 sort : function(fn, scope){
25158 var cs = this.childNodes;
25159 var len = cs.length;
25161 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25163 for(var i = 0; i < len; i++){
25165 n.previousSibling = cs[i-1];
25166 n.nextSibling = cs[i+1];
25168 this.setFirstChild(n);
25171 this.setLastChild(n);
25178 * Returns true if this node is an ancestor (at any point) of the passed node.
25179 * @param {Node} node
25180 * @return {Boolean}
25182 contains : function(node){
25183 return node.isAncestor(this);
25187 * Returns true if the passed node is an ancestor (at any point) of this node.
25188 * @param {Node} node
25189 * @return {Boolean}
25191 isAncestor : function(node){
25192 var p = this.parentNode;
25202 toString : function(){
25203 return "[Node"+(this.id?" "+this.id:"")+"]";
25207 * Ext JS Library 1.1.1
25208 * Copyright(c) 2006-2007, Ext JS, LLC.
25210 * Originally Released Under LGPL - original licence link has changed is not relivant.
25213 * <script type="text/javascript">
25218 * @extends Roo.Element
25219 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25220 * automatic maintaining of shadow/shim positions.
25221 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25222 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25223 * you can pass a string with a CSS class name. False turns off the shadow.
25224 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25225 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25226 * @cfg {String} cls CSS class to add to the element
25227 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25228 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25230 * @param {Object} config An object with config options.
25231 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25234 Roo.Layer = function(config, existingEl){
25235 config = config || {};
25236 var dh = Roo.DomHelper;
25237 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25239 this.dom = Roo.getDom(existingEl);
25242 var o = config.dh || {tag: "div", cls: "x-layer"};
25243 this.dom = dh.append(pel, o);
25246 this.addClass(config.cls);
25248 this.constrain = config.constrain !== false;
25249 this.visibilityMode = Roo.Element.VISIBILITY;
25251 this.id = this.dom.id = config.id;
25253 this.id = Roo.id(this.dom);
25255 this.zindex = config.zindex || this.getZIndex();
25256 this.position("absolute", this.zindex);
25258 this.shadowOffset = config.shadowOffset || 4;
25259 this.shadow = new Roo.Shadow({
25260 offset : this.shadowOffset,
25261 mode : config.shadow
25264 this.shadowOffset = 0;
25266 this.useShim = config.shim !== false && Roo.useShims;
25267 this.useDisplay = config.useDisplay;
25271 var supr = Roo.Element.prototype;
25273 // shims are shared among layer to keep from having 100 iframes
25276 Roo.extend(Roo.Layer, Roo.Element, {
25278 getZIndex : function(){
25279 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25282 getShim : function(){
25289 var shim = shims.shift();
25291 shim = this.createShim();
25292 shim.enableDisplayMode('block');
25293 shim.dom.style.display = 'none';
25294 shim.dom.style.visibility = 'visible';
25296 var pn = this.dom.parentNode;
25297 if(shim.dom.parentNode != pn){
25298 pn.insertBefore(shim.dom, this.dom);
25300 shim.setStyle('z-index', this.getZIndex()-2);
25305 hideShim : function(){
25307 this.shim.setDisplayed(false);
25308 shims.push(this.shim);
25313 disableShadow : function(){
25315 this.shadowDisabled = true;
25316 this.shadow.hide();
25317 this.lastShadowOffset = this.shadowOffset;
25318 this.shadowOffset = 0;
25322 enableShadow : function(show){
25324 this.shadowDisabled = false;
25325 this.shadowOffset = this.lastShadowOffset;
25326 delete this.lastShadowOffset;
25334 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25335 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25336 sync : function(doShow){
25337 var sw = this.shadow;
25338 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25339 var sh = this.getShim();
25341 var w = this.getWidth(),
25342 h = this.getHeight();
25344 var l = this.getLeft(true),
25345 t = this.getTop(true);
25347 if(sw && !this.shadowDisabled){
25348 if(doShow && !sw.isVisible()){
25351 sw.realign(l, t, w, h);
25357 // fit the shim behind the shadow, so it is shimmed too
25358 var a = sw.adjusts, s = sh.dom.style;
25359 s.left = (Math.min(l, l+a.l))+"px";
25360 s.top = (Math.min(t, t+a.t))+"px";
25361 s.width = (w+a.w)+"px";
25362 s.height = (h+a.h)+"px";
25369 sh.setLeftTop(l, t);
25376 destroy : function(){
25379 this.shadow.hide();
25381 this.removeAllListeners();
25382 var pn = this.dom.parentNode;
25384 pn.removeChild(this.dom);
25386 Roo.Element.uncache(this.id);
25389 remove : function(){
25394 beginUpdate : function(){
25395 this.updating = true;
25399 endUpdate : function(){
25400 this.updating = false;
25405 hideUnders : function(negOffset){
25407 this.shadow.hide();
25413 constrainXY : function(){
25414 if(this.constrain){
25415 var vw = Roo.lib.Dom.getViewWidth(),
25416 vh = Roo.lib.Dom.getViewHeight();
25417 var s = Roo.get(document).getScroll();
25419 var xy = this.getXY();
25420 var x = xy[0], y = xy[1];
25421 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25422 // only move it if it needs it
25424 // first validate right/bottom
25425 if((x + w) > vw+s.left){
25426 x = vw - w - this.shadowOffset;
25429 if((y + h) > vh+s.top){
25430 y = vh - h - this.shadowOffset;
25433 // then make sure top/left isn't negative
25444 var ay = this.avoidY;
25445 if(y <= ay && (y+h) >= ay){
25451 supr.setXY.call(this, xy);
25457 isVisible : function(){
25458 return this.visible;
25462 showAction : function(){
25463 this.visible = true; // track visibility to prevent getStyle calls
25464 if(this.useDisplay === true){
25465 this.setDisplayed("");
25466 }else if(this.lastXY){
25467 supr.setXY.call(this, this.lastXY);
25468 }else if(this.lastLT){
25469 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25474 hideAction : function(){
25475 this.visible = false;
25476 if(this.useDisplay === true){
25477 this.setDisplayed(false);
25479 this.setLeftTop(-10000,-10000);
25483 // overridden Element method
25484 setVisible : function(v, a, d, c, e){
25489 var cb = function(){
25494 }.createDelegate(this);
25495 supr.setVisible.call(this, true, true, d, cb, e);
25498 this.hideUnders(true);
25507 }.createDelegate(this);
25509 supr.setVisible.call(this, v, a, d, cb, e);
25518 storeXY : function(xy){
25519 delete this.lastLT;
25523 storeLeftTop : function(left, top){
25524 delete this.lastXY;
25525 this.lastLT = [left, top];
25529 beforeFx : function(){
25530 this.beforeAction();
25531 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25535 afterFx : function(){
25536 Roo.Layer.superclass.afterFx.apply(this, arguments);
25537 this.sync(this.isVisible());
25541 beforeAction : function(){
25542 if(!this.updating && this.shadow){
25543 this.shadow.hide();
25547 // overridden Element method
25548 setLeft : function(left){
25549 this.storeLeftTop(left, this.getTop(true));
25550 supr.setLeft.apply(this, arguments);
25554 setTop : function(top){
25555 this.storeLeftTop(this.getLeft(true), top);
25556 supr.setTop.apply(this, arguments);
25560 setLeftTop : function(left, top){
25561 this.storeLeftTop(left, top);
25562 supr.setLeftTop.apply(this, arguments);
25566 setXY : function(xy, a, d, c, e){
25568 this.beforeAction();
25570 var cb = this.createCB(c);
25571 supr.setXY.call(this, xy, a, d, cb, e);
25578 createCB : function(c){
25589 // overridden Element method
25590 setX : function(x, a, d, c, e){
25591 this.setXY([x, this.getY()], a, d, c, e);
25594 // overridden Element method
25595 setY : function(y, a, d, c, e){
25596 this.setXY([this.getX(), y], a, d, c, e);
25599 // overridden Element method
25600 setSize : function(w, h, a, d, c, e){
25601 this.beforeAction();
25602 var cb = this.createCB(c);
25603 supr.setSize.call(this, w, h, a, d, cb, e);
25609 // overridden Element method
25610 setWidth : function(w, a, d, c, e){
25611 this.beforeAction();
25612 var cb = this.createCB(c);
25613 supr.setWidth.call(this, w, a, d, cb, e);
25619 // overridden Element method
25620 setHeight : function(h, a, d, c, e){
25621 this.beforeAction();
25622 var cb = this.createCB(c);
25623 supr.setHeight.call(this, h, a, d, cb, e);
25629 // overridden Element method
25630 setBounds : function(x, y, w, h, a, d, c, e){
25631 this.beforeAction();
25632 var cb = this.createCB(c);
25634 this.storeXY([x, y]);
25635 supr.setXY.call(this, [x, y]);
25636 supr.setSize.call(this, w, h, a, d, cb, e);
25639 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25645 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25646 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25647 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25648 * @param {Number} zindex The new z-index to set
25649 * @return {this} The Layer
25651 setZIndex : function(zindex){
25652 this.zindex = zindex;
25653 this.setStyle("z-index", zindex + 2);
25655 this.shadow.setZIndex(zindex + 1);
25658 this.shim.setStyle("z-index", zindex);
25664 * Ext JS Library 1.1.1
25665 * Copyright(c) 2006-2007, Ext JS, LLC.
25667 * Originally Released Under LGPL - original licence link has changed is not relivant.
25670 * <script type="text/javascript">
25675 * @class Roo.Shadow
25676 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25677 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25678 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25680 * Create a new Shadow
25681 * @param {Object} config The config object
25683 Roo.Shadow = function(config){
25684 Roo.apply(this, config);
25685 if(typeof this.mode != "string"){
25686 this.mode = this.defaultMode;
25688 var o = this.offset, a = {h: 0};
25689 var rad = Math.floor(this.offset/2);
25690 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25696 a.l -= this.offset + rad;
25697 a.t -= this.offset + rad;
25708 a.l -= (this.offset - rad);
25709 a.t -= this.offset + rad;
25711 a.w -= (this.offset - rad)*2;
25722 a.l -= (this.offset - rad);
25723 a.t -= (this.offset - rad);
25725 a.w -= (this.offset + rad + 1);
25726 a.h -= (this.offset + rad);
25735 Roo.Shadow.prototype = {
25737 * @cfg {String} mode
25738 * The shadow display mode. Supports the following options:<br />
25739 * sides: Shadow displays on both sides and bottom only<br />
25740 * frame: Shadow displays equally on all four sides<br />
25741 * drop: Traditional bottom-right drop shadow (default)
25744 * @cfg {String} offset
25745 * The number of pixels to offset the shadow from the element (defaults to 4)
25750 defaultMode: "drop",
25753 * Displays the shadow under the target element
25754 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25756 show : function(target){
25757 target = Roo.get(target);
25759 this.el = Roo.Shadow.Pool.pull();
25760 if(this.el.dom.nextSibling != target.dom){
25761 this.el.insertBefore(target);
25764 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25766 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25769 target.getLeft(true),
25770 target.getTop(true),
25774 this.el.dom.style.display = "block";
25778 * Returns true if the shadow is visible, else false
25780 isVisible : function(){
25781 return this.el ? true : false;
25785 * Direct alignment when values are already available. Show must be called at least once before
25786 * calling this method to ensure it is initialized.
25787 * @param {Number} left The target element left position
25788 * @param {Number} top The target element top position
25789 * @param {Number} width The target element width
25790 * @param {Number} height The target element height
25792 realign : function(l, t, w, h){
25796 var a = this.adjusts, d = this.el.dom, s = d.style;
25798 s.left = (l+a.l)+"px";
25799 s.top = (t+a.t)+"px";
25800 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25802 if(s.width != sws || s.height != shs){
25806 var cn = d.childNodes;
25807 var sww = Math.max(0, (sw-12))+"px";
25808 cn[0].childNodes[1].style.width = sww;
25809 cn[1].childNodes[1].style.width = sww;
25810 cn[2].childNodes[1].style.width = sww;
25811 cn[1].style.height = Math.max(0, (sh-12))+"px";
25817 * Hides this shadow
25821 this.el.dom.style.display = "none";
25822 Roo.Shadow.Pool.push(this.el);
25828 * Adjust the z-index of this shadow
25829 * @param {Number} zindex The new z-index
25831 setZIndex : function(z){
25834 this.el.setStyle("z-index", z);
25839 // Private utility class that manages the internal Shadow cache
25840 Roo.Shadow.Pool = function(){
25842 var markup = Roo.isIE ?
25843 '<div class="x-ie-shadow"></div>' :
25844 '<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>';
25847 var sh = p.shift();
25849 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
25850 sh.autoBoxAdjust = false;
25855 push : function(sh){
25861 * Ext JS Library 1.1.1
25862 * Copyright(c) 2006-2007, Ext JS, LLC.
25864 * Originally Released Under LGPL - original licence link has changed is not relivant.
25867 * <script type="text/javascript">
25872 * @class Roo.SplitBar
25873 * @extends Roo.util.Observable
25874 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
25878 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
25879 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
25880 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
25881 split.minSize = 100;
25882 split.maxSize = 600;
25883 split.animate = true;
25884 split.on('moved', splitterMoved);
25887 * Create a new SplitBar
25888 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
25889 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
25890 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25891 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
25892 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
25893 position of the SplitBar).
25895 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
25898 this.el = Roo.get(dragElement, true);
25899 this.el.dom.unselectable = "on";
25901 this.resizingEl = Roo.get(resizingElement, true);
25905 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25906 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
25909 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
25912 * The minimum size of the resizing element. (Defaults to 0)
25918 * The maximum size of the resizing element. (Defaults to 2000)
25921 this.maxSize = 2000;
25924 * Whether to animate the transition to the new size
25927 this.animate = false;
25930 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
25933 this.useShim = false;
25938 if(!existingProxy){
25940 this.proxy = Roo.SplitBar.createProxy(this.orientation);
25942 this.proxy = Roo.get(existingProxy).dom;
25945 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
25948 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
25951 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
25954 this.dragSpecs = {};
25957 * @private The adapter to use to positon and resize elements
25959 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
25960 this.adapter.init(this);
25962 if(this.orientation == Roo.SplitBar.HORIZONTAL){
25964 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
25965 this.el.addClass("x-splitbar-h");
25968 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
25969 this.el.addClass("x-splitbar-v");
25975 * Fires when the splitter is moved (alias for {@link #event-moved})
25976 * @param {Roo.SplitBar} this
25977 * @param {Number} newSize the new width or height
25982 * Fires when the splitter is moved
25983 * @param {Roo.SplitBar} this
25984 * @param {Number} newSize the new width or height
25988 * @event beforeresize
25989 * Fires before the splitter is dragged
25990 * @param {Roo.SplitBar} this
25992 "beforeresize" : true,
25994 "beforeapply" : true
25997 Roo.util.Observable.call(this);
26000 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26001 onStartProxyDrag : function(x, y){
26002 this.fireEvent("beforeresize", this);
26004 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26006 o.enableDisplayMode("block");
26007 // all splitbars share the same overlay
26008 Roo.SplitBar.prototype.overlay = o;
26010 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26011 this.overlay.show();
26012 Roo.get(this.proxy).setDisplayed("block");
26013 var size = this.adapter.getElementSize(this);
26014 this.activeMinSize = this.getMinimumSize();;
26015 this.activeMaxSize = this.getMaximumSize();;
26016 var c1 = size - this.activeMinSize;
26017 var c2 = Math.max(this.activeMaxSize - size, 0);
26018 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26019 this.dd.resetConstraints();
26020 this.dd.setXConstraint(
26021 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26022 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26024 this.dd.setYConstraint(0, 0);
26026 this.dd.resetConstraints();
26027 this.dd.setXConstraint(0, 0);
26028 this.dd.setYConstraint(
26029 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26030 this.placement == Roo.SplitBar.TOP ? c2 : c1
26033 this.dragSpecs.startSize = size;
26034 this.dragSpecs.startPoint = [x, y];
26035 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26039 * @private Called after the drag operation by the DDProxy
26041 onEndProxyDrag : function(e){
26042 Roo.get(this.proxy).setDisplayed(false);
26043 var endPoint = Roo.lib.Event.getXY(e);
26045 this.overlay.hide();
26048 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26049 newSize = this.dragSpecs.startSize +
26050 (this.placement == Roo.SplitBar.LEFT ?
26051 endPoint[0] - this.dragSpecs.startPoint[0] :
26052 this.dragSpecs.startPoint[0] - endPoint[0]
26055 newSize = this.dragSpecs.startSize +
26056 (this.placement == Roo.SplitBar.TOP ?
26057 endPoint[1] - this.dragSpecs.startPoint[1] :
26058 this.dragSpecs.startPoint[1] - endPoint[1]
26061 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26062 if(newSize != this.dragSpecs.startSize){
26063 if(this.fireEvent('beforeapply', this, newSize) !== false){
26064 this.adapter.setElementSize(this, newSize);
26065 this.fireEvent("moved", this, newSize);
26066 this.fireEvent("resize", this, newSize);
26072 * Get the adapter this SplitBar uses
26073 * @return The adapter object
26075 getAdapter : function(){
26076 return this.adapter;
26080 * Set the adapter this SplitBar uses
26081 * @param {Object} adapter A SplitBar adapter object
26083 setAdapter : function(adapter){
26084 this.adapter = adapter;
26085 this.adapter.init(this);
26089 * Gets the minimum size for the resizing element
26090 * @return {Number} The minimum size
26092 getMinimumSize : function(){
26093 return this.minSize;
26097 * Sets the minimum size for the resizing element
26098 * @param {Number} minSize The minimum size
26100 setMinimumSize : function(minSize){
26101 this.minSize = minSize;
26105 * Gets the maximum size for the resizing element
26106 * @return {Number} The maximum size
26108 getMaximumSize : function(){
26109 return this.maxSize;
26113 * Sets the maximum size for the resizing element
26114 * @param {Number} maxSize The maximum size
26116 setMaximumSize : function(maxSize){
26117 this.maxSize = maxSize;
26121 * Sets the initialize size for the resizing element
26122 * @param {Number} size The initial size
26124 setCurrentSize : function(size){
26125 var oldAnimate = this.animate;
26126 this.animate = false;
26127 this.adapter.setElementSize(this, size);
26128 this.animate = oldAnimate;
26132 * Destroy this splitbar.
26133 * @param {Boolean} removeEl True to remove the element
26135 destroy : function(removeEl){
26137 this.shim.remove();
26140 this.proxy.parentNode.removeChild(this.proxy);
26148 * @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.
26150 Roo.SplitBar.createProxy = function(dir){
26151 var proxy = new Roo.Element(document.createElement("div"));
26152 proxy.unselectable();
26153 var cls = 'x-splitbar-proxy';
26154 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26155 document.body.appendChild(proxy.dom);
26160 * @class Roo.SplitBar.BasicLayoutAdapter
26161 * Default Adapter. It assumes the splitter and resizing element are not positioned
26162 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26164 Roo.SplitBar.BasicLayoutAdapter = function(){
26167 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26168 // do nothing for now
26169 init : function(s){
26173 * Called before drag operations to get the current size of the resizing element.
26174 * @param {Roo.SplitBar} s The SplitBar using this adapter
26176 getElementSize : function(s){
26177 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26178 return s.resizingEl.getWidth();
26180 return s.resizingEl.getHeight();
26185 * Called after drag operations to set the size of the resizing element.
26186 * @param {Roo.SplitBar} s The SplitBar using this adapter
26187 * @param {Number} newSize The new size to set
26188 * @param {Function} onComplete A function to be invoked when resizing is complete
26190 setElementSize : function(s, newSize, onComplete){
26191 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26193 s.resizingEl.setWidth(newSize);
26195 onComplete(s, newSize);
26198 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26203 s.resizingEl.setHeight(newSize);
26205 onComplete(s, newSize);
26208 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26215 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26216 * @extends Roo.SplitBar.BasicLayoutAdapter
26217 * Adapter that moves the splitter element to align with the resized sizing element.
26218 * Used with an absolute positioned SplitBar.
26219 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26220 * document.body, make sure you assign an id to the body element.
26222 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26223 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26224 this.container = Roo.get(container);
26227 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26228 init : function(s){
26229 this.basic.init(s);
26232 getElementSize : function(s){
26233 return this.basic.getElementSize(s);
26236 setElementSize : function(s, newSize, onComplete){
26237 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26240 moveSplitter : function(s){
26241 var yes = Roo.SplitBar;
26242 switch(s.placement){
26244 s.el.setX(s.resizingEl.getRight());
26247 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26250 s.el.setY(s.resizingEl.getBottom());
26253 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26260 * Orientation constant - Create a vertical SplitBar
26264 Roo.SplitBar.VERTICAL = 1;
26267 * Orientation constant - Create a horizontal SplitBar
26271 Roo.SplitBar.HORIZONTAL = 2;
26274 * Placement constant - The resizing element is to the left of the splitter element
26278 Roo.SplitBar.LEFT = 1;
26281 * Placement constant - The resizing element is to the right of the splitter element
26285 Roo.SplitBar.RIGHT = 2;
26288 * Placement constant - The resizing element is positioned above the splitter element
26292 Roo.SplitBar.TOP = 3;
26295 * Placement constant - The resizing element is positioned under splitter element
26299 Roo.SplitBar.BOTTOM = 4;
26302 * Ext JS Library 1.1.1
26303 * Copyright(c) 2006-2007, Ext JS, LLC.
26305 * Originally Released Under LGPL - original licence link has changed is not relivant.
26308 * <script type="text/javascript">
26313 * @extends Roo.util.Observable
26314 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26315 * This class also supports single and multi selection modes. <br>
26316 * Create a data model bound view:
26318 var store = new Roo.data.Store(...);
26320 var view = new Roo.View({
26322 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26324 singleSelect: true,
26325 selectedClass: "ydataview-selected",
26329 // listen for node click?
26330 view.on("click", function(vw, index, node, e){
26331 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26335 dataModel.load("foobar.xml");
26337 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26339 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26340 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26342 * Note: old style constructor is still suported (container, template, config)
26345 * Create a new View
26346 * @param {Object} config The config object
26349 Roo.View = function(config, depreciated_tpl, depreciated_config){
26351 this.parent = false;
26353 if (typeof(depreciated_tpl) == 'undefined') {
26354 // new way.. - universal constructor.
26355 Roo.apply(this, config);
26356 this.el = Roo.get(this.el);
26359 this.el = Roo.get(config);
26360 this.tpl = depreciated_tpl;
26361 Roo.apply(this, depreciated_config);
26363 this.wrapEl = this.el.wrap().wrap();
26364 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26367 if(typeof(this.tpl) == "string"){
26368 this.tpl = new Roo.Template(this.tpl);
26370 // support xtype ctors..
26371 this.tpl = new Roo.factory(this.tpl, Roo);
26375 this.tpl.compile();
26380 * @event beforeclick
26381 * Fires before a click is processed. Returns false to cancel the default action.
26382 * @param {Roo.View} this
26383 * @param {Number} index The index of the target node
26384 * @param {HTMLElement} node The target node
26385 * @param {Roo.EventObject} e The raw event object
26387 "beforeclick" : true,
26390 * Fires when a template node is clicked.
26391 * @param {Roo.View} this
26392 * @param {Number} index The index of the target node
26393 * @param {HTMLElement} node The target node
26394 * @param {Roo.EventObject} e The raw event object
26399 * Fires when a template node is double clicked.
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
26407 * @event contextmenu
26408 * Fires when a template node is right 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
26414 "contextmenu" : true,
26416 * @event selectionchange
26417 * Fires when the selected nodes change.
26418 * @param {Roo.View} this
26419 * @param {Array} selections Array of the selected nodes
26421 "selectionchange" : true,
26424 * @event beforeselect
26425 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26426 * @param {Roo.View} this
26427 * @param {HTMLElement} node The node to be selected
26428 * @param {Array} selections Array of currently selected nodes
26430 "beforeselect" : true,
26432 * @event preparedata
26433 * Fires on every row to render, to allow you to change the data.
26434 * @param {Roo.View} this
26435 * @param {Object} data to be rendered (change this)
26437 "preparedata" : true
26445 "click": this.onClick,
26446 "dblclick": this.onDblClick,
26447 "contextmenu": this.onContextMenu,
26451 this.selections = [];
26453 this.cmp = new Roo.CompositeElementLite([]);
26455 this.store = Roo.factory(this.store, Roo.data);
26456 this.setStore(this.store, true);
26459 if ( this.footer && this.footer.xtype) {
26461 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26463 this.footer.dataSource = this.store;
26464 this.footer.container = fctr;
26465 this.footer = Roo.factory(this.footer, Roo);
26466 fctr.insertFirst(this.el);
26468 // this is a bit insane - as the paging toolbar seems to detach the el..
26469 // dom.parentNode.parentNode.parentNode
26470 // they get detached?
26474 Roo.View.superclass.constructor.call(this);
26479 Roo.extend(Roo.View, Roo.util.Observable, {
26482 * @cfg {Roo.data.Store} store Data store to load data from.
26487 * @cfg {String|Roo.Element} el The container element.
26492 * @cfg {String|Roo.Template} tpl The template used by this View
26496 * @cfg {String} dataName the named area of the template to use as the data area
26497 * Works with domtemplates roo-name="name"
26501 * @cfg {String} selectedClass The css class to add to selected nodes
26503 selectedClass : "x-view-selected",
26505 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26510 * @cfg {String} text to display on mask (default Loading)
26514 * @cfg {Boolean} multiSelect Allow multiple selection
26516 multiSelect : false,
26518 * @cfg {Boolean} singleSelect Allow single selection
26520 singleSelect: false,
26523 * @cfg {Boolean} toggleSelect - selecting
26525 toggleSelect : false,
26528 * @cfg {Boolean} tickable - selecting
26533 * Returns the element this view is bound to.
26534 * @return {Roo.Element}
26536 getEl : function(){
26537 return this.wrapEl;
26543 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26545 refresh : function(){
26546 //Roo.log('refresh');
26549 // if we are using something like 'domtemplate', then
26550 // the what gets used is:
26551 // t.applySubtemplate(NAME, data, wrapping data..)
26552 // the outer template then get' applied with
26553 // the store 'extra data'
26554 // and the body get's added to the
26555 // roo-name="data" node?
26556 // <span class='roo-tpl-{name}'></span> ?????
26560 this.clearSelections();
26561 this.el.update("");
26563 var records = this.store.getRange();
26564 if(records.length < 1) {
26566 // is this valid?? = should it render a template??
26568 this.el.update(this.emptyText);
26572 if (this.dataName) {
26573 this.el.update(t.apply(this.store.meta)); //????
26574 el = this.el.child('.roo-tpl-' + this.dataName);
26577 for(var i = 0, len = records.length; i < len; i++){
26578 var data = this.prepareData(records[i].data, i, records[i]);
26579 this.fireEvent("preparedata", this, data, i, records[i]);
26581 var d = Roo.apply({}, data);
26584 Roo.apply(d, {'roo-id' : Roo.id()});
26588 Roo.each(this.parent.item, function(item){
26589 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26592 Roo.apply(d, {'roo-data-checked' : 'checked'});
26596 html[html.length] = Roo.util.Format.trim(
26598 t.applySubtemplate(this.dataName, d, this.store.meta) :
26605 el.update(html.join(""));
26606 this.nodes = el.dom.childNodes;
26607 this.updateIndexes(0);
26612 * Function to override to reformat the data that is sent to
26613 * the template for each node.
26614 * DEPRICATED - use the preparedata event handler.
26615 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26616 * a JSON object for an UpdateManager bound view).
26618 prepareData : function(data, index, record)
26620 this.fireEvent("preparedata", this, data, index, record);
26624 onUpdate : function(ds, record){
26625 // Roo.log('on update');
26626 this.clearSelections();
26627 var index = this.store.indexOf(record);
26628 var n = this.nodes[index];
26629 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26630 n.parentNode.removeChild(n);
26631 this.updateIndexes(index, index);
26637 onAdd : function(ds, records, index)
26639 //Roo.log(['on Add', ds, records, index] );
26640 this.clearSelections();
26641 if(this.nodes.length == 0){
26645 var n = this.nodes[index];
26646 for(var i = 0, len = records.length; i < len; i++){
26647 var d = this.prepareData(records[i].data, i, records[i]);
26649 this.tpl.insertBefore(n, d);
26652 this.tpl.append(this.el, d);
26655 this.updateIndexes(index);
26658 onRemove : function(ds, record, index){
26659 // Roo.log('onRemove');
26660 this.clearSelections();
26661 var el = this.dataName ?
26662 this.el.child('.roo-tpl-' + this.dataName) :
26665 el.dom.removeChild(this.nodes[index]);
26666 this.updateIndexes(index);
26670 * Refresh an individual node.
26671 * @param {Number} index
26673 refreshNode : function(index){
26674 this.onUpdate(this.store, this.store.getAt(index));
26677 updateIndexes : function(startIndex, endIndex){
26678 var ns = this.nodes;
26679 startIndex = startIndex || 0;
26680 endIndex = endIndex || ns.length - 1;
26681 for(var i = startIndex; i <= endIndex; i++){
26682 ns[i].nodeIndex = i;
26687 * Changes the data store this view uses and refresh the view.
26688 * @param {Store} store
26690 setStore : function(store, initial){
26691 if(!initial && this.store){
26692 this.store.un("datachanged", this.refresh);
26693 this.store.un("add", this.onAdd);
26694 this.store.un("remove", this.onRemove);
26695 this.store.un("update", this.onUpdate);
26696 this.store.un("clear", this.refresh);
26697 this.store.un("beforeload", this.onBeforeLoad);
26698 this.store.un("load", this.onLoad);
26699 this.store.un("loadexception", this.onLoad);
26703 store.on("datachanged", this.refresh, this);
26704 store.on("add", this.onAdd, this);
26705 store.on("remove", this.onRemove, this);
26706 store.on("update", this.onUpdate, this);
26707 store.on("clear", this.refresh, this);
26708 store.on("beforeload", this.onBeforeLoad, this);
26709 store.on("load", this.onLoad, this);
26710 store.on("loadexception", this.onLoad, this);
26718 * onbeforeLoad - masks the loading area.
26721 onBeforeLoad : function(store,opts)
26723 //Roo.log('onBeforeLoad');
26725 this.el.update("");
26727 this.el.mask(this.mask ? this.mask : "Loading" );
26729 onLoad : function ()
26736 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26737 * @param {HTMLElement} node
26738 * @return {HTMLElement} The template node
26740 findItemFromChild : function(node){
26741 var el = this.dataName ?
26742 this.el.child('.roo-tpl-' + this.dataName,true) :
26745 if(!node || node.parentNode == el){
26748 var p = node.parentNode;
26749 while(p && p != el){
26750 if(p.parentNode == el){
26759 onClick : function(e){
26760 var item = this.findItemFromChild(e.getTarget());
26762 var index = this.indexOf(item);
26763 if(this.onItemClick(item, index, e) !== false){
26764 this.fireEvent("click", this, index, item, e);
26767 this.clearSelections();
26772 onContextMenu : function(e){
26773 var item = this.findItemFromChild(e.getTarget());
26775 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26780 onDblClick : function(e){
26781 var item = this.findItemFromChild(e.getTarget());
26783 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26787 onItemClick : function(item, index, e)
26789 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26792 if (this.toggleSelect) {
26793 var m = this.isSelected(item) ? 'unselect' : 'select';
26796 _t[m](item, true, false);
26799 if(this.multiSelect || this.singleSelect){
26800 if(this.multiSelect && e.shiftKey && this.lastSelection){
26801 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26803 this.select(item, this.multiSelect && e.ctrlKey);
26804 this.lastSelection = item;
26807 if(!this.tickable){
26808 e.preventDefault();
26816 * Get the number of selected nodes.
26819 getSelectionCount : function(){
26820 return this.selections.length;
26824 * Get the currently selected nodes.
26825 * @return {Array} An array of HTMLElements
26827 getSelectedNodes : function(){
26828 return this.selections;
26832 * Get the indexes of the selected nodes.
26835 getSelectedIndexes : function(){
26836 var indexes = [], s = this.selections;
26837 for(var i = 0, len = s.length; i < len; i++){
26838 indexes.push(s[i].nodeIndex);
26844 * Clear all selections
26845 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
26847 clearSelections : function(suppressEvent){
26848 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
26849 this.cmp.elements = this.selections;
26850 this.cmp.removeClass(this.selectedClass);
26851 this.selections = [];
26852 if(!suppressEvent){
26853 this.fireEvent("selectionchange", this, this.selections);
26859 * Returns true if the passed node is selected
26860 * @param {HTMLElement/Number} node The node or node index
26861 * @return {Boolean}
26863 isSelected : function(node){
26864 var s = this.selections;
26868 node = this.getNode(node);
26869 return s.indexOf(node) !== -1;
26874 * @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
26875 * @param {Boolean} keepExisting (optional) true to keep existing selections
26876 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26878 select : function(nodeInfo, keepExisting, suppressEvent){
26879 if(nodeInfo instanceof Array){
26881 this.clearSelections(true);
26883 for(var i = 0, len = nodeInfo.length; i < len; i++){
26884 this.select(nodeInfo[i], true, true);
26888 var node = this.getNode(nodeInfo);
26889 if(!node || this.isSelected(node)){
26890 return; // already selected.
26893 this.clearSelections(true);
26896 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
26897 Roo.fly(node).addClass(this.selectedClass);
26898 this.selections.push(node);
26899 if(!suppressEvent){
26900 this.fireEvent("selectionchange", this, this.selections);
26908 * @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
26909 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
26910 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26912 unselect : function(nodeInfo, keepExisting, suppressEvent)
26914 if(nodeInfo instanceof Array){
26915 Roo.each(this.selections, function(s) {
26916 this.unselect(s, nodeInfo);
26920 var node = this.getNode(nodeInfo);
26921 if(!node || !this.isSelected(node)){
26922 //Roo.log("not selected");
26923 return; // not selected.
26927 Roo.each(this.selections, function(s) {
26929 Roo.fly(node).removeClass(this.selectedClass);
26936 this.selections= ns;
26937 this.fireEvent("selectionchange", this, this.selections);
26941 * Gets a template node.
26942 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26943 * @return {HTMLElement} The node or null if it wasn't found
26945 getNode : function(nodeInfo){
26946 if(typeof nodeInfo == "string"){
26947 return document.getElementById(nodeInfo);
26948 }else if(typeof nodeInfo == "number"){
26949 return this.nodes[nodeInfo];
26955 * Gets a range template nodes.
26956 * @param {Number} startIndex
26957 * @param {Number} endIndex
26958 * @return {Array} An array of nodes
26960 getNodes : function(start, end){
26961 var ns = this.nodes;
26962 start = start || 0;
26963 end = typeof end == "undefined" ? ns.length - 1 : end;
26966 for(var i = start; i <= end; i++){
26970 for(var i = start; i >= end; i--){
26978 * Finds the index of the passed node
26979 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26980 * @return {Number} The index of the node or -1
26982 indexOf : function(node){
26983 node = this.getNode(node);
26984 if(typeof node.nodeIndex == "number"){
26985 return node.nodeIndex;
26987 var ns = this.nodes;
26988 for(var i = 0, len = ns.length; i < len; i++){
26998 * Ext JS Library 1.1.1
26999 * Copyright(c) 2006-2007, Ext JS, LLC.
27001 * Originally Released Under LGPL - original licence link has changed is not relivant.
27004 * <script type="text/javascript">
27008 * @class Roo.JsonView
27009 * @extends Roo.View
27010 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27012 var view = new Roo.JsonView({
27013 container: "my-element",
27014 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27019 // listen for node click?
27020 view.on("click", function(vw, index, node, e){
27021 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27024 // direct load of JSON data
27025 view.load("foobar.php");
27027 // Example from my blog list
27028 var tpl = new Roo.Template(
27029 '<div class="entry">' +
27030 '<a class="entry-title" href="{link}">{title}</a>' +
27031 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27032 "</div><hr />"
27035 var moreView = new Roo.JsonView({
27036 container : "entry-list",
27040 moreView.on("beforerender", this.sortEntries, this);
27042 url: "/blog/get-posts.php",
27043 params: "allposts=true",
27044 text: "Loading Blog Entries..."
27048 * Note: old code is supported with arguments : (container, template, config)
27052 * Create a new JsonView
27054 * @param {Object} config The config object
27057 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27060 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27062 var um = this.el.getUpdateManager();
27063 um.setRenderer(this);
27064 um.on("update", this.onLoad, this);
27065 um.on("failure", this.onLoadException, this);
27068 * @event beforerender
27069 * Fires before rendering of the downloaded JSON data.
27070 * @param {Roo.JsonView} this
27071 * @param {Object} data The JSON data loaded
27075 * Fires when data is loaded.
27076 * @param {Roo.JsonView} this
27077 * @param {Object} data The JSON data loaded
27078 * @param {Object} response The raw Connect response object
27081 * @event loadexception
27082 * Fires when loading fails.
27083 * @param {Roo.JsonView} this
27084 * @param {Object} response The raw Connect response object
27087 'beforerender' : true,
27089 'loadexception' : true
27092 Roo.extend(Roo.JsonView, Roo.View, {
27094 * @type {String} The root property in the loaded JSON object that contains the data
27099 * Refreshes the view.
27101 refresh : function(){
27102 this.clearSelections();
27103 this.el.update("");
27105 var o = this.jsonData;
27106 if(o && o.length > 0){
27107 for(var i = 0, len = o.length; i < len; i++){
27108 var data = this.prepareData(o[i], i, o);
27109 html[html.length] = this.tpl.apply(data);
27112 html.push(this.emptyText);
27114 this.el.update(html.join(""));
27115 this.nodes = this.el.dom.childNodes;
27116 this.updateIndexes(0);
27120 * 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.
27121 * @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:
27124 url: "your-url.php",
27125 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27126 callback: yourFunction,
27127 scope: yourObject, //(optional scope)
27130 text: "Loading...",
27135 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27136 * 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.
27137 * @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}
27138 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27139 * @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.
27142 var um = this.el.getUpdateManager();
27143 um.update.apply(um, arguments);
27146 // note - render is a standard framework call...
27147 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27148 render : function(el, response){
27150 this.clearSelections();
27151 this.el.update("");
27154 if (response != '') {
27155 o = Roo.util.JSON.decode(response.responseText);
27158 o = o[this.jsonRoot];
27164 * The current JSON data or null
27167 this.beforeRender();
27172 * Get the number of records in the current JSON dataset
27175 getCount : function(){
27176 return this.jsonData ? this.jsonData.length : 0;
27180 * Returns the JSON object for the specified node(s)
27181 * @param {HTMLElement/Array} node The node or an array of nodes
27182 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27183 * you get the JSON object for the node
27185 getNodeData : function(node){
27186 if(node instanceof Array){
27188 for(var i = 0, len = node.length; i < len; i++){
27189 data.push(this.getNodeData(node[i]));
27193 return this.jsonData[this.indexOf(node)] || null;
27196 beforeRender : function(){
27197 this.snapshot = this.jsonData;
27199 this.sort.apply(this, this.sortInfo);
27201 this.fireEvent("beforerender", this, this.jsonData);
27204 onLoad : function(el, o){
27205 this.fireEvent("load", this, this.jsonData, o);
27208 onLoadException : function(el, o){
27209 this.fireEvent("loadexception", this, o);
27213 * Filter the data by a specific property.
27214 * @param {String} property A property on your JSON objects
27215 * @param {String/RegExp} value Either string that the property values
27216 * should start with, or a RegExp to test against the property
27218 filter : function(property, value){
27221 var ss = this.snapshot;
27222 if(typeof value == "string"){
27223 var vlen = value.length;
27225 this.clearFilter();
27228 value = value.toLowerCase();
27229 for(var i = 0, len = ss.length; i < len; i++){
27231 if(o[property].substr(0, vlen).toLowerCase() == value){
27235 } else if(value.exec){ // regex?
27236 for(var i = 0, len = ss.length; i < len; i++){
27238 if(value.test(o[property])){
27245 this.jsonData = data;
27251 * Filter by a function. The passed function will be called with each
27252 * object in the current dataset. If the function returns true the value is kept,
27253 * otherwise it is filtered.
27254 * @param {Function} fn
27255 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27257 filterBy : function(fn, scope){
27260 var ss = this.snapshot;
27261 for(var i = 0, len = ss.length; i < len; i++){
27263 if(fn.call(scope || this, o)){
27267 this.jsonData = data;
27273 * Clears the current filter.
27275 clearFilter : function(){
27276 if(this.snapshot && this.jsonData != this.snapshot){
27277 this.jsonData = this.snapshot;
27284 * Sorts the data for this view and refreshes it.
27285 * @param {String} property A property on your JSON objects to sort on
27286 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27287 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27289 sort : function(property, dir, sortType){
27290 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27293 var dsc = dir && dir.toLowerCase() == "desc";
27294 var f = function(o1, o2){
27295 var v1 = sortType ? sortType(o1[p]) : o1[p];
27296 var v2 = sortType ? sortType(o2[p]) : o2[p];
27299 return dsc ? +1 : -1;
27300 } else if(v1 > v2){
27301 return dsc ? -1 : +1;
27306 this.jsonData.sort(f);
27308 if(this.jsonData != this.snapshot){
27309 this.snapshot.sort(f);
27315 * Ext JS Library 1.1.1
27316 * Copyright(c) 2006-2007, Ext JS, LLC.
27318 * Originally Released Under LGPL - original licence link has changed is not relivant.
27321 * <script type="text/javascript">
27326 * @class Roo.ColorPalette
27327 * @extends Roo.Component
27328 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27329 * Here's an example of typical usage:
27331 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27332 cp.render('my-div');
27334 cp.on('select', function(palette, selColor){
27335 // do something with selColor
27339 * Create a new ColorPalette
27340 * @param {Object} config The config object
27342 Roo.ColorPalette = function(config){
27343 Roo.ColorPalette.superclass.constructor.call(this, config);
27347 * Fires when a color is selected
27348 * @param {ColorPalette} this
27349 * @param {String} color The 6-digit color hex code (without the # symbol)
27355 this.on("select", this.handler, this.scope, true);
27358 Roo.extend(Roo.ColorPalette, Roo.Component, {
27360 * @cfg {String} itemCls
27361 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27363 itemCls : "x-color-palette",
27365 * @cfg {String} value
27366 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27367 * the hex codes are case-sensitive.
27370 clickEvent:'click',
27372 ctype: "Roo.ColorPalette",
27375 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27377 allowReselect : false,
27380 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27381 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27382 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27383 * of colors with the width setting until the box is symmetrical.</p>
27384 * <p>You can override individual colors if needed:</p>
27386 var cp = new Roo.ColorPalette();
27387 cp.colors[0] = "FF0000"; // change the first box to red
27390 Or you can provide a custom array of your own for complete control:
27392 var cp = new Roo.ColorPalette();
27393 cp.colors = ["000000", "993300", "333300"];
27398 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27399 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27400 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27401 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27402 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27406 onRender : function(container, position){
27407 var t = new Roo.MasterTemplate(
27408 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27410 var c = this.colors;
27411 for(var i = 0, len = c.length; i < len; i++){
27414 var el = document.createElement("div");
27415 el.className = this.itemCls;
27417 container.dom.insertBefore(el, position);
27418 this.el = Roo.get(el);
27419 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27420 if(this.clickEvent != 'click'){
27421 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27426 afterRender : function(){
27427 Roo.ColorPalette.superclass.afterRender.call(this);
27429 var s = this.value;
27436 handleClick : function(e, t){
27437 e.preventDefault();
27438 if(!this.disabled){
27439 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27440 this.select(c.toUpperCase());
27445 * Selects the specified color in the palette (fires the select event)
27446 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27448 select : function(color){
27449 color = color.replace("#", "");
27450 if(color != this.value || this.allowReselect){
27453 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27455 el.child("a.color-"+color).addClass("x-color-palette-sel");
27456 this.value = color;
27457 this.fireEvent("select", this, color);
27462 * Ext JS Library 1.1.1
27463 * Copyright(c) 2006-2007, Ext JS, LLC.
27465 * Originally Released Under LGPL - original licence link has changed is not relivant.
27468 * <script type="text/javascript">
27472 * @class Roo.DatePicker
27473 * @extends Roo.Component
27474 * Simple date picker class.
27476 * Create a new DatePicker
27477 * @param {Object} config The config object
27479 Roo.DatePicker = function(config){
27480 Roo.DatePicker.superclass.constructor.call(this, config);
27482 this.value = config && config.value ?
27483 config.value.clearTime() : new Date().clearTime();
27488 * Fires when a date is selected
27489 * @param {DatePicker} this
27490 * @param {Date} date The selected date
27494 * @event monthchange
27495 * Fires when the displayed month changes
27496 * @param {DatePicker} this
27497 * @param {Date} date The selected month
27499 'monthchange': true
27503 this.on("select", this.handler, this.scope || this);
27505 // build the disabledDatesRE
27506 if(!this.disabledDatesRE && this.disabledDates){
27507 var dd = this.disabledDates;
27509 for(var i = 0; i < dd.length; i++){
27511 if(i != dd.length-1) {
27515 this.disabledDatesRE = new RegExp(re + ")");
27519 Roo.extend(Roo.DatePicker, Roo.Component, {
27521 * @cfg {String} todayText
27522 * The text to display on the button that selects the current date (defaults to "Today")
27524 todayText : "Today",
27526 * @cfg {String} okText
27527 * The text to display on the ok button
27529 okText : " OK ", //   to give the user extra clicking room
27531 * @cfg {String} cancelText
27532 * The text to display on the cancel button
27534 cancelText : "Cancel",
27536 * @cfg {String} todayTip
27537 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27539 todayTip : "{0} (Spacebar)",
27541 * @cfg {Date} minDate
27542 * Minimum allowable date (JavaScript date object, defaults to null)
27546 * @cfg {Date} maxDate
27547 * Maximum allowable date (JavaScript date object, defaults to null)
27551 * @cfg {String} minText
27552 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27554 minText : "This date is before the minimum date",
27556 * @cfg {String} maxText
27557 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27559 maxText : "This date is after the maximum date",
27561 * @cfg {String} format
27562 * The default date format string which can be overriden for localization support. The format must be
27563 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27567 * @cfg {Array} disabledDays
27568 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27570 disabledDays : null,
27572 * @cfg {String} disabledDaysText
27573 * The tooltip to display when the date falls on a disabled day (defaults to "")
27575 disabledDaysText : "",
27577 * @cfg {RegExp} disabledDatesRE
27578 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27580 disabledDatesRE : null,
27582 * @cfg {String} disabledDatesText
27583 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27585 disabledDatesText : "",
27587 * @cfg {Boolean} constrainToViewport
27588 * True to constrain the date picker to the viewport (defaults to true)
27590 constrainToViewport : true,
27592 * @cfg {Array} monthNames
27593 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27595 monthNames : Date.monthNames,
27597 * @cfg {Array} dayNames
27598 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27600 dayNames : Date.dayNames,
27602 * @cfg {String} nextText
27603 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27605 nextText: 'Next Month (Control+Right)',
27607 * @cfg {String} prevText
27608 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27610 prevText: 'Previous Month (Control+Left)',
27612 * @cfg {String} monthYearText
27613 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27615 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27617 * @cfg {Number} startDay
27618 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27622 * @cfg {Bool} showClear
27623 * Show a clear button (usefull for date form elements that can be blank.)
27629 * Sets the value of the date field
27630 * @param {Date} value The date to set
27632 setValue : function(value){
27633 var old = this.value;
27635 if (typeof(value) == 'string') {
27637 value = Date.parseDate(value, this.format);
27640 value = new Date();
27643 this.value = value.clearTime(true);
27645 this.update(this.value);
27650 * Gets the current selected value of the date field
27651 * @return {Date} The selected date
27653 getValue : function(){
27658 focus : function(){
27660 this.update(this.activeDate);
27665 onRender : function(container, position){
27668 '<table cellspacing="0">',
27669 '<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>',
27670 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27671 var dn = this.dayNames;
27672 for(var i = 0; i < 7; i++){
27673 var d = this.startDay+i;
27677 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27679 m[m.length] = "</tr></thead><tbody><tr>";
27680 for(var i = 0; i < 42; i++) {
27681 if(i % 7 == 0 && i != 0){
27682 m[m.length] = "</tr><tr>";
27684 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27686 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27687 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27689 var el = document.createElement("div");
27690 el.className = "x-date-picker";
27691 el.innerHTML = m.join("");
27693 container.dom.insertBefore(el, position);
27695 this.el = Roo.get(el);
27696 this.eventEl = Roo.get(el.firstChild);
27698 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27699 handler: this.showPrevMonth,
27701 preventDefault:true,
27705 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27706 handler: this.showNextMonth,
27708 preventDefault:true,
27712 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27714 this.monthPicker = this.el.down('div.x-date-mp');
27715 this.monthPicker.enableDisplayMode('block');
27717 var kn = new Roo.KeyNav(this.eventEl, {
27718 "left" : function(e){
27720 this.showPrevMonth() :
27721 this.update(this.activeDate.add("d", -1));
27724 "right" : function(e){
27726 this.showNextMonth() :
27727 this.update(this.activeDate.add("d", 1));
27730 "up" : function(e){
27732 this.showNextYear() :
27733 this.update(this.activeDate.add("d", -7));
27736 "down" : function(e){
27738 this.showPrevYear() :
27739 this.update(this.activeDate.add("d", 7));
27742 "pageUp" : function(e){
27743 this.showNextMonth();
27746 "pageDown" : function(e){
27747 this.showPrevMonth();
27750 "enter" : function(e){
27751 e.stopPropagation();
27758 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27760 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27762 this.el.unselectable();
27764 this.cells = this.el.select("table.x-date-inner tbody td");
27765 this.textNodes = this.el.query("table.x-date-inner tbody span");
27767 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27769 tooltip: this.monthYearText
27772 this.mbtn.on('click', this.showMonthPicker, this);
27773 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27776 var today = (new Date()).dateFormat(this.format);
27778 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27779 if (this.showClear) {
27780 baseTb.add( new Roo.Toolbar.Fill());
27783 text: String.format(this.todayText, today),
27784 tooltip: String.format(this.todayTip, today),
27785 handler: this.selectToday,
27789 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27792 if (this.showClear) {
27794 baseTb.add( new Roo.Toolbar.Fill());
27797 cls: 'x-btn-icon x-btn-clear',
27798 handler: function() {
27800 this.fireEvent("select", this, '');
27810 this.update(this.value);
27813 createMonthPicker : function(){
27814 if(!this.monthPicker.dom.firstChild){
27815 var buf = ['<table border="0" cellspacing="0">'];
27816 for(var i = 0; i < 6; i++){
27818 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27819 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27821 '<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>' :
27822 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27826 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27828 '</button><button type="button" class="x-date-mp-cancel">',
27830 '</button></td></tr>',
27833 this.monthPicker.update(buf.join(''));
27834 this.monthPicker.on('click', this.onMonthClick, this);
27835 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
27837 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
27838 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
27840 this.mpMonths.each(function(m, a, i){
27843 m.dom.xmonth = 5 + Math.round(i * .5);
27845 m.dom.xmonth = Math.round((i-1) * .5);
27851 showMonthPicker : function(){
27852 this.createMonthPicker();
27853 var size = this.el.getSize();
27854 this.monthPicker.setSize(size);
27855 this.monthPicker.child('table').setSize(size);
27857 this.mpSelMonth = (this.activeDate || this.value).getMonth();
27858 this.updateMPMonth(this.mpSelMonth);
27859 this.mpSelYear = (this.activeDate || this.value).getFullYear();
27860 this.updateMPYear(this.mpSelYear);
27862 this.monthPicker.slideIn('t', {duration:.2});
27865 updateMPYear : function(y){
27867 var ys = this.mpYears.elements;
27868 for(var i = 1; i <= 10; i++){
27869 var td = ys[i-1], y2;
27871 y2 = y + Math.round(i * .5);
27872 td.firstChild.innerHTML = y2;
27875 y2 = y - (5-Math.round(i * .5));
27876 td.firstChild.innerHTML = y2;
27879 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
27883 updateMPMonth : function(sm){
27884 this.mpMonths.each(function(m, a, i){
27885 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
27889 selectMPMonth: function(m){
27893 onMonthClick : function(e, t){
27895 var el = new Roo.Element(t), pn;
27896 if(el.is('button.x-date-mp-cancel')){
27897 this.hideMonthPicker();
27899 else if(el.is('button.x-date-mp-ok')){
27900 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27901 this.hideMonthPicker();
27903 else if(pn = el.up('td.x-date-mp-month', 2)){
27904 this.mpMonths.removeClass('x-date-mp-sel');
27905 pn.addClass('x-date-mp-sel');
27906 this.mpSelMonth = pn.dom.xmonth;
27908 else if(pn = el.up('td.x-date-mp-year', 2)){
27909 this.mpYears.removeClass('x-date-mp-sel');
27910 pn.addClass('x-date-mp-sel');
27911 this.mpSelYear = pn.dom.xyear;
27913 else if(el.is('a.x-date-mp-prev')){
27914 this.updateMPYear(this.mpyear-10);
27916 else if(el.is('a.x-date-mp-next')){
27917 this.updateMPYear(this.mpyear+10);
27921 onMonthDblClick : function(e, t){
27923 var el = new Roo.Element(t), pn;
27924 if(pn = el.up('td.x-date-mp-month', 2)){
27925 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
27926 this.hideMonthPicker();
27928 else if(pn = el.up('td.x-date-mp-year', 2)){
27929 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27930 this.hideMonthPicker();
27934 hideMonthPicker : function(disableAnim){
27935 if(this.monthPicker){
27936 if(disableAnim === true){
27937 this.monthPicker.hide();
27939 this.monthPicker.slideOut('t', {duration:.2});
27945 showPrevMonth : function(e){
27946 this.update(this.activeDate.add("mo", -1));
27950 showNextMonth : function(e){
27951 this.update(this.activeDate.add("mo", 1));
27955 showPrevYear : function(){
27956 this.update(this.activeDate.add("y", -1));
27960 showNextYear : function(){
27961 this.update(this.activeDate.add("y", 1));
27965 handleMouseWheel : function(e){
27966 var delta = e.getWheelDelta();
27968 this.showPrevMonth();
27970 } else if(delta < 0){
27971 this.showNextMonth();
27977 handleDateClick : function(e, t){
27979 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
27980 this.setValue(new Date(t.dateValue));
27981 this.fireEvent("select", this, this.value);
27986 selectToday : function(){
27987 this.setValue(new Date().clearTime());
27988 this.fireEvent("select", this, this.value);
27992 update : function(date)
27994 var vd = this.activeDate;
27995 this.activeDate = date;
27997 var t = date.getTime();
27998 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
27999 this.cells.removeClass("x-date-selected");
28000 this.cells.each(function(c){
28001 if(c.dom.firstChild.dateValue == t){
28002 c.addClass("x-date-selected");
28003 setTimeout(function(){
28004 try{c.dom.firstChild.focus();}catch(e){}
28013 var days = date.getDaysInMonth();
28014 var firstOfMonth = date.getFirstDateOfMonth();
28015 var startingPos = firstOfMonth.getDay()-this.startDay;
28017 if(startingPos <= this.startDay){
28021 var pm = date.add("mo", -1);
28022 var prevStart = pm.getDaysInMonth()-startingPos;
28024 var cells = this.cells.elements;
28025 var textEls = this.textNodes;
28026 days += startingPos;
28028 // convert everything to numbers so it's fast
28029 var day = 86400000;
28030 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28031 var today = new Date().clearTime().getTime();
28032 var sel = date.clearTime().getTime();
28033 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28034 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28035 var ddMatch = this.disabledDatesRE;
28036 var ddText = this.disabledDatesText;
28037 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28038 var ddaysText = this.disabledDaysText;
28039 var format = this.format;
28041 var setCellClass = function(cal, cell){
28043 var t = d.getTime();
28044 cell.firstChild.dateValue = t;
28046 cell.className += " x-date-today";
28047 cell.title = cal.todayText;
28050 cell.className += " x-date-selected";
28051 setTimeout(function(){
28052 try{cell.firstChild.focus();}catch(e){}
28057 cell.className = " x-date-disabled";
28058 cell.title = cal.minText;
28062 cell.className = " x-date-disabled";
28063 cell.title = cal.maxText;
28067 if(ddays.indexOf(d.getDay()) != -1){
28068 cell.title = ddaysText;
28069 cell.className = " x-date-disabled";
28072 if(ddMatch && format){
28073 var fvalue = d.dateFormat(format);
28074 if(ddMatch.test(fvalue)){
28075 cell.title = ddText.replace("%0", fvalue);
28076 cell.className = " x-date-disabled";
28082 for(; i < startingPos; i++) {
28083 textEls[i].innerHTML = (++prevStart);
28084 d.setDate(d.getDate()+1);
28085 cells[i].className = "x-date-prevday";
28086 setCellClass(this, cells[i]);
28088 for(; i < days; i++){
28089 intDay = i - startingPos + 1;
28090 textEls[i].innerHTML = (intDay);
28091 d.setDate(d.getDate()+1);
28092 cells[i].className = "x-date-active";
28093 setCellClass(this, cells[i]);
28096 for(; i < 42; i++) {
28097 textEls[i].innerHTML = (++extraDays);
28098 d.setDate(d.getDate()+1);
28099 cells[i].className = "x-date-nextday";
28100 setCellClass(this, cells[i]);
28103 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28104 this.fireEvent('monthchange', this, date);
28106 if(!this.internalRender){
28107 var main = this.el.dom.firstChild;
28108 var w = main.offsetWidth;
28109 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28110 Roo.fly(main).setWidth(w);
28111 this.internalRender = true;
28112 // opera does not respect the auto grow header center column
28113 // then, after it gets a width opera refuses to recalculate
28114 // without a second pass
28115 if(Roo.isOpera && !this.secondPass){
28116 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28117 this.secondPass = true;
28118 this.update.defer(10, this, [date]);
28126 * Ext JS Library 1.1.1
28127 * Copyright(c) 2006-2007, Ext JS, LLC.
28129 * Originally Released Under LGPL - original licence link has changed is not relivant.
28132 * <script type="text/javascript">
28135 * @class Roo.TabPanel
28136 * @extends Roo.util.Observable
28137 * A lightweight tab container.
28141 // basic tabs 1, built from existing content
28142 var tabs = new Roo.TabPanel("tabs1");
28143 tabs.addTab("script", "View Script");
28144 tabs.addTab("markup", "View Markup");
28145 tabs.activate("script");
28147 // more advanced tabs, built from javascript
28148 var jtabs = new Roo.TabPanel("jtabs");
28149 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28151 // set up the UpdateManager
28152 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28153 var updater = tab2.getUpdateManager();
28154 updater.setDefaultUrl("ajax1.htm");
28155 tab2.on('activate', updater.refresh, updater, true);
28157 // Use setUrl for Ajax loading
28158 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28159 tab3.setUrl("ajax2.htm", null, true);
28162 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28165 jtabs.activate("jtabs-1");
28168 * Create a new TabPanel.
28169 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28170 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28172 Roo.TabPanel = function(container, config){
28174 * The container element for this TabPanel.
28175 * @type Roo.Element
28177 this.el = Roo.get(container, true);
28179 if(typeof config == "boolean"){
28180 this.tabPosition = config ? "bottom" : "top";
28182 Roo.apply(this, config);
28185 if(this.tabPosition == "bottom"){
28186 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28187 this.el.addClass("x-tabs-bottom");
28189 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28190 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28191 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28193 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28195 if(this.tabPosition != "bottom"){
28196 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28197 * @type Roo.Element
28199 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28200 this.el.addClass("x-tabs-top");
28204 this.bodyEl.setStyle("position", "relative");
28206 this.active = null;
28207 this.activateDelegate = this.activate.createDelegate(this);
28212 * Fires when the active tab changes
28213 * @param {Roo.TabPanel} this
28214 * @param {Roo.TabPanelItem} activePanel The new active tab
28218 * @event beforetabchange
28219 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28220 * @param {Roo.TabPanel} this
28221 * @param {Object} e Set cancel to true on this object to cancel the tab change
28222 * @param {Roo.TabPanelItem} tab The tab being changed to
28224 "beforetabchange" : true
28227 Roo.EventManager.onWindowResize(this.onResize, this);
28228 this.cpad = this.el.getPadding("lr");
28229 this.hiddenCount = 0;
28232 // toolbar on the tabbar support...
28233 if (this.toolbar) {
28234 var tcfg = this.toolbar;
28235 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28236 this.toolbar = new Roo.Toolbar(tcfg);
28237 if (Roo.isSafari) {
28238 var tbl = tcfg.container.child('table', true);
28239 tbl.setAttribute('width', '100%');
28246 Roo.TabPanel.superclass.constructor.call(this);
28249 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28251 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28253 tabPosition : "top",
28255 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28257 currentTabWidth : 0,
28259 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28263 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28267 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28269 preferredTabWidth : 175,
28271 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28273 resizeTabs : false,
28275 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28277 monitorResize : true,
28279 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28284 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28285 * @param {String} id The id of the div to use <b>or create</b>
28286 * @param {String} text The text for the tab
28287 * @param {String} content (optional) Content to put in the TabPanelItem body
28288 * @param {Boolean} closable (optional) True to create a close icon on the tab
28289 * @return {Roo.TabPanelItem} The created TabPanelItem
28291 addTab : function(id, text, content, closable){
28292 var item = new Roo.TabPanelItem(this, id, text, closable);
28293 this.addTabItem(item);
28295 item.setContent(content);
28301 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28302 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28303 * @return {Roo.TabPanelItem}
28305 getTab : function(id){
28306 return this.items[id];
28310 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28311 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28313 hideTab : function(id){
28314 var t = this.items[id];
28317 this.hiddenCount++;
28318 this.autoSizeTabs();
28323 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28324 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28326 unhideTab : function(id){
28327 var t = this.items[id];
28329 t.setHidden(false);
28330 this.hiddenCount--;
28331 this.autoSizeTabs();
28336 * Adds an existing {@link Roo.TabPanelItem}.
28337 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28339 addTabItem : function(item){
28340 this.items[item.id] = item;
28341 this.items.push(item);
28342 if(this.resizeTabs){
28343 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28344 this.autoSizeTabs();
28351 * Removes a {@link Roo.TabPanelItem}.
28352 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28354 removeTab : function(id){
28355 var items = this.items;
28356 var tab = items[id];
28357 if(!tab) { return; }
28358 var index = items.indexOf(tab);
28359 if(this.active == tab && items.length > 1){
28360 var newTab = this.getNextAvailable(index);
28365 this.stripEl.dom.removeChild(tab.pnode.dom);
28366 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28367 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28369 items.splice(index, 1);
28370 delete this.items[tab.id];
28371 tab.fireEvent("close", tab);
28372 tab.purgeListeners();
28373 this.autoSizeTabs();
28376 getNextAvailable : function(start){
28377 var items = this.items;
28379 // look for a next tab that will slide over to
28380 // replace the one being removed
28381 while(index < items.length){
28382 var item = items[++index];
28383 if(item && !item.isHidden()){
28387 // if one isn't found select the previous tab (on the left)
28390 var item = items[--index];
28391 if(item && !item.isHidden()){
28399 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28400 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28402 disableTab : function(id){
28403 var tab = this.items[id];
28404 if(tab && this.active != tab){
28410 * Enables a {@link Roo.TabPanelItem} that is disabled.
28411 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28413 enableTab : function(id){
28414 var tab = this.items[id];
28419 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28420 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28421 * @return {Roo.TabPanelItem} The TabPanelItem.
28423 activate : function(id){
28424 var tab = this.items[id];
28428 if(tab == this.active || tab.disabled){
28432 this.fireEvent("beforetabchange", this, e, tab);
28433 if(e.cancel !== true && !tab.disabled){
28435 this.active.hide();
28437 this.active = this.items[id];
28438 this.active.show();
28439 this.fireEvent("tabchange", this, this.active);
28445 * Gets the active {@link Roo.TabPanelItem}.
28446 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28448 getActiveTab : function(){
28449 return this.active;
28453 * Updates the tab body element to fit the height of the container element
28454 * for overflow scrolling
28455 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28457 syncHeight : function(targetHeight){
28458 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28459 var bm = this.bodyEl.getMargins();
28460 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28461 this.bodyEl.setHeight(newHeight);
28465 onResize : function(){
28466 if(this.monitorResize){
28467 this.autoSizeTabs();
28472 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28474 beginUpdate : function(){
28475 this.updating = true;
28479 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28481 endUpdate : function(){
28482 this.updating = false;
28483 this.autoSizeTabs();
28487 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28489 autoSizeTabs : function(){
28490 var count = this.items.length;
28491 var vcount = count - this.hiddenCount;
28492 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28495 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28496 var availWidth = Math.floor(w / vcount);
28497 var b = this.stripBody;
28498 if(b.getWidth() > w){
28499 var tabs = this.items;
28500 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28501 if(availWidth < this.minTabWidth){
28502 /*if(!this.sleft){ // incomplete scrolling code
28503 this.createScrollButtons();
28506 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28509 if(this.currentTabWidth < this.preferredTabWidth){
28510 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28516 * Returns the number of tabs in this TabPanel.
28519 getCount : function(){
28520 return this.items.length;
28524 * Resizes all the tabs to the passed width
28525 * @param {Number} The new width
28527 setTabWidth : function(width){
28528 this.currentTabWidth = width;
28529 for(var i = 0, len = this.items.length; i < len; i++) {
28530 if(!this.items[i].isHidden()) {
28531 this.items[i].setWidth(width);
28537 * Destroys this TabPanel
28538 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28540 destroy : function(removeEl){
28541 Roo.EventManager.removeResizeListener(this.onResize, this);
28542 for(var i = 0, len = this.items.length; i < len; i++){
28543 this.items[i].purgeListeners();
28545 if(removeEl === true){
28546 this.el.update("");
28553 * @class Roo.TabPanelItem
28554 * @extends Roo.util.Observable
28555 * Represents an individual item (tab plus body) in a TabPanel.
28556 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28557 * @param {String} id The id of this TabPanelItem
28558 * @param {String} text The text for the tab of this TabPanelItem
28559 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28561 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28563 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28564 * @type Roo.TabPanel
28566 this.tabPanel = tabPanel;
28568 * The id for this TabPanelItem
28573 this.disabled = false;
28577 this.loaded = false;
28578 this.closable = closable;
28581 * The body element for this TabPanelItem.
28582 * @type Roo.Element
28584 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28585 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28586 this.bodyEl.setStyle("display", "block");
28587 this.bodyEl.setStyle("zoom", "1");
28590 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28592 this.el = Roo.get(els.el, true);
28593 this.inner = Roo.get(els.inner, true);
28594 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28595 this.pnode = Roo.get(els.el.parentNode, true);
28596 this.el.on("mousedown", this.onTabMouseDown, this);
28597 this.el.on("click", this.onTabClick, this);
28600 var c = Roo.get(els.close, true);
28601 c.dom.title = this.closeText;
28602 c.addClassOnOver("close-over");
28603 c.on("click", this.closeClick, this);
28609 * Fires when this tab becomes the active tab.
28610 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28611 * @param {Roo.TabPanelItem} this
28615 * @event beforeclose
28616 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28617 * @param {Roo.TabPanelItem} this
28618 * @param {Object} e Set cancel to true on this object to cancel the close.
28620 "beforeclose": true,
28623 * Fires when this tab is closed.
28624 * @param {Roo.TabPanelItem} this
28628 * @event deactivate
28629 * Fires when this tab is no longer the active tab.
28630 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28631 * @param {Roo.TabPanelItem} this
28633 "deactivate" : true
28635 this.hidden = false;
28637 Roo.TabPanelItem.superclass.constructor.call(this);
28640 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28641 purgeListeners : function(){
28642 Roo.util.Observable.prototype.purgeListeners.call(this);
28643 this.el.removeAllListeners();
28646 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28649 this.pnode.addClass("on");
28652 this.tabPanel.stripWrap.repaint();
28654 this.fireEvent("activate", this.tabPanel, this);
28658 * Returns true if this tab is the active tab.
28659 * @return {Boolean}
28661 isActive : function(){
28662 return this.tabPanel.getActiveTab() == this;
28666 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28669 this.pnode.removeClass("on");
28671 this.fireEvent("deactivate", this.tabPanel, this);
28674 hideAction : function(){
28675 this.bodyEl.hide();
28676 this.bodyEl.setStyle("position", "absolute");
28677 this.bodyEl.setLeft("-20000px");
28678 this.bodyEl.setTop("-20000px");
28681 showAction : function(){
28682 this.bodyEl.setStyle("position", "relative");
28683 this.bodyEl.setTop("");
28684 this.bodyEl.setLeft("");
28685 this.bodyEl.show();
28689 * Set the tooltip for the tab.
28690 * @param {String} tooltip The tab's tooltip
28692 setTooltip : function(text){
28693 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28694 this.textEl.dom.qtip = text;
28695 this.textEl.dom.removeAttribute('title');
28697 this.textEl.dom.title = text;
28701 onTabClick : function(e){
28702 e.preventDefault();
28703 this.tabPanel.activate(this.id);
28706 onTabMouseDown : function(e){
28707 e.preventDefault();
28708 this.tabPanel.activate(this.id);
28711 getWidth : function(){
28712 return this.inner.getWidth();
28715 setWidth : function(width){
28716 var iwidth = width - this.pnode.getPadding("lr");
28717 this.inner.setWidth(iwidth);
28718 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28719 this.pnode.setWidth(width);
28723 * Show or hide the tab
28724 * @param {Boolean} hidden True to hide or false to show.
28726 setHidden : function(hidden){
28727 this.hidden = hidden;
28728 this.pnode.setStyle("display", hidden ? "none" : "");
28732 * Returns true if this tab is "hidden"
28733 * @return {Boolean}
28735 isHidden : function(){
28736 return this.hidden;
28740 * Returns the text for this tab
28743 getText : function(){
28747 autoSize : function(){
28748 //this.el.beginMeasure();
28749 this.textEl.setWidth(1);
28751 * #2804 [new] Tabs in Roojs
28752 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28754 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28755 //this.el.endMeasure();
28759 * Sets the text for the tab (Note: this also sets the tooltip text)
28760 * @param {String} text The tab's text and tooltip
28762 setText : function(text){
28764 this.textEl.update(text);
28765 this.setTooltip(text);
28766 if(!this.tabPanel.resizeTabs){
28771 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28773 activate : function(){
28774 this.tabPanel.activate(this.id);
28778 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28780 disable : function(){
28781 if(this.tabPanel.active != this){
28782 this.disabled = true;
28783 this.pnode.addClass("disabled");
28788 * Enables this TabPanelItem if it was previously disabled.
28790 enable : function(){
28791 this.disabled = false;
28792 this.pnode.removeClass("disabled");
28796 * Sets the content for this TabPanelItem.
28797 * @param {String} content The content
28798 * @param {Boolean} loadScripts true to look for and load scripts
28800 setContent : function(content, loadScripts){
28801 this.bodyEl.update(content, loadScripts);
28805 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28806 * @return {Roo.UpdateManager} The UpdateManager
28808 getUpdateManager : function(){
28809 return this.bodyEl.getUpdateManager();
28813 * Set a URL to be used to load the content for this TabPanelItem.
28814 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28815 * @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)
28816 * @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)
28817 * @return {Roo.UpdateManager} The UpdateManager
28819 setUrl : function(url, params, loadOnce){
28820 if(this.refreshDelegate){
28821 this.un('activate', this.refreshDelegate);
28823 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28824 this.on("activate", this.refreshDelegate);
28825 return this.bodyEl.getUpdateManager();
28829 _handleRefresh : function(url, params, loadOnce){
28830 if(!loadOnce || !this.loaded){
28831 var updater = this.bodyEl.getUpdateManager();
28832 updater.update(url, params, this._setLoaded.createDelegate(this));
28837 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
28838 * Will fail silently if the setUrl method has not been called.
28839 * This does not activate the panel, just updates its content.
28841 refresh : function(){
28842 if(this.refreshDelegate){
28843 this.loaded = false;
28844 this.refreshDelegate();
28849 _setLoaded : function(){
28850 this.loaded = true;
28854 closeClick : function(e){
28857 this.fireEvent("beforeclose", this, o);
28858 if(o.cancel !== true){
28859 this.tabPanel.removeTab(this.id);
28863 * The text displayed in the tooltip for the close icon.
28866 closeText : "Close this tab"
28870 Roo.TabPanel.prototype.createStrip = function(container){
28871 var strip = document.createElement("div");
28872 strip.className = "x-tabs-wrap";
28873 container.appendChild(strip);
28877 Roo.TabPanel.prototype.createStripList = function(strip){
28878 // div wrapper for retard IE
28879 // returns the "tr" element.
28880 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
28881 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
28882 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
28883 return strip.firstChild.firstChild.firstChild.firstChild;
28886 Roo.TabPanel.prototype.createBody = function(container){
28887 var body = document.createElement("div");
28888 Roo.id(body, "tab-body");
28889 Roo.fly(body).addClass("x-tabs-body");
28890 container.appendChild(body);
28894 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
28895 var body = Roo.getDom(id);
28897 body = document.createElement("div");
28900 Roo.fly(body).addClass("x-tabs-item-body");
28901 bodyEl.insertBefore(body, bodyEl.firstChild);
28905 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
28906 var td = document.createElement("td");
28907 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
28908 //stripEl.appendChild(td);
28910 td.className = "x-tabs-closable";
28911 if(!this.closeTpl){
28912 this.closeTpl = new Roo.Template(
28913 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28914 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
28915 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
28918 var el = this.closeTpl.overwrite(td, {"text": text});
28919 var close = el.getElementsByTagName("div")[0];
28920 var inner = el.getElementsByTagName("em")[0];
28921 return {"el": el, "close": close, "inner": inner};
28924 this.tabTpl = new Roo.Template(
28925 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28926 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
28929 var el = this.tabTpl.overwrite(td, {"text": text});
28930 var inner = el.getElementsByTagName("em")[0];
28931 return {"el": el, "inner": inner};
28935 * Ext JS Library 1.1.1
28936 * Copyright(c) 2006-2007, Ext JS, LLC.
28938 * Originally Released Under LGPL - original licence link has changed is not relivant.
28941 * <script type="text/javascript">
28945 * @class Roo.Button
28946 * @extends Roo.util.Observable
28947 * Simple Button class
28948 * @cfg {String} text The button text
28949 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
28950 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
28951 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
28952 * @cfg {Object} scope The scope of the handler
28953 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
28954 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
28955 * @cfg {Boolean} hidden True to start hidden (defaults to false)
28956 * @cfg {Boolean} disabled True to start disabled (defaults to false)
28957 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
28958 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
28959 applies if enableToggle = true)
28960 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
28961 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
28962 an {@link Roo.util.ClickRepeater} config object (defaults to false).
28964 * Create a new button
28965 * @param {Object} config The config object
28967 Roo.Button = function(renderTo, config)
28971 renderTo = config.renderTo || false;
28974 Roo.apply(this, config);
28978 * Fires when this button is clicked
28979 * @param {Button} this
28980 * @param {EventObject} e The click event
28985 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
28986 * @param {Button} this
28987 * @param {Boolean} pressed
28992 * Fires when the mouse hovers over the button
28993 * @param {Button} this
28994 * @param {Event} e The event object
28996 'mouseover' : true,
28999 * Fires when the mouse exits the button
29000 * @param {Button} this
29001 * @param {Event} e The event object
29006 * Fires when the button is rendered
29007 * @param {Button} this
29012 this.menu = Roo.menu.MenuMgr.get(this.menu);
29014 // register listeners first!! - so render can be captured..
29015 Roo.util.Observable.call(this);
29017 this.render(renderTo);
29023 Roo.extend(Roo.Button, Roo.util.Observable, {
29029 * Read-only. True if this button is hidden
29034 * Read-only. True if this button is disabled
29039 * Read-only. True if this button is pressed (only if enableToggle = true)
29045 * @cfg {Number} tabIndex
29046 * The DOM tabIndex for this button (defaults to undefined)
29048 tabIndex : undefined,
29051 * @cfg {Boolean} enableToggle
29052 * True to enable pressed/not pressed toggling (defaults to false)
29054 enableToggle: false,
29056 * @cfg {Mixed} menu
29057 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29061 * @cfg {String} menuAlign
29062 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29064 menuAlign : "tl-bl?",
29067 * @cfg {String} iconCls
29068 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29070 iconCls : undefined,
29072 * @cfg {String} type
29073 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29078 menuClassTarget: 'tr',
29081 * @cfg {String} clickEvent
29082 * The type of event to map to the button's event handler (defaults to 'click')
29084 clickEvent : 'click',
29087 * @cfg {Boolean} handleMouseEvents
29088 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29090 handleMouseEvents : true,
29093 * @cfg {String} tooltipType
29094 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29096 tooltipType : 'qtip',
29099 * @cfg {String} cls
29100 * A CSS class to apply to the button's main element.
29104 * @cfg {Roo.Template} template (Optional)
29105 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29106 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29107 * require code modifications if required elements (e.g. a button) aren't present.
29111 render : function(renderTo){
29113 if(this.hideParent){
29114 this.parentEl = Roo.get(renderTo);
29116 if(!this.dhconfig){
29117 if(!this.template){
29118 if(!Roo.Button.buttonTemplate){
29119 // hideous table template
29120 Roo.Button.buttonTemplate = new Roo.Template(
29121 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29122 '<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>',
29123 "</tr></tbody></table>");
29125 this.template = Roo.Button.buttonTemplate;
29127 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29128 var btnEl = btn.child("button:first");
29129 btnEl.on('focus', this.onFocus, this);
29130 btnEl.on('blur', this.onBlur, this);
29132 btn.addClass(this.cls);
29135 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29138 btnEl.addClass(this.iconCls);
29140 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29143 if(this.tabIndex !== undefined){
29144 btnEl.dom.tabIndex = this.tabIndex;
29147 if(typeof this.tooltip == 'object'){
29148 Roo.QuickTips.tips(Roo.apply({
29152 btnEl.dom[this.tooltipType] = this.tooltip;
29156 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29160 this.el.dom.id = this.el.id = this.id;
29163 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29164 this.menu.on("show", this.onMenuShow, this);
29165 this.menu.on("hide", this.onMenuHide, this);
29167 btn.addClass("x-btn");
29168 if(Roo.isIE && !Roo.isIE7){
29169 this.autoWidth.defer(1, this);
29173 if(this.handleMouseEvents){
29174 btn.on("mouseover", this.onMouseOver, this);
29175 btn.on("mouseout", this.onMouseOut, this);
29176 btn.on("mousedown", this.onMouseDown, this);
29178 btn.on(this.clickEvent, this.onClick, this);
29179 //btn.on("mouseup", this.onMouseUp, this);
29186 Roo.ButtonToggleMgr.register(this);
29188 this.el.addClass("x-btn-pressed");
29191 var repeater = new Roo.util.ClickRepeater(btn,
29192 typeof this.repeat == "object" ? this.repeat : {}
29194 repeater.on("click", this.onClick, this);
29197 this.fireEvent('render', this);
29201 * Returns the button's underlying element
29202 * @return {Roo.Element} The element
29204 getEl : function(){
29209 * Destroys this Button and removes any listeners.
29211 destroy : function(){
29212 Roo.ButtonToggleMgr.unregister(this);
29213 this.el.removeAllListeners();
29214 this.purgeListeners();
29219 autoWidth : function(){
29221 this.el.setWidth("auto");
29222 if(Roo.isIE7 && Roo.isStrict){
29223 var ib = this.el.child('button');
29224 if(ib && ib.getWidth() > 20){
29226 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29231 this.el.beginMeasure();
29233 if(this.el.getWidth() < this.minWidth){
29234 this.el.setWidth(this.minWidth);
29237 this.el.endMeasure();
29244 * Assigns this button's click handler
29245 * @param {Function} handler The function to call when the button is clicked
29246 * @param {Object} scope (optional) Scope for the function passed in
29248 setHandler : function(handler, scope){
29249 this.handler = handler;
29250 this.scope = scope;
29254 * Sets this button's text
29255 * @param {String} text The button text
29257 setText : function(text){
29260 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29266 * Gets the text for this button
29267 * @return {String} The button text
29269 getText : function(){
29277 this.hidden = false;
29279 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29287 this.hidden = true;
29289 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29294 * Convenience function for boolean show/hide
29295 * @param {Boolean} visible True to show, false to hide
29297 setVisible: function(visible){
29306 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29307 * @param {Boolean} state (optional) Force a particular state
29309 toggle : function(state){
29310 state = state === undefined ? !this.pressed : state;
29311 if(state != this.pressed){
29313 this.el.addClass("x-btn-pressed");
29314 this.pressed = true;
29315 this.fireEvent("toggle", this, true);
29317 this.el.removeClass("x-btn-pressed");
29318 this.pressed = false;
29319 this.fireEvent("toggle", this, false);
29321 if(this.toggleHandler){
29322 this.toggleHandler.call(this.scope || this, this, state);
29330 focus : function(){
29331 this.el.child('button:first').focus();
29335 * Disable this button
29337 disable : function(){
29339 this.el.addClass("x-btn-disabled");
29341 this.disabled = true;
29345 * Enable this button
29347 enable : function(){
29349 this.el.removeClass("x-btn-disabled");
29351 this.disabled = false;
29355 * Convenience function for boolean enable/disable
29356 * @param {Boolean} enabled True to enable, false to disable
29358 setDisabled : function(v){
29359 this[v !== true ? "enable" : "disable"]();
29363 onClick : function(e)
29366 e.preventDefault();
29371 if(!this.disabled){
29372 if(this.enableToggle){
29375 if(this.menu && !this.menu.isVisible()){
29376 this.menu.show(this.el, this.menuAlign);
29378 this.fireEvent("click", this, e);
29380 this.el.removeClass("x-btn-over");
29381 this.handler.call(this.scope || this, this, e);
29386 onMouseOver : function(e){
29387 if(!this.disabled){
29388 this.el.addClass("x-btn-over");
29389 this.fireEvent('mouseover', this, e);
29393 onMouseOut : function(e){
29394 if(!e.within(this.el, true)){
29395 this.el.removeClass("x-btn-over");
29396 this.fireEvent('mouseout', this, e);
29400 onFocus : function(e){
29401 if(!this.disabled){
29402 this.el.addClass("x-btn-focus");
29406 onBlur : function(e){
29407 this.el.removeClass("x-btn-focus");
29410 onMouseDown : function(e){
29411 if(!this.disabled && e.button == 0){
29412 this.el.addClass("x-btn-click");
29413 Roo.get(document).on('mouseup', this.onMouseUp, this);
29417 onMouseUp : function(e){
29419 this.el.removeClass("x-btn-click");
29420 Roo.get(document).un('mouseup', this.onMouseUp, this);
29424 onMenuShow : function(e){
29425 this.el.addClass("x-btn-menu-active");
29428 onMenuHide : function(e){
29429 this.el.removeClass("x-btn-menu-active");
29433 // Private utility class used by Button
29434 Roo.ButtonToggleMgr = function(){
29437 function toggleGroup(btn, state){
29439 var g = groups[btn.toggleGroup];
29440 for(var i = 0, l = g.length; i < l; i++){
29442 g[i].toggle(false);
29449 register : function(btn){
29450 if(!btn.toggleGroup){
29453 var g = groups[btn.toggleGroup];
29455 g = groups[btn.toggleGroup] = [];
29458 btn.on("toggle", toggleGroup);
29461 unregister : function(btn){
29462 if(!btn.toggleGroup){
29465 var g = groups[btn.toggleGroup];
29468 btn.un("toggle", toggleGroup);
29474 * Ext JS Library 1.1.1
29475 * Copyright(c) 2006-2007, Ext JS, LLC.
29477 * Originally Released Under LGPL - original licence link has changed is not relivant.
29480 * <script type="text/javascript">
29484 * @class Roo.SplitButton
29485 * @extends Roo.Button
29486 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29487 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29488 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29489 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29490 * @cfg {String} arrowTooltip The title attribute of the arrow
29492 * Create a new menu button
29493 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29494 * @param {Object} config The config object
29496 Roo.SplitButton = function(renderTo, config){
29497 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29499 * @event arrowclick
29500 * Fires when this button's arrow is clicked
29501 * @param {SplitButton} this
29502 * @param {EventObject} e The click event
29504 this.addEvents({"arrowclick":true});
29507 Roo.extend(Roo.SplitButton, Roo.Button, {
29508 render : function(renderTo){
29509 // this is one sweet looking template!
29510 var tpl = new Roo.Template(
29511 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29512 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29513 '<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>',
29514 "</tbody></table></td><td>",
29515 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29516 '<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>',
29517 "</tbody></table></td></tr></table>"
29519 var btn = tpl.append(renderTo, [this.text, this.type], true);
29520 var btnEl = btn.child("button");
29522 btn.addClass(this.cls);
29525 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29528 btnEl.addClass(this.iconCls);
29530 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29534 if(this.handleMouseEvents){
29535 btn.on("mouseover", this.onMouseOver, this);
29536 btn.on("mouseout", this.onMouseOut, this);
29537 btn.on("mousedown", this.onMouseDown, this);
29538 btn.on("mouseup", this.onMouseUp, this);
29540 btn.on(this.clickEvent, this.onClick, this);
29542 if(typeof this.tooltip == 'object'){
29543 Roo.QuickTips.tips(Roo.apply({
29547 btnEl.dom[this.tooltipType] = this.tooltip;
29550 if(this.arrowTooltip){
29551 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29560 this.el.addClass("x-btn-pressed");
29562 if(Roo.isIE && !Roo.isIE7){
29563 this.autoWidth.defer(1, this);
29568 this.menu.on("show", this.onMenuShow, this);
29569 this.menu.on("hide", this.onMenuHide, this);
29571 this.fireEvent('render', this);
29575 autoWidth : function(){
29577 var tbl = this.el.child("table:first");
29578 var tbl2 = this.el.child("table:last");
29579 this.el.setWidth("auto");
29580 tbl.setWidth("auto");
29581 if(Roo.isIE7 && Roo.isStrict){
29582 var ib = this.el.child('button:first');
29583 if(ib && ib.getWidth() > 20){
29585 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29590 this.el.beginMeasure();
29592 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29593 tbl.setWidth(this.minWidth-tbl2.getWidth());
29596 this.el.endMeasure();
29599 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29603 * Sets this button's click handler
29604 * @param {Function} handler The function to call when the button is clicked
29605 * @param {Object} scope (optional) Scope for the function passed above
29607 setHandler : function(handler, scope){
29608 this.handler = handler;
29609 this.scope = scope;
29613 * Sets this button's arrow click handler
29614 * @param {Function} handler The function to call when the arrow is clicked
29615 * @param {Object} scope (optional) Scope for the function passed above
29617 setArrowHandler : function(handler, scope){
29618 this.arrowHandler = handler;
29619 this.scope = scope;
29625 focus : function(){
29627 this.el.child("button:first").focus();
29632 onClick : function(e){
29633 e.preventDefault();
29634 if(!this.disabled){
29635 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29636 if(this.menu && !this.menu.isVisible()){
29637 this.menu.show(this.el, this.menuAlign);
29639 this.fireEvent("arrowclick", this, e);
29640 if(this.arrowHandler){
29641 this.arrowHandler.call(this.scope || this, this, e);
29644 this.fireEvent("click", this, e);
29646 this.handler.call(this.scope || this, this, e);
29652 onMouseDown : function(e){
29653 if(!this.disabled){
29654 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29658 onMouseUp : function(e){
29659 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29664 // backwards compat
29665 Roo.MenuButton = Roo.SplitButton;/*
29667 * Ext JS Library 1.1.1
29668 * Copyright(c) 2006-2007, Ext JS, LLC.
29670 * Originally Released Under LGPL - original licence link has changed is not relivant.
29673 * <script type="text/javascript">
29677 * @class Roo.Toolbar
29678 * Basic Toolbar class.
29680 * Creates a new Toolbar
29681 * @param {Object} container The config object
29683 Roo.Toolbar = function(container, buttons, config)
29685 /// old consturctor format still supported..
29686 if(container instanceof Array){ // omit the container for later rendering
29687 buttons = container;
29691 if (typeof(container) == 'object' && container.xtype) {
29692 config = container;
29693 container = config.container;
29694 buttons = config.buttons || []; // not really - use items!!
29697 if (config && config.items) {
29698 xitems = config.items;
29699 delete config.items;
29701 Roo.apply(this, config);
29702 this.buttons = buttons;
29705 this.render(container);
29707 this.xitems = xitems;
29708 Roo.each(xitems, function(b) {
29714 Roo.Toolbar.prototype = {
29716 * @cfg {Array} items
29717 * array of button configs or elements to add (will be converted to a MixedCollection)
29721 * @cfg {String/HTMLElement/Element} container
29722 * The id or element that will contain the toolbar
29725 render : function(ct){
29726 this.el = Roo.get(ct);
29728 this.el.addClass(this.cls);
29730 // using a table allows for vertical alignment
29731 // 100% width is needed by Safari...
29732 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29733 this.tr = this.el.child("tr", true);
29735 this.items = new Roo.util.MixedCollection(false, function(o){
29736 return o.id || ("item" + (++autoId));
29739 this.add.apply(this, this.buttons);
29740 delete this.buttons;
29745 * Adds element(s) to the toolbar -- this function takes a variable number of
29746 * arguments of mixed type and adds them to the toolbar.
29747 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29749 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29750 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29751 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29752 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29753 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29754 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29755 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29756 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29757 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29759 * @param {Mixed} arg2
29760 * @param {Mixed} etc.
29763 var a = arguments, l = a.length;
29764 for(var i = 0; i < l; i++){
29769 _add : function(el) {
29772 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29775 if (el.applyTo){ // some kind of form field
29776 return this.addField(el);
29778 if (el.render){ // some kind of Toolbar.Item
29779 return this.addItem(el);
29781 if (typeof el == "string"){ // string
29782 if(el == "separator" || el == "-"){
29783 return this.addSeparator();
29786 return this.addSpacer();
29789 return this.addFill();
29791 return this.addText(el);
29794 if(el.tagName){ // element
29795 return this.addElement(el);
29797 if(typeof el == "object"){ // must be button config?
29798 return this.addButton(el);
29800 // and now what?!?!
29806 * Add an Xtype element
29807 * @param {Object} xtype Xtype Object
29808 * @return {Object} created Object
29810 addxtype : function(e){
29811 return this.add(e);
29815 * Returns the Element for this toolbar.
29816 * @return {Roo.Element}
29818 getEl : function(){
29824 * @return {Roo.Toolbar.Item} The separator item
29826 addSeparator : function(){
29827 return this.addItem(new Roo.Toolbar.Separator());
29831 * Adds a spacer element
29832 * @return {Roo.Toolbar.Spacer} The spacer item
29834 addSpacer : function(){
29835 return this.addItem(new Roo.Toolbar.Spacer());
29839 * Adds a fill element that forces subsequent additions to the right side of the toolbar
29840 * @return {Roo.Toolbar.Fill} The fill item
29842 addFill : function(){
29843 return this.addItem(new Roo.Toolbar.Fill());
29847 * Adds any standard HTML element to the toolbar
29848 * @param {String/HTMLElement/Element} el The element or id of the element to add
29849 * @return {Roo.Toolbar.Item} The element's item
29851 addElement : function(el){
29852 return this.addItem(new Roo.Toolbar.Item(el));
29855 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
29856 * @type Roo.util.MixedCollection
29861 * Adds any Toolbar.Item or subclass
29862 * @param {Roo.Toolbar.Item} item
29863 * @return {Roo.Toolbar.Item} The item
29865 addItem : function(item){
29866 var td = this.nextBlock();
29868 this.items.add(item);
29873 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
29874 * @param {Object/Array} config A button config or array of configs
29875 * @return {Roo.Toolbar.Button/Array}
29877 addButton : function(config){
29878 if(config instanceof Array){
29880 for(var i = 0, len = config.length; i < len; i++) {
29881 buttons.push(this.addButton(config[i]));
29886 if(!(config instanceof Roo.Toolbar.Button)){
29888 new Roo.Toolbar.SplitButton(config) :
29889 new Roo.Toolbar.Button(config);
29891 var td = this.nextBlock();
29898 * Adds text to the toolbar
29899 * @param {String} text The text to add
29900 * @return {Roo.Toolbar.Item} The element's item
29902 addText : function(text){
29903 return this.addItem(new Roo.Toolbar.TextItem(text));
29907 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
29908 * @param {Number} index The index where the item is to be inserted
29909 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
29910 * @return {Roo.Toolbar.Button/Item}
29912 insertButton : function(index, item){
29913 if(item instanceof Array){
29915 for(var i = 0, len = item.length; i < len; i++) {
29916 buttons.push(this.insertButton(index + i, item[i]));
29920 if (!(item instanceof Roo.Toolbar.Button)){
29921 item = new Roo.Toolbar.Button(item);
29923 var td = document.createElement("td");
29924 this.tr.insertBefore(td, this.tr.childNodes[index]);
29926 this.items.insert(index, item);
29931 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
29932 * @param {Object} config
29933 * @return {Roo.Toolbar.Item} The element's item
29935 addDom : function(config, returnEl){
29936 var td = this.nextBlock();
29937 Roo.DomHelper.overwrite(td, config);
29938 var ti = new Roo.Toolbar.Item(td.firstChild);
29940 this.items.add(ti);
29945 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
29946 * @type Roo.util.MixedCollection
29951 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
29952 * Note: the field should not have been rendered yet. For a field that has already been
29953 * rendered, use {@link #addElement}.
29954 * @param {Roo.form.Field} field
29955 * @return {Roo.ToolbarItem}
29959 addField : function(field) {
29960 if (!this.fields) {
29962 this.fields = new Roo.util.MixedCollection(false, function(o){
29963 return o.id || ("item" + (++autoId));
29968 var td = this.nextBlock();
29970 var ti = new Roo.Toolbar.Item(td.firstChild);
29972 this.items.add(ti);
29973 this.fields.add(field);
29984 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
29985 this.el.child('div').hide();
29993 this.el.child('div').show();
29997 nextBlock : function(){
29998 var td = document.createElement("td");
29999 this.tr.appendChild(td);
30004 destroy : function(){
30005 if(this.items){ // rendered?
30006 Roo.destroy.apply(Roo, this.items.items);
30008 if(this.fields){ // rendered?
30009 Roo.destroy.apply(Roo, this.fields.items);
30011 Roo.Element.uncache(this.el, this.tr);
30016 * @class Roo.Toolbar.Item
30017 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30019 * Creates a new Item
30020 * @param {HTMLElement} el
30022 Roo.Toolbar.Item = function(el){
30024 if (typeof (el.xtype) != 'undefined') {
30029 this.el = Roo.getDom(el);
30030 this.id = Roo.id(this.el);
30031 this.hidden = false;
30036 * Fires when the button is rendered
30037 * @param {Button} this
30041 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30043 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30044 //Roo.Toolbar.Item.prototype = {
30047 * Get this item's HTML Element
30048 * @return {HTMLElement}
30050 getEl : function(){
30055 render : function(td){
30058 td.appendChild(this.el);
30060 this.fireEvent('render', this);
30064 * Removes and destroys this item.
30066 destroy : function(){
30067 this.td.parentNode.removeChild(this.td);
30074 this.hidden = false;
30075 this.td.style.display = "";
30082 this.hidden = true;
30083 this.td.style.display = "none";
30087 * Convenience function for boolean show/hide.
30088 * @param {Boolean} visible true to show/false to hide
30090 setVisible: function(visible){
30099 * Try to focus this item.
30101 focus : function(){
30102 Roo.fly(this.el).focus();
30106 * Disables this item.
30108 disable : function(){
30109 Roo.fly(this.td).addClass("x-item-disabled");
30110 this.disabled = true;
30111 this.el.disabled = true;
30115 * Enables this item.
30117 enable : function(){
30118 Roo.fly(this.td).removeClass("x-item-disabled");
30119 this.disabled = false;
30120 this.el.disabled = false;
30126 * @class Roo.Toolbar.Separator
30127 * @extends Roo.Toolbar.Item
30128 * A simple toolbar separator class
30130 * Creates a new Separator
30132 Roo.Toolbar.Separator = function(cfg){
30134 var s = document.createElement("span");
30135 s.className = "ytb-sep";
30140 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30142 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30143 enable:Roo.emptyFn,
30144 disable:Roo.emptyFn,
30149 * @class Roo.Toolbar.Spacer
30150 * @extends Roo.Toolbar.Item
30151 * A simple element that adds extra horizontal space to a toolbar.
30153 * Creates a new Spacer
30155 Roo.Toolbar.Spacer = function(cfg){
30156 var s = document.createElement("div");
30157 s.className = "ytb-spacer";
30161 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30163 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30164 enable:Roo.emptyFn,
30165 disable:Roo.emptyFn,
30170 * @class Roo.Toolbar.Fill
30171 * @extends Roo.Toolbar.Spacer
30172 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30174 * Creates a new Spacer
30176 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30178 render : function(td){
30179 td.style.width = '100%';
30180 Roo.Toolbar.Fill.superclass.render.call(this, td);
30185 * @class Roo.Toolbar.TextItem
30186 * @extends Roo.Toolbar.Item
30187 * A simple class that renders text directly into a toolbar.
30189 * Creates a new TextItem
30190 * @param {String} text
30192 Roo.Toolbar.TextItem = function(cfg){
30193 var text = cfg || "";
30194 if (typeof(cfg) == 'object') {
30195 text = cfg.text || "";
30199 var s = document.createElement("span");
30200 s.className = "ytb-text";
30201 s.innerHTML = text;
30206 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30208 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30211 enable:Roo.emptyFn,
30212 disable:Roo.emptyFn,
30217 * @class Roo.Toolbar.Button
30218 * @extends Roo.Button
30219 * A button that renders into a toolbar.
30221 * Creates a new Button
30222 * @param {Object} config A standard {@link Roo.Button} config object
30224 Roo.Toolbar.Button = function(config){
30225 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30227 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30228 render : function(td){
30230 Roo.Toolbar.Button.superclass.render.call(this, td);
30234 * Removes and destroys this button
30236 destroy : function(){
30237 Roo.Toolbar.Button.superclass.destroy.call(this);
30238 this.td.parentNode.removeChild(this.td);
30242 * Shows this button
30245 this.hidden = false;
30246 this.td.style.display = "";
30250 * Hides this button
30253 this.hidden = true;
30254 this.td.style.display = "none";
30258 * Disables this item
30260 disable : function(){
30261 Roo.fly(this.td).addClass("x-item-disabled");
30262 this.disabled = true;
30266 * Enables this item
30268 enable : function(){
30269 Roo.fly(this.td).removeClass("x-item-disabled");
30270 this.disabled = false;
30273 // backwards compat
30274 Roo.ToolbarButton = Roo.Toolbar.Button;
30277 * @class Roo.Toolbar.SplitButton
30278 * @extends Roo.SplitButton
30279 * A menu button that renders into a toolbar.
30281 * Creates a new SplitButton
30282 * @param {Object} config A standard {@link Roo.SplitButton} config object
30284 Roo.Toolbar.SplitButton = function(config){
30285 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30287 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30288 render : function(td){
30290 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30294 * Removes and destroys this button
30296 destroy : function(){
30297 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30298 this.td.parentNode.removeChild(this.td);
30302 * Shows this button
30305 this.hidden = false;
30306 this.td.style.display = "";
30310 * Hides this button
30313 this.hidden = true;
30314 this.td.style.display = "none";
30318 // backwards compat
30319 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30321 * Ext JS Library 1.1.1
30322 * Copyright(c) 2006-2007, Ext JS, LLC.
30324 * Originally Released Under LGPL - original licence link has changed is not relivant.
30327 * <script type="text/javascript">
30331 * @class Roo.PagingToolbar
30332 * @extends Roo.Toolbar
30333 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30335 * Create a new PagingToolbar
30336 * @param {Object} config The config object
30338 Roo.PagingToolbar = function(el, ds, config)
30340 // old args format still supported... - xtype is prefered..
30341 if (typeof(el) == 'object' && el.xtype) {
30342 // created from xtype...
30344 ds = el.dataSource;
30345 el = config.container;
30348 if (config.items) {
30349 items = config.items;
30353 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30356 this.renderButtons(this.el);
30359 // supprot items array.
30361 Roo.each(items, function(e) {
30362 this.add(Roo.factory(e));
30367 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30369 * @cfg {Roo.data.Store} dataSource
30370 * The underlying data store providing the paged data
30373 * @cfg {String/HTMLElement/Element} container
30374 * container The id or element that will contain the toolbar
30377 * @cfg {Boolean} displayInfo
30378 * True to display the displayMsg (defaults to false)
30381 * @cfg {Number} pageSize
30382 * The number of records to display per page (defaults to 20)
30386 * @cfg {String} displayMsg
30387 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30389 displayMsg : 'Displaying {0} - {1} of {2}',
30391 * @cfg {String} emptyMsg
30392 * The message to display when no records are found (defaults to "No data to display")
30394 emptyMsg : 'No data to display',
30396 * Customizable piece of the default paging text (defaults to "Page")
30399 beforePageText : "Page",
30401 * Customizable piece of the default paging text (defaults to "of %0")
30404 afterPageText : "of {0}",
30406 * Customizable piece of the default paging text (defaults to "First Page")
30409 firstText : "First Page",
30411 * Customizable piece of the default paging text (defaults to "Previous Page")
30414 prevText : "Previous Page",
30416 * Customizable piece of the default paging text (defaults to "Next Page")
30419 nextText : "Next Page",
30421 * Customizable piece of the default paging text (defaults to "Last Page")
30424 lastText : "Last Page",
30426 * Customizable piece of the default paging text (defaults to "Refresh")
30429 refreshText : "Refresh",
30432 renderButtons : function(el){
30433 Roo.PagingToolbar.superclass.render.call(this, el);
30434 this.first = this.addButton({
30435 tooltip: this.firstText,
30436 cls: "x-btn-icon x-grid-page-first",
30438 handler: this.onClick.createDelegate(this, ["first"])
30440 this.prev = this.addButton({
30441 tooltip: this.prevText,
30442 cls: "x-btn-icon x-grid-page-prev",
30444 handler: this.onClick.createDelegate(this, ["prev"])
30446 //this.addSeparator();
30447 this.add(this.beforePageText);
30448 this.field = Roo.get(this.addDom({
30453 cls: "x-grid-page-number"
30455 this.field.on("keydown", this.onPagingKeydown, this);
30456 this.field.on("focus", function(){this.dom.select();});
30457 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30458 this.field.setHeight(18);
30459 //this.addSeparator();
30460 this.next = this.addButton({
30461 tooltip: this.nextText,
30462 cls: "x-btn-icon x-grid-page-next",
30464 handler: this.onClick.createDelegate(this, ["next"])
30466 this.last = this.addButton({
30467 tooltip: this.lastText,
30468 cls: "x-btn-icon x-grid-page-last",
30470 handler: this.onClick.createDelegate(this, ["last"])
30472 //this.addSeparator();
30473 this.loading = this.addButton({
30474 tooltip: this.refreshText,
30475 cls: "x-btn-icon x-grid-loading",
30476 handler: this.onClick.createDelegate(this, ["refresh"])
30479 if(this.displayInfo){
30480 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30485 updateInfo : function(){
30486 if(this.displayEl){
30487 var count = this.ds.getCount();
30488 var msg = count == 0 ?
30492 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30494 this.displayEl.update(msg);
30499 onLoad : function(ds, r, o){
30500 this.cursor = o.params ? o.params.start : 0;
30501 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30503 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30504 this.field.dom.value = ap;
30505 this.first.setDisabled(ap == 1);
30506 this.prev.setDisabled(ap == 1);
30507 this.next.setDisabled(ap == ps);
30508 this.last.setDisabled(ap == ps);
30509 this.loading.enable();
30514 getPageData : function(){
30515 var total = this.ds.getTotalCount();
30518 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30519 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30524 onLoadError : function(){
30525 this.loading.enable();
30529 onPagingKeydown : function(e){
30530 var k = e.getKey();
30531 var d = this.getPageData();
30533 var v = this.field.dom.value, pageNum;
30534 if(!v || isNaN(pageNum = parseInt(v, 10))){
30535 this.field.dom.value = d.activePage;
30538 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30539 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30542 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))
30544 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30545 this.field.dom.value = pageNum;
30546 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30549 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30551 var v = this.field.dom.value, pageNum;
30552 var increment = (e.shiftKey) ? 10 : 1;
30553 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30556 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30557 this.field.dom.value = d.activePage;
30560 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30562 this.field.dom.value = parseInt(v, 10) + increment;
30563 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30564 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30571 beforeLoad : function(){
30573 this.loading.disable();
30578 onClick : function(which){
30582 ds.load({params:{start: 0, limit: this.pageSize}});
30585 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30588 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30591 var total = ds.getTotalCount();
30592 var extra = total % this.pageSize;
30593 var lastStart = extra ? (total - extra) : total-this.pageSize;
30594 ds.load({params:{start: lastStart, limit: this.pageSize}});
30597 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30603 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30604 * @param {Roo.data.Store} store The data store to unbind
30606 unbind : function(ds){
30607 ds.un("beforeload", this.beforeLoad, this);
30608 ds.un("load", this.onLoad, this);
30609 ds.un("loadexception", this.onLoadError, this);
30610 ds.un("remove", this.updateInfo, this);
30611 ds.un("add", this.updateInfo, this);
30612 this.ds = undefined;
30616 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30617 * @param {Roo.data.Store} store The data store to bind
30619 bind : function(ds){
30620 ds.on("beforeload", this.beforeLoad, this);
30621 ds.on("load", this.onLoad, this);
30622 ds.on("loadexception", this.onLoadError, this);
30623 ds.on("remove", this.updateInfo, this);
30624 ds.on("add", this.updateInfo, this);
30629 * Ext JS Library 1.1.1
30630 * Copyright(c) 2006-2007, Ext JS, LLC.
30632 * Originally Released Under LGPL - original licence link has changed is not relivant.
30635 * <script type="text/javascript">
30639 * @class Roo.Resizable
30640 * @extends Roo.util.Observable
30641 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30642 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30643 * 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
30644 * the element will be wrapped for you automatically.</p>
30645 * <p>Here is the list of valid resize handles:</p>
30648 ------ -------------------
30657 'hd' horizontal drag
30660 * <p>Here's an example showing the creation of a typical Resizable:</p>
30662 var resizer = new Roo.Resizable("element-id", {
30670 resizer.on("resize", myHandler);
30672 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30673 * resizer.east.setDisplayed(false);</p>
30674 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30675 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30676 * resize operation's new size (defaults to [0, 0])
30677 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30678 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30679 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30680 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30681 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30682 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30683 * @cfg {Number} width The width of the element in pixels (defaults to null)
30684 * @cfg {Number} height The height of the element in pixels (defaults to null)
30685 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30686 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30687 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30688 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30689 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30690 * in favor of the handles config option (defaults to false)
30691 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30692 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30693 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30694 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30695 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30696 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30697 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30698 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30699 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30700 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30701 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30703 * Create a new resizable component
30704 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30705 * @param {Object} config configuration options
30707 Roo.Resizable = function(el, config)
30709 this.el = Roo.get(el);
30711 if(config && config.wrap){
30712 config.resizeChild = this.el;
30713 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30714 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30715 this.el.setStyle("overflow", "hidden");
30716 this.el.setPositioning(config.resizeChild.getPositioning());
30717 config.resizeChild.clearPositioning();
30718 if(!config.width || !config.height){
30719 var csize = config.resizeChild.getSize();
30720 this.el.setSize(csize.width, csize.height);
30722 if(config.pinned && !config.adjustments){
30723 config.adjustments = "auto";
30727 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30728 this.proxy.unselectable();
30729 this.proxy.enableDisplayMode('block');
30731 Roo.apply(this, config);
30734 this.disableTrackOver = true;
30735 this.el.addClass("x-resizable-pinned");
30737 // if the element isn't positioned, make it relative
30738 var position = this.el.getStyle("position");
30739 if(position != "absolute" && position != "fixed"){
30740 this.el.setStyle("position", "relative");
30742 if(!this.handles){ // no handles passed, must be legacy style
30743 this.handles = 's,e,se';
30744 if(this.multiDirectional){
30745 this.handles += ',n,w';
30748 if(this.handles == "all"){
30749 this.handles = "n s e w ne nw se sw";
30751 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30752 var ps = Roo.Resizable.positions;
30753 for(var i = 0, len = hs.length; i < len; i++){
30754 if(hs[i] && ps[hs[i]]){
30755 var pos = ps[hs[i]];
30756 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30760 this.corner = this.southeast;
30762 // updateBox = the box can move..
30763 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30764 this.updateBox = true;
30767 this.activeHandle = null;
30769 if(this.resizeChild){
30770 if(typeof this.resizeChild == "boolean"){
30771 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30773 this.resizeChild = Roo.get(this.resizeChild, true);
30777 if(this.adjustments == "auto"){
30778 var rc = this.resizeChild;
30779 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30780 if(rc && (hw || hn)){
30781 rc.position("relative");
30782 rc.setLeft(hw ? hw.el.getWidth() : 0);
30783 rc.setTop(hn ? hn.el.getHeight() : 0);
30785 this.adjustments = [
30786 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30787 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30791 if(this.draggable){
30792 this.dd = this.dynamic ?
30793 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30794 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30800 * @event beforeresize
30801 * Fired before resize is allowed. Set enabled to false to cancel resize.
30802 * @param {Roo.Resizable} this
30803 * @param {Roo.EventObject} e The mousedown event
30805 "beforeresize" : true,
30808 * Fired a resizing.
30809 * @param {Roo.Resizable} this
30810 * @param {Number} x The new x position
30811 * @param {Number} y The new y position
30812 * @param {Number} w The new w width
30813 * @param {Number} h The new h hight
30814 * @param {Roo.EventObject} e The mouseup event
30819 * Fired after a resize.
30820 * @param {Roo.Resizable} this
30821 * @param {Number} width The new width
30822 * @param {Number} height The new height
30823 * @param {Roo.EventObject} e The mouseup event
30828 if(this.width !== null && this.height !== null){
30829 this.resizeTo(this.width, this.height);
30831 this.updateChildSize();
30834 this.el.dom.style.zoom = 1;
30836 Roo.Resizable.superclass.constructor.call(this);
30839 Roo.extend(Roo.Resizable, Roo.util.Observable, {
30840 resizeChild : false,
30841 adjustments : [0, 0],
30851 multiDirectional : false,
30852 disableTrackOver : false,
30853 easing : 'easeOutStrong',
30854 widthIncrement : 0,
30855 heightIncrement : 0,
30859 preserveRatio : false,
30860 transparent: false,
30866 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
30868 constrainTo: undefined,
30870 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
30872 resizeRegion: undefined,
30876 * Perform a manual resize
30877 * @param {Number} width
30878 * @param {Number} height
30880 resizeTo : function(width, height){
30881 this.el.setSize(width, height);
30882 this.updateChildSize();
30883 this.fireEvent("resize", this, width, height, null);
30887 startSizing : function(e, handle){
30888 this.fireEvent("beforeresize", this, e);
30889 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
30892 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
30893 this.overlay.unselectable();
30894 this.overlay.enableDisplayMode("block");
30895 this.overlay.on("mousemove", this.onMouseMove, this);
30896 this.overlay.on("mouseup", this.onMouseUp, this);
30898 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
30900 this.resizing = true;
30901 this.startBox = this.el.getBox();
30902 this.startPoint = e.getXY();
30903 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
30904 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
30906 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30907 this.overlay.show();
30909 if(this.constrainTo) {
30910 var ct = Roo.get(this.constrainTo);
30911 this.resizeRegion = ct.getRegion().adjust(
30912 ct.getFrameWidth('t'),
30913 ct.getFrameWidth('l'),
30914 -ct.getFrameWidth('b'),
30915 -ct.getFrameWidth('r')
30919 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
30921 this.proxy.setBox(this.startBox);
30923 this.proxy.setStyle('visibility', 'visible');
30929 onMouseDown : function(handle, e){
30932 this.activeHandle = handle;
30933 this.startSizing(e, handle);
30938 onMouseUp : function(e){
30939 var size = this.resizeElement();
30940 this.resizing = false;
30942 this.overlay.hide();
30944 this.fireEvent("resize", this, size.width, size.height, e);
30948 updateChildSize : function(){
30950 if(this.resizeChild){
30952 var child = this.resizeChild;
30953 var adj = this.adjustments;
30954 if(el.dom.offsetWidth){
30955 var b = el.getSize(true);
30956 child.setSize(b.width+adj[0], b.height+adj[1]);
30958 // Second call here for IE
30959 // The first call enables instant resizing and
30960 // the second call corrects scroll bars if they
30963 setTimeout(function(){
30964 if(el.dom.offsetWidth){
30965 var b = el.getSize(true);
30966 child.setSize(b.width+adj[0], b.height+adj[1]);
30974 snap : function(value, inc, min){
30975 if(!inc || !value) {
30978 var newValue = value;
30979 var m = value % inc;
30982 newValue = value + (inc-m);
30984 newValue = value - m;
30987 return Math.max(min, newValue);
30991 resizeElement : function(){
30992 var box = this.proxy.getBox();
30993 if(this.updateBox){
30994 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
30996 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
30998 this.updateChildSize();
31006 constrain : function(v, diff, m, mx){
31009 }else if(v - diff > mx){
31016 onMouseMove : function(e){
31019 try{// try catch so if something goes wrong the user doesn't get hung
31021 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31025 //var curXY = this.startPoint;
31026 var curSize = this.curSize || this.startBox;
31027 var x = this.startBox.x, y = this.startBox.y;
31028 var ox = x, oy = y;
31029 var w = curSize.width, h = curSize.height;
31030 var ow = w, oh = h;
31031 var mw = this.minWidth, mh = this.minHeight;
31032 var mxw = this.maxWidth, mxh = this.maxHeight;
31033 var wi = this.widthIncrement;
31034 var hi = this.heightIncrement;
31036 var eventXY = e.getXY();
31037 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31038 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31040 var pos = this.activeHandle.position;
31045 w = Math.min(Math.max(mw, w), mxw);
31050 h = Math.min(Math.max(mh, h), mxh);
31055 w = Math.min(Math.max(mw, w), mxw);
31056 h = Math.min(Math.max(mh, h), mxh);
31059 diffY = this.constrain(h, diffY, mh, mxh);
31066 var adiffX = Math.abs(diffX);
31067 var sub = (adiffX % wi); // how much
31068 if (sub > (wi/2)) { // far enough to snap
31069 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31071 // remove difference..
31072 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31076 x = Math.max(this.minX, x);
31079 diffX = this.constrain(w, diffX, mw, mxw);
31085 w = Math.min(Math.max(mw, w), mxw);
31086 diffY = this.constrain(h, diffY, mh, mxh);
31091 diffX = this.constrain(w, diffX, mw, mxw);
31092 diffY = this.constrain(h, diffY, mh, mxh);
31099 diffX = this.constrain(w, diffX, mw, mxw);
31101 h = Math.min(Math.max(mh, h), mxh);
31107 var sw = this.snap(w, wi, mw);
31108 var sh = this.snap(h, hi, mh);
31109 if(sw != w || sh != h){
31132 if(this.preserveRatio){
31137 h = Math.min(Math.max(mh, h), mxh);
31142 w = Math.min(Math.max(mw, w), mxw);
31147 w = Math.min(Math.max(mw, w), mxw);
31153 w = Math.min(Math.max(mw, w), mxw);
31159 h = Math.min(Math.max(mh, h), mxh);
31167 h = Math.min(Math.max(mh, h), mxh);
31177 h = Math.min(Math.max(mh, h), mxh);
31185 if (pos == 'hdrag') {
31188 this.proxy.setBounds(x, y, w, h);
31190 this.resizeElement();
31194 this.fireEvent("resizing", this, x, y, w, h, e);
31198 handleOver : function(){
31200 this.el.addClass("x-resizable-over");
31205 handleOut : function(){
31206 if(!this.resizing){
31207 this.el.removeClass("x-resizable-over");
31212 * Returns the element this component is bound to.
31213 * @return {Roo.Element}
31215 getEl : function(){
31220 * Returns the resizeChild element (or null).
31221 * @return {Roo.Element}
31223 getResizeChild : function(){
31224 return this.resizeChild;
31226 groupHandler : function()
31231 * Destroys this resizable. If the element was wrapped and
31232 * removeEl is not true then the element remains.
31233 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31235 destroy : function(removeEl){
31236 this.proxy.remove();
31238 this.overlay.removeAllListeners();
31239 this.overlay.remove();
31241 var ps = Roo.Resizable.positions;
31243 if(typeof ps[k] != "function" && this[ps[k]]){
31244 var h = this[ps[k]];
31245 h.el.removeAllListeners();
31250 this.el.update("");
31257 // hash to map config positions to true positions
31258 Roo.Resizable.positions = {
31259 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31264 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31266 // only initialize the template if resizable is used
31267 var tpl = Roo.DomHelper.createTemplate(
31268 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31271 Roo.Resizable.Handle.prototype.tpl = tpl;
31273 this.position = pos;
31275 // show north drag fro topdra
31276 var handlepos = pos == 'hdrag' ? 'north' : pos;
31278 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31279 if (pos == 'hdrag') {
31280 this.el.setStyle('cursor', 'pointer');
31282 this.el.unselectable();
31284 this.el.setOpacity(0);
31286 this.el.on("mousedown", this.onMouseDown, this);
31287 if(!disableTrackOver){
31288 this.el.on("mouseover", this.onMouseOver, this);
31289 this.el.on("mouseout", this.onMouseOut, this);
31294 Roo.Resizable.Handle.prototype = {
31295 afterResize : function(rz){
31300 onMouseDown : function(e){
31301 this.rz.onMouseDown(this, e);
31304 onMouseOver : function(e){
31305 this.rz.handleOver(this, e);
31308 onMouseOut : function(e){
31309 this.rz.handleOut(this, e);
31313 * Ext JS Library 1.1.1
31314 * Copyright(c) 2006-2007, Ext JS, LLC.
31316 * Originally Released Under LGPL - original licence link has changed is not relivant.
31319 * <script type="text/javascript">
31323 * @class Roo.Editor
31324 * @extends Roo.Component
31325 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31327 * Create a new Editor
31328 * @param {Roo.form.Field} field The Field object (or descendant)
31329 * @param {Object} config The config object
31331 Roo.Editor = function(field, config){
31332 Roo.Editor.superclass.constructor.call(this, config);
31333 this.field = field;
31336 * @event beforestartedit
31337 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31338 * false from the handler of this event.
31339 * @param {Editor} this
31340 * @param {Roo.Element} boundEl The underlying element bound to this editor
31341 * @param {Mixed} value The field value being set
31343 "beforestartedit" : true,
31346 * Fires when this editor is displayed
31347 * @param {Roo.Element} boundEl The underlying element bound to this editor
31348 * @param {Mixed} value The starting field value
31350 "startedit" : true,
31352 * @event beforecomplete
31353 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31354 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31355 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31356 * event will not fire since no edit actually occurred.
31357 * @param {Editor} this
31358 * @param {Mixed} value The current field value
31359 * @param {Mixed} startValue The original field value
31361 "beforecomplete" : true,
31364 * Fires after editing is complete and any changed value has been written to the underlying field.
31365 * @param {Editor} this
31366 * @param {Mixed} value The current field value
31367 * @param {Mixed} startValue The original field value
31371 * @event specialkey
31372 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31373 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31374 * @param {Roo.form.Field} this
31375 * @param {Roo.EventObject} e The event object
31377 "specialkey" : true
31381 Roo.extend(Roo.Editor, Roo.Component, {
31383 * @cfg {Boolean/String} autosize
31384 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31385 * or "height" to adopt the height only (defaults to false)
31388 * @cfg {Boolean} revertInvalid
31389 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31390 * validation fails (defaults to true)
31393 * @cfg {Boolean} ignoreNoChange
31394 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31395 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31396 * will never be ignored.
31399 * @cfg {Boolean} hideEl
31400 * False to keep the bound element visible while the editor is displayed (defaults to true)
31403 * @cfg {Mixed} value
31404 * The data value of the underlying field (defaults to "")
31408 * @cfg {String} alignment
31409 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31413 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31414 * for bottom-right shadow (defaults to "frame")
31418 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31422 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31424 completeOnEnter : false,
31426 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31428 cancelOnEsc : false,
31430 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31435 onRender : function(ct, position){
31436 this.el = new Roo.Layer({
31437 shadow: this.shadow,
31443 constrain: this.constrain
31445 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31446 if(this.field.msgTarget != 'title'){
31447 this.field.msgTarget = 'qtip';
31449 this.field.render(this.el);
31451 this.field.el.dom.setAttribute('autocomplete', 'off');
31453 this.field.on("specialkey", this.onSpecialKey, this);
31454 if(this.swallowKeys){
31455 this.field.el.swallowEvent(['keydown','keypress']);
31458 this.field.on("blur", this.onBlur, this);
31459 if(this.field.grow){
31460 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31464 onSpecialKey : function(field, e)
31466 //Roo.log('editor onSpecialKey');
31467 if(this.completeOnEnter && e.getKey() == e.ENTER){
31469 this.completeEdit();
31472 // do not fire special key otherwise it might hide close the editor...
31473 if(e.getKey() == e.ENTER){
31476 if(this.cancelOnEsc && e.getKey() == e.ESC){
31480 this.fireEvent('specialkey', field, e);
31485 * Starts the editing process and shows the editor.
31486 * @param {String/HTMLElement/Element} el The element to edit
31487 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31488 * to the innerHTML of el.
31490 startEdit : function(el, value){
31492 this.completeEdit();
31494 this.boundEl = Roo.get(el);
31495 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31496 if(!this.rendered){
31497 this.render(this.parentEl || document.body);
31499 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31502 this.startValue = v;
31503 this.field.setValue(v);
31505 var sz = this.boundEl.getSize();
31506 switch(this.autoSize){
31508 this.setSize(sz.width, "");
31511 this.setSize("", sz.height);
31514 this.setSize(sz.width, sz.height);
31517 this.el.alignTo(this.boundEl, this.alignment);
31518 this.editing = true;
31520 Roo.QuickTips.disable();
31526 * Sets the height and width of this editor.
31527 * @param {Number} width The new width
31528 * @param {Number} height The new height
31530 setSize : function(w, h){
31531 this.field.setSize(w, h);
31538 * Realigns the editor to the bound field based on the current alignment config value.
31540 realign : function(){
31541 this.el.alignTo(this.boundEl, this.alignment);
31545 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31546 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31548 completeEdit : function(remainVisible){
31552 var v = this.getValue();
31553 if(this.revertInvalid !== false && !this.field.isValid()){
31554 v = this.startValue;
31555 this.cancelEdit(true);
31557 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31558 this.editing = false;
31562 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31563 this.editing = false;
31564 if(this.updateEl && this.boundEl){
31565 this.boundEl.update(v);
31567 if(remainVisible !== true){
31570 this.fireEvent("complete", this, v, this.startValue);
31575 onShow : function(){
31577 if(this.hideEl !== false){
31578 this.boundEl.hide();
31581 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31582 this.fixIEFocus = true;
31583 this.deferredFocus.defer(50, this);
31585 this.field.focus();
31587 this.fireEvent("startedit", this.boundEl, this.startValue);
31590 deferredFocus : function(){
31592 this.field.focus();
31597 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31598 * reverted to the original starting value.
31599 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31600 * cancel (defaults to false)
31602 cancelEdit : function(remainVisible){
31604 this.setValue(this.startValue);
31605 if(remainVisible !== true){
31612 onBlur : function(){
31613 if(this.allowBlur !== true && this.editing){
31614 this.completeEdit();
31619 onHide : function(){
31621 this.completeEdit();
31625 if(this.field.collapse){
31626 this.field.collapse();
31629 if(this.hideEl !== false){
31630 this.boundEl.show();
31633 Roo.QuickTips.enable();
31638 * Sets the data value of the editor
31639 * @param {Mixed} value Any valid value supported by the underlying field
31641 setValue : function(v){
31642 this.field.setValue(v);
31646 * Gets the data value of the editor
31647 * @return {Mixed} The data value
31649 getValue : function(){
31650 return this.field.getValue();
31654 * Ext JS Library 1.1.1
31655 * Copyright(c) 2006-2007, Ext JS, LLC.
31657 * Originally Released Under LGPL - original licence link has changed is not relivant.
31660 * <script type="text/javascript">
31664 * @class Roo.BasicDialog
31665 * @extends Roo.util.Observable
31666 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31668 var dlg = new Roo.BasicDialog("my-dlg", {
31677 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31678 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31679 dlg.addButton('Cancel', dlg.hide, dlg);
31682 <b>A Dialog should always be a direct child of the body element.</b>
31683 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31684 * @cfg {String} title Default text to display in the title bar (defaults to null)
31685 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31686 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31687 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31688 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31689 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31690 * (defaults to null with no animation)
31691 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31692 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31693 * property for valid values (defaults to 'all')
31694 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31695 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31696 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31697 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31698 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31699 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31700 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31701 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31702 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31703 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31704 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31705 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31706 * draggable = true (defaults to false)
31707 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31708 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31709 * shadow (defaults to false)
31710 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31711 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31712 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31713 * @cfg {Array} buttons Array of buttons
31714 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31716 * Create a new BasicDialog.
31717 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31718 * @param {Object} config Configuration options
31720 Roo.BasicDialog = function(el, config){
31721 this.el = Roo.get(el);
31722 var dh = Roo.DomHelper;
31723 if(!this.el && config && config.autoCreate){
31724 if(typeof config.autoCreate == "object"){
31725 if(!config.autoCreate.id){
31726 config.autoCreate.id = el;
31728 this.el = dh.append(document.body,
31729 config.autoCreate, true);
31731 this.el = dh.append(document.body,
31732 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31736 el.setDisplayed(true);
31737 el.hide = this.hideAction;
31739 el.addClass("x-dlg");
31741 Roo.apply(this, config);
31743 this.proxy = el.createProxy("x-dlg-proxy");
31744 this.proxy.hide = this.hideAction;
31745 this.proxy.setOpacity(.5);
31749 el.setWidth(config.width);
31752 el.setHeight(config.height);
31754 this.size = el.getSize();
31755 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31756 this.xy = [config.x,config.y];
31758 this.xy = el.getCenterXY(true);
31760 /** The header element @type Roo.Element */
31761 this.header = el.child("> .x-dlg-hd");
31762 /** The body element @type Roo.Element */
31763 this.body = el.child("> .x-dlg-bd");
31764 /** The footer element @type Roo.Element */
31765 this.footer = el.child("> .x-dlg-ft");
31768 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31771 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31774 this.header.unselectable();
31776 this.header.update(this.title);
31778 // this element allows the dialog to be focused for keyboard event
31779 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31780 this.focusEl.swallowEvent("click", true);
31782 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31784 // wrap the body and footer for special rendering
31785 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31787 this.bwrap.dom.appendChild(this.footer.dom);
31790 this.bg = this.el.createChild({
31791 tag: "div", cls:"x-dlg-bg",
31792 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31794 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31797 if(this.autoScroll !== false && !this.autoTabs){
31798 this.body.setStyle("overflow", "auto");
31801 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31803 if(this.closable !== false){
31804 this.el.addClass("x-dlg-closable");
31805 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31806 this.close.on("click", this.closeClick, this);
31807 this.close.addClassOnOver("x-dlg-close-over");
31809 if(this.collapsible !== false){
31810 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31811 this.collapseBtn.on("click", this.collapseClick, this);
31812 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31813 this.header.on("dblclick", this.collapseClick, this);
31815 if(this.resizable !== false){
31816 this.el.addClass("x-dlg-resizable");
31817 this.resizer = new Roo.Resizable(el, {
31818 minWidth: this.minWidth || 80,
31819 minHeight:this.minHeight || 80,
31820 handles: this.resizeHandles || "all",
31823 this.resizer.on("beforeresize", this.beforeResize, this);
31824 this.resizer.on("resize", this.onResize, this);
31826 if(this.draggable !== false){
31827 el.addClass("x-dlg-draggable");
31828 if (!this.proxyDrag) {
31829 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
31832 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
31834 dd.setHandleElId(this.header.id);
31835 dd.endDrag = this.endMove.createDelegate(this);
31836 dd.startDrag = this.startMove.createDelegate(this);
31837 dd.onDrag = this.onDrag.createDelegate(this);
31842 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
31843 this.mask.enableDisplayMode("block");
31845 this.el.addClass("x-dlg-modal");
31848 this.shadow = new Roo.Shadow({
31849 mode : typeof this.shadow == "string" ? this.shadow : "sides",
31850 offset : this.shadowOffset
31853 this.shadowOffset = 0;
31855 if(Roo.useShims && this.shim !== false){
31856 this.shim = this.el.createShim();
31857 this.shim.hide = this.hideAction;
31865 if (this.buttons) {
31866 var bts= this.buttons;
31868 Roo.each(bts, function(b) {
31877 * Fires when a key is pressed
31878 * @param {Roo.BasicDialog} this
31879 * @param {Roo.EventObject} e
31884 * Fires when this dialog is moved by the user.
31885 * @param {Roo.BasicDialog} this
31886 * @param {Number} x The new page X
31887 * @param {Number} y The new page Y
31892 * Fires when this dialog is resized by the user.
31893 * @param {Roo.BasicDialog} this
31894 * @param {Number} width The new width
31895 * @param {Number} height The new height
31899 * @event beforehide
31900 * Fires before this dialog is hidden.
31901 * @param {Roo.BasicDialog} this
31903 "beforehide" : true,
31906 * Fires when this dialog is hidden.
31907 * @param {Roo.BasicDialog} this
31911 * @event beforeshow
31912 * Fires before this dialog is shown.
31913 * @param {Roo.BasicDialog} this
31915 "beforeshow" : true,
31918 * Fires when this dialog is shown.
31919 * @param {Roo.BasicDialog} this
31923 el.on("keydown", this.onKeyDown, this);
31924 el.on("mousedown", this.toFront, this);
31925 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
31927 Roo.DialogManager.register(this);
31928 Roo.BasicDialog.superclass.constructor.call(this);
31931 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
31932 shadowOffset: Roo.isIE ? 6 : 5,
31935 minButtonWidth: 75,
31936 defaultButton: null,
31937 buttonAlign: "right",
31942 * Sets the dialog title text
31943 * @param {String} text The title text to display
31944 * @return {Roo.BasicDialog} this
31946 setTitle : function(text){
31947 this.header.update(text);
31952 closeClick : function(){
31957 collapseClick : function(){
31958 this[this.collapsed ? "expand" : "collapse"]();
31962 * Collapses the dialog to its minimized state (only the title bar is visible).
31963 * Equivalent to the user clicking the collapse dialog button.
31965 collapse : function(){
31966 if(!this.collapsed){
31967 this.collapsed = true;
31968 this.el.addClass("x-dlg-collapsed");
31969 this.restoreHeight = this.el.getHeight();
31970 this.resizeTo(this.el.getWidth(), this.header.getHeight());
31975 * Expands a collapsed dialog back to its normal state. Equivalent to the user
31976 * clicking the expand dialog button.
31978 expand : function(){
31979 if(this.collapsed){
31980 this.collapsed = false;
31981 this.el.removeClass("x-dlg-collapsed");
31982 this.resizeTo(this.el.getWidth(), this.restoreHeight);
31987 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
31988 * @return {Roo.TabPanel} The tabs component
31990 initTabs : function(){
31991 var tabs = this.getTabs();
31992 while(tabs.getTab(0)){
31995 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
31997 tabs.addTab(Roo.id(dom), dom.title);
32005 beforeResize : function(){
32006 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32010 onResize : function(){
32011 this.refreshSize();
32012 this.syncBodyHeight();
32013 this.adjustAssets();
32015 this.fireEvent("resize", this, this.size.width, this.size.height);
32019 onKeyDown : function(e){
32020 if(this.isVisible()){
32021 this.fireEvent("keydown", this, e);
32026 * Resizes the dialog.
32027 * @param {Number} width
32028 * @param {Number} height
32029 * @return {Roo.BasicDialog} this
32031 resizeTo : function(width, height){
32032 this.el.setSize(width, height);
32033 this.size = {width: width, height: height};
32034 this.syncBodyHeight();
32035 if(this.fixedcenter){
32038 if(this.isVisible()){
32039 this.constrainXY();
32040 this.adjustAssets();
32042 this.fireEvent("resize", this, width, height);
32048 * Resizes the dialog to fit the specified content size.
32049 * @param {Number} width
32050 * @param {Number} height
32051 * @return {Roo.BasicDialog} this
32053 setContentSize : function(w, h){
32054 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32055 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32056 //if(!this.el.isBorderBox()){
32057 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32058 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32061 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32062 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32064 this.resizeTo(w, h);
32069 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32070 * executed in response to a particular key being pressed while the dialog is active.
32071 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32072 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32073 * @param {Function} fn The function to call
32074 * @param {Object} scope (optional) The scope of the function
32075 * @return {Roo.BasicDialog} this
32077 addKeyListener : function(key, fn, scope){
32078 var keyCode, shift, ctrl, alt;
32079 if(typeof key == "object" && !(key instanceof Array)){
32080 keyCode = key["key"];
32081 shift = key["shift"];
32082 ctrl = key["ctrl"];
32087 var handler = function(dlg, e){
32088 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32089 var k = e.getKey();
32090 if(keyCode instanceof Array){
32091 for(var i = 0, len = keyCode.length; i < len; i++){
32092 if(keyCode[i] == k){
32093 fn.call(scope || window, dlg, k, e);
32099 fn.call(scope || window, dlg, k, e);
32104 this.on("keydown", handler);
32109 * Returns the TabPanel component (creates it if it doesn't exist).
32110 * Note: If you wish to simply check for the existence of tabs without creating them,
32111 * check for a null 'tabs' property.
32112 * @return {Roo.TabPanel} The tabs component
32114 getTabs : function(){
32116 this.el.addClass("x-dlg-auto-tabs");
32117 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32118 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32124 * Adds a button to the footer section of the dialog.
32125 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32126 * object or a valid Roo.DomHelper element config
32127 * @param {Function} handler The function called when the button is clicked
32128 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32129 * @return {Roo.Button} The new button
32131 addButton : function(config, handler, scope){
32132 var dh = Roo.DomHelper;
32134 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32136 if(!this.btnContainer){
32137 var tb = this.footer.createChild({
32139 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32140 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32142 this.btnContainer = tb.firstChild.firstChild.firstChild;
32147 minWidth: this.minButtonWidth,
32150 if(typeof config == "string"){
32151 bconfig.text = config;
32154 bconfig.dhconfig = config;
32156 Roo.apply(bconfig, config);
32160 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32161 bconfig.position = Math.max(0, bconfig.position);
32162 fc = this.btnContainer.childNodes[bconfig.position];
32165 var btn = new Roo.Button(
32167 this.btnContainer.insertBefore(document.createElement("td"),fc)
32168 : this.btnContainer.appendChild(document.createElement("td")),
32169 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32172 this.syncBodyHeight();
32175 * Array of all the buttons that have been added to this dialog via addButton
32180 this.buttons.push(btn);
32185 * Sets the default button to be focused when the dialog is displayed.
32186 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32187 * @return {Roo.BasicDialog} this
32189 setDefaultButton : function(btn){
32190 this.defaultButton = btn;
32195 getHeaderFooterHeight : function(safe){
32198 height += this.header.getHeight();
32201 var fm = this.footer.getMargins();
32202 height += (this.footer.getHeight()+fm.top+fm.bottom);
32204 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32205 height += this.centerBg.getPadding("tb");
32210 syncBodyHeight : function()
32212 var bd = this.body, // the text
32213 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32215 var height = this.size.height - this.getHeaderFooterHeight(false);
32216 bd.setHeight(height-bd.getMargins("tb"));
32217 var hh = this.header.getHeight();
32218 var h = this.size.height-hh;
32221 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32222 bw.setHeight(h-cb.getPadding("tb"));
32224 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32225 bd.setWidth(bw.getWidth(true));
32227 this.tabs.syncHeight();
32229 this.tabs.el.repaint();
32235 * Restores the previous state of the dialog if Roo.state is configured.
32236 * @return {Roo.BasicDialog} this
32238 restoreState : function(){
32239 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32240 if(box && box.width){
32241 this.xy = [box.x, box.y];
32242 this.resizeTo(box.width, box.height);
32248 beforeShow : function(){
32250 if(this.fixedcenter){
32251 this.xy = this.el.getCenterXY(true);
32254 Roo.get(document.body).addClass("x-body-masked");
32255 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32258 this.constrainXY();
32262 animShow : function(){
32263 var b = Roo.get(this.animateTarget).getBox();
32264 this.proxy.setSize(b.width, b.height);
32265 this.proxy.setLocation(b.x, b.y);
32267 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32268 true, .35, this.showEl.createDelegate(this));
32272 * Shows the dialog.
32273 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32274 * @return {Roo.BasicDialog} this
32276 show : function(animateTarget){
32277 if (this.fireEvent("beforeshow", this) === false){
32280 if(this.syncHeightBeforeShow){
32281 this.syncBodyHeight();
32282 }else if(this.firstShow){
32283 this.firstShow = false;
32284 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32286 this.animateTarget = animateTarget || this.animateTarget;
32287 if(!this.el.isVisible()){
32289 if(this.animateTarget && Roo.get(this.animateTarget)){
32299 showEl : function(){
32301 this.el.setXY(this.xy);
32303 this.adjustAssets(true);
32306 // IE peekaboo bug - fix found by Dave Fenwick
32310 this.fireEvent("show", this);
32314 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32315 * dialog itself will receive focus.
32317 focus : function(){
32318 if(this.defaultButton){
32319 this.defaultButton.focus();
32321 this.focusEl.focus();
32326 constrainXY : function(){
32327 if(this.constraintoviewport !== false){
32328 if(!this.viewSize){
32329 if(this.container){
32330 var s = this.container.getSize();
32331 this.viewSize = [s.width, s.height];
32333 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32336 var s = Roo.get(this.container||document).getScroll();
32338 var x = this.xy[0], y = this.xy[1];
32339 var w = this.size.width, h = this.size.height;
32340 var vw = this.viewSize[0], vh = this.viewSize[1];
32341 // only move it if it needs it
32343 // first validate right/bottom
32344 if(x + w > vw+s.left){
32348 if(y + h > vh+s.top){
32352 // then make sure top/left isn't negative
32364 if(this.isVisible()){
32365 this.el.setLocation(x, y);
32366 this.adjustAssets();
32373 onDrag : function(){
32374 if(!this.proxyDrag){
32375 this.xy = this.el.getXY();
32376 this.adjustAssets();
32381 adjustAssets : function(doShow){
32382 var x = this.xy[0], y = this.xy[1];
32383 var w = this.size.width, h = this.size.height;
32384 if(doShow === true){
32386 this.shadow.show(this.el);
32392 if(this.shadow && this.shadow.isVisible()){
32393 this.shadow.show(this.el);
32395 if(this.shim && this.shim.isVisible()){
32396 this.shim.setBounds(x, y, w, h);
32401 adjustViewport : function(w, h){
32403 w = Roo.lib.Dom.getViewWidth();
32404 h = Roo.lib.Dom.getViewHeight();
32407 this.viewSize = [w, h];
32408 if(this.modal && this.mask.isVisible()){
32409 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32410 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32412 if(this.isVisible()){
32413 this.constrainXY();
32418 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32419 * shadow, proxy, mask, etc.) Also removes all event listeners.
32420 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32422 destroy : function(removeEl){
32423 if(this.isVisible()){
32424 this.animateTarget = null;
32427 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32429 this.tabs.destroy(removeEl);
32442 for(var i = 0, len = this.buttons.length; i < len; i++){
32443 this.buttons[i].destroy();
32446 this.el.removeAllListeners();
32447 if(removeEl === true){
32448 this.el.update("");
32451 Roo.DialogManager.unregister(this);
32455 startMove : function(){
32456 if(this.proxyDrag){
32459 if(this.constraintoviewport !== false){
32460 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32465 endMove : function(){
32466 if(!this.proxyDrag){
32467 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32469 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32472 this.refreshSize();
32473 this.adjustAssets();
32475 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32479 * Brings this dialog to the front of any other visible dialogs
32480 * @return {Roo.BasicDialog} this
32482 toFront : function(){
32483 Roo.DialogManager.bringToFront(this);
32488 * Sends this dialog to the back (under) of any other visible dialogs
32489 * @return {Roo.BasicDialog} this
32491 toBack : function(){
32492 Roo.DialogManager.sendToBack(this);
32497 * Centers this dialog in the viewport
32498 * @return {Roo.BasicDialog} this
32500 center : function(){
32501 var xy = this.el.getCenterXY(true);
32502 this.moveTo(xy[0], xy[1]);
32507 * Moves the dialog's top-left corner to the specified point
32508 * @param {Number} x
32509 * @param {Number} y
32510 * @return {Roo.BasicDialog} this
32512 moveTo : function(x, y){
32514 if(this.isVisible()){
32515 this.el.setXY(this.xy);
32516 this.adjustAssets();
32522 * Aligns the dialog to the specified element
32523 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32524 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32525 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32526 * @return {Roo.BasicDialog} this
32528 alignTo : function(element, position, offsets){
32529 this.xy = this.el.getAlignToXY(element, position, offsets);
32530 if(this.isVisible()){
32531 this.el.setXY(this.xy);
32532 this.adjustAssets();
32538 * Anchors an element to another element and realigns it when the window is resized.
32539 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32540 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32541 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32542 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32543 * is a number, it is used as the buffer delay (defaults to 50ms).
32544 * @return {Roo.BasicDialog} this
32546 anchorTo : function(el, alignment, offsets, monitorScroll){
32547 var action = function(){
32548 this.alignTo(el, alignment, offsets);
32550 Roo.EventManager.onWindowResize(action, this);
32551 var tm = typeof monitorScroll;
32552 if(tm != 'undefined'){
32553 Roo.EventManager.on(window, 'scroll', action, this,
32554 {buffer: tm == 'number' ? monitorScroll : 50});
32561 * Returns true if the dialog is visible
32562 * @return {Boolean}
32564 isVisible : function(){
32565 return this.el.isVisible();
32569 animHide : function(callback){
32570 var b = Roo.get(this.animateTarget).getBox();
32572 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32574 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32575 this.hideEl.createDelegate(this, [callback]));
32579 * Hides the dialog.
32580 * @param {Function} callback (optional) Function to call when the dialog is hidden
32581 * @return {Roo.BasicDialog} this
32583 hide : function(callback){
32584 if (this.fireEvent("beforehide", this) === false){
32588 this.shadow.hide();
32593 // sometimes animateTarget seems to get set.. causing problems...
32594 // this just double checks..
32595 if(this.animateTarget && Roo.get(this.animateTarget)) {
32596 this.animHide(callback);
32599 this.hideEl(callback);
32605 hideEl : function(callback){
32609 Roo.get(document.body).removeClass("x-body-masked");
32611 this.fireEvent("hide", this);
32612 if(typeof callback == "function"){
32618 hideAction : function(){
32619 this.setLeft("-10000px");
32620 this.setTop("-10000px");
32621 this.setStyle("visibility", "hidden");
32625 refreshSize : function(){
32626 this.size = this.el.getSize();
32627 this.xy = this.el.getXY();
32628 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32632 // z-index is managed by the DialogManager and may be overwritten at any time
32633 setZIndex : function(index){
32635 this.mask.setStyle("z-index", index);
32638 this.shim.setStyle("z-index", ++index);
32641 this.shadow.setZIndex(++index);
32643 this.el.setStyle("z-index", ++index);
32645 this.proxy.setStyle("z-index", ++index);
32648 this.resizer.proxy.setStyle("z-index", ++index);
32651 this.lastZIndex = index;
32655 * Returns the element for this dialog
32656 * @return {Roo.Element} The underlying dialog Element
32658 getEl : function(){
32664 * @class Roo.DialogManager
32665 * Provides global access to BasicDialogs that have been created and
32666 * support for z-indexing (layering) multiple open dialogs.
32668 Roo.DialogManager = function(){
32670 var accessList = [];
32674 var sortDialogs = function(d1, d2){
32675 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32679 var orderDialogs = function(){
32680 accessList.sort(sortDialogs);
32681 var seed = Roo.DialogManager.zseed;
32682 for(var i = 0, len = accessList.length; i < len; i++){
32683 var dlg = accessList[i];
32685 dlg.setZIndex(seed + (i*10));
32692 * The starting z-index for BasicDialogs (defaults to 9000)
32693 * @type Number The z-index value
32698 register : function(dlg){
32699 list[dlg.id] = dlg;
32700 accessList.push(dlg);
32704 unregister : function(dlg){
32705 delete list[dlg.id];
32708 if(!accessList.indexOf){
32709 for( i = 0, len = accessList.length; i < len; i++){
32710 if(accessList[i] == dlg){
32711 accessList.splice(i, 1);
32716 i = accessList.indexOf(dlg);
32718 accessList.splice(i, 1);
32724 * Gets a registered dialog by id
32725 * @param {String/Object} id The id of the dialog or a dialog
32726 * @return {Roo.BasicDialog} this
32728 get : function(id){
32729 return typeof id == "object" ? id : list[id];
32733 * Brings the specified dialog to the front
32734 * @param {String/Object} dlg The id of the dialog or a dialog
32735 * @return {Roo.BasicDialog} this
32737 bringToFront : function(dlg){
32738 dlg = this.get(dlg);
32741 dlg._lastAccess = new Date().getTime();
32748 * Sends the specified dialog to the back
32749 * @param {String/Object} dlg The id of the dialog or a dialog
32750 * @return {Roo.BasicDialog} this
32752 sendToBack : function(dlg){
32753 dlg = this.get(dlg);
32754 dlg._lastAccess = -(new Date().getTime());
32760 * Hides all dialogs
32762 hideAll : function(){
32763 for(var id in list){
32764 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32773 * @class Roo.LayoutDialog
32774 * @extends Roo.BasicDialog
32775 * Dialog which provides adjustments for working with a layout in a Dialog.
32776 * Add your necessary layout config options to the dialog's config.<br>
32777 * Example usage (including a nested layout):
32780 dialog = new Roo.LayoutDialog("download-dlg", {
32789 // layout config merges with the dialog config
32791 tabPosition: "top",
32792 alwaysShowTabs: true
32795 dialog.addKeyListener(27, dialog.hide, dialog);
32796 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32797 dialog.addButton("Build It!", this.getDownload, this);
32799 // we can even add nested layouts
32800 var innerLayout = new Roo.BorderLayout("dl-inner", {
32810 innerLayout.beginUpdate();
32811 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32812 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32813 innerLayout.endUpdate(true);
32815 var layout = dialog.getLayout();
32816 layout.beginUpdate();
32817 layout.add("center", new Roo.ContentPanel("standard-panel",
32818 {title: "Download the Source", fitToFrame:true}));
32819 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32820 {title: "Build your own roo.js"}));
32821 layout.getRegion("center").showPanel(sp);
32822 layout.endUpdate();
32826 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32827 * @param {Object} config configuration options
32829 Roo.LayoutDialog = function(el, cfg){
32832 if (typeof(cfg) == 'undefined') {
32833 config = Roo.apply({}, el);
32834 // not sure why we use documentElement here.. - it should always be body.
32835 // IE7 borks horribly if we use documentElement.
32836 // webkit also does not like documentElement - it creates a body element...
32837 el = Roo.get( document.body || document.documentElement ).createChild();
32838 //config.autoCreate = true;
32842 config.autoTabs = false;
32843 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
32844 this.body.setStyle({overflow:"hidden", position:"relative"});
32845 this.layout = new Roo.BorderLayout(this.body.dom, config);
32846 this.layout.monitorWindowResize = false;
32847 this.el.addClass("x-dlg-auto-layout");
32848 // fix case when center region overwrites center function
32849 this.center = Roo.BasicDialog.prototype.center;
32850 this.on("show", this.layout.layout, this.layout, true);
32851 if (config.items) {
32852 var xitems = config.items;
32853 delete config.items;
32854 Roo.each(xitems, this.addxtype, this);
32859 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
32861 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
32864 endUpdate : function(){
32865 this.layout.endUpdate();
32869 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
32872 beginUpdate : function(){
32873 this.layout.beginUpdate();
32877 * Get the BorderLayout for this dialog
32878 * @return {Roo.BorderLayout}
32880 getLayout : function(){
32881 return this.layout;
32884 showEl : function(){
32885 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
32887 this.layout.layout();
32892 // Use the syncHeightBeforeShow config option to control this automatically
32893 syncBodyHeight : function(){
32894 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
32895 if(this.layout){this.layout.layout();}
32899 * Add an xtype element (actually adds to the layout.)
32900 * @return {Object} xdata xtype object data.
32903 addxtype : function(c) {
32904 return this.layout.addxtype(c);
32908 * Ext JS Library 1.1.1
32909 * Copyright(c) 2006-2007, Ext JS, LLC.
32911 * Originally Released Under LGPL - original licence link has changed is not relivant.
32914 * <script type="text/javascript">
32918 * @class Roo.MessageBox
32919 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
32923 Roo.Msg.alert('Status', 'Changes saved successfully.');
32925 // Prompt for user data:
32926 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
32928 // process text value...
32932 // Show a dialog using config options:
32934 title:'Save Changes?',
32935 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
32936 buttons: Roo.Msg.YESNOCANCEL,
32943 Roo.MessageBox = function(){
32944 var dlg, opt, mask, waitTimer;
32945 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
32946 var buttons, activeTextEl, bwidth;
32949 var handleButton = function(button){
32951 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
32955 var handleHide = function(){
32956 if(opt && opt.cls){
32957 dlg.el.removeClass(opt.cls);
32960 Roo.TaskMgr.stop(waitTimer);
32966 var updateButtons = function(b){
32969 buttons["ok"].hide();
32970 buttons["cancel"].hide();
32971 buttons["yes"].hide();
32972 buttons["no"].hide();
32973 dlg.footer.dom.style.display = 'none';
32976 dlg.footer.dom.style.display = '';
32977 for(var k in buttons){
32978 if(typeof buttons[k] != "function"){
32981 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
32982 width += buttons[k].el.getWidth()+15;
32992 var handleEsc = function(d, k, e){
32993 if(opt && opt.closable !== false){
33003 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33004 * @return {Roo.BasicDialog} The BasicDialog element
33006 getDialog : function(){
33008 dlg = new Roo.BasicDialog("x-msg-box", {
33013 constraintoviewport:false,
33015 collapsible : false,
33018 width:400, height:100,
33019 buttonAlign:"center",
33020 closeClick : function(){
33021 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33022 handleButton("no");
33024 handleButton("cancel");
33028 dlg.on("hide", handleHide);
33030 dlg.addKeyListener(27, handleEsc);
33032 var bt = this.buttonText;
33033 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33034 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33035 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33036 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33037 bodyEl = dlg.body.createChild({
33039 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>'
33041 msgEl = bodyEl.dom.firstChild;
33042 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33043 textboxEl.enableDisplayMode();
33044 textboxEl.addKeyListener([10,13], function(){
33045 if(dlg.isVisible() && opt && opt.buttons){
33046 if(opt.buttons.ok){
33047 handleButton("ok");
33048 }else if(opt.buttons.yes){
33049 handleButton("yes");
33053 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33054 textareaEl.enableDisplayMode();
33055 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33056 progressEl.enableDisplayMode();
33057 var pf = progressEl.dom.firstChild;
33059 pp = Roo.get(pf.firstChild);
33060 pp.setHeight(pf.offsetHeight);
33068 * Updates the message box body text
33069 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33070 * the XHTML-compliant non-breaking space character '&#160;')
33071 * @return {Roo.MessageBox} This message box
33073 updateText : function(text){
33074 if(!dlg.isVisible() && !opt.width){
33075 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33077 msgEl.innerHTML = text || ' ';
33079 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33080 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33082 Math.min(opt.width || cw , this.maxWidth),
33083 Math.max(opt.minWidth || this.minWidth, bwidth)
33086 activeTextEl.setWidth(w);
33088 if(dlg.isVisible()){
33089 dlg.fixedcenter = false;
33091 // to big, make it scroll. = But as usual stupid IE does not support
33094 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33095 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33096 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33098 bodyEl.dom.style.height = '';
33099 bodyEl.dom.style.overflowY = '';
33102 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33104 bodyEl.dom.style.overflowX = '';
33107 dlg.setContentSize(w, bodyEl.getHeight());
33108 if(dlg.isVisible()){
33109 dlg.fixedcenter = true;
33115 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33116 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33117 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33118 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33119 * @return {Roo.MessageBox} This message box
33121 updateProgress : function(value, text){
33123 this.updateText(text);
33125 if (pp) { // weird bug on my firefox - for some reason this is not defined
33126 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33132 * Returns true if the message box is currently displayed
33133 * @return {Boolean} True if the message box is visible, else false
33135 isVisible : function(){
33136 return dlg && dlg.isVisible();
33140 * Hides the message box if it is displayed
33143 if(this.isVisible()){
33149 * Displays a new message box, or reinitializes an existing message box, based on the config options
33150 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33151 * The following config object properties are supported:
33153 Property Type Description
33154 ---------- --------------- ------------------------------------------------------------------------------------
33155 animEl String/Element An id or Element from which the message box should animate as it opens and
33156 closes (defaults to undefined)
33157 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33158 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33159 closable Boolean False to hide the top-right close button (defaults to true). Note that
33160 progress and wait dialogs will ignore this property and always hide the
33161 close button as they can only be closed programmatically.
33162 cls String A custom CSS class to apply to the message box element
33163 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33164 displayed (defaults to 75)
33165 fn Function A callback function to execute after closing the dialog. The arguments to the
33166 function will be btn (the name of the button that was clicked, if applicable,
33167 e.g. "ok"), and text (the value of the active text field, if applicable).
33168 Progress and wait dialogs will ignore this option since they do not respond to
33169 user actions and can only be closed programmatically, so any required function
33170 should be called by the same code after it closes the dialog.
33171 icon String A CSS class that provides a background image to be used as an icon for
33172 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33173 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33174 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33175 modal Boolean False to allow user interaction with the page while the message box is
33176 displayed (defaults to true)
33177 msg String A string that will replace the existing message box body text (defaults
33178 to the XHTML-compliant non-breaking space character ' ')
33179 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33180 progress Boolean True to display a progress bar (defaults to false)
33181 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33182 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33183 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33184 title String The title text
33185 value String The string value to set into the active textbox element if displayed
33186 wait Boolean True to display a progress bar (defaults to false)
33187 width Number The width of the dialog in pixels
33194 msg: 'Please enter your address:',
33196 buttons: Roo.MessageBox.OKCANCEL,
33199 animEl: 'addAddressBtn'
33202 * @param {Object} config Configuration options
33203 * @return {Roo.MessageBox} This message box
33205 show : function(options)
33208 // this causes nightmares if you show one dialog after another
33209 // especially on callbacks..
33211 if(this.isVisible()){
33214 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33215 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33216 Roo.log("New Dialog Message:" + options.msg )
33217 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33218 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33221 var d = this.getDialog();
33223 d.setTitle(opt.title || " ");
33224 d.close.setDisplayed(opt.closable !== false);
33225 activeTextEl = textboxEl;
33226 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33231 textareaEl.setHeight(typeof opt.multiline == "number" ?
33232 opt.multiline : this.defaultTextHeight);
33233 activeTextEl = textareaEl;
33242 progressEl.setDisplayed(opt.progress === true);
33243 this.updateProgress(0);
33244 activeTextEl.dom.value = opt.value || "";
33246 dlg.setDefaultButton(activeTextEl);
33248 var bs = opt.buttons;
33251 db = buttons["ok"];
33252 }else if(bs && bs.yes){
33253 db = buttons["yes"];
33255 dlg.setDefaultButton(db);
33257 bwidth = updateButtons(opt.buttons);
33258 this.updateText(opt.msg);
33260 d.el.addClass(opt.cls);
33262 d.proxyDrag = opt.proxyDrag === true;
33263 d.modal = opt.modal !== false;
33264 d.mask = opt.modal !== false ? mask : false;
33265 if(!d.isVisible()){
33266 // force it to the end of the z-index stack so it gets a cursor in FF
33267 document.body.appendChild(dlg.el.dom);
33268 d.animateTarget = null;
33269 d.show(options.animEl);
33275 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33276 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33277 * and closing the message box when the process is complete.
33278 * @param {String} title The title bar text
33279 * @param {String} msg The message box body text
33280 * @return {Roo.MessageBox} This message box
33282 progress : function(title, msg){
33289 minWidth: this.minProgressWidth,
33296 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33297 * If a callback function is passed it will be called after the user clicks the button, and the
33298 * id of the button that was clicked will be passed as the only parameter to the callback
33299 * (could also be the top-right close button).
33300 * @param {String} title The title bar text
33301 * @param {String} msg The message box body text
33302 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33303 * @param {Object} scope (optional) The scope of the callback function
33304 * @return {Roo.MessageBox} This message box
33306 alert : function(title, msg, fn, scope){
33319 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33320 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33321 * You are responsible for closing the message box when the process is complete.
33322 * @param {String} msg The message box body text
33323 * @param {String} title (optional) The title bar text
33324 * @return {Roo.MessageBox} This message box
33326 wait : function(msg, title){
33337 waitTimer = Roo.TaskMgr.start({
33339 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33347 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33348 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33349 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33350 * @param {String} title The title bar text
33351 * @param {String} msg The message box body text
33352 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33353 * @param {Object} scope (optional) The scope of the callback function
33354 * @return {Roo.MessageBox} This message box
33356 confirm : function(title, msg, fn, scope){
33360 buttons: this.YESNO,
33369 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33370 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33371 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33372 * (could also be the top-right close button) and the text that was entered will be passed as the two
33373 * parameters to the callback.
33374 * @param {String} title The title bar text
33375 * @param {String} msg The message box body text
33376 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33377 * @param {Object} scope (optional) The scope of the callback function
33378 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33379 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33380 * @return {Roo.MessageBox} This message box
33382 prompt : function(title, msg, fn, scope, multiline){
33386 buttons: this.OKCANCEL,
33391 multiline: multiline,
33398 * Button config that displays a single OK button
33403 * Button config that displays Yes and No buttons
33406 YESNO : {yes:true, no:true},
33408 * Button config that displays OK and Cancel buttons
33411 OKCANCEL : {ok:true, cancel:true},
33413 * Button config that displays Yes, No and Cancel buttons
33416 YESNOCANCEL : {yes:true, no:true, cancel:true},
33419 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33422 defaultTextHeight : 75,
33424 * The maximum width in pixels of the message box (defaults to 600)
33429 * The minimum width in pixels of the message box (defaults to 100)
33434 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33435 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33438 minProgressWidth : 250,
33440 * An object containing the default button text strings that can be overriden for localized language support.
33441 * Supported properties are: ok, cancel, yes and no.
33442 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33455 * Shorthand for {@link Roo.MessageBox}
33457 Roo.Msg = Roo.MessageBox;/*
33459 * Ext JS Library 1.1.1
33460 * Copyright(c) 2006-2007, Ext JS, LLC.
33462 * Originally Released Under LGPL - original licence link has changed is not relivant.
33465 * <script type="text/javascript">
33468 * @class Roo.QuickTips
33469 * Provides attractive and customizable tooltips for any element.
33472 Roo.QuickTips = function(){
33473 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33474 var ce, bd, xy, dd;
33475 var visible = false, disabled = true, inited = false;
33476 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33478 var onOver = function(e){
33482 var t = e.getTarget();
33483 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33486 if(ce && t == ce.el){
33487 clearTimeout(hideProc);
33490 if(t && tagEls[t.id]){
33491 tagEls[t.id].el = t;
33492 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33495 var ttp, et = Roo.fly(t);
33496 var ns = cfg.namespace;
33497 if(tm.interceptTitles && t.title){
33500 t.removeAttribute("title");
33501 e.preventDefault();
33503 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33506 showProc = show.defer(tm.showDelay, tm, [{
33509 width: et.getAttributeNS(ns, cfg.width),
33510 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33511 title: et.getAttributeNS(ns, cfg.title),
33512 cls: et.getAttributeNS(ns, cfg.cls)
33517 var onOut = function(e){
33518 clearTimeout(showProc);
33519 var t = e.getTarget();
33520 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33521 hideProc = setTimeout(hide, tm.hideDelay);
33525 var onMove = function(e){
33531 if(tm.trackMouse && ce){
33536 var onDown = function(e){
33537 clearTimeout(showProc);
33538 clearTimeout(hideProc);
33540 if(tm.hideOnClick){
33543 tm.enable.defer(100, tm);
33548 var getPad = function(){
33549 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33552 var show = function(o){
33556 clearTimeout(dismissProc);
33558 if(removeCls){ // in case manually hidden
33559 el.removeClass(removeCls);
33563 el.addClass(ce.cls);
33564 removeCls = ce.cls;
33567 tipTitle.update(ce.title);
33570 tipTitle.update('');
33573 el.dom.style.width = tm.maxWidth+'px';
33574 //tipBody.dom.style.width = '';
33575 tipBodyText.update(o.text);
33576 var p = getPad(), w = ce.width;
33578 var td = tipBodyText.dom;
33579 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33580 if(aw > tm.maxWidth){
33582 }else if(aw < tm.minWidth){
33588 //tipBody.setWidth(w);
33589 el.setWidth(parseInt(w, 10) + p);
33590 if(ce.autoHide === false){
33591 close.setDisplayed(true);
33596 close.setDisplayed(false);
33602 el.avoidY = xy[1]-18;
33607 el.setStyle("visibility", "visible");
33608 el.fadeIn({callback: afterShow});
33614 var afterShow = function(){
33618 if(tm.autoDismiss && ce.autoHide !== false){
33619 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33624 var hide = function(noanim){
33625 clearTimeout(dismissProc);
33626 clearTimeout(hideProc);
33628 if(el.isVisible()){
33630 if(noanim !== true && tm.animate){
33631 el.fadeOut({callback: afterHide});
33638 var afterHide = function(){
33641 el.removeClass(removeCls);
33648 * @cfg {Number} minWidth
33649 * The minimum width of the quick tip (defaults to 40)
33653 * @cfg {Number} maxWidth
33654 * The maximum width of the quick tip (defaults to 300)
33658 * @cfg {Boolean} interceptTitles
33659 * True to automatically use the element's DOM title value if available (defaults to false)
33661 interceptTitles : false,
33663 * @cfg {Boolean} trackMouse
33664 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33666 trackMouse : false,
33668 * @cfg {Boolean} hideOnClick
33669 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33671 hideOnClick : true,
33673 * @cfg {Number} showDelay
33674 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33678 * @cfg {Number} hideDelay
33679 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33683 * @cfg {Boolean} autoHide
33684 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33685 * Used in conjunction with hideDelay.
33690 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33691 * (defaults to true). Used in conjunction with autoDismissDelay.
33693 autoDismiss : true,
33696 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33698 autoDismissDelay : 5000,
33700 * @cfg {Boolean} animate
33701 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33706 * @cfg {String} title
33707 * Title text to display (defaults to ''). This can be any valid HTML markup.
33711 * @cfg {String} text
33712 * Body text to display (defaults to ''). This can be any valid HTML markup.
33716 * @cfg {String} cls
33717 * A CSS class to apply to the base quick tip element (defaults to '').
33721 * @cfg {Number} width
33722 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33723 * minWidth or maxWidth.
33728 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33729 * or display QuickTips in a page.
33732 tm = Roo.QuickTips;
33733 cfg = tm.tagConfig;
33735 if(!Roo.isReady){ // allow calling of init() before onReady
33736 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33739 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33740 el.fxDefaults = {stopFx: true};
33741 // maximum custom styling
33742 //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>');
33743 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>');
33744 tipTitle = el.child('h3');
33745 tipTitle.enableDisplayMode("block");
33746 tipBody = el.child('div.x-tip-bd');
33747 tipBodyText = el.child('div.x-tip-bd-inner');
33748 //bdLeft = el.child('div.x-tip-bd-left');
33749 //bdRight = el.child('div.x-tip-bd-right');
33750 close = el.child('div.x-tip-close');
33751 close.enableDisplayMode("block");
33752 close.on("click", hide);
33753 var d = Roo.get(document);
33754 d.on("mousedown", onDown);
33755 d.on("mouseover", onOver);
33756 d.on("mouseout", onOut);
33757 d.on("mousemove", onMove);
33758 esc = d.addKeyListener(27, hide);
33761 dd = el.initDD("default", null, {
33762 onDrag : function(){
33766 dd.setHandleElId(tipTitle.id);
33775 * Configures a new quick tip instance and assigns it to a target element. The following config options
33778 Property Type Description
33779 ---------- --------------------- ------------------------------------------------------------------------
33780 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33782 * @param {Object} config The config object
33784 register : function(config){
33785 var cs = config instanceof Array ? config : arguments;
33786 for(var i = 0, len = cs.length; i < len; i++) {
33788 var target = c.target;
33790 if(target instanceof Array){
33791 for(var j = 0, jlen = target.length; j < jlen; j++){
33792 tagEls[target[j]] = c;
33795 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33802 * Removes this quick tip from its element and destroys it.
33803 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33805 unregister : function(el){
33806 delete tagEls[Roo.id(el)];
33810 * Enable this quick tip.
33812 enable : function(){
33813 if(inited && disabled){
33815 if(locks.length < 1){
33822 * Disable this quick tip.
33824 disable : function(){
33826 clearTimeout(showProc);
33827 clearTimeout(hideProc);
33828 clearTimeout(dismissProc);
33836 * Returns true if the quick tip is enabled, else false.
33838 isEnabled : function(){
33844 namespace : "roo", // was ext?? this may break..
33845 alt_namespace : "ext",
33846 attribute : "qtip",
33856 // backwards compat
33857 Roo.QuickTips.tips = Roo.QuickTips.register;/*
33859 * Ext JS Library 1.1.1
33860 * Copyright(c) 2006-2007, Ext JS, LLC.
33862 * Originally Released Under LGPL - original licence link has changed is not relivant.
33865 * <script type="text/javascript">
33870 * @class Roo.tree.TreePanel
33871 * @extends Roo.data.Tree
33873 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
33874 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
33875 * @cfg {Boolean} enableDD true to enable drag and drop
33876 * @cfg {Boolean} enableDrag true to enable just drag
33877 * @cfg {Boolean} enableDrop true to enable just drop
33878 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
33879 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
33880 * @cfg {String} ddGroup The DD group this TreePanel belongs to
33881 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
33882 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
33883 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
33884 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
33885 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
33886 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
33887 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
33888 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
33889 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
33890 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
33891 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
33892 * @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>
33893 * @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>
33896 * @param {String/HTMLElement/Element} el The container element
33897 * @param {Object} config
33899 Roo.tree.TreePanel = function(el, config){
33901 var loader = false;
33903 root = config.root;
33904 delete config.root;
33906 if (config.loader) {
33907 loader = config.loader;
33908 delete config.loader;
33911 Roo.apply(this, config);
33912 Roo.tree.TreePanel.superclass.constructor.call(this);
33913 this.el = Roo.get(el);
33914 this.el.addClass('x-tree');
33915 //console.log(root);
33917 this.setRootNode( Roo.factory(root, Roo.tree));
33920 this.loader = Roo.factory(loader, Roo.tree);
33923 * Read-only. The id of the container element becomes this TreePanel's id.
33925 this.id = this.el.id;
33928 * @event beforeload
33929 * Fires before a node is loaded, return false to cancel
33930 * @param {Node} node The node being loaded
33932 "beforeload" : true,
33935 * Fires when a node is loaded
33936 * @param {Node} node The node that was loaded
33940 * @event textchange
33941 * Fires when the text for a node is changed
33942 * @param {Node} node The node
33943 * @param {String} text The new text
33944 * @param {String} oldText The old text
33946 "textchange" : true,
33948 * @event beforeexpand
33949 * Fires before a node is expanded, return false to cancel.
33950 * @param {Node} node The node
33951 * @param {Boolean} deep
33952 * @param {Boolean} anim
33954 "beforeexpand" : true,
33956 * @event beforecollapse
33957 * Fires before a node is collapsed, return false to cancel.
33958 * @param {Node} node The node
33959 * @param {Boolean} deep
33960 * @param {Boolean} anim
33962 "beforecollapse" : true,
33965 * Fires when a node is expanded
33966 * @param {Node} node The node
33970 * @event disabledchange
33971 * Fires when the disabled status of a node changes
33972 * @param {Node} node The node
33973 * @param {Boolean} disabled
33975 "disabledchange" : true,
33978 * Fires when a node is collapsed
33979 * @param {Node} node The node
33983 * @event beforeclick
33984 * Fires before click processing on a node. Return false to cancel the default action.
33985 * @param {Node} node The node
33986 * @param {Roo.EventObject} e The event object
33988 "beforeclick":true,
33990 * @event checkchange
33991 * Fires when a node with a checkbox's checked property changes
33992 * @param {Node} this This node
33993 * @param {Boolean} checked
33995 "checkchange":true,
33998 * Fires when a node is clicked
33999 * @param {Node} node The node
34000 * @param {Roo.EventObject} e The event object
34005 * Fires when a node is double clicked
34006 * @param {Node} node The node
34007 * @param {Roo.EventObject} e The event object
34011 * @event contextmenu
34012 * Fires when a node is right clicked
34013 * @param {Node} node The node
34014 * @param {Roo.EventObject} e The event object
34016 "contextmenu":true,
34018 * @event beforechildrenrendered
34019 * Fires right before the child nodes for a node are rendered
34020 * @param {Node} node The node
34022 "beforechildrenrendered":true,
34025 * Fires when a node starts being dragged
34026 * @param {Roo.tree.TreePanel} this
34027 * @param {Roo.tree.TreeNode} node
34028 * @param {event} e The raw browser event
34030 "startdrag" : true,
34033 * Fires when a drag operation is complete
34034 * @param {Roo.tree.TreePanel} this
34035 * @param {Roo.tree.TreeNode} node
34036 * @param {event} e The raw browser event
34041 * Fires when a dragged node is dropped on a valid DD target
34042 * @param {Roo.tree.TreePanel} this
34043 * @param {Roo.tree.TreeNode} node
34044 * @param {DD} dd The dd it was dropped on
34045 * @param {event} e The raw browser event
34049 * @event beforenodedrop
34050 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34051 * passed to handlers has the following properties:<br />
34052 * <ul style="padding:5px;padding-left:16px;">
34053 * <li>tree - The TreePanel</li>
34054 * <li>target - The node being targeted for the drop</li>
34055 * <li>data - The drag data from the drag source</li>
34056 * <li>point - The point of the drop - append, above or below</li>
34057 * <li>source - The drag source</li>
34058 * <li>rawEvent - Raw mouse event</li>
34059 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34060 * to be inserted by setting them on this object.</li>
34061 * <li>cancel - Set this to true to cancel the drop.</li>
34063 * @param {Object} dropEvent
34065 "beforenodedrop" : true,
34068 * Fires after a DD object is dropped on a node in this tree. 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 - Dropped node(s).</li>
34079 * @param {Object} dropEvent
34083 * @event nodedragover
34084 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34085 * passed to handlers has the following properties:<br />
34086 * <ul style="padding:5px;padding-left:16px;">
34087 * <li>tree - The TreePanel</li>
34088 * <li>target - The node being targeted for the drop</li>
34089 * <li>data - The drag data from the drag source</li>
34090 * <li>point - The point of the drop - append, above or below</li>
34091 * <li>source - The drag source</li>
34092 * <li>rawEvent - Raw mouse event</li>
34093 * <li>dropNode - Drop node(s) provided by the source.</li>
34094 * <li>cancel - Set this to true to signal drop not allowed.</li>
34096 * @param {Object} dragOverEvent
34098 "nodedragover" : true
34101 if(this.singleExpand){
34102 this.on("beforeexpand", this.restrictExpand, this);
34105 this.editor.tree = this;
34106 this.editor = Roo.factory(this.editor, Roo.tree);
34109 if (this.selModel) {
34110 this.selModel = Roo.factory(this.selModel, Roo.tree);
34114 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34115 rootVisible : true,
34116 animate: Roo.enableFx,
34119 hlDrop : Roo.enableFx,
34123 rendererTip: false,
34125 restrictExpand : function(node){
34126 var p = node.parentNode;
34128 if(p.expandedChild && p.expandedChild.parentNode == p){
34129 p.expandedChild.collapse();
34131 p.expandedChild = node;
34135 // private override
34136 setRootNode : function(node){
34137 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34138 if(!this.rootVisible){
34139 node.ui = new Roo.tree.RootTreeNodeUI(node);
34145 * Returns the container element for this TreePanel
34147 getEl : function(){
34152 * Returns the default TreeLoader for this TreePanel
34154 getLoader : function(){
34155 return this.loader;
34161 expandAll : function(){
34162 this.root.expand(true);
34166 * Collapse all nodes
34168 collapseAll : function(){
34169 this.root.collapse(true);
34173 * Returns the selection model used by this TreePanel
34175 getSelectionModel : function(){
34176 if(!this.selModel){
34177 this.selModel = new Roo.tree.DefaultSelectionModel();
34179 return this.selModel;
34183 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34184 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34185 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34188 getChecked : function(a, startNode){
34189 startNode = startNode || this.root;
34191 var f = function(){
34192 if(this.attributes.checked){
34193 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34196 startNode.cascade(f);
34201 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34202 * @param {String} path
34203 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34204 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34205 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34207 expandPath : function(path, attr, callback){
34208 attr = attr || "id";
34209 var keys = path.split(this.pathSeparator);
34210 var curNode = this.root;
34211 if(curNode.attributes[attr] != keys[1]){ // invalid root
34213 callback(false, null);
34218 var f = function(){
34219 if(++index == keys.length){
34221 callback(true, curNode);
34225 var c = curNode.findChild(attr, keys[index]);
34228 callback(false, curNode);
34233 c.expand(false, false, f);
34235 curNode.expand(false, false, f);
34239 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34240 * @param {String} path
34241 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34242 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34243 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34245 selectPath : function(path, attr, callback){
34246 attr = attr || "id";
34247 var keys = path.split(this.pathSeparator);
34248 var v = keys.pop();
34249 if(keys.length > 0){
34250 var f = function(success, node){
34251 if(success && node){
34252 var n = node.findChild(attr, v);
34258 }else if(callback){
34259 callback(false, n);
34263 callback(false, n);
34267 this.expandPath(keys.join(this.pathSeparator), attr, f);
34269 this.root.select();
34271 callback(true, this.root);
34276 getTreeEl : function(){
34281 * Trigger rendering of this TreePanel
34283 render : function(){
34284 if (this.innerCt) {
34285 return this; // stop it rendering more than once!!
34288 this.innerCt = this.el.createChild({tag:"ul",
34289 cls:"x-tree-root-ct " +
34290 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34292 if(this.containerScroll){
34293 Roo.dd.ScrollManager.register(this.el);
34295 if((this.enableDD || this.enableDrop) && !this.dropZone){
34297 * The dropZone used by this tree if drop is enabled
34298 * @type Roo.tree.TreeDropZone
34300 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34301 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34304 if((this.enableDD || this.enableDrag) && !this.dragZone){
34306 * The dragZone used by this tree if drag is enabled
34307 * @type Roo.tree.TreeDragZone
34309 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34310 ddGroup: this.ddGroup || "TreeDD",
34311 scroll: this.ddScroll
34314 this.getSelectionModel().init(this);
34316 Roo.log("ROOT not set in tree");
34319 this.root.render();
34320 if(!this.rootVisible){
34321 this.root.renderChildren();
34327 * Ext JS Library 1.1.1
34328 * Copyright(c) 2006-2007, Ext JS, LLC.
34330 * Originally Released Under LGPL - original licence link has changed is not relivant.
34333 * <script type="text/javascript">
34338 * @class Roo.tree.DefaultSelectionModel
34339 * @extends Roo.util.Observable
34340 * The default single selection for a TreePanel.
34341 * @param {Object} cfg Configuration
34343 Roo.tree.DefaultSelectionModel = function(cfg){
34344 this.selNode = null;
34350 * @event selectionchange
34351 * Fires when the selected node changes
34352 * @param {DefaultSelectionModel} this
34353 * @param {TreeNode} node the new selection
34355 "selectionchange" : true,
34358 * @event beforeselect
34359 * Fires before the selected node changes, return false to cancel the change
34360 * @param {DefaultSelectionModel} this
34361 * @param {TreeNode} node the new selection
34362 * @param {TreeNode} node the old selection
34364 "beforeselect" : true
34367 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34370 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34371 init : function(tree){
34373 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34374 tree.on("click", this.onNodeClick, this);
34377 onNodeClick : function(node, e){
34378 if (e.ctrlKey && this.selNode == node) {
34379 this.unselect(node);
34387 * @param {TreeNode} node The node to select
34388 * @return {TreeNode} The selected node
34390 select : function(node){
34391 var last = this.selNode;
34392 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34394 last.ui.onSelectedChange(false);
34396 this.selNode = node;
34397 node.ui.onSelectedChange(true);
34398 this.fireEvent("selectionchange", this, node, last);
34405 * @param {TreeNode} node The node to unselect
34407 unselect : function(node){
34408 if(this.selNode == node){
34409 this.clearSelections();
34414 * Clear all selections
34416 clearSelections : function(){
34417 var n = this.selNode;
34419 n.ui.onSelectedChange(false);
34420 this.selNode = null;
34421 this.fireEvent("selectionchange", this, null);
34427 * Get the selected node
34428 * @return {TreeNode} The selected node
34430 getSelectedNode : function(){
34431 return this.selNode;
34435 * Returns true if the node is selected
34436 * @param {TreeNode} node The node to check
34437 * @return {Boolean}
34439 isSelected : function(node){
34440 return this.selNode == node;
34444 * Selects the node above the selected node in the tree, intelligently walking the nodes
34445 * @return TreeNode The new selection
34447 selectPrevious : function(){
34448 var s = this.selNode || this.lastSelNode;
34452 var ps = s.previousSibling;
34454 if(!ps.isExpanded() || ps.childNodes.length < 1){
34455 return this.select(ps);
34457 var lc = ps.lastChild;
34458 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34461 return this.select(lc);
34463 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34464 return this.select(s.parentNode);
34470 * Selects the node above the selected node in the tree, intelligently walking the nodes
34471 * @return TreeNode The new selection
34473 selectNext : function(){
34474 var s = this.selNode || this.lastSelNode;
34478 if(s.firstChild && s.isExpanded()){
34479 return this.select(s.firstChild);
34480 }else if(s.nextSibling){
34481 return this.select(s.nextSibling);
34482 }else if(s.parentNode){
34484 s.parentNode.bubble(function(){
34485 if(this.nextSibling){
34486 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34495 onKeyDown : function(e){
34496 var s = this.selNode || this.lastSelNode;
34497 // undesirable, but required
34502 var k = e.getKey();
34510 this.selectPrevious();
34513 e.preventDefault();
34514 if(s.hasChildNodes()){
34515 if(!s.isExpanded()){
34517 }else if(s.firstChild){
34518 this.select(s.firstChild, e);
34523 e.preventDefault();
34524 if(s.hasChildNodes() && s.isExpanded()){
34526 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34527 this.select(s.parentNode, e);
34535 * @class Roo.tree.MultiSelectionModel
34536 * @extends Roo.util.Observable
34537 * Multi selection for a TreePanel.
34538 * @param {Object} cfg Configuration
34540 Roo.tree.MultiSelectionModel = function(){
34541 this.selNodes = [];
34545 * @event selectionchange
34546 * Fires when the selected nodes change
34547 * @param {MultiSelectionModel} this
34548 * @param {Array} nodes Array of the selected nodes
34550 "selectionchange" : true
34552 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34556 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34557 init : function(tree){
34559 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34560 tree.on("click", this.onNodeClick, this);
34563 onNodeClick : function(node, e){
34564 this.select(node, e, e.ctrlKey);
34569 * @param {TreeNode} node The node to select
34570 * @param {EventObject} e (optional) An event associated with the selection
34571 * @param {Boolean} keepExisting True to retain existing selections
34572 * @return {TreeNode} The selected node
34574 select : function(node, e, keepExisting){
34575 if(keepExisting !== true){
34576 this.clearSelections(true);
34578 if(this.isSelected(node)){
34579 this.lastSelNode = node;
34582 this.selNodes.push(node);
34583 this.selMap[node.id] = node;
34584 this.lastSelNode = node;
34585 node.ui.onSelectedChange(true);
34586 this.fireEvent("selectionchange", this, this.selNodes);
34592 * @param {TreeNode} node The node to unselect
34594 unselect : function(node){
34595 if(this.selMap[node.id]){
34596 node.ui.onSelectedChange(false);
34597 var sn = this.selNodes;
34600 index = sn.indexOf(node);
34602 for(var i = 0, len = sn.length; i < len; i++){
34610 this.selNodes.splice(index, 1);
34612 delete this.selMap[node.id];
34613 this.fireEvent("selectionchange", this, this.selNodes);
34618 * Clear all selections
34620 clearSelections : function(suppressEvent){
34621 var sn = this.selNodes;
34623 for(var i = 0, len = sn.length; i < len; i++){
34624 sn[i].ui.onSelectedChange(false);
34626 this.selNodes = [];
34628 if(suppressEvent !== true){
34629 this.fireEvent("selectionchange", this, this.selNodes);
34635 * Returns true if the node is selected
34636 * @param {TreeNode} node The node to check
34637 * @return {Boolean}
34639 isSelected : function(node){
34640 return this.selMap[node.id] ? true : false;
34644 * Returns an array of the selected nodes
34647 getSelectedNodes : function(){
34648 return this.selNodes;
34651 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34653 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34655 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34658 * Ext JS Library 1.1.1
34659 * Copyright(c) 2006-2007, Ext JS, LLC.
34661 * Originally Released Under LGPL - original licence link has changed is not relivant.
34664 * <script type="text/javascript">
34668 * @class Roo.tree.TreeNode
34669 * @extends Roo.data.Node
34670 * @cfg {String} text The text for this node
34671 * @cfg {Boolean} expanded true to start the node expanded
34672 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34673 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34674 * @cfg {Boolean} disabled true to start the node disabled
34675 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34676 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34677 * @cfg {String} cls A css class to be added to the node
34678 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34679 * @cfg {String} href URL of the link used for the node (defaults to #)
34680 * @cfg {String} hrefTarget target frame for the link
34681 * @cfg {String} qtip An Ext QuickTip for the node
34682 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34683 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34684 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34685 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34686 * (defaults to undefined with no checkbox rendered)
34688 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34690 Roo.tree.TreeNode = function(attributes){
34691 attributes = attributes || {};
34692 if(typeof attributes == "string"){
34693 attributes = {text: attributes};
34695 this.childrenRendered = false;
34696 this.rendered = false;
34697 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34698 this.expanded = attributes.expanded === true;
34699 this.isTarget = attributes.isTarget !== false;
34700 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34701 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34704 * Read-only. The text for this node. To change it use setText().
34707 this.text = attributes.text;
34709 * True if this node is disabled.
34712 this.disabled = attributes.disabled === true;
34716 * @event textchange
34717 * Fires when the text for this node is changed
34718 * @param {Node} this This node
34719 * @param {String} text The new text
34720 * @param {String} oldText The old text
34722 "textchange" : true,
34724 * @event beforeexpand
34725 * Fires before this node is expanded, return false to cancel.
34726 * @param {Node} this This node
34727 * @param {Boolean} deep
34728 * @param {Boolean} anim
34730 "beforeexpand" : true,
34732 * @event beforecollapse
34733 * Fires before this node is collapsed, return false to cancel.
34734 * @param {Node} this This node
34735 * @param {Boolean} deep
34736 * @param {Boolean} anim
34738 "beforecollapse" : true,
34741 * Fires when this node is expanded
34742 * @param {Node} this This node
34746 * @event disabledchange
34747 * Fires when the disabled status of this node changes
34748 * @param {Node} this This node
34749 * @param {Boolean} disabled
34751 "disabledchange" : true,
34754 * Fires when this node is collapsed
34755 * @param {Node} this This node
34759 * @event beforeclick
34760 * Fires before click processing. Return false to cancel the default action.
34761 * @param {Node} this This node
34762 * @param {Roo.EventObject} e The event object
34764 "beforeclick":true,
34766 * @event checkchange
34767 * Fires when a node with a checkbox's checked property changes
34768 * @param {Node} this This node
34769 * @param {Boolean} checked
34771 "checkchange":true,
34774 * Fires when this node is clicked
34775 * @param {Node} this This node
34776 * @param {Roo.EventObject} e The event object
34781 * Fires when this node is double clicked
34782 * @param {Node} this This node
34783 * @param {Roo.EventObject} e The event object
34787 * @event contextmenu
34788 * Fires when this node is right clicked
34789 * @param {Node} this This node
34790 * @param {Roo.EventObject} e The event object
34792 "contextmenu":true,
34794 * @event beforechildrenrendered
34795 * Fires right before the child nodes for this node are rendered
34796 * @param {Node} this This node
34798 "beforechildrenrendered":true
34801 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34804 * Read-only. The UI for this node
34807 this.ui = new uiClass(this);
34809 // finally support items[]
34810 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34815 Roo.each(this.attributes.items, function(c) {
34816 this.appendChild(Roo.factory(c,Roo.Tree));
34818 delete this.attributes.items;
34823 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34824 preventHScroll: true,
34826 * Returns true if this node is expanded
34827 * @return {Boolean}
34829 isExpanded : function(){
34830 return this.expanded;
34834 * Returns the UI object for this node
34835 * @return {TreeNodeUI}
34837 getUI : function(){
34841 // private override
34842 setFirstChild : function(node){
34843 var of = this.firstChild;
34844 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
34845 if(this.childrenRendered && of && node != of){
34846 of.renderIndent(true, true);
34849 this.renderIndent(true, true);
34853 // private override
34854 setLastChild : function(node){
34855 var ol = this.lastChild;
34856 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
34857 if(this.childrenRendered && ol && node != ol){
34858 ol.renderIndent(true, true);
34861 this.renderIndent(true, true);
34865 // these methods are overridden to provide lazy rendering support
34866 // private override
34867 appendChild : function()
34869 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
34870 if(node && this.childrenRendered){
34873 this.ui.updateExpandIcon();
34877 // private override
34878 removeChild : function(node){
34879 this.ownerTree.getSelectionModel().unselect(node);
34880 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
34881 // if it's been rendered remove dom node
34882 if(this.childrenRendered){
34885 if(this.childNodes.length < 1){
34886 this.collapse(false, false);
34888 this.ui.updateExpandIcon();
34890 if(!this.firstChild) {
34891 this.childrenRendered = false;
34896 // private override
34897 insertBefore : function(node, refNode){
34898 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
34899 if(newNode && refNode && this.childrenRendered){
34902 this.ui.updateExpandIcon();
34907 * Sets the text for this node
34908 * @param {String} text
34910 setText : function(text){
34911 var oldText = this.text;
34913 this.attributes.text = text;
34914 if(this.rendered){ // event without subscribing
34915 this.ui.onTextChange(this, text, oldText);
34917 this.fireEvent("textchange", this, text, oldText);
34921 * Triggers selection of this node
34923 select : function(){
34924 this.getOwnerTree().getSelectionModel().select(this);
34928 * Triggers deselection of this node
34930 unselect : function(){
34931 this.getOwnerTree().getSelectionModel().unselect(this);
34935 * Returns true if this node is selected
34936 * @return {Boolean}
34938 isSelected : function(){
34939 return this.getOwnerTree().getSelectionModel().isSelected(this);
34943 * Expand this node.
34944 * @param {Boolean} deep (optional) True to expand all children as well
34945 * @param {Boolean} anim (optional) false to cancel the default animation
34946 * @param {Function} callback (optional) A callback to be called when
34947 * expanding this node completes (does not wait for deep expand to complete).
34948 * Called with 1 parameter, this node.
34950 expand : function(deep, anim, callback){
34951 if(!this.expanded){
34952 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
34955 if(!this.childrenRendered){
34956 this.renderChildren();
34958 this.expanded = true;
34959 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
34960 this.ui.animExpand(function(){
34961 this.fireEvent("expand", this);
34962 if(typeof callback == "function"){
34966 this.expandChildNodes(true);
34968 }.createDelegate(this));
34972 this.fireEvent("expand", this);
34973 if(typeof callback == "function"){
34978 if(typeof callback == "function"){
34983 this.expandChildNodes(true);
34987 isHiddenRoot : function(){
34988 return this.isRoot && !this.getOwnerTree().rootVisible;
34992 * Collapse this node.
34993 * @param {Boolean} deep (optional) True to collapse all children as well
34994 * @param {Boolean} anim (optional) false to cancel the default animation
34996 collapse : function(deep, anim){
34997 if(this.expanded && !this.isHiddenRoot()){
34998 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35001 this.expanded = false;
35002 if((this.getOwnerTree().animate && anim !== false) || anim){
35003 this.ui.animCollapse(function(){
35004 this.fireEvent("collapse", this);
35006 this.collapseChildNodes(true);
35008 }.createDelegate(this));
35011 this.ui.collapse();
35012 this.fireEvent("collapse", this);
35016 var cs = this.childNodes;
35017 for(var i = 0, len = cs.length; i < len; i++) {
35018 cs[i].collapse(true, false);
35024 delayedExpand : function(delay){
35025 if(!this.expandProcId){
35026 this.expandProcId = this.expand.defer(delay, this);
35031 cancelExpand : function(){
35032 if(this.expandProcId){
35033 clearTimeout(this.expandProcId);
35035 this.expandProcId = false;
35039 * Toggles expanded/collapsed state of the node
35041 toggle : function(){
35050 * Ensures all parent nodes are expanded
35052 ensureVisible : function(callback){
35053 var tree = this.getOwnerTree();
35054 tree.expandPath(this.parentNode.getPath(), false, function(){
35055 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35056 Roo.callback(callback);
35057 }.createDelegate(this));
35061 * Expand all child nodes
35062 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35064 expandChildNodes : function(deep){
35065 var cs = this.childNodes;
35066 for(var i = 0, len = cs.length; i < len; i++) {
35067 cs[i].expand(deep);
35072 * Collapse all child nodes
35073 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35075 collapseChildNodes : function(deep){
35076 var cs = this.childNodes;
35077 for(var i = 0, len = cs.length; i < len; i++) {
35078 cs[i].collapse(deep);
35083 * Disables this node
35085 disable : function(){
35086 this.disabled = true;
35088 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35089 this.ui.onDisableChange(this, true);
35091 this.fireEvent("disabledchange", this, true);
35095 * Enables this node
35097 enable : function(){
35098 this.disabled = false;
35099 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35100 this.ui.onDisableChange(this, false);
35102 this.fireEvent("disabledchange", this, false);
35106 renderChildren : function(suppressEvent){
35107 if(suppressEvent !== false){
35108 this.fireEvent("beforechildrenrendered", this);
35110 var cs = this.childNodes;
35111 for(var i = 0, len = cs.length; i < len; i++){
35112 cs[i].render(true);
35114 this.childrenRendered = true;
35118 sort : function(fn, scope){
35119 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35120 if(this.childrenRendered){
35121 var cs = this.childNodes;
35122 for(var i = 0, len = cs.length; i < len; i++){
35123 cs[i].render(true);
35129 render : function(bulkRender){
35130 this.ui.render(bulkRender);
35131 if(!this.rendered){
35132 this.rendered = true;
35134 this.expanded = false;
35135 this.expand(false, false);
35141 renderIndent : function(deep, refresh){
35143 this.ui.childIndent = null;
35145 this.ui.renderIndent();
35146 if(deep === true && this.childrenRendered){
35147 var cs = this.childNodes;
35148 for(var i = 0, len = cs.length; i < len; i++){
35149 cs[i].renderIndent(true, refresh);
35155 * Ext JS Library 1.1.1
35156 * Copyright(c) 2006-2007, Ext JS, LLC.
35158 * Originally Released Under LGPL - original licence link has changed is not relivant.
35161 * <script type="text/javascript">
35165 * @class Roo.tree.AsyncTreeNode
35166 * @extends Roo.tree.TreeNode
35167 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35169 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35171 Roo.tree.AsyncTreeNode = function(config){
35172 this.loaded = false;
35173 this.loading = false;
35174 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35176 * @event beforeload
35177 * Fires before this node is loaded, return false to cancel
35178 * @param {Node} this This node
35180 this.addEvents({'beforeload':true, 'load': true});
35183 * Fires when this node is loaded
35184 * @param {Node} this This node
35187 * The loader used by this node (defaults to using the tree's defined loader)
35192 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35193 expand : function(deep, anim, callback){
35194 if(this.loading){ // if an async load is already running, waiting til it's done
35196 var f = function(){
35197 if(!this.loading){ // done loading
35198 clearInterval(timer);
35199 this.expand(deep, anim, callback);
35201 }.createDelegate(this);
35202 timer = setInterval(f, 200);
35206 if(this.fireEvent("beforeload", this) === false){
35209 this.loading = true;
35210 this.ui.beforeLoad(this);
35211 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35213 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35217 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35221 * Returns true if this node is currently loading
35222 * @return {Boolean}
35224 isLoading : function(){
35225 return this.loading;
35228 loadComplete : function(deep, anim, callback){
35229 this.loading = false;
35230 this.loaded = true;
35231 this.ui.afterLoad(this);
35232 this.fireEvent("load", this);
35233 this.expand(deep, anim, callback);
35237 * Returns true if this node has been loaded
35238 * @return {Boolean}
35240 isLoaded : function(){
35241 return this.loaded;
35244 hasChildNodes : function(){
35245 if(!this.isLeaf() && !this.loaded){
35248 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35253 * Trigger a reload for this node
35254 * @param {Function} callback
35256 reload : function(callback){
35257 this.collapse(false, false);
35258 while(this.firstChild){
35259 this.removeChild(this.firstChild);
35261 this.childrenRendered = false;
35262 this.loaded = false;
35263 if(this.isHiddenRoot()){
35264 this.expanded = false;
35266 this.expand(false, false, callback);
35270 * Ext JS Library 1.1.1
35271 * Copyright(c) 2006-2007, Ext JS, LLC.
35273 * Originally Released Under LGPL - original licence link has changed is not relivant.
35276 * <script type="text/javascript">
35280 * @class Roo.tree.TreeNodeUI
35282 * @param {Object} node The node to render
35283 * The TreeNode UI implementation is separate from the
35284 * tree implementation. Unless you are customizing the tree UI,
35285 * you should never have to use this directly.
35287 Roo.tree.TreeNodeUI = function(node){
35289 this.rendered = false;
35290 this.animating = false;
35291 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35294 Roo.tree.TreeNodeUI.prototype = {
35295 removeChild : function(node){
35297 this.ctNode.removeChild(node.ui.getEl());
35301 beforeLoad : function(){
35302 this.addClass("x-tree-node-loading");
35305 afterLoad : function(){
35306 this.removeClass("x-tree-node-loading");
35309 onTextChange : function(node, text, oldText){
35311 this.textNode.innerHTML = text;
35315 onDisableChange : function(node, state){
35316 this.disabled = state;
35318 this.addClass("x-tree-node-disabled");
35320 this.removeClass("x-tree-node-disabled");
35324 onSelectedChange : function(state){
35327 this.addClass("x-tree-selected");
35330 this.removeClass("x-tree-selected");
35334 onMove : function(tree, node, oldParent, newParent, index, refNode){
35335 this.childIndent = null;
35337 var targetNode = newParent.ui.getContainer();
35338 if(!targetNode){//target not rendered
35339 this.holder = document.createElement("div");
35340 this.holder.appendChild(this.wrap);
35343 var insertBefore = refNode ? refNode.ui.getEl() : null;
35345 targetNode.insertBefore(this.wrap, insertBefore);
35347 targetNode.appendChild(this.wrap);
35349 this.node.renderIndent(true);
35353 addClass : function(cls){
35355 Roo.fly(this.elNode).addClass(cls);
35359 removeClass : function(cls){
35361 Roo.fly(this.elNode).removeClass(cls);
35365 remove : function(){
35367 this.holder = document.createElement("div");
35368 this.holder.appendChild(this.wrap);
35372 fireEvent : function(){
35373 return this.node.fireEvent.apply(this.node, arguments);
35376 initEvents : function(){
35377 this.node.on("move", this.onMove, this);
35378 var E = Roo.EventManager;
35379 var a = this.anchor;
35381 var el = Roo.fly(a, '_treeui');
35383 if(Roo.isOpera){ // opera render bug ignores the CSS
35384 el.setStyle("text-decoration", "none");
35387 el.on("click", this.onClick, this);
35388 el.on("dblclick", this.onDblClick, this);
35391 Roo.EventManager.on(this.checkbox,
35392 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35395 el.on("contextmenu", this.onContextMenu, this);
35397 var icon = Roo.fly(this.iconNode);
35398 icon.on("click", this.onClick, this);
35399 icon.on("dblclick", this.onDblClick, this);
35400 icon.on("contextmenu", this.onContextMenu, this);
35401 E.on(this.ecNode, "click", this.ecClick, this, true);
35403 if(this.node.disabled){
35404 this.addClass("x-tree-node-disabled");
35406 if(this.node.hidden){
35407 this.addClass("x-tree-node-disabled");
35409 var ot = this.node.getOwnerTree();
35410 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35411 if(dd && (!this.node.isRoot || ot.rootVisible)){
35412 Roo.dd.Registry.register(this.elNode, {
35414 handles: this.getDDHandles(),
35420 getDDHandles : function(){
35421 return [this.iconNode, this.textNode];
35426 this.wrap.style.display = "none";
35432 this.wrap.style.display = "";
35436 onContextMenu : function(e){
35437 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35438 e.preventDefault();
35440 this.fireEvent("contextmenu", this.node, e);
35444 onClick : function(e){
35449 if(this.fireEvent("beforeclick", this.node, e) !== false){
35450 if(!this.disabled && this.node.attributes.href){
35451 this.fireEvent("click", this.node, e);
35454 e.preventDefault();
35459 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35460 this.node.toggle();
35463 this.fireEvent("click", this.node, e);
35469 onDblClick : function(e){
35470 e.preventDefault();
35475 this.toggleCheck();
35477 if(!this.animating && this.node.hasChildNodes()){
35478 this.node.toggle();
35480 this.fireEvent("dblclick", this.node, e);
35483 onCheckChange : function(){
35484 var checked = this.checkbox.checked;
35485 this.node.attributes.checked = checked;
35486 this.fireEvent('checkchange', this.node, checked);
35489 ecClick : function(e){
35490 if(!this.animating && this.node.hasChildNodes()){
35491 this.node.toggle();
35495 startDrop : function(){
35496 this.dropping = true;
35499 // delayed drop so the click event doesn't get fired on a drop
35500 endDrop : function(){
35501 setTimeout(function(){
35502 this.dropping = false;
35503 }.createDelegate(this), 50);
35506 expand : function(){
35507 this.updateExpandIcon();
35508 this.ctNode.style.display = "";
35511 focus : function(){
35512 if(!this.node.preventHScroll){
35513 try{this.anchor.focus();
35515 }else if(!Roo.isIE){
35517 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35518 var l = noscroll.scrollLeft;
35519 this.anchor.focus();
35520 noscroll.scrollLeft = l;
35525 toggleCheck : function(value){
35526 var cb = this.checkbox;
35528 cb.checked = (value === undefined ? !cb.checked : value);
35534 this.anchor.blur();
35538 animExpand : function(callback){
35539 var ct = Roo.get(this.ctNode);
35541 if(!this.node.hasChildNodes()){
35542 this.updateExpandIcon();
35543 this.ctNode.style.display = "";
35544 Roo.callback(callback);
35547 this.animating = true;
35548 this.updateExpandIcon();
35551 callback : function(){
35552 this.animating = false;
35553 Roo.callback(callback);
35556 duration: this.node.ownerTree.duration || .25
35560 highlight : function(){
35561 var tree = this.node.getOwnerTree();
35562 Roo.fly(this.wrap).highlight(
35563 tree.hlColor || "C3DAF9",
35564 {endColor: tree.hlBaseColor}
35568 collapse : function(){
35569 this.updateExpandIcon();
35570 this.ctNode.style.display = "none";
35573 animCollapse : function(callback){
35574 var ct = Roo.get(this.ctNode);
35575 ct.enableDisplayMode('block');
35578 this.animating = true;
35579 this.updateExpandIcon();
35582 callback : function(){
35583 this.animating = false;
35584 Roo.callback(callback);
35587 duration: this.node.ownerTree.duration || .25
35591 getContainer : function(){
35592 return this.ctNode;
35595 getEl : function(){
35599 appendDDGhost : function(ghostNode){
35600 ghostNode.appendChild(this.elNode.cloneNode(true));
35603 getDDRepairXY : function(){
35604 return Roo.lib.Dom.getXY(this.iconNode);
35607 onRender : function(){
35611 render : function(bulkRender){
35612 var n = this.node, a = n.attributes;
35613 var targetNode = n.parentNode ?
35614 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35616 if(!this.rendered){
35617 this.rendered = true;
35619 this.renderElements(n, a, targetNode, bulkRender);
35622 if(this.textNode.setAttributeNS){
35623 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35625 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35628 this.textNode.setAttribute("ext:qtip", a.qtip);
35630 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35633 }else if(a.qtipCfg){
35634 a.qtipCfg.target = Roo.id(this.textNode);
35635 Roo.QuickTips.register(a.qtipCfg);
35638 if(!this.node.expanded){
35639 this.updateExpandIcon();
35642 if(bulkRender === true) {
35643 targetNode.appendChild(this.wrap);
35648 renderElements : function(n, a, targetNode, bulkRender)
35650 // add some indent caching, this helps performance when rendering a large tree
35651 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35652 var t = n.getOwnerTree();
35653 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35654 if (typeof(n.attributes.html) != 'undefined') {
35655 txt = n.attributes.html;
35657 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35658 var cb = typeof a.checked == 'boolean';
35659 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35660 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35661 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35662 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35663 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35664 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35665 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35666 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35667 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35668 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35671 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35672 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35673 n.nextSibling.ui.getEl(), buf.join(""));
35675 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35678 this.elNode = this.wrap.childNodes[0];
35679 this.ctNode = this.wrap.childNodes[1];
35680 var cs = this.elNode.childNodes;
35681 this.indentNode = cs[0];
35682 this.ecNode = cs[1];
35683 this.iconNode = cs[2];
35686 this.checkbox = cs[3];
35689 this.anchor = cs[index];
35690 this.textNode = cs[index].firstChild;
35693 getAnchor : function(){
35694 return this.anchor;
35697 getTextEl : function(){
35698 return this.textNode;
35701 getIconEl : function(){
35702 return this.iconNode;
35705 isChecked : function(){
35706 return this.checkbox ? this.checkbox.checked : false;
35709 updateExpandIcon : function(){
35711 var n = this.node, c1, c2;
35712 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35713 var hasChild = n.hasChildNodes();
35717 c1 = "x-tree-node-collapsed";
35718 c2 = "x-tree-node-expanded";
35721 c1 = "x-tree-node-expanded";
35722 c2 = "x-tree-node-collapsed";
35725 this.removeClass("x-tree-node-leaf");
35726 this.wasLeaf = false;
35728 if(this.c1 != c1 || this.c2 != c2){
35729 Roo.fly(this.elNode).replaceClass(c1, c2);
35730 this.c1 = c1; this.c2 = c2;
35733 // this changes non-leafs into leafs if they have no children.
35734 // it's not very rational behaviour..
35736 if(!this.wasLeaf && this.node.leaf){
35737 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35740 this.wasLeaf = true;
35743 var ecc = "x-tree-ec-icon "+cls;
35744 if(this.ecc != ecc){
35745 this.ecNode.className = ecc;
35751 getChildIndent : function(){
35752 if(!this.childIndent){
35756 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35758 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35760 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35765 this.childIndent = buf.join("");
35767 return this.childIndent;
35770 renderIndent : function(){
35773 var p = this.node.parentNode;
35775 indent = p.ui.getChildIndent();
35777 if(this.indentMarkup != indent){ // don't rerender if not required
35778 this.indentNode.innerHTML = indent;
35779 this.indentMarkup = indent;
35781 this.updateExpandIcon();
35786 Roo.tree.RootTreeNodeUI = function(){
35787 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35789 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35790 render : function(){
35791 if(!this.rendered){
35792 var targetNode = this.node.ownerTree.innerCt.dom;
35793 this.node.expanded = true;
35794 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35795 this.wrap = this.ctNode = targetNode.firstChild;
35798 collapse : function(){
35800 expand : function(){
35804 * Ext JS Library 1.1.1
35805 * Copyright(c) 2006-2007, Ext JS, LLC.
35807 * Originally Released Under LGPL - original licence link has changed is not relivant.
35810 * <script type="text/javascript">
35813 * @class Roo.tree.TreeLoader
35814 * @extends Roo.util.Observable
35815 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35816 * nodes from a specified URL. The response must be a javascript Array definition
35817 * who's elements are node definition objects. eg:
35822 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35823 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
35830 * The old style respose with just an array is still supported, but not recommended.
35833 * A server request is sent, and child nodes are loaded only when a node is expanded.
35834 * The loading node's id is passed to the server under the parameter name "node" to
35835 * enable the server to produce the correct child nodes.
35837 * To pass extra parameters, an event handler may be attached to the "beforeload"
35838 * event, and the parameters specified in the TreeLoader's baseParams property:
35840 myTreeLoader.on("beforeload", function(treeLoader, node) {
35841 this.baseParams.category = node.attributes.category;
35844 * This would pass an HTTP parameter called "category" to the server containing
35845 * the value of the Node's "category" attribute.
35847 * Creates a new Treeloader.
35848 * @param {Object} config A config object containing config properties.
35850 Roo.tree.TreeLoader = function(config){
35851 this.baseParams = {};
35852 this.requestMethod = "POST";
35853 Roo.apply(this, config);
35858 * @event beforeload
35859 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
35860 * @param {Object} This TreeLoader object.
35861 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35862 * @param {Object} callback The callback function specified in the {@link #load} call.
35867 * Fires when the node has been successfuly loaded.
35868 * @param {Object} This TreeLoader object.
35869 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35870 * @param {Object} response The response object containing the data from the server.
35874 * @event loadexception
35875 * Fires if the network request failed.
35876 * @param {Object} This TreeLoader object.
35877 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35878 * @param {Object} response The response object containing the data from the server.
35880 loadexception : true,
35883 * Fires before a node is created, enabling you to return custom Node types
35884 * @param {Object} This TreeLoader object.
35885 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
35890 Roo.tree.TreeLoader.superclass.constructor.call(this);
35893 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
35895 * @cfg {String} dataUrl The URL from which to request a Json string which
35896 * specifies an array of node definition object representing the child nodes
35900 * @cfg {String} requestMethod either GET or POST
35901 * defaults to POST (due to BC)
35905 * @cfg {Object} baseParams (optional) An object containing properties which
35906 * specify HTTP parameters to be passed to each request for child nodes.
35909 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
35910 * created by this loader. If the attributes sent by the server have an attribute in this object,
35911 * they take priority.
35914 * @cfg {Object} uiProviders (optional) An object containing properties which
35916 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
35917 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
35918 * <i>uiProvider</i> attribute of a returned child node is a string rather
35919 * than a reference to a TreeNodeUI implementation, this that string value
35920 * is used as a property name in the uiProviders object. You can define the provider named
35921 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
35926 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
35927 * child nodes before loading.
35929 clearOnLoad : true,
35932 * @cfg {String} root (optional) Default to false. Use this to read data from an object
35933 * property on loading, rather than expecting an array. (eg. more compatible to a standard
35934 * Grid query { data : [ .....] }
35939 * @cfg {String} queryParam (optional)
35940 * Name of the query as it will be passed on the querystring (defaults to 'node')
35941 * eg. the request will be ?node=[id]
35948 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
35949 * This is called automatically when a node is expanded, but may be used to reload
35950 * a node (or append new children if the {@link #clearOnLoad} option is false.)
35951 * @param {Roo.tree.TreeNode} node
35952 * @param {Function} callback
35954 load : function(node, callback){
35955 if(this.clearOnLoad){
35956 while(node.firstChild){
35957 node.removeChild(node.firstChild);
35960 if(node.attributes.children){ // preloaded json children
35961 var cs = node.attributes.children;
35962 for(var i = 0, len = cs.length; i < len; i++){
35963 node.appendChild(this.createNode(cs[i]));
35965 if(typeof callback == "function"){
35968 }else if(this.dataUrl){
35969 this.requestData(node, callback);
35973 getParams: function(node){
35974 var buf = [], bp = this.baseParams;
35975 for(var key in bp){
35976 if(typeof bp[key] != "function"){
35977 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
35980 var n = this.queryParam === false ? 'node' : this.queryParam;
35981 buf.push(n + "=", encodeURIComponent(node.id));
35982 return buf.join("");
35985 requestData : function(node, callback){
35986 if(this.fireEvent("beforeload", this, node, callback) !== false){
35987 this.transId = Roo.Ajax.request({
35988 method:this.requestMethod,
35989 url: this.dataUrl||this.url,
35990 success: this.handleResponse,
35991 failure: this.handleFailure,
35993 argument: {callback: callback, node: node},
35994 params: this.getParams(node)
35997 // if the load is cancelled, make sure we notify
35998 // the node that we are done
35999 if(typeof callback == "function"){
36005 isLoading : function(){
36006 return this.transId ? true : false;
36009 abort : function(){
36010 if(this.isLoading()){
36011 Roo.Ajax.abort(this.transId);
36016 createNode : function(attr)
36018 // apply baseAttrs, nice idea Corey!
36019 if(this.baseAttrs){
36020 Roo.applyIf(attr, this.baseAttrs);
36022 if(this.applyLoader !== false){
36023 attr.loader = this;
36025 // uiProvider = depreciated..
36027 if(typeof(attr.uiProvider) == 'string'){
36028 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36029 /** eval:var:attr */ eval(attr.uiProvider);
36031 if(typeof(this.uiProviders['default']) != 'undefined') {
36032 attr.uiProvider = this.uiProviders['default'];
36035 this.fireEvent('create', this, attr);
36037 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36039 new Roo.tree.TreeNode(attr) :
36040 new Roo.tree.AsyncTreeNode(attr));
36043 processResponse : function(response, node, callback)
36045 var json = response.responseText;
36048 var o = Roo.decode(json);
36050 if (this.root === false && typeof(o.success) != undefined) {
36051 this.root = 'data'; // the default behaviour for list like data..
36054 if (this.root !== false && !o.success) {
36055 // it's a failure condition.
36056 var a = response.argument;
36057 this.fireEvent("loadexception", this, a.node, response);
36058 Roo.log("Load failed - should have a handler really");
36064 if (this.root !== false) {
36068 for(var i = 0, len = o.length; i < len; i++){
36069 var n = this.createNode(o[i]);
36071 node.appendChild(n);
36074 if(typeof callback == "function"){
36075 callback(this, node);
36078 this.handleFailure(response);
36082 handleResponse : function(response){
36083 this.transId = false;
36084 var a = response.argument;
36085 this.processResponse(response, a.node, a.callback);
36086 this.fireEvent("load", this, a.node, response);
36089 handleFailure : function(response)
36091 // should handle failure better..
36092 this.transId = false;
36093 var a = response.argument;
36094 this.fireEvent("loadexception", this, a.node, response);
36095 if(typeof a.callback == "function"){
36096 a.callback(this, a.node);
36101 * Ext JS Library 1.1.1
36102 * Copyright(c) 2006-2007, Ext JS, LLC.
36104 * Originally Released Under LGPL - original licence link has changed is not relivant.
36107 * <script type="text/javascript">
36111 * @class Roo.tree.TreeFilter
36112 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36113 * @param {TreePanel} tree
36114 * @param {Object} config (optional)
36116 Roo.tree.TreeFilter = function(tree, config){
36118 this.filtered = {};
36119 Roo.apply(this, config);
36122 Roo.tree.TreeFilter.prototype = {
36129 * Filter the data by a specific attribute.
36130 * @param {String/RegExp} value Either string that the attribute value
36131 * should start with or a RegExp to test against the attribute
36132 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36133 * @param {TreeNode} startNode (optional) The node to start the filter at.
36135 filter : function(value, attr, startNode){
36136 attr = attr || "text";
36138 if(typeof value == "string"){
36139 var vlen = value.length;
36140 // auto clear empty filter
36141 if(vlen == 0 && this.clearBlank){
36145 value = value.toLowerCase();
36147 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36149 }else if(value.exec){ // regex?
36151 return value.test(n.attributes[attr]);
36154 throw 'Illegal filter type, must be string or regex';
36156 this.filterBy(f, null, startNode);
36160 * Filter by a function. The passed function will be called with each
36161 * node in the tree (or from the startNode). If the function returns true, the node is kept
36162 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36163 * @param {Function} fn The filter function
36164 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36166 filterBy : function(fn, scope, startNode){
36167 startNode = startNode || this.tree.root;
36168 if(this.autoClear){
36171 var af = this.filtered, rv = this.reverse;
36172 var f = function(n){
36173 if(n == startNode){
36179 var m = fn.call(scope || n, n);
36187 startNode.cascade(f);
36190 if(typeof id != "function"){
36192 if(n && n.parentNode){
36193 n.parentNode.removeChild(n);
36201 * Clears the current filter. Note: with the "remove" option
36202 * set a filter cannot be cleared.
36204 clear : function(){
36206 var af = this.filtered;
36208 if(typeof id != "function"){
36215 this.filtered = {};
36220 * Ext JS Library 1.1.1
36221 * Copyright(c) 2006-2007, Ext JS, LLC.
36223 * Originally Released Under LGPL - original licence link has changed is not relivant.
36226 * <script type="text/javascript">
36231 * @class Roo.tree.TreeSorter
36232 * Provides sorting of nodes in a TreePanel
36234 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36235 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36236 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36237 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36238 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36239 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36241 * @param {TreePanel} tree
36242 * @param {Object} config
36244 Roo.tree.TreeSorter = function(tree, config){
36245 Roo.apply(this, config);
36246 tree.on("beforechildrenrendered", this.doSort, this);
36247 tree.on("append", this.updateSort, this);
36248 tree.on("insert", this.updateSort, this);
36250 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36251 var p = this.property || "text";
36252 var sortType = this.sortType;
36253 var fs = this.folderSort;
36254 var cs = this.caseSensitive === true;
36255 var leafAttr = this.leafAttr || 'leaf';
36257 this.sortFn = function(n1, n2){
36259 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36262 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36266 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36267 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36269 return dsc ? +1 : -1;
36271 return dsc ? -1 : +1;
36278 Roo.tree.TreeSorter.prototype = {
36279 doSort : function(node){
36280 node.sort(this.sortFn);
36283 compareNodes : function(n1, n2){
36284 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36287 updateSort : function(tree, node){
36288 if(node.childrenRendered){
36289 this.doSort.defer(1, this, [node]);
36294 * Ext JS Library 1.1.1
36295 * Copyright(c) 2006-2007, Ext JS, LLC.
36297 * Originally Released Under LGPL - original licence link has changed is not relivant.
36300 * <script type="text/javascript">
36303 if(Roo.dd.DropZone){
36305 Roo.tree.TreeDropZone = function(tree, config){
36306 this.allowParentInsert = false;
36307 this.allowContainerDrop = false;
36308 this.appendOnly = false;
36309 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36311 this.lastInsertClass = "x-tree-no-status";
36312 this.dragOverData = {};
36315 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36316 ddGroup : "TreeDD",
36319 expandDelay : 1000,
36321 expandNode : function(node){
36322 if(node.hasChildNodes() && !node.isExpanded()){
36323 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36327 queueExpand : function(node){
36328 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36331 cancelExpand : function(){
36332 if(this.expandProcId){
36333 clearTimeout(this.expandProcId);
36334 this.expandProcId = false;
36338 isValidDropPoint : function(n, pt, dd, e, data){
36339 if(!n || !data){ return false; }
36340 var targetNode = n.node;
36341 var dropNode = data.node;
36342 // default drop rules
36343 if(!(targetNode && targetNode.isTarget && pt)){
36346 if(pt == "append" && targetNode.allowChildren === false){
36349 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36352 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36355 // reuse the object
36356 var overEvent = this.dragOverData;
36357 overEvent.tree = this.tree;
36358 overEvent.target = targetNode;
36359 overEvent.data = data;
36360 overEvent.point = pt;
36361 overEvent.source = dd;
36362 overEvent.rawEvent = e;
36363 overEvent.dropNode = dropNode;
36364 overEvent.cancel = false;
36365 var result = this.tree.fireEvent("nodedragover", overEvent);
36366 return overEvent.cancel === false && result !== false;
36369 getDropPoint : function(e, n, dd)
36373 return tn.allowChildren !== false ? "append" : false; // always append for root
36375 var dragEl = n.ddel;
36376 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36377 var y = Roo.lib.Event.getPageY(e);
36378 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36380 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36381 var noAppend = tn.allowChildren === false;
36382 if(this.appendOnly || tn.parentNode.allowChildren === false){
36383 return noAppend ? false : "append";
36385 var noBelow = false;
36386 if(!this.allowParentInsert){
36387 noBelow = tn.hasChildNodes() && tn.isExpanded();
36389 var q = (b - t) / (noAppend ? 2 : 3);
36390 if(y >= t && y < (t + q)){
36392 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36399 onNodeEnter : function(n, dd, e, data)
36401 this.cancelExpand();
36404 onNodeOver : function(n, dd, e, data)
36407 var pt = this.getDropPoint(e, n, dd);
36410 // auto node expand check
36411 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36412 this.queueExpand(node);
36413 }else if(pt != "append"){
36414 this.cancelExpand();
36417 // set the insert point style on the target node
36418 var returnCls = this.dropNotAllowed;
36419 if(this.isValidDropPoint(n, pt, dd, e, data)){
36424 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36425 cls = "x-tree-drag-insert-above";
36426 }else if(pt == "below"){
36427 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36428 cls = "x-tree-drag-insert-below";
36430 returnCls = "x-tree-drop-ok-append";
36431 cls = "x-tree-drag-append";
36433 if(this.lastInsertClass != cls){
36434 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36435 this.lastInsertClass = cls;
36442 onNodeOut : function(n, dd, e, data){
36444 this.cancelExpand();
36445 this.removeDropIndicators(n);
36448 onNodeDrop : function(n, dd, e, data){
36449 var point = this.getDropPoint(e, n, dd);
36450 var targetNode = n.node;
36451 targetNode.ui.startDrop();
36452 if(!this.isValidDropPoint(n, point, dd, e, data)){
36453 targetNode.ui.endDrop();
36456 // first try to find the drop node
36457 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36460 target: targetNode,
36465 dropNode: dropNode,
36468 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36469 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36470 targetNode.ui.endDrop();
36473 // allow target changing
36474 targetNode = dropEvent.target;
36475 if(point == "append" && !targetNode.isExpanded()){
36476 targetNode.expand(false, null, function(){
36477 this.completeDrop(dropEvent);
36478 }.createDelegate(this));
36480 this.completeDrop(dropEvent);
36485 completeDrop : function(de){
36486 var ns = de.dropNode, p = de.point, t = de.target;
36487 if(!(ns instanceof Array)){
36491 for(var i = 0, len = ns.length; i < len; i++){
36494 t.parentNode.insertBefore(n, t);
36495 }else if(p == "below"){
36496 t.parentNode.insertBefore(n, t.nextSibling);
36502 if(this.tree.hlDrop){
36506 this.tree.fireEvent("nodedrop", de);
36509 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36510 if(this.tree.hlDrop){
36511 dropNode.ui.focus();
36512 dropNode.ui.highlight();
36514 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36517 getTree : function(){
36521 removeDropIndicators : function(n){
36524 Roo.fly(el).removeClass([
36525 "x-tree-drag-insert-above",
36526 "x-tree-drag-insert-below",
36527 "x-tree-drag-append"]);
36528 this.lastInsertClass = "_noclass";
36532 beforeDragDrop : function(target, e, id){
36533 this.cancelExpand();
36537 afterRepair : function(data){
36538 if(data && Roo.enableFx){
36539 data.node.ui.highlight();
36549 * Ext JS Library 1.1.1
36550 * Copyright(c) 2006-2007, Ext JS, LLC.
36552 * Originally Released Under LGPL - original licence link has changed is not relivant.
36555 * <script type="text/javascript">
36559 if(Roo.dd.DragZone){
36560 Roo.tree.TreeDragZone = function(tree, config){
36561 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36565 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36566 ddGroup : "TreeDD",
36568 onBeforeDrag : function(data, e){
36570 return n && n.draggable && !n.disabled;
36574 onInitDrag : function(e){
36575 var data = this.dragData;
36576 this.tree.getSelectionModel().select(data.node);
36577 this.proxy.update("");
36578 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36579 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36582 getRepairXY : function(e, data){
36583 return data.node.ui.getDDRepairXY();
36586 onEndDrag : function(data, e){
36587 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36592 onValidDrop : function(dd, e, id){
36593 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36597 beforeInvalidDrop : function(e, id){
36598 // this scrolls the original position back into view
36599 var sm = this.tree.getSelectionModel();
36600 sm.clearSelections();
36601 sm.select(this.dragData.node);
36606 * Ext JS Library 1.1.1
36607 * Copyright(c) 2006-2007, Ext JS, LLC.
36609 * Originally Released Under LGPL - original licence link has changed is not relivant.
36612 * <script type="text/javascript">
36615 * @class Roo.tree.TreeEditor
36616 * @extends Roo.Editor
36617 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36618 * as the editor field.
36620 * @param {Object} config (used to be the tree panel.)
36621 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36623 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36624 * @cfg {Roo.form.TextField|Object} field The field configuration
36628 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36631 if (oldconfig) { // old style..
36632 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36635 tree = config.tree;
36636 config.field = config.field || {};
36637 config.field.xtype = 'TextField';
36638 field = Roo.factory(config.field, Roo.form);
36640 config = config || {};
36645 * @event beforenodeedit
36646 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36647 * false from the handler of this event.
36648 * @param {Editor} this
36649 * @param {Roo.tree.Node} node
36651 "beforenodeedit" : true
36655 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36659 tree.on('beforeclick', this.beforeNodeClick, this);
36660 tree.getTreeEl().on('mousedown', this.hide, this);
36661 this.on('complete', this.updateNode, this);
36662 this.on('beforestartedit', this.fitToTree, this);
36663 this.on('startedit', this.bindScroll, this, {delay:10});
36664 this.on('specialkey', this.onSpecialKey, this);
36667 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36669 * @cfg {String} alignment
36670 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36676 * @cfg {Boolean} hideEl
36677 * True to hide the bound element while the editor is displayed (defaults to false)
36681 * @cfg {String} cls
36682 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36684 cls: "x-small-editor x-tree-editor",
36686 * @cfg {Boolean} shim
36687 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36693 * @cfg {Number} maxWidth
36694 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36695 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36696 * scroll and client offsets into account prior to each edit.
36703 fitToTree : function(ed, el){
36704 var td = this.tree.getTreeEl().dom, nd = el.dom;
36705 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36706 td.scrollLeft = nd.offsetLeft;
36710 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36711 this.setSize(w, '');
36713 return this.fireEvent('beforenodeedit', this, this.editNode);
36718 triggerEdit : function(node){
36719 this.completeEdit();
36720 this.editNode = node;
36721 this.startEdit(node.ui.textNode, node.text);
36725 bindScroll : function(){
36726 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36730 beforeNodeClick : function(node, e){
36731 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36732 this.lastClick = new Date();
36733 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36735 this.triggerEdit(node);
36742 updateNode : function(ed, value){
36743 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36744 this.editNode.setText(value);
36748 onHide : function(){
36749 Roo.tree.TreeEditor.superclass.onHide.call(this);
36751 this.editNode.ui.focus();
36756 onSpecialKey : function(field, e){
36757 var k = e.getKey();
36761 }else if(k == e.ENTER && !e.hasModifier()){
36763 this.completeEdit();
36766 });//<Script type="text/javascript">
36769 * Ext JS Library 1.1.1
36770 * Copyright(c) 2006-2007, Ext JS, LLC.
36772 * Originally Released Under LGPL - original licence link has changed is not relivant.
36775 * <script type="text/javascript">
36779 * Not documented??? - probably should be...
36782 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36783 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36785 renderElements : function(n, a, targetNode, bulkRender){
36786 //consel.log("renderElements?");
36787 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36789 var t = n.getOwnerTree();
36790 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36792 var cols = t.columns;
36793 var bw = t.borderWidth;
36795 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36796 var cb = typeof a.checked == "boolean";
36797 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36798 var colcls = 'x-t-' + tid + '-c0';
36800 '<li class="x-tree-node">',
36803 '<div class="x-tree-node-el ', a.cls,'">',
36805 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36808 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36809 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36810 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36811 (a.icon ? ' x-tree-node-inline-icon' : ''),
36812 (a.iconCls ? ' '+a.iconCls : ''),
36813 '" unselectable="on" />',
36814 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36815 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36817 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36818 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36819 '<span unselectable="on" qtip="' + tx + '">',
36823 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36824 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36826 for(var i = 1, len = cols.length; i < len; i++){
36828 colcls = 'x-t-' + tid + '-c' +i;
36829 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36830 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
36831 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
36837 '<div class="x-clear"></div></div>',
36838 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36841 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36842 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36843 n.nextSibling.ui.getEl(), buf.join(""));
36845 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36847 var el = this.wrap.firstChild;
36849 this.elNode = el.firstChild;
36850 this.ranchor = el.childNodes[1];
36851 this.ctNode = this.wrap.childNodes[1];
36852 var cs = el.firstChild.childNodes;
36853 this.indentNode = cs[0];
36854 this.ecNode = cs[1];
36855 this.iconNode = cs[2];
36858 this.checkbox = cs[3];
36861 this.anchor = cs[index];
36863 this.textNode = cs[index].firstChild;
36865 //el.on("click", this.onClick, this);
36866 //el.on("dblclick", this.onDblClick, this);
36869 // console.log(this);
36871 initEvents : function(){
36872 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
36875 var a = this.ranchor;
36877 var el = Roo.get(a);
36879 if(Roo.isOpera){ // opera render bug ignores the CSS
36880 el.setStyle("text-decoration", "none");
36883 el.on("click", this.onClick, this);
36884 el.on("dblclick", this.onDblClick, this);
36885 el.on("contextmenu", this.onContextMenu, this);
36889 /*onSelectedChange : function(state){
36892 this.addClass("x-tree-selected");
36895 this.removeClass("x-tree-selected");
36898 addClass : function(cls){
36900 Roo.fly(this.elRow).addClass(cls);
36906 removeClass : function(cls){
36908 Roo.fly(this.elRow).removeClass(cls);
36914 });//<Script type="text/javascript">
36918 * Ext JS Library 1.1.1
36919 * Copyright(c) 2006-2007, Ext JS, LLC.
36921 * Originally Released Under LGPL - original licence link has changed is not relivant.
36924 * <script type="text/javascript">
36929 * @class Roo.tree.ColumnTree
36930 * @extends Roo.data.TreePanel
36931 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
36932 * @cfg {int} borderWidth compined right/left border allowance
36934 * @param {String/HTMLElement/Element} el The container element
36935 * @param {Object} config
36937 Roo.tree.ColumnTree = function(el, config)
36939 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
36943 * Fire this event on a container when it resizes
36944 * @param {int} w Width
36945 * @param {int} h Height
36949 this.on('resize', this.onResize, this);
36952 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
36956 borderWidth: Roo.isBorderBox ? 0 : 2,
36959 render : function(){
36960 // add the header.....
36962 Roo.tree.ColumnTree.superclass.render.apply(this);
36964 this.el.addClass('x-column-tree');
36966 this.headers = this.el.createChild(
36967 {cls:'x-tree-headers'},this.innerCt.dom);
36969 var cols = this.columns, c;
36970 var totalWidth = 0;
36972 var len = cols.length;
36973 for(var i = 0; i < len; i++){
36975 totalWidth += c.width;
36976 this.headEls.push(this.headers.createChild({
36977 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
36979 cls:'x-tree-hd-text',
36982 style:'width:'+(c.width-this.borderWidth)+'px;'
36985 this.headers.createChild({cls:'x-clear'});
36986 // prevent floats from wrapping when clipped
36987 this.headers.setWidth(totalWidth);
36988 //this.innerCt.setWidth(totalWidth);
36989 this.innerCt.setStyle({ overflow: 'auto' });
36990 this.onResize(this.width, this.height);
36994 onResize : function(w,h)
36999 this.innerCt.setWidth(this.width);
37000 this.innerCt.setHeight(this.height-20);
37003 var cols = this.columns, c;
37004 var totalWidth = 0;
37006 var len = cols.length;
37007 for(var i = 0; i < len; i++){
37009 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37010 // it's the expander..
37011 expEl = this.headEls[i];
37014 totalWidth += c.width;
37018 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37020 this.headers.setWidth(w-20);
37029 * Ext JS Library 1.1.1
37030 * Copyright(c) 2006-2007, Ext JS, LLC.
37032 * Originally Released Under LGPL - original licence link has changed is not relivant.
37035 * <script type="text/javascript">
37039 * @class Roo.menu.Menu
37040 * @extends Roo.util.Observable
37041 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37042 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37044 * Creates a new Menu
37045 * @param {Object} config Configuration options
37047 Roo.menu.Menu = function(config){
37048 Roo.apply(this, config);
37049 this.id = this.id || Roo.id();
37052 * @event beforeshow
37053 * Fires before this menu is displayed
37054 * @param {Roo.menu.Menu} this
37058 * @event beforehide
37059 * Fires before this menu is hidden
37060 * @param {Roo.menu.Menu} this
37065 * Fires after this menu is displayed
37066 * @param {Roo.menu.Menu} this
37071 * Fires after this menu is hidden
37072 * @param {Roo.menu.Menu} this
37077 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37078 * @param {Roo.menu.Menu} this
37079 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37080 * @param {Roo.EventObject} e
37085 * Fires when the mouse is hovering over this menu
37086 * @param {Roo.menu.Menu} this
37087 * @param {Roo.EventObject} e
37088 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37093 * Fires when the mouse exits this menu
37094 * @param {Roo.menu.Menu} this
37095 * @param {Roo.EventObject} e
37096 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37101 * Fires when a menu item contained in this menu is clicked
37102 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37103 * @param {Roo.EventObject} e
37107 if (this.registerMenu) {
37108 Roo.menu.MenuMgr.register(this);
37111 var mis = this.items;
37112 this.items = new Roo.util.MixedCollection();
37114 this.add.apply(this, mis);
37118 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37120 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37124 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37125 * for bottom-right shadow (defaults to "sides")
37129 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37130 * this menu (defaults to "tl-tr?")
37132 subMenuAlign : "tl-tr?",
37134 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37135 * relative to its element of origin (defaults to "tl-bl?")
37137 defaultAlign : "tl-bl?",
37139 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37141 allowOtherMenus : false,
37143 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37145 registerMenu : true,
37150 render : function(){
37154 var el = this.el = new Roo.Layer({
37156 shadow:this.shadow,
37158 parentEl: this.parentEl || document.body,
37162 this.keyNav = new Roo.menu.MenuNav(this);
37165 el.addClass("x-menu-plain");
37168 el.addClass(this.cls);
37170 // generic focus element
37171 this.focusEl = el.createChild({
37172 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37174 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37175 //disabling touch- as it's causing issues ..
37176 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37177 ul.on('click' , this.onClick, this);
37180 ul.on("mouseover", this.onMouseOver, this);
37181 ul.on("mouseout", this.onMouseOut, this);
37182 this.items.each(function(item){
37187 var li = document.createElement("li");
37188 li.className = "x-menu-list-item";
37189 ul.dom.appendChild(li);
37190 item.render(li, this);
37197 autoWidth : function(){
37198 var el = this.el, ul = this.ul;
37202 var w = this.width;
37205 }else if(Roo.isIE){
37206 el.setWidth(this.minWidth);
37207 var t = el.dom.offsetWidth; // force recalc
37208 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37213 delayAutoWidth : function(){
37216 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37218 this.awTask.delay(20);
37223 findTargetItem : function(e){
37224 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37225 if(t && t.menuItemId){
37226 return this.items.get(t.menuItemId);
37231 onClick : function(e){
37232 Roo.log("menu.onClick");
37233 var t = this.findTargetItem(e);
37238 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37239 if(t == this.activeItem && t.shouldDeactivate(e)){
37240 this.activeItem.deactivate();
37241 delete this.activeItem;
37245 this.setActiveItem(t, true);
37253 this.fireEvent("click", this, t, e);
37257 setActiveItem : function(item, autoExpand){
37258 if(item != this.activeItem){
37259 if(this.activeItem){
37260 this.activeItem.deactivate();
37262 this.activeItem = item;
37263 item.activate(autoExpand);
37264 }else if(autoExpand){
37270 tryActivate : function(start, step){
37271 var items = this.items;
37272 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37273 var item = items.get(i);
37274 if(!item.disabled && item.canActivate){
37275 this.setActiveItem(item, false);
37283 onMouseOver : function(e){
37285 if(t = this.findTargetItem(e)){
37286 if(t.canActivate && !t.disabled){
37287 this.setActiveItem(t, true);
37290 this.fireEvent("mouseover", this, e, t);
37294 onMouseOut : function(e){
37296 if(t = this.findTargetItem(e)){
37297 if(t == this.activeItem && t.shouldDeactivate(e)){
37298 this.activeItem.deactivate();
37299 delete this.activeItem;
37302 this.fireEvent("mouseout", this, e, t);
37306 * Read-only. Returns true if the menu is currently displayed, else false.
37309 isVisible : function(){
37310 return this.el && !this.hidden;
37314 * Displays this menu relative to another element
37315 * @param {String/HTMLElement/Roo.Element} element The element to align to
37316 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37317 * the element (defaults to this.defaultAlign)
37318 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37320 show : function(el, pos, parentMenu){
37321 this.parentMenu = parentMenu;
37325 this.fireEvent("beforeshow", this);
37326 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37330 * Displays this menu at a specific xy position
37331 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37332 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37334 showAt : function(xy, parentMenu, /* private: */_e){
37335 this.parentMenu = parentMenu;
37340 this.fireEvent("beforeshow", this);
37341 xy = this.el.adjustForConstraints(xy);
37345 this.hidden = false;
37347 this.fireEvent("show", this);
37350 focus : function(){
37352 this.doFocus.defer(50, this);
37356 doFocus : function(){
37358 this.focusEl.focus();
37363 * Hides this menu and optionally all parent menus
37364 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37366 hide : function(deep){
37367 if(this.el && this.isVisible()){
37368 this.fireEvent("beforehide", this);
37369 if(this.activeItem){
37370 this.activeItem.deactivate();
37371 this.activeItem = null;
37374 this.hidden = true;
37375 this.fireEvent("hide", this);
37377 if(deep === true && this.parentMenu){
37378 this.parentMenu.hide(true);
37383 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37384 * Any of the following are valid:
37386 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37387 * <li>An HTMLElement object which will be converted to a menu item</li>
37388 * <li>A menu item config object that will be created as a new menu item</li>
37389 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37390 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37395 var menu = new Roo.menu.Menu();
37397 // Create a menu item to add by reference
37398 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37400 // Add a bunch of items at once using different methods.
37401 // Only the last item added will be returned.
37402 var item = menu.add(
37403 menuItem, // add existing item by ref
37404 'Dynamic Item', // new TextItem
37405 '-', // new separator
37406 { text: 'Config Item' } // new item by config
37409 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37410 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37413 var a = arguments, l = a.length, item;
37414 for(var i = 0; i < l; i++){
37416 if ((typeof(el) == "object") && el.xtype && el.xns) {
37417 el = Roo.factory(el, Roo.menu);
37420 if(el.render){ // some kind of Item
37421 item = this.addItem(el);
37422 }else if(typeof el == "string"){ // string
37423 if(el == "separator" || el == "-"){
37424 item = this.addSeparator();
37426 item = this.addText(el);
37428 }else if(el.tagName || el.el){ // element
37429 item = this.addElement(el);
37430 }else if(typeof el == "object"){ // must be menu item config?
37431 item = this.addMenuItem(el);
37438 * Returns this menu's underlying {@link Roo.Element} object
37439 * @return {Roo.Element} The element
37441 getEl : function(){
37449 * Adds a separator bar to the menu
37450 * @return {Roo.menu.Item} The menu item that was added
37452 addSeparator : function(){
37453 return this.addItem(new Roo.menu.Separator());
37457 * Adds an {@link Roo.Element} object to the menu
37458 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37459 * @return {Roo.menu.Item} The menu item that was added
37461 addElement : function(el){
37462 return this.addItem(new Roo.menu.BaseItem(el));
37466 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37467 * @param {Roo.menu.Item} item The menu item to add
37468 * @return {Roo.menu.Item} The menu item that was added
37470 addItem : function(item){
37471 this.items.add(item);
37473 var li = document.createElement("li");
37474 li.className = "x-menu-list-item";
37475 this.ul.dom.appendChild(li);
37476 item.render(li, this);
37477 this.delayAutoWidth();
37483 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37484 * @param {Object} config A MenuItem config object
37485 * @return {Roo.menu.Item} The menu item that was added
37487 addMenuItem : function(config){
37488 if(!(config instanceof Roo.menu.Item)){
37489 if(typeof config.checked == "boolean"){ // must be check menu item config?
37490 config = new Roo.menu.CheckItem(config);
37492 config = new Roo.menu.Item(config);
37495 return this.addItem(config);
37499 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37500 * @param {String} text The text to display in the menu item
37501 * @return {Roo.menu.Item} The menu item that was added
37503 addText : function(text){
37504 return this.addItem(new Roo.menu.TextItem({ text : text }));
37508 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37509 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37510 * @param {Roo.menu.Item} item The menu item to add
37511 * @return {Roo.menu.Item} The menu item that was added
37513 insert : function(index, item){
37514 this.items.insert(index, item);
37516 var li = document.createElement("li");
37517 li.className = "x-menu-list-item";
37518 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37519 item.render(li, this);
37520 this.delayAutoWidth();
37526 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37527 * @param {Roo.menu.Item} item The menu item to remove
37529 remove : function(item){
37530 this.items.removeKey(item.id);
37535 * Removes and destroys all items in the menu
37537 removeAll : function(){
37539 while(f = this.items.first()){
37545 // MenuNav is a private utility class used internally by the Menu
37546 Roo.menu.MenuNav = function(menu){
37547 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37548 this.scope = this.menu = menu;
37551 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37552 doRelay : function(e, h){
37553 var k = e.getKey();
37554 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37555 this.menu.tryActivate(0, 1);
37558 return h.call(this.scope || this, e, this.menu);
37561 up : function(e, m){
37562 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37563 m.tryActivate(m.items.length-1, -1);
37567 down : function(e, m){
37568 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37569 m.tryActivate(0, 1);
37573 right : function(e, m){
37575 m.activeItem.expandMenu(true);
37579 left : function(e, m){
37581 if(m.parentMenu && m.parentMenu.activeItem){
37582 m.parentMenu.activeItem.activate();
37586 enter : function(e, m){
37588 e.stopPropagation();
37589 m.activeItem.onClick(e);
37590 m.fireEvent("click", this, m.activeItem);
37596 * Ext JS Library 1.1.1
37597 * Copyright(c) 2006-2007, Ext JS, LLC.
37599 * Originally Released Under LGPL - original licence link has changed is not relivant.
37602 * <script type="text/javascript">
37606 * @class Roo.menu.MenuMgr
37607 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37610 Roo.menu.MenuMgr = function(){
37611 var menus, active, groups = {}, attached = false, lastShow = new Date();
37613 // private - called when first menu is created
37616 active = new Roo.util.MixedCollection();
37617 Roo.get(document).addKeyListener(27, function(){
37618 if(active.length > 0){
37625 function hideAll(){
37626 if(active && active.length > 0){
37627 var c = active.clone();
37628 c.each(function(m){
37635 function onHide(m){
37637 if(active.length < 1){
37638 Roo.get(document).un("mousedown", onMouseDown);
37644 function onShow(m){
37645 var last = active.last();
37646 lastShow = new Date();
37649 Roo.get(document).on("mousedown", onMouseDown);
37653 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37654 m.parentMenu.activeChild = m;
37655 }else if(last && last.isVisible()){
37656 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37661 function onBeforeHide(m){
37663 m.activeChild.hide();
37665 if(m.autoHideTimer){
37666 clearTimeout(m.autoHideTimer);
37667 delete m.autoHideTimer;
37672 function onBeforeShow(m){
37673 var pm = m.parentMenu;
37674 if(!pm && !m.allowOtherMenus){
37676 }else if(pm && pm.activeChild && active != m){
37677 pm.activeChild.hide();
37682 function onMouseDown(e){
37683 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37689 function onBeforeCheck(mi, state){
37691 var g = groups[mi.group];
37692 for(var i = 0, l = g.length; i < l; i++){
37694 g[i].setChecked(false);
37703 * Hides all menus that are currently visible
37705 hideAll : function(){
37710 register : function(menu){
37714 menus[menu.id] = menu;
37715 menu.on("beforehide", onBeforeHide);
37716 menu.on("hide", onHide);
37717 menu.on("beforeshow", onBeforeShow);
37718 menu.on("show", onShow);
37719 var g = menu.group;
37720 if(g && menu.events["checkchange"]){
37724 groups[g].push(menu);
37725 menu.on("checkchange", onCheck);
37730 * Returns a {@link Roo.menu.Menu} object
37731 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37732 * be used to generate and return a new Menu instance.
37734 get : function(menu){
37735 if(typeof menu == "string"){ // menu id
37736 return menus[menu];
37737 }else if(menu.events){ // menu instance
37739 }else if(typeof menu.length == 'number'){ // array of menu items?
37740 return new Roo.menu.Menu({items:menu});
37741 }else{ // otherwise, must be a config
37742 return new Roo.menu.Menu(menu);
37747 unregister : function(menu){
37748 delete menus[menu.id];
37749 menu.un("beforehide", onBeforeHide);
37750 menu.un("hide", onHide);
37751 menu.un("beforeshow", onBeforeShow);
37752 menu.un("show", onShow);
37753 var g = menu.group;
37754 if(g && menu.events["checkchange"]){
37755 groups[g].remove(menu);
37756 menu.un("checkchange", onCheck);
37761 registerCheckable : function(menuItem){
37762 var g = menuItem.group;
37767 groups[g].push(menuItem);
37768 menuItem.on("beforecheckchange", onBeforeCheck);
37773 unregisterCheckable : function(menuItem){
37774 var g = menuItem.group;
37776 groups[g].remove(menuItem);
37777 menuItem.un("beforecheckchange", onBeforeCheck);
37783 * Ext JS Library 1.1.1
37784 * Copyright(c) 2006-2007, Ext JS, LLC.
37786 * Originally Released Under LGPL - original licence link has changed is not relivant.
37789 * <script type="text/javascript">
37794 * @class Roo.menu.BaseItem
37795 * @extends Roo.Component
37796 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37797 * management and base configuration options shared by all menu components.
37799 * Creates a new BaseItem
37800 * @param {Object} config Configuration options
37802 Roo.menu.BaseItem = function(config){
37803 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37808 * Fires when this item is clicked
37809 * @param {Roo.menu.BaseItem} this
37810 * @param {Roo.EventObject} e
37815 * Fires when this item is activated
37816 * @param {Roo.menu.BaseItem} this
37820 * @event deactivate
37821 * Fires when this item is deactivated
37822 * @param {Roo.menu.BaseItem} this
37828 this.on("click", this.handler, this.scope, true);
37832 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
37834 * @cfg {Function} handler
37835 * A function that will handle the click event of this menu item (defaults to undefined)
37838 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
37840 canActivate : false,
37843 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
37848 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
37850 activeClass : "x-menu-item-active",
37852 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
37854 hideOnClick : true,
37856 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
37861 ctype: "Roo.menu.BaseItem",
37864 actionMode : "container",
37867 render : function(container, parentMenu){
37868 this.parentMenu = parentMenu;
37869 Roo.menu.BaseItem.superclass.render.call(this, container);
37870 this.container.menuItemId = this.id;
37874 onRender : function(container, position){
37875 this.el = Roo.get(this.el);
37876 container.dom.appendChild(this.el.dom);
37880 onClick : function(e){
37881 if(!this.disabled && this.fireEvent("click", this, e) !== false
37882 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
37883 this.handleClick(e);
37890 activate : function(){
37894 var li = this.container;
37895 li.addClass(this.activeClass);
37896 this.region = li.getRegion().adjust(2, 2, -2, -2);
37897 this.fireEvent("activate", this);
37902 deactivate : function(){
37903 this.container.removeClass(this.activeClass);
37904 this.fireEvent("deactivate", this);
37908 shouldDeactivate : function(e){
37909 return !this.region || !this.region.contains(e.getPoint());
37913 handleClick : function(e){
37914 if(this.hideOnClick){
37915 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
37920 expandMenu : function(autoActivate){
37925 hideMenu : function(){
37930 * Ext JS Library 1.1.1
37931 * Copyright(c) 2006-2007, Ext JS, LLC.
37933 * Originally Released Under LGPL - original licence link has changed is not relivant.
37936 * <script type="text/javascript">
37940 * @class Roo.menu.Adapter
37941 * @extends Roo.menu.BaseItem
37942 * 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.
37943 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
37945 * Creates a new Adapter
37946 * @param {Object} config Configuration options
37948 Roo.menu.Adapter = function(component, config){
37949 Roo.menu.Adapter.superclass.constructor.call(this, config);
37950 this.component = component;
37952 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
37954 canActivate : true,
37957 onRender : function(container, position){
37958 this.component.render(container);
37959 this.el = this.component.getEl();
37963 activate : function(){
37967 this.component.focus();
37968 this.fireEvent("activate", this);
37973 deactivate : function(){
37974 this.fireEvent("deactivate", this);
37978 disable : function(){
37979 this.component.disable();
37980 Roo.menu.Adapter.superclass.disable.call(this);
37984 enable : function(){
37985 this.component.enable();
37986 Roo.menu.Adapter.superclass.enable.call(this);
37990 * Ext JS Library 1.1.1
37991 * Copyright(c) 2006-2007, Ext JS, LLC.
37993 * Originally Released Under LGPL - original licence link has changed is not relivant.
37996 * <script type="text/javascript">
38000 * @class Roo.menu.TextItem
38001 * @extends Roo.menu.BaseItem
38002 * Adds a static text string to a menu, usually used as either a heading or group separator.
38003 * Note: old style constructor with text is still supported.
38006 * Creates a new TextItem
38007 * @param {Object} cfg Configuration
38009 Roo.menu.TextItem = function(cfg){
38010 if (typeof(cfg) == 'string') {
38013 Roo.apply(this,cfg);
38016 Roo.menu.TextItem.superclass.constructor.call(this);
38019 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38021 * @cfg {Boolean} text Text to show on item.
38026 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38028 hideOnClick : false,
38030 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38032 itemCls : "x-menu-text",
38035 onRender : function(){
38036 var s = document.createElement("span");
38037 s.className = this.itemCls;
38038 s.innerHTML = this.text;
38040 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38044 * Ext JS Library 1.1.1
38045 * Copyright(c) 2006-2007, Ext JS, LLC.
38047 * Originally Released Under LGPL - original licence link has changed is not relivant.
38050 * <script type="text/javascript">
38054 * @class Roo.menu.Separator
38055 * @extends Roo.menu.BaseItem
38056 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38057 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38059 * @param {Object} config Configuration options
38061 Roo.menu.Separator = function(config){
38062 Roo.menu.Separator.superclass.constructor.call(this, config);
38065 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38067 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38069 itemCls : "x-menu-sep",
38071 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38073 hideOnClick : false,
38076 onRender : function(li){
38077 var s = document.createElement("span");
38078 s.className = this.itemCls;
38079 s.innerHTML = " ";
38081 li.addClass("x-menu-sep-li");
38082 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38086 * Ext JS Library 1.1.1
38087 * Copyright(c) 2006-2007, Ext JS, LLC.
38089 * Originally Released Under LGPL - original licence link has changed is not relivant.
38092 * <script type="text/javascript">
38095 * @class Roo.menu.Item
38096 * @extends Roo.menu.BaseItem
38097 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38098 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38099 * activation and click handling.
38101 * Creates a new Item
38102 * @param {Object} config Configuration options
38104 Roo.menu.Item = function(config){
38105 Roo.menu.Item.superclass.constructor.call(this, config);
38107 this.menu = Roo.menu.MenuMgr.get(this.menu);
38110 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38113 * @cfg {String} text
38114 * The text to show on the menu item.
38118 * @cfg {String} HTML to render in menu
38119 * The text to show on the menu item (HTML version).
38123 * @cfg {String} icon
38124 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38128 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38130 itemCls : "x-menu-item",
38132 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38134 canActivate : true,
38136 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38139 // doc'd in BaseItem
38143 ctype: "Roo.menu.Item",
38146 onRender : function(container, position){
38147 var el = document.createElement("a");
38148 el.hideFocus = true;
38149 el.unselectable = "on";
38150 el.href = this.href || "#";
38151 if(this.hrefTarget){
38152 el.target = this.hrefTarget;
38154 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38156 var html = this.html.length ? this.html : String.format('{0}',this.text);
38158 el.innerHTML = String.format(
38159 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38160 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38162 Roo.menu.Item.superclass.onRender.call(this, container, position);
38166 * Sets the text to display in this menu item
38167 * @param {String} text The text to display
38168 * @param {Boolean} isHTML true to indicate text is pure html.
38170 setText : function(text, isHTML){
38178 var html = this.html.length ? this.html : String.format('{0}',this.text);
38180 this.el.update(String.format(
38181 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38182 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38183 this.parentMenu.autoWidth();
38188 handleClick : function(e){
38189 if(!this.href){ // if no link defined, stop the event automatically
38192 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38196 activate : function(autoExpand){
38197 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38207 shouldDeactivate : function(e){
38208 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38209 if(this.menu && this.menu.isVisible()){
38210 return !this.menu.getEl().getRegion().contains(e.getPoint());
38218 deactivate : function(){
38219 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38224 expandMenu : function(autoActivate){
38225 if(!this.disabled && this.menu){
38226 clearTimeout(this.hideTimer);
38227 delete this.hideTimer;
38228 if(!this.menu.isVisible() && !this.showTimer){
38229 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38230 }else if (this.menu.isVisible() && autoActivate){
38231 this.menu.tryActivate(0, 1);
38237 deferExpand : function(autoActivate){
38238 delete this.showTimer;
38239 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38241 this.menu.tryActivate(0, 1);
38246 hideMenu : function(){
38247 clearTimeout(this.showTimer);
38248 delete this.showTimer;
38249 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38250 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38255 deferHide : function(){
38256 delete this.hideTimer;
38261 * Ext JS Library 1.1.1
38262 * Copyright(c) 2006-2007, Ext JS, LLC.
38264 * Originally Released Under LGPL - original licence link has changed is not relivant.
38267 * <script type="text/javascript">
38271 * @class Roo.menu.CheckItem
38272 * @extends Roo.menu.Item
38273 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38275 * Creates a new CheckItem
38276 * @param {Object} config Configuration options
38278 Roo.menu.CheckItem = function(config){
38279 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38282 * @event beforecheckchange
38283 * Fires before the checked value is set, providing an opportunity to cancel if needed
38284 * @param {Roo.menu.CheckItem} this
38285 * @param {Boolean} checked The new checked value that will be set
38287 "beforecheckchange" : true,
38289 * @event checkchange
38290 * Fires after the checked value has been set
38291 * @param {Roo.menu.CheckItem} this
38292 * @param {Boolean} checked The checked value that was set
38294 "checkchange" : true
38296 if(this.checkHandler){
38297 this.on('checkchange', this.checkHandler, this.scope);
38300 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38302 * @cfg {String} group
38303 * All check items with the same group name will automatically be grouped into a single-select
38304 * radio button group (defaults to '')
38307 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38309 itemCls : "x-menu-item x-menu-check-item",
38311 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38313 groupClass : "x-menu-group-item",
38316 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38317 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38318 * initialized with checked = true will be rendered as checked.
38323 ctype: "Roo.menu.CheckItem",
38326 onRender : function(c){
38327 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38329 this.el.addClass(this.groupClass);
38331 Roo.menu.MenuMgr.registerCheckable(this);
38333 this.checked = false;
38334 this.setChecked(true, true);
38339 destroy : function(){
38341 Roo.menu.MenuMgr.unregisterCheckable(this);
38343 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38347 * Set the checked state of this item
38348 * @param {Boolean} checked The new checked value
38349 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38351 setChecked : function(state, suppressEvent){
38352 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38353 if(this.container){
38354 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38356 this.checked = state;
38357 if(suppressEvent !== true){
38358 this.fireEvent("checkchange", this, state);
38364 handleClick : function(e){
38365 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38366 this.setChecked(!this.checked);
38368 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38372 * Ext JS Library 1.1.1
38373 * Copyright(c) 2006-2007, Ext JS, LLC.
38375 * Originally Released Under LGPL - original licence link has changed is not relivant.
38378 * <script type="text/javascript">
38382 * @class Roo.menu.DateItem
38383 * @extends Roo.menu.Adapter
38384 * A menu item that wraps the {@link Roo.DatPicker} component.
38386 * Creates a new DateItem
38387 * @param {Object} config Configuration options
38389 Roo.menu.DateItem = function(config){
38390 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38391 /** The Roo.DatePicker object @type Roo.DatePicker */
38392 this.picker = this.component;
38393 this.addEvents({select: true});
38395 this.picker.on("render", function(picker){
38396 picker.getEl().swallowEvent("click");
38397 picker.container.addClass("x-menu-date-item");
38400 this.picker.on("select", this.onSelect, this);
38403 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38405 onSelect : function(picker, date){
38406 this.fireEvent("select", this, date, picker);
38407 Roo.menu.DateItem.superclass.handleClick.call(this);
38411 * Ext JS Library 1.1.1
38412 * Copyright(c) 2006-2007, Ext JS, LLC.
38414 * Originally Released Under LGPL - original licence link has changed is not relivant.
38417 * <script type="text/javascript">
38421 * @class Roo.menu.ColorItem
38422 * @extends Roo.menu.Adapter
38423 * A menu item that wraps the {@link Roo.ColorPalette} component.
38425 * Creates a new ColorItem
38426 * @param {Object} config Configuration options
38428 Roo.menu.ColorItem = function(config){
38429 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38430 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38431 this.palette = this.component;
38432 this.relayEvents(this.palette, ["select"]);
38433 if(this.selectHandler){
38434 this.on('select', this.selectHandler, this.scope);
38437 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38439 * Ext JS Library 1.1.1
38440 * Copyright(c) 2006-2007, Ext JS, LLC.
38442 * Originally Released Under LGPL - original licence link has changed is not relivant.
38445 * <script type="text/javascript">
38450 * @class Roo.menu.DateMenu
38451 * @extends Roo.menu.Menu
38452 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38454 * Creates a new DateMenu
38455 * @param {Object} config Configuration options
38457 Roo.menu.DateMenu = function(config){
38458 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38460 var di = new Roo.menu.DateItem(config);
38463 * The {@link Roo.DatePicker} instance for this DateMenu
38466 this.picker = di.picker;
38469 * @param {DatePicker} picker
38470 * @param {Date} date
38472 this.relayEvents(di, ["select"]);
38473 this.on('beforeshow', function(){
38475 this.picker.hideMonthPicker(false);
38479 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38483 * Ext JS Library 1.1.1
38484 * Copyright(c) 2006-2007, Ext JS, LLC.
38486 * Originally Released Under LGPL - original licence link has changed is not relivant.
38489 * <script type="text/javascript">
38494 * @class Roo.menu.ColorMenu
38495 * @extends Roo.menu.Menu
38496 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38498 * Creates a new ColorMenu
38499 * @param {Object} config Configuration options
38501 Roo.menu.ColorMenu = function(config){
38502 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38504 var ci = new Roo.menu.ColorItem(config);
38507 * The {@link Roo.ColorPalette} instance for this ColorMenu
38508 * @type ColorPalette
38510 this.palette = ci.palette;
38513 * @param {ColorPalette} palette
38514 * @param {String} color
38516 this.relayEvents(ci, ["select"]);
38518 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38520 * Ext JS Library 1.1.1
38521 * Copyright(c) 2006-2007, Ext JS, LLC.
38523 * Originally Released Under LGPL - original licence link has changed is not relivant.
38526 * <script type="text/javascript">
38530 * @class Roo.form.Field
38531 * @extends Roo.BoxComponent
38532 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38534 * Creates a new Field
38535 * @param {Object} config Configuration options
38537 Roo.form.Field = function(config){
38538 Roo.form.Field.superclass.constructor.call(this, config);
38541 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38543 * @cfg {String} fieldLabel Label to use when rendering a form.
38546 * @cfg {String} qtip Mouse over tip
38550 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38552 invalidClass : "x-form-invalid",
38554 * @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")
38556 invalidText : "The value in this field is invalid",
38558 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38560 focusClass : "x-form-focus",
38562 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38563 automatic validation (defaults to "keyup").
38565 validationEvent : "keyup",
38567 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38569 validateOnBlur : true,
38571 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38573 validationDelay : 250,
38575 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38576 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38578 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38580 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38582 fieldClass : "x-form-field",
38584 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38587 ----------- ----------------------------------------------------------------------
38588 qtip Display a quick tip when the user hovers over the field
38589 title Display a default browser title attribute popup
38590 under Add a block div beneath the field containing the error text
38591 side Add an error icon to the right of the field with a popup on hover
38592 [element id] Add the error text directly to the innerHTML of the specified element
38595 msgTarget : 'qtip',
38597 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38602 * @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.
38607 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38612 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38614 inputType : undefined,
38617 * @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).
38619 tabIndex : undefined,
38622 isFormField : true,
38627 * @property {Roo.Element} fieldEl
38628 * Element Containing the rendered Field (with label etc.)
38631 * @cfg {Mixed} value A value to initialize this field with.
38636 * @cfg {String} name The field's HTML name attribute.
38639 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38642 loadedValue : false,
38646 initComponent : function(){
38647 Roo.form.Field.superclass.initComponent.call(this);
38651 * Fires when this field receives input focus.
38652 * @param {Roo.form.Field} this
38657 * Fires when this field loses input focus.
38658 * @param {Roo.form.Field} this
38662 * @event specialkey
38663 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38664 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38665 * @param {Roo.form.Field} this
38666 * @param {Roo.EventObject} e The event object
38671 * Fires just before the field blurs if the field value has changed.
38672 * @param {Roo.form.Field} this
38673 * @param {Mixed} newValue The new value
38674 * @param {Mixed} oldValue The original value
38679 * Fires after the field has been marked as invalid.
38680 * @param {Roo.form.Field} this
38681 * @param {String} msg The validation message
38686 * Fires after the field has been validated with no errors.
38687 * @param {Roo.form.Field} this
38692 * Fires after the key up
38693 * @param {Roo.form.Field} this
38694 * @param {Roo.EventObject} e The event Object
38701 * Returns the name attribute of the field if available
38702 * @return {String} name The field name
38704 getName: function(){
38705 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38709 onRender : function(ct, position){
38710 Roo.form.Field.superclass.onRender.call(this, ct, position);
38712 var cfg = this.getAutoCreate();
38714 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38716 if (!cfg.name.length) {
38719 if(this.inputType){
38720 cfg.type = this.inputType;
38722 this.el = ct.createChild(cfg, position);
38724 var type = this.el.dom.type;
38726 if(type == 'password'){
38729 this.el.addClass('x-form-'+type);
38732 this.el.dom.readOnly = true;
38734 if(this.tabIndex !== undefined){
38735 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38738 this.el.addClass([this.fieldClass, this.cls]);
38743 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38744 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38745 * @return {Roo.form.Field} this
38747 applyTo : function(target){
38748 this.allowDomMove = false;
38749 this.el = Roo.get(target);
38750 this.render(this.el.dom.parentNode);
38755 initValue : function(){
38756 if(this.value !== undefined){
38757 this.setValue(this.value);
38758 }else if(this.el.dom.value.length > 0){
38759 this.setValue(this.el.dom.value);
38764 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38765 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38767 isDirty : function() {
38768 if(this.disabled) {
38771 return String(this.getValue()) !== String(this.originalValue);
38775 * stores the current value in loadedValue
38777 resetHasChanged : function()
38779 this.loadedValue = String(this.getValue());
38782 * checks the current value against the 'loaded' value.
38783 * Note - will return false if 'resetHasChanged' has not been called first.
38785 hasChanged : function()
38787 if(this.disabled || this.readOnly) {
38790 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38796 afterRender : function(){
38797 Roo.form.Field.superclass.afterRender.call(this);
38802 fireKey : function(e){
38803 //Roo.log('field ' + e.getKey());
38804 if(e.isNavKeyPress()){
38805 this.fireEvent("specialkey", this, e);
38810 * Resets the current field value to the originally loaded value and clears any validation messages
38812 reset : function(){
38813 this.setValue(this.resetValue);
38814 this.clearInvalid();
38818 initEvents : function(){
38819 // safari killled keypress - so keydown is now used..
38820 this.el.on("keydown" , this.fireKey, this);
38821 this.el.on("focus", this.onFocus, this);
38822 this.el.on("blur", this.onBlur, this);
38823 this.el.relayEvent('keyup', this);
38825 // reference to original value for reset
38826 this.originalValue = this.getValue();
38827 this.resetValue = this.getValue();
38831 onFocus : function(){
38832 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38833 this.el.addClass(this.focusClass);
38835 if(!this.hasFocus){
38836 this.hasFocus = true;
38837 this.startValue = this.getValue();
38838 this.fireEvent("focus", this);
38842 beforeBlur : Roo.emptyFn,
38845 onBlur : function(){
38847 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38848 this.el.removeClass(this.focusClass);
38850 this.hasFocus = false;
38851 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
38854 var v = this.getValue();
38855 if(String(v) !== String(this.startValue)){
38856 this.fireEvent('change', this, v, this.startValue);
38858 this.fireEvent("blur", this);
38862 * Returns whether or not the field value is currently valid
38863 * @param {Boolean} preventMark True to disable marking the field invalid
38864 * @return {Boolean} True if the value is valid, else false
38866 isValid : function(preventMark){
38870 var restore = this.preventMark;
38871 this.preventMark = preventMark === true;
38872 var v = this.validateValue(this.processValue(this.getRawValue()));
38873 this.preventMark = restore;
38878 * Validates the field value
38879 * @return {Boolean} True if the value is valid, else false
38881 validate : function(){
38882 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
38883 this.clearInvalid();
38889 processValue : function(value){
38894 // Subclasses should provide the validation implementation by overriding this
38895 validateValue : function(value){
38900 * Mark this field as invalid
38901 * @param {String} msg The validation message
38903 markInvalid : function(msg){
38904 if(!this.rendered || this.preventMark){ // not rendered
38908 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38910 obj.el.addClass(this.invalidClass);
38911 msg = msg || this.invalidText;
38912 switch(this.msgTarget){
38914 obj.el.dom.qtip = msg;
38915 obj.el.dom.qclass = 'x-form-invalid-tip';
38916 if(Roo.QuickTips){ // fix for floating editors interacting with DND
38917 Roo.QuickTips.enable();
38921 this.el.dom.title = msg;
38925 var elp = this.el.findParent('.x-form-element', 5, true);
38926 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
38927 this.errorEl.setWidth(elp.getWidth(true)-20);
38929 this.errorEl.update(msg);
38930 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
38933 if(!this.errorIcon){
38934 var elp = this.el.findParent('.x-form-element', 5, true);
38935 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
38937 this.alignErrorIcon();
38938 this.errorIcon.dom.qtip = msg;
38939 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
38940 this.errorIcon.show();
38941 this.on('resize', this.alignErrorIcon, this);
38944 var t = Roo.getDom(this.msgTarget);
38946 t.style.display = this.msgDisplay;
38949 this.fireEvent('invalid', this, msg);
38953 alignErrorIcon : function(){
38954 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
38958 * Clear any invalid styles/messages for this field
38960 clearInvalid : function(){
38961 if(!this.rendered || this.preventMark){ // not rendered
38964 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38966 obj.el.removeClass(this.invalidClass);
38967 switch(this.msgTarget){
38969 obj.el.dom.qtip = '';
38972 this.el.dom.title = '';
38976 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
38980 if(this.errorIcon){
38981 this.errorIcon.dom.qtip = '';
38982 this.errorIcon.hide();
38983 this.un('resize', this.alignErrorIcon, this);
38987 var t = Roo.getDom(this.msgTarget);
38989 t.style.display = 'none';
38992 this.fireEvent('valid', this);
38996 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
38997 * @return {Mixed} value The field value
38999 getRawValue : function(){
39000 var v = this.el.getValue();
39006 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39007 * @return {Mixed} value The field value
39009 getValue : function(){
39010 var v = this.el.getValue();
39016 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39017 * @param {Mixed} value The value to set
39019 setRawValue : function(v){
39020 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39024 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39025 * @param {Mixed} value The value to set
39027 setValue : function(v){
39030 this.el.dom.value = (v === null || v === undefined ? '' : v);
39035 adjustSize : function(w, h){
39036 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39037 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39041 adjustWidth : function(tag, w){
39042 tag = tag.toLowerCase();
39043 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39044 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39045 if(tag == 'input'){
39048 if(tag == 'textarea'){
39051 }else if(Roo.isOpera){
39052 if(tag == 'input'){
39055 if(tag == 'textarea'){
39065 // anything other than normal should be considered experimental
39066 Roo.form.Field.msgFx = {
39068 show: function(msgEl, f){
39069 msgEl.setDisplayed('block');
39072 hide : function(msgEl, f){
39073 msgEl.setDisplayed(false).update('');
39078 show: function(msgEl, f){
39079 msgEl.slideIn('t', {stopFx:true});
39082 hide : function(msgEl, f){
39083 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39088 show: function(msgEl, f){
39089 msgEl.fixDisplay();
39090 msgEl.alignTo(f.el, 'tl-tr');
39091 msgEl.slideIn('l', {stopFx:true});
39094 hide : function(msgEl, f){
39095 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39100 * Ext JS Library 1.1.1
39101 * Copyright(c) 2006-2007, Ext JS, LLC.
39103 * Originally Released Under LGPL - original licence link has changed is not relivant.
39106 * <script type="text/javascript">
39111 * @class Roo.form.TextField
39112 * @extends Roo.form.Field
39113 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39114 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39116 * Creates a new TextField
39117 * @param {Object} config Configuration options
39119 Roo.form.TextField = function(config){
39120 Roo.form.TextField.superclass.constructor.call(this, config);
39124 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39125 * according to the default logic, but this event provides a hook for the developer to apply additional
39126 * logic at runtime to resize the field if needed.
39127 * @param {Roo.form.Field} this This text field
39128 * @param {Number} width The new field width
39134 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39136 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39140 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39144 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39148 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39152 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39156 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39158 disableKeyFilter : false,
39160 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39164 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39168 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39170 maxLength : Number.MAX_VALUE,
39172 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39174 minLengthText : "The minimum length for this field is {0}",
39176 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39178 maxLengthText : "The maximum length for this field is {0}",
39180 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39182 selectOnFocus : false,
39184 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39186 blankText : "This field is required",
39188 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39189 * If available, this function will be called only after the basic validators all return true, and will be passed the
39190 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39194 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39195 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39196 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39200 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39204 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39210 initEvents : function()
39212 if (this.emptyText) {
39213 this.el.attr('placeholder', this.emptyText);
39216 Roo.form.TextField.superclass.initEvents.call(this);
39217 if(this.validationEvent == 'keyup'){
39218 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39219 this.el.on('keyup', this.filterValidation, this);
39221 else if(this.validationEvent !== false){
39222 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39225 if(this.selectOnFocus){
39226 this.on("focus", this.preFocus, this);
39229 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39230 this.el.on("keypress", this.filterKeys, this);
39233 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39234 this.el.on("click", this.autoSize, this);
39236 if(this.el.is('input[type=password]') && Roo.isSafari){
39237 this.el.on('keydown', this.SafariOnKeyDown, this);
39241 processValue : function(value){
39242 if(this.stripCharsRe){
39243 var newValue = value.replace(this.stripCharsRe, '');
39244 if(newValue !== value){
39245 this.setRawValue(newValue);
39252 filterValidation : function(e){
39253 if(!e.isNavKeyPress()){
39254 this.validationTask.delay(this.validationDelay);
39259 onKeyUp : function(e){
39260 if(!e.isNavKeyPress()){
39266 * Resets the current field value to the originally-loaded value and clears any validation messages.
39269 reset : function(){
39270 Roo.form.TextField.superclass.reset.call(this);
39276 preFocus : function(){
39278 if(this.selectOnFocus){
39279 this.el.dom.select();
39285 filterKeys : function(e){
39286 var k = e.getKey();
39287 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39290 var c = e.getCharCode(), cc = String.fromCharCode(c);
39291 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39294 if(!this.maskRe.test(cc)){
39299 setValue : function(v){
39301 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39307 * Validates a value according to the field's validation rules and marks the field as invalid
39308 * if the validation fails
39309 * @param {Mixed} value The value to validate
39310 * @return {Boolean} True if the value is valid, else false
39312 validateValue : function(value){
39313 if(value.length < 1) { // if it's blank
39314 if(this.allowBlank){
39315 this.clearInvalid();
39318 this.markInvalid(this.blankText);
39322 if(value.length < this.minLength){
39323 this.markInvalid(String.format(this.minLengthText, this.minLength));
39326 if(value.length > this.maxLength){
39327 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39331 var vt = Roo.form.VTypes;
39332 if(!vt[this.vtype](value, this)){
39333 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39337 if(typeof this.validator == "function"){
39338 var msg = this.validator(value);
39340 this.markInvalid(msg);
39344 if(this.regex && !this.regex.test(value)){
39345 this.markInvalid(this.regexText);
39352 * Selects text in this field
39353 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39354 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39356 selectText : function(start, end){
39357 var v = this.getRawValue();
39359 start = start === undefined ? 0 : start;
39360 end = end === undefined ? v.length : end;
39361 var d = this.el.dom;
39362 if(d.setSelectionRange){
39363 d.setSelectionRange(start, end);
39364 }else if(d.createTextRange){
39365 var range = d.createTextRange();
39366 range.moveStart("character", start);
39367 range.moveEnd("character", v.length-end);
39374 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39375 * This only takes effect if grow = true, and fires the autosize event.
39377 autoSize : function(){
39378 if(!this.grow || !this.rendered){
39382 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39385 var v = el.dom.value;
39386 var d = document.createElement('div');
39387 d.appendChild(document.createTextNode(v));
39391 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39392 this.el.setWidth(w);
39393 this.fireEvent("autosize", this, w);
39397 SafariOnKeyDown : function(event)
39399 // this is a workaround for a password hang bug on chrome/ webkit.
39401 var isSelectAll = false;
39403 if(this.el.dom.selectionEnd > 0){
39404 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39406 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39407 event.preventDefault();
39412 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39414 event.preventDefault();
39415 // this is very hacky as keydown always get's upper case.
39417 var cc = String.fromCharCode(event.getCharCode());
39420 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39428 * Ext JS Library 1.1.1
39429 * Copyright(c) 2006-2007, Ext JS, LLC.
39431 * Originally Released Under LGPL - original licence link has changed is not relivant.
39434 * <script type="text/javascript">
39438 * @class Roo.form.Hidden
39439 * @extends Roo.form.TextField
39440 * Simple Hidden element used on forms
39442 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39445 * Creates a new Hidden form element.
39446 * @param {Object} config Configuration options
39451 // easy hidden field...
39452 Roo.form.Hidden = function(config){
39453 Roo.form.Hidden.superclass.constructor.call(this, config);
39456 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39458 inputType: 'hidden',
39461 labelSeparator: '',
39463 itemCls : 'x-form-item-display-none'
39471 * Ext JS Library 1.1.1
39472 * Copyright(c) 2006-2007, Ext JS, LLC.
39474 * Originally Released Under LGPL - original licence link has changed is not relivant.
39477 * <script type="text/javascript">
39481 * @class Roo.form.TriggerField
39482 * @extends Roo.form.TextField
39483 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39484 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39485 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39486 * for which you can provide a custom implementation. For example:
39488 var trigger = new Roo.form.TriggerField();
39489 trigger.onTriggerClick = myTriggerFn;
39490 trigger.applyTo('my-field');
39493 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39494 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39495 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39496 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39498 * Create a new TriggerField.
39499 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39500 * to the base TextField)
39502 Roo.form.TriggerField = function(config){
39503 this.mimicing = false;
39504 Roo.form.TriggerField.superclass.constructor.call(this, config);
39507 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39509 * @cfg {String} triggerClass A CSS class to apply to the trigger
39512 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39513 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39515 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39517 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39521 /** @cfg {Boolean} grow @hide */
39522 /** @cfg {Number} growMin @hide */
39523 /** @cfg {Number} growMax @hide */
39529 autoSize: Roo.emptyFn,
39533 deferHeight : true,
39536 actionMode : 'wrap',
39538 onResize : function(w, h){
39539 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39540 if(typeof w == 'number'){
39541 var x = w - this.trigger.getWidth();
39542 this.el.setWidth(this.adjustWidth('input', x));
39543 this.trigger.setStyle('left', x+'px');
39548 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39551 getResizeEl : function(){
39556 getPositionEl : function(){
39561 alignErrorIcon : function(){
39562 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39566 onRender : function(ct, position){
39567 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39568 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39569 this.trigger = this.wrap.createChild(this.triggerConfig ||
39570 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39571 if(this.hideTrigger){
39572 this.trigger.setDisplayed(false);
39574 this.initTrigger();
39576 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39581 initTrigger : function(){
39582 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39583 this.trigger.addClassOnOver('x-form-trigger-over');
39584 this.trigger.addClassOnClick('x-form-trigger-click');
39588 onDestroy : function(){
39590 this.trigger.removeAllListeners();
39591 this.trigger.remove();
39594 this.wrap.remove();
39596 Roo.form.TriggerField.superclass.onDestroy.call(this);
39600 onFocus : function(){
39601 Roo.form.TriggerField.superclass.onFocus.call(this);
39602 if(!this.mimicing){
39603 this.wrap.addClass('x-trigger-wrap-focus');
39604 this.mimicing = true;
39605 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39606 if(this.monitorTab){
39607 this.el.on("keydown", this.checkTab, this);
39613 checkTab : function(e){
39614 if(e.getKey() == e.TAB){
39615 this.triggerBlur();
39620 onBlur : function(){
39625 mimicBlur : function(e, t){
39626 if(!this.wrap.contains(t) && this.validateBlur()){
39627 this.triggerBlur();
39632 triggerBlur : function(){
39633 this.mimicing = false;
39634 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39635 if(this.monitorTab){
39636 this.el.un("keydown", this.checkTab, this);
39638 this.wrap.removeClass('x-trigger-wrap-focus');
39639 Roo.form.TriggerField.superclass.onBlur.call(this);
39643 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39644 validateBlur : function(e, t){
39649 onDisable : function(){
39650 Roo.form.TriggerField.superclass.onDisable.call(this);
39652 this.wrap.addClass('x-item-disabled');
39657 onEnable : function(){
39658 Roo.form.TriggerField.superclass.onEnable.call(this);
39660 this.wrap.removeClass('x-item-disabled');
39665 onShow : function(){
39666 var ae = this.getActionEl();
39669 ae.dom.style.display = '';
39670 ae.dom.style.visibility = 'visible';
39676 onHide : function(){
39677 var ae = this.getActionEl();
39678 ae.dom.style.display = 'none';
39682 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39683 * by an implementing function.
39685 * @param {EventObject} e
39687 onTriggerClick : Roo.emptyFn
39690 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39691 // to be extended by an implementing class. For an example of implementing this class, see the custom
39692 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39693 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39694 initComponent : function(){
39695 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39697 this.triggerConfig = {
39698 tag:'span', cls:'x-form-twin-triggers', cn:[
39699 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39700 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39704 getTrigger : function(index){
39705 return this.triggers[index];
39708 initTrigger : function(){
39709 var ts = this.trigger.select('.x-form-trigger', true);
39710 this.wrap.setStyle('overflow', 'hidden');
39711 var triggerField = this;
39712 ts.each(function(t, all, index){
39713 t.hide = function(){
39714 var w = triggerField.wrap.getWidth();
39715 this.dom.style.display = 'none';
39716 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39718 t.show = function(){
39719 var w = triggerField.wrap.getWidth();
39720 this.dom.style.display = '';
39721 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39723 var triggerIndex = 'Trigger'+(index+1);
39725 if(this['hide'+triggerIndex]){
39726 t.dom.style.display = 'none';
39728 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39729 t.addClassOnOver('x-form-trigger-over');
39730 t.addClassOnClick('x-form-trigger-click');
39732 this.triggers = ts.elements;
39735 onTrigger1Click : Roo.emptyFn,
39736 onTrigger2Click : Roo.emptyFn
39739 * Ext JS Library 1.1.1
39740 * Copyright(c) 2006-2007, Ext JS, LLC.
39742 * Originally Released Under LGPL - original licence link has changed is not relivant.
39745 * <script type="text/javascript">
39749 * @class Roo.form.TextArea
39750 * @extends Roo.form.TextField
39751 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39752 * support for auto-sizing.
39754 * Creates a new TextArea
39755 * @param {Object} config Configuration options
39757 Roo.form.TextArea = function(config){
39758 Roo.form.TextArea.superclass.constructor.call(this, config);
39759 // these are provided exchanges for backwards compat
39760 // minHeight/maxHeight were replaced by growMin/growMax to be
39761 // compatible with TextField growing config values
39762 if(this.minHeight !== undefined){
39763 this.growMin = this.minHeight;
39765 if(this.maxHeight !== undefined){
39766 this.growMax = this.maxHeight;
39770 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39772 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39776 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39780 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39781 * in the field (equivalent to setting overflow: hidden, defaults to false)
39783 preventScrollbars: false,
39785 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39786 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39790 onRender : function(ct, position){
39792 this.defaultAutoCreate = {
39794 style:"width:300px;height:60px;",
39795 autocomplete: "new-password"
39798 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39800 this.textSizeEl = Roo.DomHelper.append(document.body, {
39801 tag: "pre", cls: "x-form-grow-sizer"
39803 if(this.preventScrollbars){
39804 this.el.setStyle("overflow", "hidden");
39806 this.el.setHeight(this.growMin);
39810 onDestroy : function(){
39811 if(this.textSizeEl){
39812 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39814 Roo.form.TextArea.superclass.onDestroy.call(this);
39818 onKeyUp : function(e){
39819 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39825 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39826 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39828 autoSize : function(){
39829 if(!this.grow || !this.textSizeEl){
39833 var v = el.dom.value;
39834 var ts = this.textSizeEl;
39837 ts.appendChild(document.createTextNode(v));
39840 Roo.fly(ts).setWidth(this.el.getWidth());
39842 v = "  ";
39845 v = v.replace(/\n/g, '<p> </p>');
39847 v += " \n ";
39850 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
39851 if(h != this.lastHeight){
39852 this.lastHeight = h;
39853 this.el.setHeight(h);
39854 this.fireEvent("autosize", this, h);
39859 * Ext JS Library 1.1.1
39860 * Copyright(c) 2006-2007, Ext JS, LLC.
39862 * Originally Released Under LGPL - original licence link has changed is not relivant.
39865 * <script type="text/javascript">
39870 * @class Roo.form.NumberField
39871 * @extends Roo.form.TextField
39872 * Numeric text field that provides automatic keystroke filtering and numeric validation.
39874 * Creates a new NumberField
39875 * @param {Object} config Configuration options
39877 Roo.form.NumberField = function(config){
39878 Roo.form.NumberField.superclass.constructor.call(this, config);
39881 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
39883 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
39885 fieldClass: "x-form-field x-form-num-field",
39887 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39889 allowDecimals : true,
39891 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39893 decimalSeparator : ".",
39895 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39897 decimalPrecision : 2,
39899 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39901 allowNegative : true,
39903 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39905 minValue : Number.NEGATIVE_INFINITY,
39907 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39909 maxValue : Number.MAX_VALUE,
39911 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39913 minText : "The minimum value for this field is {0}",
39915 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39917 maxText : "The maximum value for this field is {0}",
39919 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39920 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39922 nanText : "{0} is not a valid number",
39925 initEvents : function(){
39926 Roo.form.NumberField.superclass.initEvents.call(this);
39927 var allowed = "0123456789";
39928 if(this.allowDecimals){
39929 allowed += this.decimalSeparator;
39931 if(this.allowNegative){
39934 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
39935 var keyPress = function(e){
39936 var k = e.getKey();
39937 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39940 var c = e.getCharCode();
39941 if(allowed.indexOf(String.fromCharCode(c)) === -1){
39945 this.el.on("keypress", keyPress, this);
39949 validateValue : function(value){
39950 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
39953 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39956 var num = this.parseValue(value);
39958 this.markInvalid(String.format(this.nanText, value));
39961 if(num < this.minValue){
39962 this.markInvalid(String.format(this.minText, this.minValue));
39965 if(num > this.maxValue){
39966 this.markInvalid(String.format(this.maxText, this.maxValue));
39972 getValue : function(){
39973 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
39977 parseValue : function(value){
39978 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
39979 return isNaN(value) ? '' : value;
39983 fixPrecision : function(value){
39984 var nan = isNaN(value);
39985 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
39986 return nan ? '' : value;
39988 return parseFloat(value).toFixed(this.decimalPrecision);
39991 setValue : function(v){
39992 v = this.fixPrecision(v);
39993 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
39997 decimalPrecisionFcn : function(v){
39998 return Math.floor(v);
40001 beforeBlur : function(){
40002 var v = this.parseValue(this.getRawValue());
40009 * Ext JS Library 1.1.1
40010 * Copyright(c) 2006-2007, Ext JS, LLC.
40012 * Originally Released Under LGPL - original licence link has changed is not relivant.
40015 * <script type="text/javascript">
40019 * @class Roo.form.DateField
40020 * @extends Roo.form.TriggerField
40021 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40023 * Create a new DateField
40024 * @param {Object} config
40026 Roo.form.DateField = function(config){
40027 Roo.form.DateField.superclass.constructor.call(this, config);
40033 * Fires when a date is selected
40034 * @param {Roo.form.DateField} combo This combo box
40035 * @param {Date} date The date selected
40042 if(typeof this.minValue == "string") {
40043 this.minValue = this.parseDate(this.minValue);
40045 if(typeof this.maxValue == "string") {
40046 this.maxValue = this.parseDate(this.maxValue);
40048 this.ddMatch = null;
40049 if(this.disabledDates){
40050 var dd = this.disabledDates;
40052 for(var i = 0; i < dd.length; i++){
40054 if(i != dd.length-1) {
40058 this.ddMatch = new RegExp(re + ")");
40062 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40064 * @cfg {String} format
40065 * The default date format string which can be overriden for localization support. The format must be
40066 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40070 * @cfg {String} altFormats
40071 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40072 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40074 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40076 * @cfg {Array} disabledDays
40077 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40079 disabledDays : null,
40081 * @cfg {String} disabledDaysText
40082 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40084 disabledDaysText : "Disabled",
40086 * @cfg {Array} disabledDates
40087 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40088 * expression so they are very powerful. Some examples:
40090 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40091 * <li>["03/08", "09/16"] would disable those days for every year</li>
40092 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40093 * <li>["03/../2006"] would disable every day in March 2006</li>
40094 * <li>["^03"] would disable every day in every March</li>
40096 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40097 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40099 disabledDates : null,
40101 * @cfg {String} disabledDatesText
40102 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40104 disabledDatesText : "Disabled",
40106 * @cfg {Date/String} minValue
40107 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40108 * valid format (defaults to null).
40112 * @cfg {Date/String} maxValue
40113 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40114 * valid format (defaults to null).
40118 * @cfg {String} minText
40119 * The error text to display when the date in the cell is before minValue (defaults to
40120 * 'The date in this field must be after {minValue}').
40122 minText : "The date in this field must be equal to or after {0}",
40124 * @cfg {String} maxText
40125 * The error text to display when the date in the cell is after maxValue (defaults to
40126 * 'The date in this field must be before {maxValue}').
40128 maxText : "The date in this field must be equal to or before {0}",
40130 * @cfg {String} invalidText
40131 * The error text to display when the date in the field is invalid (defaults to
40132 * '{value} is not a valid date - it must be in the format {format}').
40134 invalidText : "{0} is not a valid date - it must be in the format {1}",
40136 * @cfg {String} triggerClass
40137 * An additional CSS class used to style the trigger button. The trigger will always get the
40138 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40139 * which displays a calendar icon).
40141 triggerClass : 'x-form-date-trigger',
40145 * @cfg {Boolean} useIso
40146 * if enabled, then the date field will use a hidden field to store the
40147 * real value as iso formated date. default (false)
40151 * @cfg {String/Object} autoCreate
40152 * A DomHelper element spec, or true for a default element spec (defaults to
40153 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40156 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40159 hiddenField: false,
40161 onRender : function(ct, position)
40163 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40165 //this.el.dom.removeAttribute('name');
40166 Roo.log("Changing name?");
40167 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40168 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40170 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40171 // prevent input submission
40172 this.hiddenName = this.name;
40179 validateValue : function(value)
40181 value = this.formatDate(value);
40182 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40183 Roo.log('super failed');
40186 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40189 var svalue = value;
40190 value = this.parseDate(value);
40192 Roo.log('parse date failed' + svalue);
40193 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40196 var time = value.getTime();
40197 if(this.minValue && time < this.minValue.getTime()){
40198 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40201 if(this.maxValue && time > this.maxValue.getTime()){
40202 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40205 if(this.disabledDays){
40206 var day = value.getDay();
40207 for(var i = 0; i < this.disabledDays.length; i++) {
40208 if(day === this.disabledDays[i]){
40209 this.markInvalid(this.disabledDaysText);
40214 var fvalue = this.formatDate(value);
40215 if(this.ddMatch && this.ddMatch.test(fvalue)){
40216 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40223 // Provides logic to override the default TriggerField.validateBlur which just returns true
40224 validateBlur : function(){
40225 return !this.menu || !this.menu.isVisible();
40228 getName: function()
40230 // returns hidden if it's set..
40231 if (!this.rendered) {return ''};
40232 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40237 * Returns the current date value of the date field.
40238 * @return {Date} The date value
40240 getValue : function(){
40242 return this.hiddenField ?
40243 this.hiddenField.value :
40244 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40248 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40249 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40250 * (the default format used is "m/d/y").
40253 //All of these calls set the same date value (May 4, 2006)
40255 //Pass a date object:
40256 var dt = new Date('5/4/06');
40257 dateField.setValue(dt);
40259 //Pass a date string (default format):
40260 dateField.setValue('5/4/06');
40262 //Pass a date string (custom format):
40263 dateField.format = 'Y-m-d';
40264 dateField.setValue('2006-5-4');
40266 * @param {String/Date} date The date or valid date string
40268 setValue : function(date){
40269 if (this.hiddenField) {
40270 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40272 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40273 // make sure the value field is always stored as a date..
40274 this.value = this.parseDate(date);
40280 parseDate : function(value){
40281 if(!value || value instanceof Date){
40284 var v = Date.parseDate(value, this.format);
40285 if (!v && this.useIso) {
40286 v = Date.parseDate(value, 'Y-m-d');
40288 if(!v && this.altFormats){
40289 if(!this.altFormatsArray){
40290 this.altFormatsArray = this.altFormats.split("|");
40292 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40293 v = Date.parseDate(value, this.altFormatsArray[i]);
40300 formatDate : function(date, fmt){
40301 return (!date || !(date instanceof Date)) ?
40302 date : date.dateFormat(fmt || this.format);
40307 select: function(m, d){
40310 this.fireEvent('select', this, d);
40312 show : function(){ // retain focus styling
40316 this.focus.defer(10, this);
40317 var ml = this.menuListeners;
40318 this.menu.un("select", ml.select, this);
40319 this.menu.un("show", ml.show, this);
40320 this.menu.un("hide", ml.hide, this);
40325 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40326 onTriggerClick : function(){
40330 if(this.menu == null){
40331 this.menu = new Roo.menu.DateMenu();
40333 Roo.apply(this.menu.picker, {
40334 showClear: this.allowBlank,
40335 minDate : this.minValue,
40336 maxDate : this.maxValue,
40337 disabledDatesRE : this.ddMatch,
40338 disabledDatesText : this.disabledDatesText,
40339 disabledDays : this.disabledDays,
40340 disabledDaysText : this.disabledDaysText,
40341 format : this.useIso ? 'Y-m-d' : this.format,
40342 minText : String.format(this.minText, this.formatDate(this.minValue)),
40343 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40345 this.menu.on(Roo.apply({}, this.menuListeners, {
40348 this.menu.picker.setValue(this.getValue() || new Date());
40349 this.menu.show(this.el, "tl-bl?");
40352 beforeBlur : function(){
40353 var v = this.parseDate(this.getRawValue());
40363 isDirty : function() {
40364 if(this.disabled) {
40368 if(typeof(this.startValue) === 'undefined'){
40372 return String(this.getValue()) !== String(this.startValue);
40377 * Ext JS Library 1.1.1
40378 * Copyright(c) 2006-2007, Ext JS, LLC.
40380 * Originally Released Under LGPL - original licence link has changed is not relivant.
40383 * <script type="text/javascript">
40387 * @class Roo.form.MonthField
40388 * @extends Roo.form.TriggerField
40389 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40391 * Create a new MonthField
40392 * @param {Object} config
40394 Roo.form.MonthField = function(config){
40396 Roo.form.MonthField.superclass.constructor.call(this, config);
40402 * Fires when a date is selected
40403 * @param {Roo.form.MonthFieeld} combo This combo box
40404 * @param {Date} date The date selected
40411 if(typeof this.minValue == "string") {
40412 this.minValue = this.parseDate(this.minValue);
40414 if(typeof this.maxValue == "string") {
40415 this.maxValue = this.parseDate(this.maxValue);
40417 this.ddMatch = null;
40418 if(this.disabledDates){
40419 var dd = this.disabledDates;
40421 for(var i = 0; i < dd.length; i++){
40423 if(i != dd.length-1) {
40427 this.ddMatch = new RegExp(re + ")");
40431 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40433 * @cfg {String} format
40434 * The default date format string which can be overriden for localization support. The format must be
40435 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40439 * @cfg {String} altFormats
40440 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40441 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40443 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40445 * @cfg {Array} disabledDays
40446 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40448 disabledDays : [0,1,2,3,4,5,6],
40450 * @cfg {String} disabledDaysText
40451 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40453 disabledDaysText : "Disabled",
40455 * @cfg {Array} disabledDates
40456 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40457 * expression so they are very powerful. Some examples:
40459 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40460 * <li>["03/08", "09/16"] would disable those days for every year</li>
40461 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40462 * <li>["03/../2006"] would disable every day in March 2006</li>
40463 * <li>["^03"] would disable every day in every March</li>
40465 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40466 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40468 disabledDates : null,
40470 * @cfg {String} disabledDatesText
40471 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40473 disabledDatesText : "Disabled",
40475 * @cfg {Date/String} minValue
40476 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40477 * valid format (defaults to null).
40481 * @cfg {Date/String} maxValue
40482 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40483 * valid format (defaults to null).
40487 * @cfg {String} minText
40488 * The error text to display when the date in the cell is before minValue (defaults to
40489 * 'The date in this field must be after {minValue}').
40491 minText : "The date in this field must be equal to or after {0}",
40493 * @cfg {String} maxTextf
40494 * The error text to display when the date in the cell is after maxValue (defaults to
40495 * 'The date in this field must be before {maxValue}').
40497 maxText : "The date in this field must be equal to or before {0}",
40499 * @cfg {String} invalidText
40500 * The error text to display when the date in the field is invalid (defaults to
40501 * '{value} is not a valid date - it must be in the format {format}').
40503 invalidText : "{0} is not a valid date - it must be in the format {1}",
40505 * @cfg {String} triggerClass
40506 * An additional CSS class used to style the trigger button. The trigger will always get the
40507 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40508 * which displays a calendar icon).
40510 triggerClass : 'x-form-date-trigger',
40514 * @cfg {Boolean} useIso
40515 * if enabled, then the date field will use a hidden field to store the
40516 * real value as iso formated date. default (true)
40520 * @cfg {String/Object} autoCreate
40521 * A DomHelper element spec, or true for a default element spec (defaults to
40522 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40525 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40528 hiddenField: false,
40530 hideMonthPicker : false,
40532 onRender : function(ct, position)
40534 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40536 this.el.dom.removeAttribute('name');
40537 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40539 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40540 // prevent input submission
40541 this.hiddenName = this.name;
40548 validateValue : function(value)
40550 value = this.formatDate(value);
40551 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40554 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40557 var svalue = value;
40558 value = this.parseDate(value);
40560 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40563 var time = value.getTime();
40564 if(this.minValue && time < this.minValue.getTime()){
40565 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40568 if(this.maxValue && time > this.maxValue.getTime()){
40569 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40572 /*if(this.disabledDays){
40573 var day = value.getDay();
40574 for(var i = 0; i < this.disabledDays.length; i++) {
40575 if(day === this.disabledDays[i]){
40576 this.markInvalid(this.disabledDaysText);
40582 var fvalue = this.formatDate(value);
40583 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40584 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40592 // Provides logic to override the default TriggerField.validateBlur which just returns true
40593 validateBlur : function(){
40594 return !this.menu || !this.menu.isVisible();
40598 * Returns the current date value of the date field.
40599 * @return {Date} The date value
40601 getValue : function(){
40605 return this.hiddenField ?
40606 this.hiddenField.value :
40607 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40611 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40612 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40613 * (the default format used is "m/d/y").
40616 //All of these calls set the same date value (May 4, 2006)
40618 //Pass a date object:
40619 var dt = new Date('5/4/06');
40620 monthField.setValue(dt);
40622 //Pass a date string (default format):
40623 monthField.setValue('5/4/06');
40625 //Pass a date string (custom format):
40626 monthField.format = 'Y-m-d';
40627 monthField.setValue('2006-5-4');
40629 * @param {String/Date} date The date or valid date string
40631 setValue : function(date){
40632 Roo.log('month setValue' + date);
40633 // can only be first of month..
40635 var val = this.parseDate(date);
40637 if (this.hiddenField) {
40638 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40640 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40641 this.value = this.parseDate(date);
40645 parseDate : function(value){
40646 if(!value || value instanceof Date){
40647 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40650 var v = Date.parseDate(value, this.format);
40651 if (!v && this.useIso) {
40652 v = Date.parseDate(value, 'Y-m-d');
40656 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40660 if(!v && this.altFormats){
40661 if(!this.altFormatsArray){
40662 this.altFormatsArray = this.altFormats.split("|");
40664 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40665 v = Date.parseDate(value, this.altFormatsArray[i]);
40672 formatDate : function(date, fmt){
40673 return (!date || !(date instanceof Date)) ?
40674 date : date.dateFormat(fmt || this.format);
40679 select: function(m, d){
40681 this.fireEvent('select', this, d);
40683 show : function(){ // retain focus styling
40687 this.focus.defer(10, this);
40688 var ml = this.menuListeners;
40689 this.menu.un("select", ml.select, this);
40690 this.menu.un("show", ml.show, this);
40691 this.menu.un("hide", ml.hide, this);
40695 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40696 onTriggerClick : function(){
40700 if(this.menu == null){
40701 this.menu = new Roo.menu.DateMenu();
40705 Roo.apply(this.menu.picker, {
40707 showClear: this.allowBlank,
40708 minDate : this.minValue,
40709 maxDate : this.maxValue,
40710 disabledDatesRE : this.ddMatch,
40711 disabledDatesText : this.disabledDatesText,
40713 format : this.useIso ? 'Y-m-d' : this.format,
40714 minText : String.format(this.minText, this.formatDate(this.minValue)),
40715 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40718 this.menu.on(Roo.apply({}, this.menuListeners, {
40726 // hide month picker get's called when we called by 'before hide';
40728 var ignorehide = true;
40729 p.hideMonthPicker = function(disableAnim){
40733 if(this.monthPicker){
40734 Roo.log("hideMonthPicker called");
40735 if(disableAnim === true){
40736 this.monthPicker.hide();
40738 this.monthPicker.slideOut('t', {duration:.2});
40739 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40740 p.fireEvent("select", this, this.value);
40746 Roo.log('picker set value');
40747 Roo.log(this.getValue());
40748 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40749 m.show(this.el, 'tl-bl?');
40750 ignorehide = false;
40751 // this will trigger hideMonthPicker..
40754 // hidden the day picker
40755 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40761 p.showMonthPicker.defer(100, p);
40767 beforeBlur : function(){
40768 var v = this.parseDate(this.getRawValue());
40774 /** @cfg {Boolean} grow @hide */
40775 /** @cfg {Number} growMin @hide */
40776 /** @cfg {Number} growMax @hide */
40783 * Ext JS Library 1.1.1
40784 * Copyright(c) 2006-2007, Ext JS, LLC.
40786 * Originally Released Under LGPL - original licence link has changed is not relivant.
40789 * <script type="text/javascript">
40794 * @class Roo.form.ComboBox
40795 * @extends Roo.form.TriggerField
40796 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40798 * Create a new ComboBox.
40799 * @param {Object} config Configuration options
40801 Roo.form.ComboBox = function(config){
40802 Roo.form.ComboBox.superclass.constructor.call(this, config);
40806 * Fires when the dropdown list is expanded
40807 * @param {Roo.form.ComboBox} combo This combo box
40812 * Fires when the dropdown list is collapsed
40813 * @param {Roo.form.ComboBox} combo This combo box
40817 * @event beforeselect
40818 * Fires before a list item is selected. Return false to cancel the selection.
40819 * @param {Roo.form.ComboBox} combo This combo box
40820 * @param {Roo.data.Record} record The data record returned from the underlying store
40821 * @param {Number} index The index of the selected item in the dropdown list
40823 'beforeselect' : true,
40826 * Fires when a list item is selected
40827 * @param {Roo.form.ComboBox} combo This combo box
40828 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
40829 * @param {Number} index The index of the selected item in the dropdown list
40833 * @event beforequery
40834 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
40835 * The event object passed has these properties:
40836 * @param {Roo.form.ComboBox} combo This combo box
40837 * @param {String} query The query
40838 * @param {Boolean} forceAll true to force "all" query
40839 * @param {Boolean} cancel true to cancel the query
40840 * @param {Object} e The query event object
40842 'beforequery': true,
40845 * Fires when the 'add' icon is pressed (add a listener to enable add button)
40846 * @param {Roo.form.ComboBox} combo This combo box
40851 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
40852 * @param {Roo.form.ComboBox} combo This combo box
40853 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
40859 if(this.transform){
40860 this.allowDomMove = false;
40861 var s = Roo.getDom(this.transform);
40862 if(!this.hiddenName){
40863 this.hiddenName = s.name;
40866 this.mode = 'local';
40867 var d = [], opts = s.options;
40868 for(var i = 0, len = opts.length;i < len; i++){
40870 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
40872 this.value = value;
40874 d.push([value, o.text]);
40876 this.store = new Roo.data.SimpleStore({
40878 fields: ['value', 'text'],
40881 this.valueField = 'value';
40882 this.displayField = 'text';
40884 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
40885 if(!this.lazyRender){
40886 this.target = true;
40887 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
40888 s.parentNode.removeChild(s); // remove it
40889 this.render(this.el.parentNode);
40891 s.parentNode.removeChild(s); // remove it
40896 this.store = Roo.factory(this.store, Roo.data);
40899 this.selectedIndex = -1;
40900 if(this.mode == 'local'){
40901 if(config.queryDelay === undefined){
40902 this.queryDelay = 10;
40904 if(config.minChars === undefined){
40910 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
40912 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
40915 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
40916 * rendering into an Roo.Editor, defaults to false)
40919 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
40920 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
40923 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
40926 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
40927 * the dropdown list (defaults to undefined, with no header element)
40931 * @cfg {String/Roo.Template} tpl The template to use to render the output
40935 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
40937 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
40939 listWidth: undefined,
40941 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
40942 * mode = 'remote' or 'text' if mode = 'local')
40944 displayField: undefined,
40946 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
40947 * mode = 'remote' or 'value' if mode = 'local').
40948 * Note: use of a valueField requires the user make a selection
40949 * in order for a value to be mapped.
40951 valueField: undefined,
40955 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
40956 * field's data value (defaults to the underlying DOM element's name)
40958 hiddenName: undefined,
40960 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
40964 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
40966 selectedClass: 'x-combo-selected',
40968 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40969 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
40970 * which displays a downward arrow icon).
40972 triggerClass : 'x-form-arrow-trigger',
40974 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
40978 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
40979 * anchor positions (defaults to 'tl-bl')
40981 listAlign: 'tl-bl?',
40983 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
40987 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
40988 * query specified by the allQuery config option (defaults to 'query')
40990 triggerAction: 'query',
40992 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
40993 * (defaults to 4, does not apply if editable = false)
40997 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
40998 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41002 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41003 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41007 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41008 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41012 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41013 * when editable = true (defaults to false)
41015 selectOnFocus:false,
41017 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41019 queryParam: 'query',
41021 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41022 * when mode = 'remote' (defaults to 'Loading...')
41024 loadingText: 'Loading...',
41026 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41030 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41034 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41035 * traditional select (defaults to true)
41039 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41043 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41047 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41048 * listWidth has a higher value)
41052 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41053 * allow the user to set arbitrary text into the field (defaults to false)
41055 forceSelection:false,
41057 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41058 * if typeAhead = true (defaults to 250)
41060 typeAheadDelay : 250,
41062 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41063 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41065 valueNotFoundText : undefined,
41067 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41069 blockFocus : false,
41072 * @cfg {Boolean} disableClear Disable showing of clear button.
41074 disableClear : false,
41076 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41078 alwaysQuery : false,
41084 // element that contains real text value.. (when hidden is used..)
41087 onRender : function(ct, position){
41088 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41089 if(this.hiddenName){
41090 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41092 this.hiddenField.value =
41093 this.hiddenValue !== undefined ? this.hiddenValue :
41094 this.value !== undefined ? this.value : '';
41096 // prevent input submission
41097 this.el.dom.removeAttribute('name');
41102 this.el.dom.setAttribute('autocomplete', 'off');
41105 var cls = 'x-combo-list';
41107 this.list = new Roo.Layer({
41108 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41111 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41112 this.list.setWidth(lw);
41113 this.list.swallowEvent('mousewheel');
41114 this.assetHeight = 0;
41117 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41118 this.assetHeight += this.header.getHeight();
41121 this.innerList = this.list.createChild({cls:cls+'-inner'});
41122 this.innerList.on('mouseover', this.onViewOver, this);
41123 this.innerList.on('mousemove', this.onViewMove, this);
41124 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41126 if(this.allowBlank && !this.pageSize && !this.disableClear){
41127 this.footer = this.list.createChild({cls:cls+'-ft'});
41128 this.pageTb = new Roo.Toolbar(this.footer);
41132 this.footer = this.list.createChild({cls:cls+'-ft'});
41133 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41134 {pageSize: this.pageSize});
41138 if (this.pageTb && this.allowBlank && !this.disableClear) {
41140 this.pageTb.add(new Roo.Toolbar.Fill(), {
41141 cls: 'x-btn-icon x-btn-clear',
41143 handler: function()
41146 _this.clearValue();
41147 _this.onSelect(false, -1);
41152 this.assetHeight += this.footer.getHeight();
41157 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41160 this.view = new Roo.View(this.innerList, this.tpl, {
41161 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41164 this.view.on('click', this.onViewClick, this);
41166 this.store.on('beforeload', this.onBeforeLoad, this);
41167 this.store.on('load', this.onLoad, this);
41168 this.store.on('loadexception', this.onLoadException, this);
41170 if(this.resizable){
41171 this.resizer = new Roo.Resizable(this.list, {
41172 pinned:true, handles:'se'
41174 this.resizer.on('resize', function(r, w, h){
41175 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41176 this.listWidth = w;
41177 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41178 this.restrictHeight();
41180 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41182 if(!this.editable){
41183 this.editable = true;
41184 this.setEditable(false);
41188 if (typeof(this.events.add.listeners) != 'undefined') {
41190 this.addicon = this.wrap.createChild(
41191 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41193 this.addicon.on('click', function(e) {
41194 this.fireEvent('add', this);
41197 if (typeof(this.events.edit.listeners) != 'undefined') {
41199 this.editicon = this.wrap.createChild(
41200 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41201 if (this.addicon) {
41202 this.editicon.setStyle('margin-left', '40px');
41204 this.editicon.on('click', function(e) {
41206 // we fire even if inothing is selected..
41207 this.fireEvent('edit', this, this.lastData );
41217 initEvents : function(){
41218 Roo.form.ComboBox.superclass.initEvents.call(this);
41220 this.keyNav = new Roo.KeyNav(this.el, {
41221 "up" : function(e){
41222 this.inKeyMode = true;
41226 "down" : function(e){
41227 if(!this.isExpanded()){
41228 this.onTriggerClick();
41230 this.inKeyMode = true;
41235 "enter" : function(e){
41236 this.onViewClick();
41240 "esc" : function(e){
41244 "tab" : function(e){
41245 this.onViewClick(false);
41246 this.fireEvent("specialkey", this, e);
41252 doRelay : function(foo, bar, hname){
41253 if(hname == 'down' || this.scope.isExpanded()){
41254 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41261 this.queryDelay = Math.max(this.queryDelay || 10,
41262 this.mode == 'local' ? 10 : 250);
41263 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41264 if(this.typeAhead){
41265 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41267 if(this.editable !== false){
41268 this.el.on("keyup", this.onKeyUp, this);
41270 if(this.forceSelection){
41271 this.on('blur', this.doForce, this);
41275 onDestroy : function(){
41277 this.view.setStore(null);
41278 this.view.el.removeAllListeners();
41279 this.view.el.remove();
41280 this.view.purgeListeners();
41283 this.list.destroy();
41286 this.store.un('beforeload', this.onBeforeLoad, this);
41287 this.store.un('load', this.onLoad, this);
41288 this.store.un('loadexception', this.onLoadException, this);
41290 Roo.form.ComboBox.superclass.onDestroy.call(this);
41294 fireKey : function(e){
41295 if(e.isNavKeyPress() && !this.list.isVisible()){
41296 this.fireEvent("specialkey", this, e);
41301 onResize: function(w, h){
41302 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41304 if(typeof w != 'number'){
41305 // we do not handle it!?!?
41308 var tw = this.trigger.getWidth();
41309 tw += this.addicon ? this.addicon.getWidth() : 0;
41310 tw += this.editicon ? this.editicon.getWidth() : 0;
41312 this.el.setWidth( this.adjustWidth('input', x));
41314 this.trigger.setStyle('left', x+'px');
41316 if(this.list && this.listWidth === undefined){
41317 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41318 this.list.setWidth(lw);
41319 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41327 * Allow or prevent the user from directly editing the field text. If false is passed,
41328 * the user will only be able to select from the items defined in the dropdown list. This method
41329 * is the runtime equivalent of setting the 'editable' config option at config time.
41330 * @param {Boolean} value True to allow the user to directly edit the field text
41332 setEditable : function(value){
41333 if(value == this.editable){
41336 this.editable = value;
41338 this.el.dom.setAttribute('readOnly', true);
41339 this.el.on('mousedown', this.onTriggerClick, this);
41340 this.el.addClass('x-combo-noedit');
41342 this.el.dom.setAttribute('readOnly', false);
41343 this.el.un('mousedown', this.onTriggerClick, this);
41344 this.el.removeClass('x-combo-noedit');
41349 onBeforeLoad : function(){
41350 if(!this.hasFocus){
41353 this.innerList.update(this.loadingText ?
41354 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41355 this.restrictHeight();
41356 this.selectedIndex = -1;
41360 onLoad : function(){
41361 if(!this.hasFocus){
41364 if(this.store.getCount() > 0){
41366 this.restrictHeight();
41367 if(this.lastQuery == this.allQuery){
41369 this.el.dom.select();
41371 if(!this.selectByValue(this.value, true)){
41372 this.select(0, true);
41376 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41377 this.taTask.delay(this.typeAheadDelay);
41381 this.onEmptyResults();
41386 onLoadException : function()
41389 Roo.log(this.store.reader.jsonData);
41390 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41391 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41397 onTypeAhead : function(){
41398 if(this.store.getCount() > 0){
41399 var r = this.store.getAt(0);
41400 var newValue = r.data[this.displayField];
41401 var len = newValue.length;
41402 var selStart = this.getRawValue().length;
41403 if(selStart != len){
41404 this.setRawValue(newValue);
41405 this.selectText(selStart, newValue.length);
41411 onSelect : function(record, index){
41412 if(this.fireEvent('beforeselect', this, record, index) !== false){
41413 this.setFromData(index > -1 ? record.data : false);
41415 this.fireEvent('select', this, record, index);
41420 * Returns the currently selected field value or empty string if no value is set.
41421 * @return {String} value The selected value
41423 getValue : function(){
41424 if(this.valueField){
41425 return typeof this.value != 'undefined' ? this.value : '';
41427 return Roo.form.ComboBox.superclass.getValue.call(this);
41431 * Clears any text/value currently set in the field
41433 clearValue : function(){
41434 if(this.hiddenField){
41435 this.hiddenField.value = '';
41438 this.setRawValue('');
41439 this.lastSelectionText = '';
41444 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41445 * will be displayed in the field. If the value does not match the data value of an existing item,
41446 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41447 * Otherwise the field will be blank (although the value will still be set).
41448 * @param {String} value The value to match
41450 setValue : function(v){
41452 if(this.valueField){
41453 var r = this.findRecord(this.valueField, v);
41455 text = r.data[this.displayField];
41456 }else if(this.valueNotFoundText !== undefined){
41457 text = this.valueNotFoundText;
41460 this.lastSelectionText = text;
41461 if(this.hiddenField){
41462 this.hiddenField.value = v;
41464 Roo.form.ComboBox.superclass.setValue.call(this, text);
41468 * @property {Object} the last set data for the element
41473 * Sets the value of the field based on a object which is related to the record format for the store.
41474 * @param {Object} value the value to set as. or false on reset?
41476 setFromData : function(o){
41477 var dv = ''; // display value
41478 var vv = ''; // value value..
41480 if (this.displayField) {
41481 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41483 // this is an error condition!!!
41484 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41487 if(this.valueField){
41488 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41490 if(this.hiddenField){
41491 this.hiddenField.value = vv;
41493 this.lastSelectionText = dv;
41494 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41498 // no hidden field.. - we store the value in 'value', but still display
41499 // display field!!!!
41500 this.lastSelectionText = dv;
41501 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41507 reset : function(){
41508 // overridden so that last data is reset..
41509 this.setValue(this.resetValue);
41510 this.clearInvalid();
41511 this.lastData = false;
41513 this.view.clearSelections();
41517 findRecord : function(prop, value){
41519 if(this.store.getCount() > 0){
41520 this.store.each(function(r){
41521 if(r.data[prop] == value){
41531 getName: function()
41533 // returns hidden if it's set..
41534 if (!this.rendered) {return ''};
41535 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41539 onViewMove : function(e, t){
41540 this.inKeyMode = false;
41544 onViewOver : function(e, t){
41545 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41548 var item = this.view.findItemFromChild(t);
41550 var index = this.view.indexOf(item);
41551 this.select(index, false);
41556 onViewClick : function(doFocus)
41558 var index = this.view.getSelectedIndexes()[0];
41559 var r = this.store.getAt(index);
41561 this.onSelect(r, index);
41563 if(doFocus !== false && !this.blockFocus){
41569 restrictHeight : function(){
41570 this.innerList.dom.style.height = '';
41571 var inner = this.innerList.dom;
41572 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41573 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41574 this.list.beginUpdate();
41575 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41576 this.list.alignTo(this.el, this.listAlign);
41577 this.list.endUpdate();
41581 onEmptyResults : function(){
41586 * Returns true if the dropdown list is expanded, else false.
41588 isExpanded : function(){
41589 return this.list.isVisible();
41593 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41594 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41595 * @param {String} value The data value of the item to select
41596 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41597 * selected item if it is not currently in view (defaults to true)
41598 * @return {Boolean} True if the value matched an item in the list, else false
41600 selectByValue : function(v, scrollIntoView){
41601 if(v !== undefined && v !== null){
41602 var r = this.findRecord(this.valueField || this.displayField, v);
41604 this.select(this.store.indexOf(r), scrollIntoView);
41612 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41613 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41614 * @param {Number} index The zero-based index of the list item to select
41615 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41616 * selected item if it is not currently in view (defaults to true)
41618 select : function(index, scrollIntoView){
41619 this.selectedIndex = index;
41620 this.view.select(index);
41621 if(scrollIntoView !== false){
41622 var el = this.view.getNode(index);
41624 this.innerList.scrollChildIntoView(el, false);
41630 selectNext : function(){
41631 var ct = this.store.getCount();
41633 if(this.selectedIndex == -1){
41635 }else if(this.selectedIndex < ct-1){
41636 this.select(this.selectedIndex+1);
41642 selectPrev : function(){
41643 var ct = this.store.getCount();
41645 if(this.selectedIndex == -1){
41647 }else if(this.selectedIndex != 0){
41648 this.select(this.selectedIndex-1);
41654 onKeyUp : function(e){
41655 if(this.editable !== false && !e.isSpecialKey()){
41656 this.lastKey = e.getKey();
41657 this.dqTask.delay(this.queryDelay);
41662 validateBlur : function(){
41663 return !this.list || !this.list.isVisible();
41667 initQuery : function(){
41668 this.doQuery(this.getRawValue());
41672 doForce : function(){
41673 if(this.el.dom.value.length > 0){
41674 this.el.dom.value =
41675 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41681 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41682 * query allowing the query action to be canceled if needed.
41683 * @param {String} query The SQL query to execute
41684 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41685 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41686 * saved in the current store (defaults to false)
41688 doQuery : function(q, forceAll){
41689 if(q === undefined || q === null){
41694 forceAll: forceAll,
41698 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41702 forceAll = qe.forceAll;
41703 if(forceAll === true || (q.length >= this.minChars)){
41704 if(this.lastQuery != q || this.alwaysQuery){
41705 this.lastQuery = q;
41706 if(this.mode == 'local'){
41707 this.selectedIndex = -1;
41709 this.store.clearFilter();
41711 this.store.filter(this.displayField, q);
41715 this.store.baseParams[this.queryParam] = q;
41717 params: this.getParams(q)
41722 this.selectedIndex = -1;
41729 getParams : function(q){
41731 //p[this.queryParam] = q;
41734 p.limit = this.pageSize;
41740 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41742 collapse : function(){
41743 if(!this.isExpanded()){
41747 Roo.get(document).un('mousedown', this.collapseIf, this);
41748 Roo.get(document).un('mousewheel', this.collapseIf, this);
41749 if (!this.editable) {
41750 Roo.get(document).un('keydown', this.listKeyPress, this);
41752 this.fireEvent('collapse', this);
41756 collapseIf : function(e){
41757 if(!e.within(this.wrap) && !e.within(this.list)){
41763 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41765 expand : function(){
41766 if(this.isExpanded() || !this.hasFocus){
41769 this.list.alignTo(this.el, this.listAlign);
41771 Roo.get(document).on('mousedown', this.collapseIf, this);
41772 Roo.get(document).on('mousewheel', this.collapseIf, this);
41773 if (!this.editable) {
41774 Roo.get(document).on('keydown', this.listKeyPress, this);
41777 this.fireEvent('expand', this);
41781 // Implements the default empty TriggerField.onTriggerClick function
41782 onTriggerClick : function(){
41786 if(this.isExpanded()){
41788 if (!this.blockFocus) {
41793 this.hasFocus = true;
41794 if(this.triggerAction == 'all') {
41795 this.doQuery(this.allQuery, true);
41797 this.doQuery(this.getRawValue());
41799 if (!this.blockFocus) {
41804 listKeyPress : function(e)
41806 //Roo.log('listkeypress');
41807 // scroll to first matching element based on key pres..
41808 if (e.isSpecialKey()) {
41811 var k = String.fromCharCode(e.getKey()).toUpperCase();
41814 var csel = this.view.getSelectedNodes();
41815 var cselitem = false;
41817 var ix = this.view.indexOf(csel[0]);
41818 cselitem = this.store.getAt(ix);
41819 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41825 this.store.each(function(v) {
41827 // start at existing selection.
41828 if (cselitem.id == v.id) {
41834 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
41835 match = this.store.indexOf(v);
41840 if (match === false) {
41841 return true; // no more action?
41844 this.view.select(match);
41845 var sn = Roo.get(this.view.getSelectedNodes()[0]);
41846 sn.scrollIntoView(sn.dom.parentNode, false);
41850 * @cfg {Boolean} grow
41854 * @cfg {Number} growMin
41858 * @cfg {Number} growMax
41866 * Copyright(c) 2010-2012, Roo J Solutions Limited
41873 * @class Roo.form.ComboBoxArray
41874 * @extends Roo.form.TextField
41875 * A facebook style adder... for lists of email / people / countries etc...
41876 * pick multiple items from a combo box, and shows each one.
41878 * Fred [x] Brian [x] [Pick another |v]
41881 * For this to work: it needs various extra information
41882 * - normal combo problay has
41884 * + displayField, valueField
41886 * For our purpose...
41889 * If we change from 'extends' to wrapping...
41896 * Create a new ComboBoxArray.
41897 * @param {Object} config Configuration options
41901 Roo.form.ComboBoxArray = function(config)
41905 * @event beforeremove
41906 * Fires before remove the value from the list
41907 * @param {Roo.form.ComboBoxArray} _self This combo box array
41908 * @param {Roo.form.ComboBoxArray.Item} item removed item
41910 'beforeremove' : true,
41913 * Fires when remove the value from the list
41914 * @param {Roo.form.ComboBoxArray} _self This combo box array
41915 * @param {Roo.form.ComboBoxArray.Item} item removed item
41922 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
41924 this.items = new Roo.util.MixedCollection(false);
41926 // construct the child combo...
41936 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
41939 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
41944 // behavies liek a hiddne field
41945 inputType: 'hidden',
41947 * @cfg {Number} width The width of the box that displays the selected element
41954 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
41958 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
41960 hiddenName : false,
41963 // private the array of items that are displayed..
41965 // private - the hidden field el.
41967 // private - the filed el..
41970 //validateValue : function() { return true; }, // all values are ok!
41971 //onAddClick: function() { },
41973 onRender : function(ct, position)
41976 // create the standard hidden element
41977 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
41980 // give fake names to child combo;
41981 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
41982 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
41984 this.combo = Roo.factory(this.combo, Roo.form);
41985 this.combo.onRender(ct, position);
41986 if (typeof(this.combo.width) != 'undefined') {
41987 this.combo.onResize(this.combo.width,0);
41990 this.combo.initEvents();
41992 // assigned so form know we need to do this..
41993 this.store = this.combo.store;
41994 this.valueField = this.combo.valueField;
41995 this.displayField = this.combo.displayField ;
41998 this.combo.wrap.addClass('x-cbarray-grp');
42000 var cbwrap = this.combo.wrap.createChild(
42001 {tag: 'div', cls: 'x-cbarray-cb'},
42006 this.hiddenEl = this.combo.wrap.createChild({
42007 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42009 this.el = this.combo.wrap.createChild({
42010 tag: 'input', type:'hidden' , name: this.name, value : ''
42012 // this.el.dom.removeAttribute("name");
42015 this.outerWrap = this.combo.wrap;
42016 this.wrap = cbwrap;
42018 this.outerWrap.setWidth(this.width);
42019 this.outerWrap.dom.removeChild(this.el.dom);
42021 this.wrap.dom.appendChild(this.el.dom);
42022 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42023 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42025 this.combo.trigger.setStyle('position','relative');
42026 this.combo.trigger.setStyle('left', '0px');
42027 this.combo.trigger.setStyle('top', '2px');
42029 this.combo.el.setStyle('vertical-align', 'text-bottom');
42031 //this.trigger.setStyle('vertical-align', 'top');
42033 // this should use the code from combo really... on('add' ....)
42037 this.adder = this.outerWrap.createChild(
42038 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42040 this.adder.on('click', function(e) {
42041 _t.fireEvent('adderclick', this, e);
42045 //this.adder.on('click', this.onAddClick, _t);
42048 this.combo.on('select', function(cb, rec, ix) {
42049 this.addItem(rec.data);
42052 cb.el.dom.value = '';
42053 //cb.lastData = rec.data;
42062 getName: function()
42064 // returns hidden if it's set..
42065 if (!this.rendered) {return ''};
42066 return this.hiddenName ? this.hiddenName : this.name;
42071 onResize: function(w, h){
42074 // not sure if this is needed..
42075 //this.combo.onResize(w,h);
42077 if(typeof w != 'number'){
42078 // we do not handle it!?!?
42081 var tw = this.combo.trigger.getWidth();
42082 tw += this.addicon ? this.addicon.getWidth() : 0;
42083 tw += this.editicon ? this.editicon.getWidth() : 0;
42085 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42087 this.combo.trigger.setStyle('left', '0px');
42089 if(this.list && this.listWidth === undefined){
42090 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42091 this.list.setWidth(lw);
42092 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42099 addItem: function(rec)
42101 var valueField = this.combo.valueField;
42102 var displayField = this.combo.displayField;
42103 if (this.items.indexOfKey(rec[valueField]) > -1) {
42104 //console.log("GOT " + rec.data.id);
42108 var x = new Roo.form.ComboBoxArray.Item({
42109 //id : rec[this.idField],
42111 displayField : displayField ,
42112 tipField : displayField ,
42116 this.items.add(rec[valueField],x);
42117 // add it before the element..
42118 this.updateHiddenEl();
42119 x.render(this.outerWrap, this.wrap.dom);
42120 // add the image handler..
42123 updateHiddenEl : function()
42126 if (!this.hiddenEl) {
42130 var idField = this.combo.valueField;
42132 this.items.each(function(f) {
42133 ar.push(f.data[idField]);
42136 this.hiddenEl.dom.value = ar.join(',');
42142 this.items.clear();
42144 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42148 this.el.dom.value = '';
42149 if (this.hiddenEl) {
42150 this.hiddenEl.dom.value = '';
42154 getValue: function()
42156 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42158 setValue: function(v) // not a valid action - must use addItems..
42165 if (this.store.isLocal && (typeof(v) == 'string')) {
42166 // then we can use the store to find the values..
42167 // comma seperated at present.. this needs to allow JSON based encoding..
42168 this.hiddenEl.value = v;
42170 Roo.each(v.split(','), function(k) {
42171 Roo.log("CHECK " + this.valueField + ',' + k);
42172 var li = this.store.query(this.valueField, k);
42177 add[this.valueField] = k;
42178 add[this.displayField] = li.item(0).data[this.displayField];
42184 if (typeof(v) == 'object' ) {
42185 // then let's assume it's an array of objects..
42186 Roo.each(v, function(l) {
42194 setFromData: function(v)
42196 // this recieves an object, if setValues is called.
42198 this.el.dom.value = v[this.displayField];
42199 this.hiddenEl.dom.value = v[this.valueField];
42200 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42203 var kv = v[this.valueField];
42204 var dv = v[this.displayField];
42205 kv = typeof(kv) != 'string' ? '' : kv;
42206 dv = typeof(dv) != 'string' ? '' : dv;
42209 var keys = kv.split(',');
42210 var display = dv.split(',');
42211 for (var i = 0 ; i < keys.length; i++) {
42214 add[this.valueField] = keys[i];
42215 add[this.displayField] = display[i];
42223 * Validates the combox array value
42224 * @return {Boolean} True if the value is valid, else false
42226 validate : function(){
42227 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42228 this.clearInvalid();
42234 validateValue : function(value){
42235 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42243 isDirty : function() {
42244 if(this.disabled) {
42249 var d = Roo.decode(String(this.originalValue));
42251 return String(this.getValue()) !== String(this.originalValue);
42254 var originalValue = [];
42256 for (var i = 0; i < d.length; i++){
42257 originalValue.push(d[i][this.valueField]);
42260 return String(this.getValue()) !== String(originalValue.join(','));
42269 * @class Roo.form.ComboBoxArray.Item
42270 * @extends Roo.BoxComponent
42271 * A selected item in the list
42272 * Fred [x] Brian [x] [Pick another |v]
42275 * Create a new item.
42276 * @param {Object} config Configuration options
42279 Roo.form.ComboBoxArray.Item = function(config) {
42280 config.id = Roo.id();
42281 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42284 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42287 displayField : false,
42291 defaultAutoCreate : {
42293 cls: 'x-cbarray-item',
42300 src : Roo.BLANK_IMAGE_URL ,
42308 onRender : function(ct, position)
42310 Roo.form.Field.superclass.onRender.call(this, ct, position);
42313 var cfg = this.getAutoCreate();
42314 this.el = ct.createChild(cfg, position);
42317 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42319 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42320 this.cb.renderer(this.data) :
42321 String.format('{0}',this.data[this.displayField]);
42324 this.el.child('div').dom.setAttribute('qtip',
42325 String.format('{0}',this.data[this.tipField])
42328 this.el.child('img').on('click', this.remove, this);
42332 remove : function()
42334 if(this.cb.disabled){
42338 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42339 this.cb.items.remove(this);
42340 this.el.child('img').un('click', this.remove, this);
42342 this.cb.updateHiddenEl();
42344 this.cb.fireEvent('remove', this.cb, this);
42350 * Ext JS Library 1.1.1
42351 * Copyright(c) 2006-2007, Ext JS, LLC.
42353 * Originally Released Under LGPL - original licence link has changed is not relivant.
42356 * <script type="text/javascript">
42359 * @class Roo.form.Checkbox
42360 * @extends Roo.form.Field
42361 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42363 * Creates a new Checkbox
42364 * @param {Object} config Configuration options
42366 Roo.form.Checkbox = function(config){
42367 Roo.form.Checkbox.superclass.constructor.call(this, config);
42371 * Fires when the checkbox is checked or unchecked.
42372 * @param {Roo.form.Checkbox} this This checkbox
42373 * @param {Boolean} checked The new checked value
42379 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42381 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42383 focusClass : undefined,
42385 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42387 fieldClass: "x-form-field",
42389 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42393 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42394 * {tag: "input", type: "checkbox", autocomplete: "off"})
42396 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42398 * @cfg {String} boxLabel The text that appears beside the checkbox
42402 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42406 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42408 valueOff: '0', // value when not checked..
42410 actionMode : 'viewEl',
42413 itemCls : 'x-menu-check-item x-form-item',
42414 groupClass : 'x-menu-group-item',
42415 inputType : 'hidden',
42418 inSetChecked: false, // check that we are not calling self...
42420 inputElement: false, // real input element?
42421 basedOn: false, // ????
42423 isFormField: true, // not sure where this is needed!!!!
42425 onResize : function(){
42426 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42427 if(!this.boxLabel){
42428 this.el.alignTo(this.wrap, 'c-c');
42432 initEvents : function(){
42433 Roo.form.Checkbox.superclass.initEvents.call(this);
42434 this.el.on("click", this.onClick, this);
42435 this.el.on("change", this.onClick, this);
42439 getResizeEl : function(){
42443 getPositionEl : function(){
42448 onRender : function(ct, position){
42449 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42451 if(this.inputValue !== undefined){
42452 this.el.dom.value = this.inputValue;
42455 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42456 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42457 var viewEl = this.wrap.createChild({
42458 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42459 this.viewEl = viewEl;
42460 this.wrap.on('click', this.onClick, this);
42462 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42463 this.el.on('propertychange', this.setFromHidden, this); //ie
42468 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42469 // viewEl.on('click', this.onClick, this);
42471 //if(this.checked){
42472 this.setChecked(this.checked);
42474 //this.checked = this.el.dom;
42480 initValue : Roo.emptyFn,
42483 * Returns the checked state of the checkbox.
42484 * @return {Boolean} True if checked, else false
42486 getValue : function(){
42488 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42490 return this.valueOff;
42495 onClick : function(){
42496 if (this.disabled) {
42499 this.setChecked(!this.checked);
42501 //if(this.el.dom.checked != this.checked){
42502 // this.setValue(this.el.dom.checked);
42507 * Sets the checked state of the checkbox.
42508 * On is always based on a string comparison between inputValue and the param.
42509 * @param {Boolean/String} value - the value to set
42510 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42512 setValue : function(v,suppressEvent){
42515 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42516 //if(this.el && this.el.dom){
42517 // this.el.dom.checked = this.checked;
42518 // this.el.dom.defaultChecked = this.checked;
42520 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42521 //this.fireEvent("check", this, this.checked);
42524 setChecked : function(state,suppressEvent)
42526 if (this.inSetChecked) {
42527 this.checked = state;
42533 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42535 this.checked = state;
42536 if(suppressEvent !== true){
42537 this.fireEvent('check', this, state);
42539 this.inSetChecked = true;
42540 this.el.dom.value = state ? this.inputValue : this.valueOff;
42541 this.inSetChecked = false;
42544 // handle setting of hidden value by some other method!!?!?
42545 setFromHidden: function()
42550 //console.log("SET FROM HIDDEN");
42551 //alert('setFrom hidden');
42552 this.setValue(this.el.dom.value);
42555 onDestroy : function()
42558 Roo.get(this.viewEl).remove();
42561 Roo.form.Checkbox.superclass.onDestroy.call(this);
42564 setBoxLabel : function(str)
42566 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42571 * Ext JS Library 1.1.1
42572 * Copyright(c) 2006-2007, Ext JS, LLC.
42574 * Originally Released Under LGPL - original licence link has changed is not relivant.
42577 * <script type="text/javascript">
42581 * @class Roo.form.Radio
42582 * @extends Roo.form.Checkbox
42583 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42584 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42586 * Creates a new Radio
42587 * @param {Object} config Configuration options
42589 Roo.form.Radio = function(){
42590 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42592 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42593 inputType: 'radio',
42596 * If this radio is part of a group, it will return the selected value
42599 getGroupValue : function(){
42600 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42604 onRender : function(ct, position){
42605 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42607 if(this.inputValue !== undefined){
42608 this.el.dom.value = this.inputValue;
42611 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42612 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42613 //var viewEl = this.wrap.createChild({
42614 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42615 //this.viewEl = viewEl;
42616 //this.wrap.on('click', this.onClick, this);
42618 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42619 //this.el.on('propertychange', this.setFromHidden, this); //ie
42624 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42625 // viewEl.on('click', this.onClick, this);
42628 this.el.dom.checked = 'checked' ;
42634 });//<script type="text/javascript">
42637 * Based Ext JS Library 1.1.1
42638 * Copyright(c) 2006-2007, Ext JS, LLC.
42644 * @class Roo.HtmlEditorCore
42645 * @extends Roo.Component
42646 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42648 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42651 Roo.HtmlEditorCore = function(config){
42654 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42659 * @event initialize
42660 * Fires when the editor is fully initialized (including the iframe)
42661 * @param {Roo.HtmlEditorCore} this
42666 * Fires when the editor is first receives the focus. Any insertion must wait
42667 * until after this event.
42668 * @param {Roo.HtmlEditorCore} this
42672 * @event beforesync
42673 * Fires before the textarea is updated with content from the editor iframe. Return false
42674 * to cancel the sync.
42675 * @param {Roo.HtmlEditorCore} this
42676 * @param {String} html
42680 * @event beforepush
42681 * Fires before the iframe editor is updated with content from the textarea. Return false
42682 * to cancel the push.
42683 * @param {Roo.HtmlEditorCore} this
42684 * @param {String} html
42689 * Fires when the textarea is updated with content from the editor iframe.
42690 * @param {Roo.HtmlEditorCore} this
42691 * @param {String} html
42696 * Fires when the iframe editor is updated with content from the textarea.
42697 * @param {Roo.HtmlEditorCore} this
42698 * @param {String} html
42703 * @event editorevent
42704 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42705 * @param {Roo.HtmlEditorCore} this
42711 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42713 // defaults : white / black...
42714 this.applyBlacklists();
42721 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42725 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42731 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42736 * @cfg {Number} height (in pixels)
42740 * @cfg {Number} width (in pixels)
42745 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42748 stylesheets: false,
42753 // private properties
42754 validationEvent : false,
42756 initialized : false,
42758 sourceEditMode : false,
42759 onFocus : Roo.emptyFn,
42761 hideMode:'offsets',
42765 // blacklist + whitelisted elements..
42772 * Protected method that will not generally be called directly. It
42773 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42774 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42776 getDocMarkup : function(){
42780 // inherit styels from page...??
42781 if (this.stylesheets === false) {
42783 Roo.get(document.head).select('style').each(function(node) {
42784 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42787 Roo.get(document.head).select('link').each(function(node) {
42788 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42791 } else if (!this.stylesheets.length) {
42793 st = '<style type="text/css">' +
42794 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42800 st += '<style type="text/css">' +
42801 'IMG { cursor: pointer } ' +
42805 return '<html><head>' + st +
42806 //<style type="text/css">' +
42807 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42809 ' </head><body class="roo-htmleditor-body"></body></html>';
42813 onRender : function(ct, position)
42816 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42817 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42820 this.el.dom.style.border = '0 none';
42821 this.el.dom.setAttribute('tabIndex', -1);
42822 this.el.addClass('x-hidden hide');
42826 if(Roo.isIE){ // fix IE 1px bogus margin
42827 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42831 this.frameId = Roo.id();
42835 var iframe = this.owner.wrap.createChild({
42837 cls: 'form-control', // bootstrap..
42839 name: this.frameId,
42840 frameBorder : 'no',
42841 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42846 this.iframe = iframe.dom;
42848 this.assignDocWin();
42850 this.doc.designMode = 'on';
42853 this.doc.write(this.getDocMarkup());
42857 var task = { // must defer to wait for browser to be ready
42859 //console.log("run task?" + this.doc.readyState);
42860 this.assignDocWin();
42861 if(this.doc.body || this.doc.readyState == 'complete'){
42863 this.doc.designMode="on";
42867 Roo.TaskMgr.stop(task);
42868 this.initEditor.defer(10, this);
42875 Roo.TaskMgr.start(task);
42880 onResize : function(w, h)
42882 Roo.log('resize: ' +w + ',' + h );
42883 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
42887 if(typeof w == 'number'){
42889 this.iframe.style.width = w + 'px';
42891 if(typeof h == 'number'){
42893 this.iframe.style.height = h + 'px';
42895 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
42902 * Toggles the editor between standard and source edit mode.
42903 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42905 toggleSourceEdit : function(sourceEditMode){
42907 this.sourceEditMode = sourceEditMode === true;
42909 if(this.sourceEditMode){
42911 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
42914 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
42915 //this.iframe.className = '';
42918 //this.setSize(this.owner.wrap.getSize());
42919 //this.fireEvent('editmodechange', this, this.sourceEditMode);
42926 * Protected method that will not generally be called directly. If you need/want
42927 * custom HTML cleanup, this is the method you should override.
42928 * @param {String} html The HTML to be cleaned
42929 * return {String} The cleaned HTML
42931 cleanHtml : function(html){
42932 html = String(html);
42933 if(html.length > 5){
42934 if(Roo.isSafari){ // strip safari nonsense
42935 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
42938 if(html == ' '){
42945 * HTML Editor -> Textarea
42946 * Protected method that will not generally be called directly. Syncs the contents
42947 * of the editor iframe with the textarea.
42949 syncValue : function(){
42950 if(this.initialized){
42951 var bd = (this.doc.body || this.doc.documentElement);
42952 //this.cleanUpPaste(); -- this is done else where and causes havoc..
42953 var html = bd.innerHTML;
42955 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
42956 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
42958 html = '<div style="'+m[0]+'">' + html + '</div>';
42961 html = this.cleanHtml(html);
42962 // fix up the special chars.. normaly like back quotes in word...
42963 // however we do not want to do this with chinese..
42964 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
42965 var cc = b.charCodeAt();
42967 (cc >= 0x4E00 && cc < 0xA000 ) ||
42968 (cc >= 0x3400 && cc < 0x4E00 ) ||
42969 (cc >= 0xf900 && cc < 0xfb00 )
42975 if(this.owner.fireEvent('beforesync', this, html) !== false){
42976 this.el.dom.value = html;
42977 this.owner.fireEvent('sync', this, html);
42983 * Protected method that will not generally be called directly. Pushes the value of the textarea
42984 * into the iframe editor.
42986 pushValue : function(){
42987 if(this.initialized){
42988 var v = this.el.dom.value.trim();
42990 // if(v.length < 1){
42994 if(this.owner.fireEvent('beforepush', this, v) !== false){
42995 var d = (this.doc.body || this.doc.documentElement);
42997 this.cleanUpPaste();
42998 this.el.dom.value = d.innerHTML;
42999 this.owner.fireEvent('push', this, v);
43005 deferFocus : function(){
43006 this.focus.defer(10, this);
43010 focus : function(){
43011 if(this.win && !this.sourceEditMode){
43018 assignDocWin: function()
43020 var iframe = this.iframe;
43023 this.doc = iframe.contentWindow.document;
43024 this.win = iframe.contentWindow;
43026 // if (!Roo.get(this.frameId)) {
43029 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43030 // this.win = Roo.get(this.frameId).dom.contentWindow;
43032 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43036 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43037 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43042 initEditor : function(){
43043 //console.log("INIT EDITOR");
43044 this.assignDocWin();
43048 this.doc.designMode="on";
43050 this.doc.write(this.getDocMarkup());
43053 var dbody = (this.doc.body || this.doc.documentElement);
43054 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43055 // this copies styles from the containing element into thsi one..
43056 // not sure why we need all of this..
43057 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43059 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43060 //ss['background-attachment'] = 'fixed'; // w3c
43061 dbody.bgProperties = 'fixed'; // ie
43062 //Roo.DomHelper.applyStyles(dbody, ss);
43063 Roo.EventManager.on(this.doc, {
43064 //'mousedown': this.onEditorEvent,
43065 'mouseup': this.onEditorEvent,
43066 'dblclick': this.onEditorEvent,
43067 'click': this.onEditorEvent,
43068 'keyup': this.onEditorEvent,
43073 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43075 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43076 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43078 this.initialized = true;
43080 this.owner.fireEvent('initialize', this);
43085 onDestroy : function(){
43091 //for (var i =0; i < this.toolbars.length;i++) {
43092 // // fixme - ask toolbars for heights?
43093 // this.toolbars[i].onDestroy();
43096 //this.wrap.dom.innerHTML = '';
43097 //this.wrap.remove();
43102 onFirstFocus : function(){
43104 this.assignDocWin();
43107 this.activated = true;
43110 if(Roo.isGecko){ // prevent silly gecko errors
43112 var s = this.win.getSelection();
43113 if(!s.focusNode || s.focusNode.nodeType != 3){
43114 var r = s.getRangeAt(0);
43115 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43120 this.execCmd('useCSS', true);
43121 this.execCmd('styleWithCSS', false);
43124 this.owner.fireEvent('activate', this);
43128 adjustFont: function(btn){
43129 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43130 //if(Roo.isSafari){ // safari
43133 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43134 if(Roo.isSafari){ // safari
43135 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43136 v = (v < 10) ? 10 : v;
43137 v = (v > 48) ? 48 : v;
43138 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43143 v = Math.max(1, v+adjust);
43145 this.execCmd('FontSize', v );
43148 onEditorEvent : function(e)
43150 this.owner.fireEvent('editorevent', this, e);
43151 // this.updateToolbar();
43152 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43155 insertTag : function(tg)
43157 // could be a bit smarter... -> wrap the current selected tRoo..
43158 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43160 range = this.createRange(this.getSelection());
43161 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43162 wrappingNode.appendChild(range.extractContents());
43163 range.insertNode(wrappingNode);
43170 this.execCmd("formatblock", tg);
43174 insertText : function(txt)
43178 var range = this.createRange();
43179 range.deleteContents();
43180 //alert(Sender.getAttribute('label'));
43182 range.insertNode(this.doc.createTextNode(txt));
43188 * Executes a Midas editor command on the editor document and performs necessary focus and
43189 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43190 * @param {String} cmd The Midas command
43191 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43193 relayCmd : function(cmd, value){
43195 this.execCmd(cmd, value);
43196 this.owner.fireEvent('editorevent', this);
43197 //this.updateToolbar();
43198 this.owner.deferFocus();
43202 * Executes a Midas editor command directly on the editor document.
43203 * For visual commands, you should use {@link #relayCmd} instead.
43204 * <b>This should only be called after the editor is initialized.</b>
43205 * @param {String} cmd The Midas command
43206 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43208 execCmd : function(cmd, value){
43209 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43216 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43218 * @param {String} text | dom node..
43220 insertAtCursor : function(text)
43225 if(!this.activated){
43231 var r = this.doc.selection.createRange();
43242 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43246 // from jquery ui (MIT licenced)
43248 var win = this.win;
43250 if (win.getSelection && win.getSelection().getRangeAt) {
43251 range = win.getSelection().getRangeAt(0);
43252 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43253 range.insertNode(node);
43254 } else if (win.document.selection && win.document.selection.createRange) {
43255 // no firefox support
43256 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43257 win.document.selection.createRange().pasteHTML(txt);
43259 // no firefox support
43260 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43261 this.execCmd('InsertHTML', txt);
43270 mozKeyPress : function(e){
43272 var c = e.getCharCode(), cmd;
43275 c = String.fromCharCode(c).toLowerCase();
43289 this.cleanUpPaste.defer(100, this);
43297 e.preventDefault();
43305 fixKeys : function(){ // load time branching for fastest keydown performance
43307 return function(e){
43308 var k = e.getKey(), r;
43311 r = this.doc.selection.createRange();
43314 r.pasteHTML('    ');
43321 r = this.doc.selection.createRange();
43323 var target = r.parentElement();
43324 if(!target || target.tagName.toLowerCase() != 'li'){
43326 r.pasteHTML('<br />');
43332 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43333 this.cleanUpPaste.defer(100, this);
43339 }else if(Roo.isOpera){
43340 return function(e){
43341 var k = e.getKey();
43345 this.execCmd('InsertHTML','    ');
43348 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43349 this.cleanUpPaste.defer(100, this);
43354 }else if(Roo.isSafari){
43355 return function(e){
43356 var k = e.getKey();
43360 this.execCmd('InsertText','\t');
43364 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43365 this.cleanUpPaste.defer(100, this);
43373 getAllAncestors: function()
43375 var p = this.getSelectedNode();
43378 a.push(p); // push blank onto stack..
43379 p = this.getParentElement();
43383 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43387 a.push(this.doc.body);
43391 lastSelNode : false,
43394 getSelection : function()
43396 this.assignDocWin();
43397 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43400 getSelectedNode: function()
43402 // this may only work on Gecko!!!
43404 // should we cache this!!!!
43409 var range = this.createRange(this.getSelection()).cloneRange();
43412 var parent = range.parentElement();
43414 var testRange = range.duplicate();
43415 testRange.moveToElementText(parent);
43416 if (testRange.inRange(range)) {
43419 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43422 parent = parent.parentElement;
43427 // is ancestor a text element.
43428 var ac = range.commonAncestorContainer;
43429 if (ac.nodeType == 3) {
43430 ac = ac.parentNode;
43433 var ar = ac.childNodes;
43436 var other_nodes = [];
43437 var has_other_nodes = false;
43438 for (var i=0;i<ar.length;i++) {
43439 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43442 // fullly contained node.
43444 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43449 // probably selected..
43450 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43451 other_nodes.push(ar[i]);
43455 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43460 has_other_nodes = true;
43462 if (!nodes.length && other_nodes.length) {
43463 nodes= other_nodes;
43465 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43471 createRange: function(sel)
43473 // this has strange effects when using with
43474 // top toolbar - not sure if it's a great idea.
43475 //this.editor.contentWindow.focus();
43476 if (typeof sel != "undefined") {
43478 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43480 return this.doc.createRange();
43483 return this.doc.createRange();
43486 getParentElement: function()
43489 this.assignDocWin();
43490 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43492 var range = this.createRange(sel);
43495 var p = range.commonAncestorContainer;
43496 while (p.nodeType == 3) { // text node
43507 * Range intersection.. the hard stuff...
43511 * [ -- selected range --- ]
43515 * if end is before start or hits it. fail.
43516 * if start is after end or hits it fail.
43518 * if either hits (but other is outside. - then it's not
43524 // @see http://www.thismuchiknow.co.uk/?p=64.
43525 rangeIntersectsNode : function(range, node)
43527 var nodeRange = node.ownerDocument.createRange();
43529 nodeRange.selectNode(node);
43531 nodeRange.selectNodeContents(node);
43534 var rangeStartRange = range.cloneRange();
43535 rangeStartRange.collapse(true);
43537 var rangeEndRange = range.cloneRange();
43538 rangeEndRange.collapse(false);
43540 var nodeStartRange = nodeRange.cloneRange();
43541 nodeStartRange.collapse(true);
43543 var nodeEndRange = nodeRange.cloneRange();
43544 nodeEndRange.collapse(false);
43546 return rangeStartRange.compareBoundaryPoints(
43547 Range.START_TO_START, nodeEndRange) == -1 &&
43548 rangeEndRange.compareBoundaryPoints(
43549 Range.START_TO_START, nodeStartRange) == 1;
43553 rangeCompareNode : function(range, node)
43555 var nodeRange = node.ownerDocument.createRange();
43557 nodeRange.selectNode(node);
43559 nodeRange.selectNodeContents(node);
43563 range.collapse(true);
43565 nodeRange.collapse(true);
43567 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43568 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43570 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43572 var nodeIsBefore = ss == 1;
43573 var nodeIsAfter = ee == -1;
43575 if (nodeIsBefore && nodeIsAfter) {
43578 if (!nodeIsBefore && nodeIsAfter) {
43579 return 1; //right trailed.
43582 if (nodeIsBefore && !nodeIsAfter) {
43583 return 2; // left trailed.
43589 // private? - in a new class?
43590 cleanUpPaste : function()
43592 // cleans up the whole document..
43593 Roo.log('cleanuppaste');
43595 this.cleanUpChildren(this.doc.body);
43596 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43597 if (clean != this.doc.body.innerHTML) {
43598 this.doc.body.innerHTML = clean;
43603 cleanWordChars : function(input) {// change the chars to hex code
43604 var he = Roo.HtmlEditorCore;
43606 var output = input;
43607 Roo.each(he.swapCodes, function(sw) {
43608 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43610 output = output.replace(swapper, sw[1]);
43617 cleanUpChildren : function (n)
43619 if (!n.childNodes.length) {
43622 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43623 this.cleanUpChild(n.childNodes[i]);
43630 cleanUpChild : function (node)
43633 //console.log(node);
43634 if (node.nodeName == "#text") {
43635 // clean up silly Windows -- stuff?
43638 if (node.nodeName == "#comment") {
43639 node.parentNode.removeChild(node);
43640 // clean up silly Windows -- stuff?
43643 var lcname = node.tagName.toLowerCase();
43644 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43645 // whitelist of tags..
43647 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43649 node.parentNode.removeChild(node);
43654 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43656 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43657 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43659 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43660 // remove_keep_children = true;
43663 if (remove_keep_children) {
43664 this.cleanUpChildren(node);
43665 // inserts everything just before this node...
43666 while (node.childNodes.length) {
43667 var cn = node.childNodes[0];
43668 node.removeChild(cn);
43669 node.parentNode.insertBefore(cn, node);
43671 node.parentNode.removeChild(node);
43675 if (!node.attributes || !node.attributes.length) {
43676 this.cleanUpChildren(node);
43680 function cleanAttr(n,v)
43683 if (v.match(/^\./) || v.match(/^\//)) {
43686 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
43689 if (v.match(/^#/)) {
43692 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43693 node.removeAttribute(n);
43697 var cwhite = this.cwhite;
43698 var cblack = this.cblack;
43700 function cleanStyle(n,v)
43702 if (v.match(/expression/)) { //XSS?? should we even bother..
43703 node.removeAttribute(n);
43707 var parts = v.split(/;/);
43710 Roo.each(parts, function(p) {
43711 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43715 var l = p.split(':').shift().replace(/\s+/g,'');
43716 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43718 if ( cwhite.length && cblack.indexOf(l) > -1) {
43719 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43720 //node.removeAttribute(n);
43724 // only allow 'c whitelisted system attributes'
43725 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43726 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43727 //node.removeAttribute(n);
43737 if (clean.length) {
43738 node.setAttribute(n, clean.join(';'));
43740 node.removeAttribute(n);
43746 for (var i = node.attributes.length-1; i > -1 ; i--) {
43747 var a = node.attributes[i];
43750 if (a.name.toLowerCase().substr(0,2)=='on') {
43751 node.removeAttribute(a.name);
43754 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43755 node.removeAttribute(a.name);
43758 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43759 cleanAttr(a.name,a.value); // fixme..
43762 if (a.name == 'style') {
43763 cleanStyle(a.name,a.value);
43766 /// clean up MS crap..
43767 // tecnically this should be a list of valid class'es..
43770 if (a.name == 'class') {
43771 if (a.value.match(/^Mso/)) {
43772 node.className = '';
43775 if (a.value.match(/body/)) {
43776 node.className = '';
43787 this.cleanUpChildren(node);
43793 * Clean up MS wordisms...
43795 cleanWord : function(node)
43800 this.cleanWord(this.doc.body);
43803 if (node.nodeName == "#text") {
43804 // clean up silly Windows -- stuff?
43807 if (node.nodeName == "#comment") {
43808 node.parentNode.removeChild(node);
43809 // clean up silly Windows -- stuff?
43813 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43814 node.parentNode.removeChild(node);
43818 // remove - but keep children..
43819 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43820 while (node.childNodes.length) {
43821 var cn = node.childNodes[0];
43822 node.removeChild(cn);
43823 node.parentNode.insertBefore(cn, node);
43825 node.parentNode.removeChild(node);
43826 this.iterateChildren(node, this.cleanWord);
43830 if (node.className.length) {
43832 var cn = node.className.split(/\W+/);
43834 Roo.each(cn, function(cls) {
43835 if (cls.match(/Mso[a-zA-Z]+/)) {
43840 node.className = cna.length ? cna.join(' ') : '';
43842 node.removeAttribute("class");
43846 if (node.hasAttribute("lang")) {
43847 node.removeAttribute("lang");
43850 if (node.hasAttribute("style")) {
43852 var styles = node.getAttribute("style").split(";");
43854 Roo.each(styles, function(s) {
43855 if (!s.match(/:/)) {
43858 var kv = s.split(":");
43859 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
43862 // what ever is left... we allow.
43865 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43866 if (!nstyle.length) {
43867 node.removeAttribute('style');
43870 this.iterateChildren(node, this.cleanWord);
43876 * iterateChildren of a Node, calling fn each time, using this as the scole..
43877 * @param {DomNode} node node to iterate children of.
43878 * @param {Function} fn method of this class to call on each item.
43880 iterateChildren : function(node, fn)
43882 if (!node.childNodes.length) {
43885 for (var i = node.childNodes.length-1; i > -1 ; i--) {
43886 fn.call(this, node.childNodes[i])
43892 * cleanTableWidths.
43894 * Quite often pasting from word etc.. results in tables with column and widths.
43895 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
43898 cleanTableWidths : function(node)
43903 this.cleanTableWidths(this.doc.body);
43908 if (node.nodeName == "#text" || node.nodeName == "#comment") {
43911 Roo.log(node.tagName);
43912 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
43913 this.iterateChildren(node, this.cleanTableWidths);
43916 if (node.hasAttribute('width')) {
43917 node.removeAttribute('width');
43921 if (node.hasAttribute("style")) {
43924 var styles = node.getAttribute("style").split(";");
43926 Roo.each(styles, function(s) {
43927 if (!s.match(/:/)) {
43930 var kv = s.split(":");
43931 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
43934 // what ever is left... we allow.
43937 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43938 if (!nstyle.length) {
43939 node.removeAttribute('style');
43943 this.iterateChildren(node, this.cleanTableWidths);
43951 domToHTML : function(currentElement, depth, nopadtext) {
43953 depth = depth || 0;
43954 nopadtext = nopadtext || false;
43956 if (!currentElement) {
43957 return this.domToHTML(this.doc.body);
43960 //Roo.log(currentElement);
43962 var allText = false;
43963 var nodeName = currentElement.nodeName;
43964 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
43966 if (nodeName == '#text') {
43968 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
43973 if (nodeName != 'BODY') {
43976 // Prints the node tagName, such as <A>, <IMG>, etc
43979 for(i = 0; i < currentElement.attributes.length;i++) {
43981 var aname = currentElement.attributes.item(i).name;
43982 if (!currentElement.attributes.item(i).value.length) {
43985 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
43988 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
43997 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44000 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44005 // Traverse the tree
44007 var currentElementChild = currentElement.childNodes.item(i);
44008 var allText = true;
44009 var innerHTML = '';
44011 while (currentElementChild) {
44012 // Formatting code (indent the tree so it looks nice on the screen)
44013 var nopad = nopadtext;
44014 if (lastnode == 'SPAN') {
44018 if (currentElementChild.nodeName == '#text') {
44019 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44020 toadd = nopadtext ? toadd : toadd.trim();
44021 if (!nopad && toadd.length > 80) {
44022 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44024 innerHTML += toadd;
44027 currentElementChild = currentElement.childNodes.item(i);
44033 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44035 // Recursively traverse the tree structure of the child node
44036 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44037 lastnode = currentElementChild.nodeName;
44039 currentElementChild=currentElement.childNodes.item(i);
44045 // The remaining code is mostly for formatting the tree
44046 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44051 ret+= "</"+tagName+">";
44057 applyBlacklists : function()
44059 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44060 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44064 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44065 if (b.indexOf(tag) > -1) {
44068 this.white.push(tag);
44072 Roo.each(w, function(tag) {
44073 if (b.indexOf(tag) > -1) {
44076 if (this.white.indexOf(tag) > -1) {
44079 this.white.push(tag);
44084 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44085 if (w.indexOf(tag) > -1) {
44088 this.black.push(tag);
44092 Roo.each(b, function(tag) {
44093 if (w.indexOf(tag) > -1) {
44096 if (this.black.indexOf(tag) > -1) {
44099 this.black.push(tag);
44104 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44105 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44109 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44110 if (b.indexOf(tag) > -1) {
44113 this.cwhite.push(tag);
44117 Roo.each(w, function(tag) {
44118 if (b.indexOf(tag) > -1) {
44121 if (this.cwhite.indexOf(tag) > -1) {
44124 this.cwhite.push(tag);
44129 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44130 if (w.indexOf(tag) > -1) {
44133 this.cblack.push(tag);
44137 Roo.each(b, function(tag) {
44138 if (w.indexOf(tag) > -1) {
44141 if (this.cblack.indexOf(tag) > -1) {
44144 this.cblack.push(tag);
44149 setStylesheets : function(stylesheets)
44151 if(typeof(stylesheets) == 'string'){
44152 Roo.get(this.iframe.contentDocument.head).createChild({
44154 rel : 'stylesheet',
44163 Roo.each(stylesheets, function(s) {
44168 Roo.get(_this.iframe.contentDocument.head).createChild({
44170 rel : 'stylesheet',
44179 removeStylesheets : function()
44183 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44188 // hide stuff that is not compatible
44202 * @event specialkey
44206 * @cfg {String} fieldClass @hide
44209 * @cfg {String} focusClass @hide
44212 * @cfg {String} autoCreate @hide
44215 * @cfg {String} inputType @hide
44218 * @cfg {String} invalidClass @hide
44221 * @cfg {String} invalidText @hide
44224 * @cfg {String} msgFx @hide
44227 * @cfg {String} validateOnBlur @hide
44231 Roo.HtmlEditorCore.white = [
44232 'area', 'br', 'img', 'input', 'hr', 'wbr',
44234 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44235 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44236 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44237 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44238 'table', 'ul', 'xmp',
44240 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44243 'dir', 'menu', 'ol', 'ul', 'dl',
44249 Roo.HtmlEditorCore.black = [
44250 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44252 'base', 'basefont', 'bgsound', 'blink', 'body',
44253 'frame', 'frameset', 'head', 'html', 'ilayer',
44254 'iframe', 'layer', 'link', 'meta', 'object',
44255 'script', 'style' ,'title', 'xml' // clean later..
44257 Roo.HtmlEditorCore.clean = [
44258 'script', 'style', 'title', 'xml'
44260 Roo.HtmlEditorCore.remove = [
44265 Roo.HtmlEditorCore.ablack = [
44269 Roo.HtmlEditorCore.aclean = [
44270 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44274 Roo.HtmlEditorCore.pwhite= [
44275 'http', 'https', 'mailto'
44278 // white listed style attributes.
44279 Roo.HtmlEditorCore.cwhite= [
44280 // 'text-align', /// default is to allow most things..
44286 // black listed style attributes.
44287 Roo.HtmlEditorCore.cblack= [
44288 // 'font-size' -- this can be set by the project
44292 Roo.HtmlEditorCore.swapCodes =[
44303 //<script type="text/javascript">
44306 * Ext JS Library 1.1.1
44307 * Copyright(c) 2006-2007, Ext JS, LLC.
44313 Roo.form.HtmlEditor = function(config){
44317 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44319 if (!this.toolbars) {
44320 this.toolbars = [];
44322 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44328 * @class Roo.form.HtmlEditor
44329 * @extends Roo.form.Field
44330 * Provides a lightweight HTML Editor component.
44332 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44334 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44335 * supported by this editor.</b><br/><br/>
44336 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44337 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44339 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44341 * @cfg {Boolean} clearUp
44345 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44350 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44355 * @cfg {Number} height (in pixels)
44359 * @cfg {Number} width (in pixels)
44364 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44367 stylesheets: false,
44371 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44376 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44382 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44387 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44395 // private properties
44396 validationEvent : false,
44398 initialized : false,
44401 onFocus : Roo.emptyFn,
44403 hideMode:'offsets',
44405 actionMode : 'container', // defaults to hiding it...
44407 defaultAutoCreate : { // modified by initCompnoent..
44409 style:"width:500px;height:300px;",
44410 autocomplete: "new-password"
44414 initComponent : function(){
44417 * @event initialize
44418 * Fires when the editor is fully initialized (including the iframe)
44419 * @param {HtmlEditor} this
44424 * Fires when the editor is first receives the focus. Any insertion must wait
44425 * until after this event.
44426 * @param {HtmlEditor} this
44430 * @event beforesync
44431 * Fires before the textarea is updated with content from the editor iframe. Return false
44432 * to cancel the sync.
44433 * @param {HtmlEditor} this
44434 * @param {String} html
44438 * @event beforepush
44439 * Fires before the iframe editor is updated with content from the textarea. Return false
44440 * to cancel the push.
44441 * @param {HtmlEditor} this
44442 * @param {String} html
44447 * Fires when the textarea is updated with content from the editor iframe.
44448 * @param {HtmlEditor} this
44449 * @param {String} html
44454 * Fires when the iframe editor is updated with content from the textarea.
44455 * @param {HtmlEditor} this
44456 * @param {String} html
44460 * @event editmodechange
44461 * Fires when the editor switches edit modes
44462 * @param {HtmlEditor} this
44463 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44465 editmodechange: true,
44467 * @event editorevent
44468 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44469 * @param {HtmlEditor} this
44473 * @event firstfocus
44474 * Fires when on first focus - needed by toolbars..
44475 * @param {HtmlEditor} this
44480 * Auto save the htmlEditor value as a file into Events
44481 * @param {HtmlEditor} this
44485 * @event savedpreview
44486 * preview the saved version of htmlEditor
44487 * @param {HtmlEditor} this
44489 savedpreview: true,
44492 * @event stylesheetsclick
44493 * Fires when press the Sytlesheets button
44494 * @param {Roo.HtmlEditorCore} this
44496 stylesheetsclick: true
44498 this.defaultAutoCreate = {
44500 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44501 autocomplete: "new-password"
44506 * Protected method that will not generally be called directly. It
44507 * is called when the editor creates its toolbar. Override this method if you need to
44508 * add custom toolbar buttons.
44509 * @param {HtmlEditor} editor
44511 createToolbar : function(editor){
44512 Roo.log("create toolbars");
44513 if (!editor.toolbars || !editor.toolbars.length) {
44514 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44517 for (var i =0 ; i < editor.toolbars.length;i++) {
44518 editor.toolbars[i] = Roo.factory(
44519 typeof(editor.toolbars[i]) == 'string' ?
44520 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44521 Roo.form.HtmlEditor);
44522 editor.toolbars[i].init(editor);
44530 onRender : function(ct, position)
44533 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44535 this.wrap = this.el.wrap({
44536 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44539 this.editorcore.onRender(ct, position);
44541 if (this.resizable) {
44542 this.resizeEl = new Roo.Resizable(this.wrap, {
44546 minHeight : this.height,
44547 height: this.height,
44548 handles : this.resizable,
44551 resize : function(r, w, h) {
44552 _t.onResize(w,h); // -something
44558 this.createToolbar(this);
44562 this.setSize(this.wrap.getSize());
44564 if (this.resizeEl) {
44565 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44566 // should trigger onReize..
44569 this.keyNav = new Roo.KeyNav(this.el, {
44571 "tab" : function(e){
44572 e.preventDefault();
44574 var value = this.getValue();
44576 var start = this.el.dom.selectionStart;
44577 var end = this.el.dom.selectionEnd;
44581 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44582 this.el.dom.setSelectionRange(end + 1, end + 1);
44586 var f = value.substring(0, start).split("\t");
44588 if(f.pop().length != 0){
44592 this.setValue(f.join("\t") + value.substring(end));
44593 this.el.dom.setSelectionRange(start - 1, start - 1);
44597 "home" : function(e){
44598 e.preventDefault();
44600 var curr = this.el.dom.selectionStart;
44601 var lines = this.getValue().split("\n");
44608 this.el.dom.setSelectionRange(0, 0);
44614 for (var i = 0; i < lines.length;i++) {
44615 pos += lines[i].length;
44625 pos -= lines[i].length;
44631 this.el.dom.setSelectionRange(pos, pos);
44635 this.el.dom.selectionStart = pos;
44636 this.el.dom.selectionEnd = curr;
44639 "end" : function(e){
44640 e.preventDefault();
44642 var curr = this.el.dom.selectionStart;
44643 var lines = this.getValue().split("\n");
44650 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44656 for (var i = 0; i < lines.length;i++) {
44658 pos += lines[i].length;
44672 this.el.dom.setSelectionRange(pos, pos);
44676 this.el.dom.selectionStart = curr;
44677 this.el.dom.selectionEnd = pos;
44682 doRelay : function(foo, bar, hname){
44683 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44689 // if(this.autosave && this.w){
44690 // this.autoSaveFn = setInterval(this.autosave, 1000);
44695 onResize : function(w, h)
44697 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44702 if(typeof w == 'number'){
44703 var aw = w - this.wrap.getFrameWidth('lr');
44704 this.el.setWidth(this.adjustWidth('textarea', aw));
44707 if(typeof h == 'number'){
44709 for (var i =0; i < this.toolbars.length;i++) {
44710 // fixme - ask toolbars for heights?
44711 tbh += this.toolbars[i].tb.el.getHeight();
44712 if (this.toolbars[i].footer) {
44713 tbh += this.toolbars[i].footer.el.getHeight();
44720 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44721 ah -= 5; // knock a few pixes off for look..
44723 this.el.setHeight(this.adjustWidth('textarea', ah));
44727 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44728 this.editorcore.onResize(ew,eh);
44733 * Toggles the editor between standard and source edit mode.
44734 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44736 toggleSourceEdit : function(sourceEditMode)
44738 this.editorcore.toggleSourceEdit(sourceEditMode);
44740 if(this.editorcore.sourceEditMode){
44741 Roo.log('editor - showing textarea');
44744 // Roo.log(this.syncValue());
44745 this.editorcore.syncValue();
44746 this.el.removeClass('x-hidden');
44747 this.el.dom.removeAttribute('tabIndex');
44750 for (var i = 0; i < this.toolbars.length; i++) {
44751 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44752 this.toolbars[i].tb.hide();
44753 this.toolbars[i].footer.hide();
44758 Roo.log('editor - hiding textarea');
44760 // Roo.log(this.pushValue());
44761 this.editorcore.pushValue();
44763 this.el.addClass('x-hidden');
44764 this.el.dom.setAttribute('tabIndex', -1);
44766 for (var i = 0; i < this.toolbars.length; i++) {
44767 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44768 this.toolbars[i].tb.show();
44769 this.toolbars[i].footer.show();
44773 //this.deferFocus();
44776 this.setSize(this.wrap.getSize());
44777 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44779 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44782 // private (for BoxComponent)
44783 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44785 // private (for BoxComponent)
44786 getResizeEl : function(){
44790 // private (for BoxComponent)
44791 getPositionEl : function(){
44796 initEvents : function(){
44797 this.originalValue = this.getValue();
44801 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44804 markInvalid : Roo.emptyFn,
44806 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44809 clearInvalid : Roo.emptyFn,
44811 setValue : function(v){
44812 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44813 this.editorcore.pushValue();
44818 deferFocus : function(){
44819 this.focus.defer(10, this);
44823 focus : function(){
44824 this.editorcore.focus();
44830 onDestroy : function(){
44836 for (var i =0; i < this.toolbars.length;i++) {
44837 // fixme - ask toolbars for heights?
44838 this.toolbars[i].onDestroy();
44841 this.wrap.dom.innerHTML = '';
44842 this.wrap.remove();
44847 onFirstFocus : function(){
44848 //Roo.log("onFirstFocus");
44849 this.editorcore.onFirstFocus();
44850 for (var i =0; i < this.toolbars.length;i++) {
44851 this.toolbars[i].onFirstFocus();
44857 syncValue : function()
44859 this.editorcore.syncValue();
44862 pushValue : function()
44864 this.editorcore.pushValue();
44867 setStylesheets : function(stylesheets)
44869 this.editorcore.setStylesheets(stylesheets);
44872 removeStylesheets : function()
44874 this.editorcore.removeStylesheets();
44878 // hide stuff that is not compatible
44892 * @event specialkey
44896 * @cfg {String} fieldClass @hide
44899 * @cfg {String} focusClass @hide
44902 * @cfg {String} autoCreate @hide
44905 * @cfg {String} inputType @hide
44908 * @cfg {String} invalidClass @hide
44911 * @cfg {String} invalidText @hide
44914 * @cfg {String} msgFx @hide
44917 * @cfg {String} validateOnBlur @hide
44921 // <script type="text/javascript">
44924 * Ext JS Library 1.1.1
44925 * Copyright(c) 2006-2007, Ext JS, LLC.
44931 * @class Roo.form.HtmlEditorToolbar1
44936 new Roo.form.HtmlEditor({
44939 new Roo.form.HtmlEditorToolbar1({
44940 disable : { fonts: 1 , format: 1, ..., ... , ...],
44946 * @cfg {Object} disable List of elements to disable..
44947 * @cfg {Array} btns List of additional buttons.
44951 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
44954 Roo.form.HtmlEditor.ToolbarStandard = function(config)
44957 Roo.apply(this, config);
44959 // default disabled, based on 'good practice'..
44960 this.disable = this.disable || {};
44961 Roo.applyIf(this.disable, {
44964 specialElements : true
44968 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44969 // dont call parent... till later.
44972 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
44979 editorcore : false,
44981 * @cfg {Object} disable List of toolbar elements to disable
44988 * @cfg {String} createLinkText The default text for the create link prompt
44990 createLinkText : 'Please enter the URL for the link:',
44992 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
44994 defaultLinkValue : 'http:/'+'/',
44998 * @cfg {Array} fontFamilies An array of available font families
45016 // "á" , ?? a acute?
45021 "°" // , // degrees
45023 // "é" , // e ecute
45024 // "ú" , // u ecute?
45027 specialElements : [
45029 text: "Insert Table",
45032 ihtml : '<table><tr><td>Cell</td></tr></table>'
45036 text: "Insert Image",
45039 ihtml : '<img src="about:blank"/>'
45048 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45049 "input:submit", "input:button", "select", "textarea", "label" ],
45052 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45054 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45062 * @cfg {String} defaultFont default font to use.
45064 defaultFont: 'tahoma',
45066 fontSelect : false,
45069 formatCombo : false,
45071 init : function(editor)
45073 this.editor = editor;
45074 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45075 var editorcore = this.editorcore;
45079 var fid = editorcore.frameId;
45081 function btn(id, toggle, handler){
45082 var xid = fid + '-'+ id ;
45086 cls : 'x-btn-icon x-edit-'+id,
45087 enableToggle:toggle !== false,
45088 scope: _t, // was editor...
45089 handler:handler||_t.relayBtnCmd,
45090 clickEvent:'mousedown',
45091 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45098 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45100 // stop form submits
45101 tb.el.on('click', function(e){
45102 e.preventDefault(); // what does this do?
45105 if(!this.disable.font) { // && !Roo.isSafari){
45106 /* why no safari for fonts
45107 editor.fontSelect = tb.el.createChild({
45110 cls:'x-font-select',
45111 html: this.createFontOptions()
45114 editor.fontSelect.on('change', function(){
45115 var font = editor.fontSelect.dom.value;
45116 editor.relayCmd('fontname', font);
45117 editor.deferFocus();
45121 editor.fontSelect.dom,
45127 if(!this.disable.formats){
45128 this.formatCombo = new Roo.form.ComboBox({
45129 store: new Roo.data.SimpleStore({
45132 data : this.formats // from states.js
45136 //autoCreate : {tag: "div", size: "20"},
45137 displayField:'tag',
45141 triggerAction: 'all',
45142 emptyText:'Add tag',
45143 selectOnFocus:true,
45146 'select': function(c, r, i) {
45147 editorcore.insertTag(r.get('tag'));
45153 tb.addField(this.formatCombo);
45157 if(!this.disable.format){
45162 btn('strikethrough')
45165 if(!this.disable.fontSize){
45170 btn('increasefontsize', false, editorcore.adjustFont),
45171 btn('decreasefontsize', false, editorcore.adjustFont)
45176 if(!this.disable.colors){
45179 id:editorcore.frameId +'-forecolor',
45180 cls:'x-btn-icon x-edit-forecolor',
45181 clickEvent:'mousedown',
45182 tooltip: this.buttonTips['forecolor'] || undefined,
45184 menu : new Roo.menu.ColorMenu({
45185 allowReselect: true,
45186 focus: Roo.emptyFn,
45189 selectHandler: function(cp, color){
45190 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45191 editor.deferFocus();
45194 clickEvent:'mousedown'
45197 id:editorcore.frameId +'backcolor',
45198 cls:'x-btn-icon x-edit-backcolor',
45199 clickEvent:'mousedown',
45200 tooltip: this.buttonTips['backcolor'] || undefined,
45202 menu : new Roo.menu.ColorMenu({
45203 focus: Roo.emptyFn,
45206 allowReselect: true,
45207 selectHandler: function(cp, color){
45209 editorcore.execCmd('useCSS', false);
45210 editorcore.execCmd('hilitecolor', color);
45211 editorcore.execCmd('useCSS', true);
45212 editor.deferFocus();
45214 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45215 Roo.isSafari || Roo.isIE ? '#'+color : color);
45216 editor.deferFocus();
45220 clickEvent:'mousedown'
45225 // now add all the items...
45228 if(!this.disable.alignments){
45231 btn('justifyleft'),
45232 btn('justifycenter'),
45233 btn('justifyright')
45237 //if(!Roo.isSafari){
45238 if(!this.disable.links){
45241 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45245 if(!this.disable.lists){
45248 btn('insertorderedlist'),
45249 btn('insertunorderedlist')
45252 if(!this.disable.sourceEdit){
45255 btn('sourceedit', true, function(btn){
45256 this.toggleSourceEdit(btn.pressed);
45263 // special menu.. - needs to be tidied up..
45264 if (!this.disable.special) {
45267 cls: 'x-edit-none',
45273 for (var i =0; i < this.specialChars.length; i++) {
45274 smenu.menu.items.push({
45276 html: this.specialChars[i],
45277 handler: function(a,b) {
45278 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45279 //editor.insertAtCursor(a.html);
45293 if (!this.disable.cleanStyles) {
45295 cls: 'x-btn-icon x-btn-clear',
45301 for (var i =0; i < this.cleanStyles.length; i++) {
45302 cmenu.menu.items.push({
45303 actiontype : this.cleanStyles[i],
45304 html: 'Remove ' + this.cleanStyles[i],
45305 handler: function(a,b) {
45308 var c = Roo.get(editorcore.doc.body);
45309 c.select('[style]').each(function(s) {
45310 s.dom.style.removeProperty(a.actiontype);
45312 editorcore.syncValue();
45317 cmenu.menu.items.push({
45318 actiontype : 'tablewidths',
45319 html: 'Remove Table Widths',
45320 handler: function(a,b) {
45321 editorcore.cleanTableWidths();
45322 editorcore.syncValue();
45326 cmenu.menu.items.push({
45327 actiontype : 'word',
45328 html: 'Remove MS Word Formating',
45329 handler: function(a,b) {
45330 editorcore.cleanWord();
45331 editorcore.syncValue();
45336 cmenu.menu.items.push({
45337 actiontype : 'all',
45338 html: 'Remove All Styles',
45339 handler: function(a,b) {
45341 var c = Roo.get(editorcore.doc.body);
45342 c.select('[style]').each(function(s) {
45343 s.dom.removeAttribute('style');
45345 editorcore.syncValue();
45350 cmenu.menu.items.push({
45351 actiontype : 'all',
45352 html: 'Remove All CSS Classes',
45353 handler: function(a,b) {
45355 var c = Roo.get(editorcore.doc.body);
45356 c.select('[class]').each(function(s) {
45357 s.dom.className = '';
45359 editorcore.syncValue();
45364 cmenu.menu.items.push({
45365 actiontype : 'tidy',
45366 html: 'Tidy HTML Source',
45367 handler: function(a,b) {
45368 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45369 editorcore.syncValue();
45378 if (!this.disable.specialElements) {
45381 cls: 'x-edit-none',
45386 for (var i =0; i < this.specialElements.length; i++) {
45387 semenu.menu.items.push(
45389 handler: function(a,b) {
45390 editor.insertAtCursor(this.ihtml);
45392 }, this.specialElements[i])
45404 for(var i =0; i< this.btns.length;i++) {
45405 var b = Roo.factory(this.btns[i],Roo.form);
45406 b.cls = 'x-edit-none';
45408 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45409 b.cls += ' x-init-enable';
45412 b.scope = editorcore;
45420 // disable everything...
45422 this.tb.items.each(function(item){
45425 item.id != editorcore.frameId+ '-sourceedit' &&
45426 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45432 this.rendered = true;
45434 // the all the btns;
45435 editor.on('editorevent', this.updateToolbar, this);
45436 // other toolbars need to implement this..
45437 //editor.on('editmodechange', this.updateToolbar, this);
45441 relayBtnCmd : function(btn) {
45442 this.editorcore.relayCmd(btn.cmd);
45444 // private used internally
45445 createLink : function(){
45446 Roo.log("create link?");
45447 var url = prompt(this.createLinkText, this.defaultLinkValue);
45448 if(url && url != 'http:/'+'/'){
45449 this.editorcore.relayCmd('createlink', url);
45455 * Protected method that will not generally be called directly. It triggers
45456 * a toolbar update by reading the markup state of the current selection in the editor.
45458 updateToolbar: function(){
45460 if(!this.editorcore.activated){
45461 this.editor.onFirstFocus();
45465 var btns = this.tb.items.map,
45466 doc = this.editorcore.doc,
45467 frameId = this.editorcore.frameId;
45469 if(!this.disable.font && !Roo.isSafari){
45471 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45472 if(name != this.fontSelect.dom.value){
45473 this.fontSelect.dom.value = name;
45477 if(!this.disable.format){
45478 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45479 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45480 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45481 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45483 if(!this.disable.alignments){
45484 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45485 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45486 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45488 if(!Roo.isSafari && !this.disable.lists){
45489 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45490 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45493 var ans = this.editorcore.getAllAncestors();
45494 if (this.formatCombo) {
45497 var store = this.formatCombo.store;
45498 this.formatCombo.setValue("");
45499 for (var i =0; i < ans.length;i++) {
45500 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45502 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45510 // hides menus... - so this cant be on a menu...
45511 Roo.menu.MenuMgr.hideAll();
45513 //this.editorsyncValue();
45517 createFontOptions : function(){
45518 var buf = [], fs = this.fontFamilies, ff, lc;
45522 for(var i = 0, len = fs.length; i< len; i++){
45524 lc = ff.toLowerCase();
45526 '<option value="',lc,'" style="font-family:',ff,';"',
45527 (this.defaultFont == lc ? ' selected="true">' : '>'),
45532 return buf.join('');
45535 toggleSourceEdit : function(sourceEditMode){
45537 Roo.log("toolbar toogle");
45538 if(sourceEditMode === undefined){
45539 sourceEditMode = !this.sourceEditMode;
45541 this.sourceEditMode = sourceEditMode === true;
45542 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45543 // just toggle the button?
45544 if(btn.pressed !== this.sourceEditMode){
45545 btn.toggle(this.sourceEditMode);
45549 if(sourceEditMode){
45550 Roo.log("disabling buttons");
45551 this.tb.items.each(function(item){
45552 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45558 Roo.log("enabling buttons");
45559 if(this.editorcore.initialized){
45560 this.tb.items.each(function(item){
45566 Roo.log("calling toggole on editor");
45567 // tell the editor that it's been pressed..
45568 this.editor.toggleSourceEdit(sourceEditMode);
45572 * Object collection of toolbar tooltips for the buttons in the editor. The key
45573 * is the command id associated with that button and the value is a valid QuickTips object.
45578 title: 'Bold (Ctrl+B)',
45579 text: 'Make the selected text bold.',
45580 cls: 'x-html-editor-tip'
45583 title: 'Italic (Ctrl+I)',
45584 text: 'Make the selected text italic.',
45585 cls: 'x-html-editor-tip'
45593 title: 'Bold (Ctrl+B)',
45594 text: 'Make the selected text bold.',
45595 cls: 'x-html-editor-tip'
45598 title: 'Italic (Ctrl+I)',
45599 text: 'Make the selected text italic.',
45600 cls: 'x-html-editor-tip'
45603 title: 'Underline (Ctrl+U)',
45604 text: 'Underline the selected text.',
45605 cls: 'x-html-editor-tip'
45608 title: 'Strikethrough',
45609 text: 'Strikethrough the selected text.',
45610 cls: 'x-html-editor-tip'
45612 increasefontsize : {
45613 title: 'Grow Text',
45614 text: 'Increase the font size.',
45615 cls: 'x-html-editor-tip'
45617 decreasefontsize : {
45618 title: 'Shrink Text',
45619 text: 'Decrease the font size.',
45620 cls: 'x-html-editor-tip'
45623 title: 'Text Highlight Color',
45624 text: 'Change the background color of the selected text.',
45625 cls: 'x-html-editor-tip'
45628 title: 'Font Color',
45629 text: 'Change the color of the selected text.',
45630 cls: 'x-html-editor-tip'
45633 title: 'Align Text Left',
45634 text: 'Align text to the left.',
45635 cls: 'x-html-editor-tip'
45638 title: 'Center Text',
45639 text: 'Center text in the editor.',
45640 cls: 'x-html-editor-tip'
45643 title: 'Align Text Right',
45644 text: 'Align text to the right.',
45645 cls: 'x-html-editor-tip'
45647 insertunorderedlist : {
45648 title: 'Bullet List',
45649 text: 'Start a bulleted list.',
45650 cls: 'x-html-editor-tip'
45652 insertorderedlist : {
45653 title: 'Numbered List',
45654 text: 'Start a numbered list.',
45655 cls: 'x-html-editor-tip'
45658 title: 'Hyperlink',
45659 text: 'Make the selected text a hyperlink.',
45660 cls: 'x-html-editor-tip'
45663 title: 'Source Edit',
45664 text: 'Switch to source editing mode.',
45665 cls: 'x-html-editor-tip'
45669 onDestroy : function(){
45672 this.tb.items.each(function(item){
45674 item.menu.removeAll();
45676 item.menu.el.destroy();
45684 onFirstFocus: function() {
45685 this.tb.items.each(function(item){
45694 // <script type="text/javascript">
45697 * Ext JS Library 1.1.1
45698 * Copyright(c) 2006-2007, Ext JS, LLC.
45705 * @class Roo.form.HtmlEditor.ToolbarContext
45710 new Roo.form.HtmlEditor({
45713 { xtype: 'ToolbarStandard', styles : {} }
45714 { xtype: 'ToolbarContext', disable : {} }
45720 * @config : {Object} disable List of elements to disable.. (not done yet.)
45721 * @config : {Object} styles Map of styles available.
45725 Roo.form.HtmlEditor.ToolbarContext = function(config)
45728 Roo.apply(this, config);
45729 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45730 // dont call parent... till later.
45731 this.styles = this.styles || {};
45736 Roo.form.HtmlEditor.ToolbarContext.types = {
45748 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45814 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45819 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45829 style : 'fontFamily',
45830 displayField: 'display',
45831 optname : 'font-family',
45880 // should we really allow this??
45881 // should this just be
45892 style : 'fontFamily',
45893 displayField: 'display',
45894 optname : 'font-family',
45901 style : 'fontFamily',
45902 displayField: 'display',
45903 optname : 'font-family',
45910 style : 'fontFamily',
45911 displayField: 'display',
45912 optname : 'font-family',
45923 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
45924 Roo.form.HtmlEditor.ToolbarContext.stores = false;
45926 Roo.form.HtmlEditor.ToolbarContext.options = {
45928 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
45929 [ 'Courier New', 'Courier New'],
45930 [ 'Tahoma', 'Tahoma'],
45931 [ 'Times New Roman,serif', 'Times'],
45932 [ 'Verdana','Verdana' ]
45936 // fixme - these need to be configurable..
45939 //Roo.form.HtmlEditor.ToolbarContext.types
45942 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
45949 editorcore : false,
45951 * @cfg {Object} disable List of toolbar elements to disable
45956 * @cfg {Object} styles List of styles
45957 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
45959 * These must be defined in the page, so they get rendered correctly..
45970 init : function(editor)
45972 this.editor = editor;
45973 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45974 var editorcore = this.editorcore;
45976 var fid = editorcore.frameId;
45978 function btn(id, toggle, handler){
45979 var xid = fid + '-'+ id ;
45983 cls : 'x-btn-icon x-edit-'+id,
45984 enableToggle:toggle !== false,
45985 scope: editorcore, // was editor...
45986 handler:handler||editorcore.relayBtnCmd,
45987 clickEvent:'mousedown',
45988 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45992 // create a new element.
45993 var wdiv = editor.wrap.createChild({
45995 }, editor.wrap.dom.firstChild.nextSibling, true);
45997 // can we do this more than once??
45999 // stop form submits
46002 // disable everything...
46003 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46004 this.toolbars = {};
46006 for (var i in ty) {
46008 this.toolbars[i] = this.buildToolbar(ty[i],i);
46010 this.tb = this.toolbars.BODY;
46012 this.buildFooter();
46013 this.footer.show();
46014 editor.on('hide', function( ) { this.footer.hide() }, this);
46015 editor.on('show', function( ) { this.footer.show() }, this);
46018 this.rendered = true;
46020 // the all the btns;
46021 editor.on('editorevent', this.updateToolbar, this);
46022 // other toolbars need to implement this..
46023 //editor.on('editmodechange', this.updateToolbar, this);
46029 * Protected method that will not generally be called directly. It triggers
46030 * a toolbar update by reading the markup state of the current selection in the editor.
46032 * Note you can force an update by calling on('editorevent', scope, false)
46034 updateToolbar: function(editor,ev,sel){
46037 // capture mouse up - this is handy for selecting images..
46038 // perhaps should go somewhere else...
46039 if(!this.editorcore.activated){
46040 this.editor.onFirstFocus();
46046 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46047 // selectNode - might want to handle IE?
46049 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46050 ev.target && ev.target.tagName == 'IMG') {
46051 // they have click on an image...
46052 // let's see if we can change the selection...
46055 var nodeRange = sel.ownerDocument.createRange();
46057 nodeRange.selectNode(sel);
46059 nodeRange.selectNodeContents(sel);
46061 //nodeRange.collapse(true);
46062 var s = this.editorcore.win.getSelection();
46063 s.removeAllRanges();
46064 s.addRange(nodeRange);
46068 var updateFooter = sel ? false : true;
46071 var ans = this.editorcore.getAllAncestors();
46074 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46077 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46078 sel = sel ? sel : this.editorcore.doc.body;
46079 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46082 // pick a menu that exists..
46083 var tn = sel.tagName.toUpperCase();
46084 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46086 tn = sel.tagName.toUpperCase();
46088 var lastSel = this.tb.selectedNode;
46090 this.tb.selectedNode = sel;
46092 // if current menu does not match..
46094 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46097 ///console.log("show: " + tn);
46098 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46101 this.tb.items.first().el.innerHTML = tn + ': ';
46104 // update attributes
46105 if (this.tb.fields) {
46106 this.tb.fields.each(function(e) {
46108 e.setValue(sel.style[e.stylename]);
46111 e.setValue(sel.getAttribute(e.attrname));
46115 var hasStyles = false;
46116 for(var i in this.styles) {
46123 var st = this.tb.fields.item(0);
46125 st.store.removeAll();
46128 var cn = sel.className.split(/\s+/);
46131 if (this.styles['*']) {
46133 Roo.each(this.styles['*'], function(v) {
46134 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46137 if (this.styles[tn]) {
46138 Roo.each(this.styles[tn], function(v) {
46139 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46143 st.store.loadData(avs);
46147 // flag our selected Node.
46148 this.tb.selectedNode = sel;
46151 Roo.menu.MenuMgr.hideAll();
46155 if (!updateFooter) {
46156 //this.footDisp.dom.innerHTML = '';
46159 // update the footer
46163 this.footerEls = ans.reverse();
46164 Roo.each(this.footerEls, function(a,i) {
46165 if (!a) { return; }
46166 html += html.length ? ' > ' : '';
46168 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46173 var sz = this.footDisp.up('td').getSize();
46174 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46175 this.footDisp.dom.style.marginLeft = '5px';
46177 this.footDisp.dom.style.overflow = 'hidden';
46179 this.footDisp.dom.innerHTML = html;
46181 //this.editorsyncValue();
46188 onDestroy : function(){
46191 this.tb.items.each(function(item){
46193 item.menu.removeAll();
46195 item.menu.el.destroy();
46203 onFirstFocus: function() {
46204 // need to do this for all the toolbars..
46205 this.tb.items.each(function(item){
46209 buildToolbar: function(tlist, nm)
46211 var editor = this.editor;
46212 var editorcore = this.editorcore;
46213 // create a new element.
46214 var wdiv = editor.wrap.createChild({
46216 }, editor.wrap.dom.firstChild.nextSibling, true);
46219 var tb = new Roo.Toolbar(wdiv);
46222 tb.add(nm+ ": ");
46225 for(var i in this.styles) {
46230 if (styles && styles.length) {
46232 // this needs a multi-select checkbox...
46233 tb.addField( new Roo.form.ComboBox({
46234 store: new Roo.data.SimpleStore({
46236 fields: ['val', 'selected'],
46239 name : '-roo-edit-className',
46240 attrname : 'className',
46241 displayField: 'val',
46245 triggerAction: 'all',
46246 emptyText:'Select Style',
46247 selectOnFocus:true,
46250 'select': function(c, r, i) {
46251 // initial support only for on class per el..
46252 tb.selectedNode.className = r ? r.get('val') : '';
46253 editorcore.syncValue();
46260 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46261 var tbops = tbc.options;
46263 for (var i in tlist) {
46265 var item = tlist[i];
46266 tb.add(item.title + ": ");
46269 //optname == used so you can configure the options available..
46270 var opts = item.opts ? item.opts : false;
46271 if (item.optname) {
46272 opts = tbops[item.optname];
46277 // opts == pulldown..
46278 tb.addField( new Roo.form.ComboBox({
46279 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46281 fields: ['val', 'display'],
46284 name : '-roo-edit-' + i,
46286 stylename : item.style ? item.style : false,
46287 displayField: item.displayField ? item.displayField : 'val',
46288 valueField : 'val',
46290 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46292 triggerAction: 'all',
46293 emptyText:'Select',
46294 selectOnFocus:true,
46295 width: item.width ? item.width : 130,
46297 'select': function(c, r, i) {
46299 tb.selectedNode.style[c.stylename] = r.get('val');
46302 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46311 tb.addField( new Roo.form.TextField({
46314 //allowBlank:false,
46319 tb.addField( new Roo.form.TextField({
46320 name: '-roo-edit-' + i,
46327 'change' : function(f, nv, ov) {
46328 tb.selectedNode.setAttribute(f.attrname, nv);
46329 editorcore.syncValue();
46342 text: 'Stylesheets',
46345 click : function ()
46347 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46355 text: 'Remove Tag',
46358 click : function ()
46361 // undo does not work.
46363 var sn = tb.selectedNode;
46365 var pn = sn.parentNode;
46367 var stn = sn.childNodes[0];
46368 var en = sn.childNodes[sn.childNodes.length - 1 ];
46369 while (sn.childNodes.length) {
46370 var node = sn.childNodes[0];
46371 sn.removeChild(node);
46373 pn.insertBefore(node, sn);
46376 pn.removeChild(sn);
46377 var range = editorcore.createRange();
46379 range.setStart(stn,0);
46380 range.setEnd(en,0); //????
46381 //range.selectNode(sel);
46384 var selection = editorcore.getSelection();
46385 selection.removeAllRanges();
46386 selection.addRange(range);
46390 //_this.updateToolbar(null, null, pn);
46391 _this.updateToolbar(null, null, null);
46392 _this.footDisp.dom.innerHTML = '';
46402 tb.el.on('click', function(e){
46403 e.preventDefault(); // what does this do?
46405 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46408 // dont need to disable them... as they will get hidden
46413 buildFooter : function()
46416 var fel = this.editor.wrap.createChild();
46417 this.footer = new Roo.Toolbar(fel);
46418 // toolbar has scrolly on left / right?
46419 var footDisp= new Roo.Toolbar.Fill();
46425 handler : function() {
46426 _t.footDisp.scrollTo('left',0,true)
46430 this.footer.add( footDisp );
46435 handler : function() {
46437 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46441 var fel = Roo.get(footDisp.el);
46442 fel.addClass('x-editor-context');
46443 this.footDispWrap = fel;
46444 this.footDispWrap.overflow = 'hidden';
46446 this.footDisp = fel.createChild();
46447 this.footDispWrap.on('click', this.onContextClick, this)
46451 onContextClick : function (ev,dom)
46453 ev.preventDefault();
46454 var cn = dom.className;
46456 if (!cn.match(/x-ed-loc-/)) {
46459 var n = cn.split('-').pop();
46460 var ans = this.footerEls;
46464 var range = this.editorcore.createRange();
46466 range.selectNodeContents(sel);
46467 //range.selectNode(sel);
46470 var selection = this.editorcore.getSelection();
46471 selection.removeAllRanges();
46472 selection.addRange(range);
46476 this.updateToolbar(null, null, sel);
46493 * Ext JS Library 1.1.1
46494 * Copyright(c) 2006-2007, Ext JS, LLC.
46496 * Originally Released Under LGPL - original licence link has changed is not relivant.
46499 * <script type="text/javascript">
46503 * @class Roo.form.BasicForm
46504 * @extends Roo.util.Observable
46505 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46507 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46508 * @param {Object} config Configuration options
46510 Roo.form.BasicForm = function(el, config){
46511 this.allItems = [];
46512 this.childForms = [];
46513 Roo.apply(this, config);
46515 * The Roo.form.Field items in this form.
46516 * @type MixedCollection
46520 this.items = new Roo.util.MixedCollection(false, function(o){
46521 return o.id || (o.id = Roo.id());
46525 * @event beforeaction
46526 * Fires before any action is performed. Return false to cancel the action.
46527 * @param {Form} this
46528 * @param {Action} action The action to be performed
46530 beforeaction: true,
46532 * @event actionfailed
46533 * Fires when an action fails.
46534 * @param {Form} this
46535 * @param {Action} action The action that failed
46537 actionfailed : true,
46539 * @event actioncomplete
46540 * Fires when an action is completed.
46541 * @param {Form} this
46542 * @param {Action} action The action that completed
46544 actioncomplete : true
46549 Roo.form.BasicForm.superclass.constructor.call(this);
46552 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46554 * @cfg {String} method
46555 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46558 * @cfg {DataReader} reader
46559 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46560 * This is optional as there is built-in support for processing JSON.
46563 * @cfg {DataReader} errorReader
46564 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46565 * This is completely optional as there is built-in support for processing JSON.
46568 * @cfg {String} url
46569 * The URL to use for form actions if one isn't supplied in the action options.
46572 * @cfg {Boolean} fileUpload
46573 * Set to true if this form is a file upload.
46577 * @cfg {Object} baseParams
46578 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46583 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46588 activeAction : null,
46591 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46592 * or setValues() data instead of when the form was first created.
46594 trackResetOnLoad : false,
46598 * childForms - used for multi-tab forms
46601 childForms : false,
46604 * allItems - full list of fields.
46610 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46611 * element by passing it or its id or mask the form itself by passing in true.
46614 waitMsgTarget : false,
46617 initEl : function(el){
46618 this.el = Roo.get(el);
46619 this.id = this.el.id || Roo.id();
46620 this.el.on('submit', this.onSubmit, this);
46621 this.el.addClass('x-form');
46625 onSubmit : function(e){
46630 * Returns true if client-side validation on the form is successful.
46633 isValid : function(){
46635 this.items.each(function(f){
46644 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46647 isDirty : function(){
46649 this.items.each(function(f){
46659 * Returns true if any fields in this form have changed since their original load. (New version)
46663 hasChanged : function()
46666 this.items.each(function(f){
46667 if(f.hasChanged()){
46676 * Resets all hasChanged to 'false' -
46677 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46678 * So hasChanged storage is only to be used for this purpose
46681 resetHasChanged : function()
46683 this.items.each(function(f){
46684 f.resetHasChanged();
46691 * Performs a predefined action (submit or load) or custom actions you define on this form.
46692 * @param {String} actionName The name of the action type
46693 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46694 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46695 * accept other config options):
46697 Property Type Description
46698 ---------------- --------------- ----------------------------------------------------------------------------------
46699 url String The url for the action (defaults to the form's url)
46700 method String The form method to use (defaults to the form's method, or POST if not defined)
46701 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46702 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46703 validate the form on the client (defaults to false)
46705 * @return {BasicForm} this
46707 doAction : function(action, options){
46708 if(typeof action == 'string'){
46709 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46711 if(this.fireEvent('beforeaction', this, action) !== false){
46712 this.beforeAction(action);
46713 action.run.defer(100, action);
46719 * Shortcut to do a submit action.
46720 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46721 * @return {BasicForm} this
46723 submit : function(options){
46724 this.doAction('submit', options);
46729 * Shortcut to do a load action.
46730 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46731 * @return {BasicForm} this
46733 load : function(options){
46734 this.doAction('load', options);
46739 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46740 * @param {Record} record The record to edit
46741 * @return {BasicForm} this
46743 updateRecord : function(record){
46744 record.beginEdit();
46745 var fs = record.fields;
46746 fs.each(function(f){
46747 var field = this.findField(f.name);
46749 record.set(f.name, field.getValue());
46757 * Loads an Roo.data.Record into this form.
46758 * @param {Record} record The record to load
46759 * @return {BasicForm} this
46761 loadRecord : function(record){
46762 this.setValues(record.data);
46767 beforeAction : function(action){
46768 var o = action.options;
46771 if(this.waitMsgTarget === true){
46772 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46773 }else if(this.waitMsgTarget){
46774 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46775 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46777 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46783 afterAction : function(action, success){
46784 this.activeAction = null;
46785 var o = action.options;
46787 if(this.waitMsgTarget === true){
46789 }else if(this.waitMsgTarget){
46790 this.waitMsgTarget.unmask();
46792 Roo.MessageBox.updateProgress(1);
46793 Roo.MessageBox.hide();
46800 Roo.callback(o.success, o.scope, [this, action]);
46801 this.fireEvent('actioncomplete', this, action);
46805 // failure condition..
46806 // we have a scenario where updates need confirming.
46807 // eg. if a locking scenario exists..
46808 // we look for { errors : { needs_confirm : true }} in the response.
46810 (typeof(action.result) != 'undefined') &&
46811 (typeof(action.result.errors) != 'undefined') &&
46812 (typeof(action.result.errors.needs_confirm) != 'undefined')
46815 Roo.MessageBox.confirm(
46816 "Change requires confirmation",
46817 action.result.errorMsg,
46822 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46832 Roo.callback(o.failure, o.scope, [this, action]);
46833 // show an error message if no failed handler is set..
46834 if (!this.hasListener('actionfailed')) {
46835 Roo.MessageBox.alert("Error",
46836 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46837 action.result.errorMsg :
46838 "Saving Failed, please check your entries or try again"
46842 this.fireEvent('actionfailed', this, action);
46848 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46849 * @param {String} id The value to search for
46852 findField : function(id){
46853 var field = this.items.get(id);
46855 this.items.each(function(f){
46856 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
46862 return field || null;
46866 * Add a secondary form to this one,
46867 * Used to provide tabbed forms. One form is primary, with hidden values
46868 * which mirror the elements from the other forms.
46870 * @param {Roo.form.Form} form to add.
46873 addForm : function(form)
46876 if (this.childForms.indexOf(form) > -1) {
46880 this.childForms.push(form);
46882 Roo.each(form.allItems, function (fe) {
46884 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
46885 if (this.findField(n)) { // already added..
46888 var add = new Roo.form.Hidden({
46891 add.render(this.el);
46898 * Mark fields in this form invalid in bulk.
46899 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
46900 * @return {BasicForm} this
46902 markInvalid : function(errors){
46903 if(errors instanceof Array){
46904 for(var i = 0, len = errors.length; i < len; i++){
46905 var fieldError = errors[i];
46906 var f = this.findField(fieldError.id);
46908 f.markInvalid(fieldError.msg);
46914 if(typeof errors[id] != 'function' && (field = this.findField(id))){
46915 field.markInvalid(errors[id]);
46919 Roo.each(this.childForms || [], function (f) {
46920 f.markInvalid(errors);
46927 * Set values for fields in this form in bulk.
46928 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
46929 * @return {BasicForm} this
46931 setValues : function(values){
46932 if(values instanceof Array){ // array of objects
46933 for(var i = 0, len = values.length; i < len; i++){
46935 var f = this.findField(v.id);
46937 f.setValue(v.value);
46938 if(this.trackResetOnLoad){
46939 f.originalValue = f.getValue();
46943 }else{ // object hash
46946 if(typeof values[id] != 'function' && (field = this.findField(id))){
46948 if (field.setFromData &&
46949 field.valueField &&
46950 field.displayField &&
46951 // combos' with local stores can
46952 // be queried via setValue()
46953 // to set their value..
46954 (field.store && !field.store.isLocal)
46958 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
46959 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
46960 field.setFromData(sd);
46963 field.setValue(values[id]);
46967 if(this.trackResetOnLoad){
46968 field.originalValue = field.getValue();
46973 this.resetHasChanged();
46976 Roo.each(this.childForms || [], function (f) {
46977 f.setValues(values);
46978 f.resetHasChanged();
46985 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
46986 * they are returned as an array.
46987 * @param {Boolean} asString
46990 getValues : function(asString){
46991 if (this.childForms) {
46992 // copy values from the child forms
46993 Roo.each(this.childForms, function (f) {
46994 this.setValues(f.getValues());
47000 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47001 if(asString === true){
47004 return Roo.urlDecode(fs);
47008 * Returns the fields in this form as an object with key/value pairs.
47009 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47012 getFieldValues : function(with_hidden)
47014 if (this.childForms) {
47015 // copy values from the child forms
47016 // should this call getFieldValues - probably not as we do not currently copy
47017 // hidden fields when we generate..
47018 Roo.each(this.childForms, function (f) {
47019 this.setValues(f.getValues());
47024 this.items.each(function(f){
47025 if (!f.getName()) {
47028 var v = f.getValue();
47029 if (f.inputType =='radio') {
47030 if (typeof(ret[f.getName()]) == 'undefined') {
47031 ret[f.getName()] = ''; // empty..
47034 if (!f.el.dom.checked) {
47038 v = f.el.dom.value;
47042 // not sure if this supported any more..
47043 if ((typeof(v) == 'object') && f.getRawValue) {
47044 v = f.getRawValue() ; // dates..
47046 // combo boxes where name != hiddenName...
47047 if (f.name != f.getName()) {
47048 ret[f.name] = f.getRawValue();
47050 ret[f.getName()] = v;
47057 * Clears all invalid messages in this form.
47058 * @return {BasicForm} this
47060 clearInvalid : function(){
47061 this.items.each(function(f){
47065 Roo.each(this.childForms || [], function (f) {
47074 * Resets this form.
47075 * @return {BasicForm} this
47077 reset : function(){
47078 this.items.each(function(f){
47082 Roo.each(this.childForms || [], function (f) {
47085 this.resetHasChanged();
47091 * Add Roo.form components to this form.
47092 * @param {Field} field1
47093 * @param {Field} field2 (optional)
47094 * @param {Field} etc (optional)
47095 * @return {BasicForm} this
47098 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47104 * Removes a field from the items collection (does NOT remove its markup).
47105 * @param {Field} field
47106 * @return {BasicForm} this
47108 remove : function(field){
47109 this.items.remove(field);
47114 * Looks at the fields in this form, checks them for an id attribute,
47115 * and calls applyTo on the existing dom element with that id.
47116 * @return {BasicForm} this
47118 render : function(){
47119 this.items.each(function(f){
47120 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47128 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47129 * @param {Object} values
47130 * @return {BasicForm} this
47132 applyToFields : function(o){
47133 this.items.each(function(f){
47140 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47141 * @param {Object} values
47142 * @return {BasicForm} this
47144 applyIfToFields : function(o){
47145 this.items.each(function(f){
47153 Roo.BasicForm = Roo.form.BasicForm;/*
47155 * Ext JS Library 1.1.1
47156 * Copyright(c) 2006-2007, Ext JS, LLC.
47158 * Originally Released Under LGPL - original licence link has changed is not relivant.
47161 * <script type="text/javascript">
47165 * @class Roo.form.Form
47166 * @extends Roo.form.BasicForm
47167 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47169 * @param {Object} config Configuration options
47171 Roo.form.Form = function(config){
47173 if (config.items) {
47174 xitems = config.items;
47175 delete config.items;
47179 Roo.form.Form.superclass.constructor.call(this, null, config);
47180 this.url = this.url || this.action;
47182 this.root = new Roo.form.Layout(Roo.applyIf({
47186 this.active = this.root;
47188 * Array of all the buttons that have been added to this form via {@link addButton}
47192 this.allItems = [];
47195 * @event clientvalidation
47196 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47197 * @param {Form} this
47198 * @param {Boolean} valid true if the form has passed client-side validation
47200 clientvalidation: true,
47203 * Fires when the form is rendered
47204 * @param {Roo.form.Form} form
47209 if (this.progressUrl) {
47210 // push a hidden field onto the list of fields..
47214 name : 'UPLOAD_IDENTIFIER'
47219 Roo.each(xitems, this.addxtype, this);
47225 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47227 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47230 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47233 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47235 buttonAlign:'center',
47238 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47243 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47244 * This property cascades to child containers if not set.
47249 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47250 * fires a looping event with that state. This is required to bind buttons to the valid
47251 * state using the config value formBind:true on the button.
47253 monitorValid : false,
47256 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47261 * @cfg {String} progressUrl - Url to return progress data
47264 progressUrl : false,
47267 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47268 * fields are added and the column is closed. If no fields are passed the column remains open
47269 * until end() is called.
47270 * @param {Object} config The config to pass to the column
47271 * @param {Field} field1 (optional)
47272 * @param {Field} field2 (optional)
47273 * @param {Field} etc (optional)
47274 * @return Column The column container object
47276 column : function(c){
47277 var col = new Roo.form.Column(c);
47279 if(arguments.length > 1){ // duplicate code required because of Opera
47280 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47287 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47288 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47289 * until end() is called.
47290 * @param {Object} config The config to pass to the fieldset
47291 * @param {Field} field1 (optional)
47292 * @param {Field} field2 (optional)
47293 * @param {Field} etc (optional)
47294 * @return FieldSet The fieldset container object
47296 fieldset : function(c){
47297 var fs = new Roo.form.FieldSet(c);
47299 if(arguments.length > 1){ // duplicate code required because of Opera
47300 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47307 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47308 * fields are added and the container is closed. If no fields are passed the container remains open
47309 * until end() is called.
47310 * @param {Object} config The config to pass to the Layout
47311 * @param {Field} field1 (optional)
47312 * @param {Field} field2 (optional)
47313 * @param {Field} etc (optional)
47314 * @return Layout The container object
47316 container : function(c){
47317 var l = new Roo.form.Layout(c);
47319 if(arguments.length > 1){ // duplicate code required because of Opera
47320 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47327 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47328 * @param {Object} container A Roo.form.Layout or subclass of Layout
47329 * @return {Form} this
47331 start : function(c){
47332 // cascade label info
47333 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47334 this.active.stack.push(c);
47335 c.ownerCt = this.active;
47341 * Closes the current open container
47342 * @return {Form} this
47345 if(this.active == this.root){
47348 this.active = this.active.ownerCt;
47353 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47354 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47355 * as the label of the field.
47356 * @param {Field} field1
47357 * @param {Field} field2 (optional)
47358 * @param {Field} etc. (optional)
47359 * @return {Form} this
47362 this.active.stack.push.apply(this.active.stack, arguments);
47363 this.allItems.push.apply(this.allItems,arguments);
47365 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47366 if(a[i].isFormField){
47371 Roo.form.Form.superclass.add.apply(this, r);
47381 * Find any element that has been added to a form, using it's ID or name
47382 * This can include framesets, columns etc. along with regular fields..
47383 * @param {String} id - id or name to find.
47385 * @return {Element} e - or false if nothing found.
47387 findbyId : function(id)
47393 Roo.each(this.allItems, function(f){
47394 if (f.id == id || f.name == id ){
47405 * Render this form into the passed container. This should only be called once!
47406 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47407 * @return {Form} this
47409 render : function(ct)
47415 var o = this.autoCreate || {
47417 method : this.method || 'POST',
47418 id : this.id || Roo.id()
47420 this.initEl(ct.createChild(o));
47422 this.root.render(this.el);
47426 this.items.each(function(f){
47427 f.render('x-form-el-'+f.id);
47430 if(this.buttons.length > 0){
47431 // tables are required to maintain order and for correct IE layout
47432 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47433 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47434 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47436 var tr = tb.getElementsByTagName('tr')[0];
47437 for(var i = 0, len = this.buttons.length; i < len; i++) {
47438 var b = this.buttons[i];
47439 var td = document.createElement('td');
47440 td.className = 'x-form-btn-td';
47441 b.render(tr.appendChild(td));
47444 if(this.monitorValid){ // initialize after render
47445 this.startMonitoring();
47447 this.fireEvent('rendered', this);
47452 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47453 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47454 * object or a valid Roo.DomHelper element config
47455 * @param {Function} handler The function called when the button is clicked
47456 * @param {Object} scope (optional) The scope of the handler function
47457 * @return {Roo.Button}
47459 addButton : function(config, handler, scope){
47463 minWidth: this.minButtonWidth,
47466 if(typeof config == "string"){
47469 Roo.apply(bc, config);
47471 var btn = new Roo.Button(null, bc);
47472 this.buttons.push(btn);
47477 * Adds a series of form elements (using the xtype property as the factory method.
47478 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47479 * @param {Object} config
47482 addxtype : function()
47484 var ar = Array.prototype.slice.call(arguments, 0);
47486 for(var i = 0; i < ar.length; i++) {
47488 continue; // skip -- if this happends something invalid got sent, we
47489 // should ignore it, as basically that interface element will not show up
47490 // and that should be pretty obvious!!
47493 if (Roo.form[ar[i].xtype]) {
47495 var fe = Roo.factory(ar[i], Roo.form);
47501 fe.store.form = this;
47506 this.allItems.push(fe);
47507 if (fe.items && fe.addxtype) {
47508 fe.addxtype.apply(fe, fe.items);
47518 // console.log('adding ' + ar[i].xtype);
47520 if (ar[i].xtype == 'Button') {
47521 //console.log('adding button');
47522 //console.log(ar[i]);
47523 this.addButton(ar[i]);
47524 this.allItems.push(fe);
47528 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47529 alert('end is not supported on xtype any more, use items');
47531 // //console.log('adding end');
47539 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47540 * option "monitorValid"
47542 startMonitoring : function(){
47545 Roo.TaskMgr.start({
47546 run : this.bindHandler,
47547 interval : this.monitorPoll || 200,
47554 * Stops monitoring of the valid state of this form
47556 stopMonitoring : function(){
47557 this.bound = false;
47561 bindHandler : function(){
47563 return false; // stops binding
47566 this.items.each(function(f){
47567 if(!f.isValid(true)){
47572 for(var i = 0, len = this.buttons.length; i < len; i++){
47573 var btn = this.buttons[i];
47574 if(btn.formBind === true && btn.disabled === valid){
47575 btn.setDisabled(!valid);
47578 this.fireEvent('clientvalidation', this, valid);
47592 Roo.Form = Roo.form.Form;
47595 * Ext JS Library 1.1.1
47596 * Copyright(c) 2006-2007, Ext JS, LLC.
47598 * Originally Released Under LGPL - original licence link has changed is not relivant.
47601 * <script type="text/javascript">
47604 // as we use this in bootstrap.
47605 Roo.namespace('Roo.form');
47607 * @class Roo.form.Action
47608 * Internal Class used to handle form actions
47610 * @param {Roo.form.BasicForm} el The form element or its id
47611 * @param {Object} config Configuration options
47616 // define the action interface
47617 Roo.form.Action = function(form, options){
47619 this.options = options || {};
47622 * Client Validation Failed
47625 Roo.form.Action.CLIENT_INVALID = 'client';
47627 * Server Validation Failed
47630 Roo.form.Action.SERVER_INVALID = 'server';
47632 * Connect to Server Failed
47635 Roo.form.Action.CONNECT_FAILURE = 'connect';
47637 * Reading Data from Server Failed
47640 Roo.form.Action.LOAD_FAILURE = 'load';
47642 Roo.form.Action.prototype = {
47644 failureType : undefined,
47645 response : undefined,
47646 result : undefined,
47648 // interface method
47649 run : function(options){
47653 // interface method
47654 success : function(response){
47658 // interface method
47659 handleResponse : function(response){
47663 // default connection failure
47664 failure : function(response){
47666 this.response = response;
47667 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47668 this.form.afterAction(this, false);
47671 processResponse : function(response){
47672 this.response = response;
47673 if(!response.responseText){
47676 this.result = this.handleResponse(response);
47677 return this.result;
47680 // utility functions used internally
47681 getUrl : function(appendParams){
47682 var url = this.options.url || this.form.url || this.form.el.dom.action;
47684 var p = this.getParams();
47686 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47692 getMethod : function(){
47693 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47696 getParams : function(){
47697 var bp = this.form.baseParams;
47698 var p = this.options.params;
47700 if(typeof p == "object"){
47701 p = Roo.urlEncode(Roo.applyIf(p, bp));
47702 }else if(typeof p == 'string' && bp){
47703 p += '&' + Roo.urlEncode(bp);
47706 p = Roo.urlEncode(bp);
47711 createCallback : function(){
47713 success: this.success,
47714 failure: this.failure,
47716 timeout: (this.form.timeout*1000),
47717 upload: this.form.fileUpload ? this.success : undefined
47722 Roo.form.Action.Submit = function(form, options){
47723 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47726 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47729 haveProgress : false,
47730 uploadComplete : false,
47732 // uploadProgress indicator.
47733 uploadProgress : function()
47735 if (!this.form.progressUrl) {
47739 if (!this.haveProgress) {
47740 Roo.MessageBox.progress("Uploading", "Uploading");
47742 if (this.uploadComplete) {
47743 Roo.MessageBox.hide();
47747 this.haveProgress = true;
47749 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47751 var c = new Roo.data.Connection();
47753 url : this.form.progressUrl,
47758 success : function(req){
47759 //console.log(data);
47763 rdata = Roo.decode(req.responseText)
47765 Roo.log("Invalid data from server..");
47769 if (!rdata || !rdata.success) {
47771 Roo.MessageBox.alert(Roo.encode(rdata));
47774 var data = rdata.data;
47776 if (this.uploadComplete) {
47777 Roo.MessageBox.hide();
47782 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47783 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47786 this.uploadProgress.defer(2000,this);
47789 failure: function(data) {
47790 Roo.log('progress url failed ');
47801 // run get Values on the form, so it syncs any secondary forms.
47802 this.form.getValues();
47804 var o = this.options;
47805 var method = this.getMethod();
47806 var isPost = method == 'POST';
47807 if(o.clientValidation === false || this.form.isValid()){
47809 if (this.form.progressUrl) {
47810 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47811 (new Date() * 1) + '' + Math.random());
47816 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47817 form:this.form.el.dom,
47818 url:this.getUrl(!isPost),
47820 params:isPost ? this.getParams() : null,
47821 isUpload: this.form.fileUpload
47824 this.uploadProgress();
47826 }else if (o.clientValidation !== false){ // client validation failed
47827 this.failureType = Roo.form.Action.CLIENT_INVALID;
47828 this.form.afterAction(this, false);
47832 success : function(response)
47834 this.uploadComplete= true;
47835 if (this.haveProgress) {
47836 Roo.MessageBox.hide();
47840 var result = this.processResponse(response);
47841 if(result === true || result.success){
47842 this.form.afterAction(this, true);
47846 this.form.markInvalid(result.errors);
47847 this.failureType = Roo.form.Action.SERVER_INVALID;
47849 this.form.afterAction(this, false);
47851 failure : function(response)
47853 this.uploadComplete= true;
47854 if (this.haveProgress) {
47855 Roo.MessageBox.hide();
47858 this.response = response;
47859 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47860 this.form.afterAction(this, false);
47863 handleResponse : function(response){
47864 if(this.form.errorReader){
47865 var rs = this.form.errorReader.read(response);
47868 for(var i = 0, len = rs.records.length; i < len; i++) {
47869 var r = rs.records[i];
47870 errors[i] = r.data;
47873 if(errors.length < 1){
47877 success : rs.success,
47883 ret = Roo.decode(response.responseText);
47887 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
47897 Roo.form.Action.Load = function(form, options){
47898 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
47899 this.reader = this.form.reader;
47902 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
47907 Roo.Ajax.request(Roo.apply(
47908 this.createCallback(), {
47909 method:this.getMethod(),
47910 url:this.getUrl(false),
47911 params:this.getParams()
47915 success : function(response){
47917 var result = this.processResponse(response);
47918 if(result === true || !result.success || !result.data){
47919 this.failureType = Roo.form.Action.LOAD_FAILURE;
47920 this.form.afterAction(this, false);
47923 this.form.clearInvalid();
47924 this.form.setValues(result.data);
47925 this.form.afterAction(this, true);
47928 handleResponse : function(response){
47929 if(this.form.reader){
47930 var rs = this.form.reader.read(response);
47931 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
47933 success : rs.success,
47937 return Roo.decode(response.responseText);
47941 Roo.form.Action.ACTION_TYPES = {
47942 'load' : Roo.form.Action.Load,
47943 'submit' : Roo.form.Action.Submit
47946 * Ext JS Library 1.1.1
47947 * Copyright(c) 2006-2007, Ext JS, LLC.
47949 * Originally Released Under LGPL - original licence link has changed is not relivant.
47952 * <script type="text/javascript">
47956 * @class Roo.form.Layout
47957 * @extends Roo.Component
47958 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
47960 * @param {Object} config Configuration options
47962 Roo.form.Layout = function(config){
47964 if (config.items) {
47965 xitems = config.items;
47966 delete config.items;
47968 Roo.form.Layout.superclass.constructor.call(this, config);
47970 Roo.each(xitems, this.addxtype, this);
47974 Roo.extend(Roo.form.Layout, Roo.Component, {
47976 * @cfg {String/Object} autoCreate
47977 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
47980 * @cfg {String/Object/Function} style
47981 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
47982 * a function which returns such a specification.
47985 * @cfg {String} labelAlign
47986 * Valid values are "left," "top" and "right" (defaults to "left")
47989 * @cfg {Number} labelWidth
47990 * Fixed width in pixels of all field labels (defaults to undefined)
47993 * @cfg {Boolean} clear
47994 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
47998 * @cfg {String} labelSeparator
47999 * The separator to use after field labels (defaults to ':')
48001 labelSeparator : ':',
48003 * @cfg {Boolean} hideLabels
48004 * True to suppress the display of field labels in this layout (defaults to false)
48006 hideLabels : false,
48009 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48014 onRender : function(ct, position){
48015 if(this.el){ // from markup
48016 this.el = Roo.get(this.el);
48017 }else { // generate
48018 var cfg = this.getAutoCreate();
48019 this.el = ct.createChild(cfg, position);
48022 this.el.applyStyles(this.style);
48024 if(this.labelAlign){
48025 this.el.addClass('x-form-label-'+this.labelAlign);
48027 if(this.hideLabels){
48028 this.labelStyle = "display:none";
48029 this.elementStyle = "padding-left:0;";
48031 if(typeof this.labelWidth == 'number'){
48032 this.labelStyle = "width:"+this.labelWidth+"px;";
48033 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48035 if(this.labelAlign == 'top'){
48036 this.labelStyle = "width:auto;";
48037 this.elementStyle = "padding-left:0;";
48040 var stack = this.stack;
48041 var slen = stack.length;
48043 if(!this.fieldTpl){
48044 var t = new Roo.Template(
48045 '<div class="x-form-item {5}">',
48046 '<label for="{0}" style="{2}">{1}{4}</label>',
48047 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48049 '</div><div class="x-form-clear-left"></div>'
48051 t.disableFormats = true;
48053 Roo.form.Layout.prototype.fieldTpl = t;
48055 for(var i = 0; i < slen; i++) {
48056 if(stack[i].isFormField){
48057 this.renderField(stack[i]);
48059 this.renderComponent(stack[i]);
48064 this.el.createChild({cls:'x-form-clear'});
48069 renderField : function(f){
48070 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48073 f.labelStyle||this.labelStyle||'', //2
48074 this.elementStyle||'', //3
48075 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48076 f.itemCls||this.itemCls||'' //5
48077 ], true).getPrevSibling());
48081 renderComponent : function(c){
48082 c.render(c.isLayout ? this.el : this.el.createChild());
48085 * Adds a object form elements (using the xtype property as the factory method.)
48086 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48087 * @param {Object} config
48089 addxtype : function(o)
48091 // create the lement.
48092 o.form = this.form;
48093 var fe = Roo.factory(o, Roo.form);
48094 this.form.allItems.push(fe);
48095 this.stack.push(fe);
48097 if (fe.isFormField) {
48098 this.form.items.add(fe);
48106 * @class Roo.form.Column
48107 * @extends Roo.form.Layout
48108 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48110 * @param {Object} config Configuration options
48112 Roo.form.Column = function(config){
48113 Roo.form.Column.superclass.constructor.call(this, config);
48116 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48118 * @cfg {Number/String} width
48119 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48122 * @cfg {String/Object} autoCreate
48123 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48127 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48130 onRender : function(ct, position){
48131 Roo.form.Column.superclass.onRender.call(this, ct, position);
48133 this.el.setWidth(this.width);
48140 * @class Roo.form.Row
48141 * @extends Roo.form.Layout
48142 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48144 * @param {Object} config Configuration options
48148 Roo.form.Row = function(config){
48149 Roo.form.Row.superclass.constructor.call(this, config);
48152 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48154 * @cfg {Number/String} width
48155 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48158 * @cfg {Number/String} height
48159 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48161 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48165 onRender : function(ct, position){
48166 //console.log('row render');
48168 var t = new Roo.Template(
48169 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48170 '<label for="{0}" style="{2}">{1}{4}</label>',
48171 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48175 t.disableFormats = true;
48177 Roo.form.Layout.prototype.rowTpl = t;
48179 this.fieldTpl = this.rowTpl;
48181 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48182 var labelWidth = 100;
48184 if ((this.labelAlign != 'top')) {
48185 if (typeof this.labelWidth == 'number') {
48186 labelWidth = this.labelWidth
48188 this.padWidth = 20 + labelWidth;
48192 Roo.form.Column.superclass.onRender.call(this, ct, position);
48194 this.el.setWidth(this.width);
48197 this.el.setHeight(this.height);
48202 renderField : function(f){
48203 f.fieldEl = this.fieldTpl.append(this.el, [
48204 f.id, f.fieldLabel,
48205 f.labelStyle||this.labelStyle||'',
48206 this.elementStyle||'',
48207 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48208 f.itemCls||this.itemCls||'',
48209 f.width ? f.width + this.padWidth : 160 + this.padWidth
48216 * @class Roo.form.FieldSet
48217 * @extends Roo.form.Layout
48218 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48220 * @param {Object} config Configuration options
48222 Roo.form.FieldSet = function(config){
48223 Roo.form.FieldSet.superclass.constructor.call(this, config);
48226 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48228 * @cfg {String} legend
48229 * The text to display as the legend for the FieldSet (defaults to '')
48232 * @cfg {String/Object} autoCreate
48233 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48237 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48240 onRender : function(ct, position){
48241 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48243 this.setLegend(this.legend);
48248 setLegend : function(text){
48250 this.el.child('legend').update(text);
48255 * Ext JS Library 1.1.1
48256 * Copyright(c) 2006-2007, Ext JS, LLC.
48258 * Originally Released Under LGPL - original licence link has changed is not relivant.
48261 * <script type="text/javascript">
48264 * @class Roo.form.VTypes
48265 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48268 Roo.form.VTypes = function(){
48269 // closure these in so they are only created once.
48270 var alpha = /^[a-zA-Z_]+$/;
48271 var alphanum = /^[a-zA-Z0-9_]+$/;
48272 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48273 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48275 // All these messages and functions are configurable
48278 * The function used to validate email addresses
48279 * @param {String} value The email address
48281 'email' : function(v){
48282 return email.test(v);
48285 * The error text to display when the email validation function returns false
48288 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48290 * The keystroke filter mask to be applied on email input
48293 'emailMask' : /[a-z0-9_\.\-@]/i,
48296 * The function used to validate URLs
48297 * @param {String} value The URL
48299 'url' : function(v){
48300 return url.test(v);
48303 * The error text to display when the url validation function returns false
48306 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48309 * The function used to validate alpha values
48310 * @param {String} value The value
48312 'alpha' : function(v){
48313 return alpha.test(v);
48316 * The error text to display when the alpha validation function returns false
48319 'alphaText' : 'This field should only contain letters and _',
48321 * The keystroke filter mask to be applied on alpha input
48324 'alphaMask' : /[a-z_]/i,
48327 * The function used to validate alphanumeric values
48328 * @param {String} value The value
48330 'alphanum' : function(v){
48331 return alphanum.test(v);
48334 * The error text to display when the alphanumeric validation function returns false
48337 'alphanumText' : 'This field should only contain letters, numbers and _',
48339 * The keystroke filter mask to be applied on alphanumeric input
48342 'alphanumMask' : /[a-z0-9_]/i
48344 }();//<script type="text/javascript">
48347 * @class Roo.form.FCKeditor
48348 * @extends Roo.form.TextArea
48349 * Wrapper around the FCKEditor http://www.fckeditor.net
48351 * Creates a new FCKeditor
48352 * @param {Object} config Configuration options
48354 Roo.form.FCKeditor = function(config){
48355 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48358 * @event editorinit
48359 * Fired when the editor is initialized - you can add extra handlers here..
48360 * @param {FCKeditor} this
48361 * @param {Object} the FCK object.
48368 Roo.form.FCKeditor.editors = { };
48369 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48371 //defaultAutoCreate : {
48372 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48376 * @cfg {Object} fck options - see fck manual for details.
48381 * @cfg {Object} fck toolbar set (Basic or Default)
48383 toolbarSet : 'Basic',
48385 * @cfg {Object} fck BasePath
48387 basePath : '/fckeditor/',
48395 onRender : function(ct, position)
48398 this.defaultAutoCreate = {
48400 style:"width:300px;height:60px;",
48401 autocomplete: "new-password"
48404 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48407 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48408 if(this.preventScrollbars){
48409 this.el.setStyle("overflow", "hidden");
48411 this.el.setHeight(this.growMin);
48414 //console.log('onrender' + this.getId() );
48415 Roo.form.FCKeditor.editors[this.getId()] = this;
48418 this.replaceTextarea() ;
48422 getEditor : function() {
48423 return this.fckEditor;
48426 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48427 * @param {Mixed} value The value to set
48431 setValue : function(value)
48433 //console.log('setValue: ' + value);
48435 if(typeof(value) == 'undefined') { // not sure why this is happending...
48438 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48440 //if(!this.el || !this.getEditor()) {
48441 // this.value = value;
48442 //this.setValue.defer(100,this,[value]);
48446 if(!this.getEditor()) {
48450 this.getEditor().SetData(value);
48457 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48458 * @return {Mixed} value The field value
48460 getValue : function()
48463 if (this.frame && this.frame.dom.style.display == 'none') {
48464 return Roo.form.FCKeditor.superclass.getValue.call(this);
48467 if(!this.el || !this.getEditor()) {
48469 // this.getValue.defer(100,this);
48474 var value=this.getEditor().GetData();
48475 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48476 return Roo.form.FCKeditor.superclass.getValue.call(this);
48482 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48483 * @return {Mixed} value The field value
48485 getRawValue : function()
48487 if (this.frame && this.frame.dom.style.display == 'none') {
48488 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48491 if(!this.el || !this.getEditor()) {
48492 //this.getRawValue.defer(100,this);
48499 var value=this.getEditor().GetData();
48500 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48501 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48505 setSize : function(w,h) {
48509 //if (this.frame && this.frame.dom.style.display == 'none') {
48510 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48513 //if(!this.el || !this.getEditor()) {
48514 // this.setSize.defer(100,this, [w,h]);
48520 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48522 this.frame.dom.setAttribute('width', w);
48523 this.frame.dom.setAttribute('height', h);
48524 this.frame.setSize(w,h);
48528 toggleSourceEdit : function(value) {
48532 this.el.dom.style.display = value ? '' : 'none';
48533 this.frame.dom.style.display = value ? 'none' : '';
48538 focus: function(tag)
48540 if (this.frame.dom.style.display == 'none') {
48541 return Roo.form.FCKeditor.superclass.focus.call(this);
48543 if(!this.el || !this.getEditor()) {
48544 this.focus.defer(100,this, [tag]);
48551 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48552 this.getEditor().Focus();
48554 if (!this.getEditor().Selection.GetSelection()) {
48555 this.focus.defer(100,this, [tag]);
48560 var r = this.getEditor().EditorDocument.createRange();
48561 r.setStart(tgs[0],0);
48562 r.setEnd(tgs[0],0);
48563 this.getEditor().Selection.GetSelection().removeAllRanges();
48564 this.getEditor().Selection.GetSelection().addRange(r);
48565 this.getEditor().Focus();
48572 replaceTextarea : function()
48574 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48577 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48579 // We must check the elements firstly using the Id and then the name.
48580 var oTextarea = document.getElementById( this.getId() );
48582 var colElementsByName = document.getElementsByName( this.getId() ) ;
48584 oTextarea.style.display = 'none' ;
48586 if ( oTextarea.tabIndex ) {
48587 this.TabIndex = oTextarea.tabIndex ;
48590 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48591 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48592 this.frame = Roo.get(this.getId() + '___Frame')
48595 _getConfigHtml : function()
48599 for ( var o in this.fckconfig ) {
48600 sConfig += sConfig.length > 0 ? '&' : '';
48601 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48604 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48608 _getIFrameHtml : function()
48610 var sFile = 'fckeditor.html' ;
48611 /* no idea what this is about..
48614 if ( (/fcksource=true/i).test( window.top.location.search ) )
48615 sFile = 'fckeditor.original.html' ;
48620 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48621 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48624 var html = '<iframe id="' + this.getId() +
48625 '___Frame" src="' + sLink +
48626 '" width="' + this.width +
48627 '" height="' + this.height + '"' +
48628 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48629 ' frameborder="0" scrolling="no"></iframe>' ;
48634 _insertHtmlBefore : function( html, element )
48636 if ( element.insertAdjacentHTML ) {
48638 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48640 var oRange = document.createRange() ;
48641 oRange.setStartBefore( element ) ;
48642 var oFragment = oRange.createContextualFragment( html );
48643 element.parentNode.insertBefore( oFragment, element ) ;
48656 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48658 function FCKeditor_OnComplete(editorInstance){
48659 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48660 f.fckEditor = editorInstance;
48661 //console.log("loaded");
48662 f.fireEvent('editorinit', f, editorInstance);
48682 //<script type="text/javascript">
48684 * @class Roo.form.GridField
48685 * @extends Roo.form.Field
48686 * Embed a grid (or editable grid into a form)
48689 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48691 * xgrid.store = Roo.data.Store
48692 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48693 * xgrid.store.reader = Roo.data.JsonReader
48697 * Creates a new GridField
48698 * @param {Object} config Configuration options
48700 Roo.form.GridField = function(config){
48701 Roo.form.GridField.superclass.constructor.call(this, config);
48705 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48707 * @cfg {Number} width - used to restrict width of grid..
48711 * @cfg {Number} height - used to restrict height of grid..
48715 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48721 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48722 * {tag: "input", type: "checkbox", autocomplete: "off"})
48724 // defaultAutoCreate : { tag: 'div' },
48725 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48727 * @cfg {String} addTitle Text to include for adding a title.
48731 onResize : function(){
48732 Roo.form.Field.superclass.onResize.apply(this, arguments);
48735 initEvents : function(){
48736 // Roo.form.Checkbox.superclass.initEvents.call(this);
48737 // has no events...
48742 getResizeEl : function(){
48746 getPositionEl : function(){
48751 onRender : function(ct, position){
48753 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48754 var style = this.style;
48757 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48758 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48759 this.viewEl = this.wrap.createChild({ tag: 'div' });
48761 this.viewEl.applyStyles(style);
48764 this.viewEl.setWidth(this.width);
48767 this.viewEl.setHeight(this.height);
48769 //if(this.inputValue !== undefined){
48770 //this.setValue(this.value);
48773 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48776 this.grid.render();
48777 this.grid.getDataSource().on('remove', this.refreshValue, this);
48778 this.grid.getDataSource().on('update', this.refreshValue, this);
48779 this.grid.on('afteredit', this.refreshValue, this);
48785 * Sets the value of the item.
48786 * @param {String} either an object or a string..
48788 setValue : function(v){
48790 v = v || []; // empty set..
48791 // this does not seem smart - it really only affects memoryproxy grids..
48792 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48793 var ds = this.grid.getDataSource();
48794 // assumes a json reader..
48796 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48797 ds.loadData( data);
48799 // clear selection so it does not get stale.
48800 if (this.grid.sm) {
48801 this.grid.sm.clearSelections();
48804 Roo.form.GridField.superclass.setValue.call(this, v);
48805 this.refreshValue();
48806 // should load data in the grid really....
48810 refreshValue: function() {
48812 this.grid.getDataSource().each(function(r) {
48815 this.el.dom.value = Roo.encode(val);
48823 * Ext JS Library 1.1.1
48824 * Copyright(c) 2006-2007, Ext JS, LLC.
48826 * Originally Released Under LGPL - original licence link has changed is not relivant.
48829 * <script type="text/javascript">
48832 * @class Roo.form.DisplayField
48833 * @extends Roo.form.Field
48834 * A generic Field to display non-editable data.
48835 * @cfg {Boolean} closable (true|false) default false
48837 * Creates a new Display Field item.
48838 * @param {Object} config Configuration options
48840 Roo.form.DisplayField = function(config){
48841 Roo.form.DisplayField.superclass.constructor.call(this, config);
48846 * Fires after the click the close btn
48847 * @param {Roo.form.DisplayField} this
48853 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
48854 inputType: 'hidden',
48860 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48862 focusClass : undefined,
48864 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48866 fieldClass: 'x-form-field',
48869 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
48871 valueRenderer: undefined,
48875 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48876 * {tag: "input", type: "checkbox", autocomplete: "off"})
48879 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
48883 onResize : function(){
48884 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
48888 initEvents : function(){
48889 // Roo.form.Checkbox.superclass.initEvents.call(this);
48890 // has no events...
48893 this.closeEl.on('click', this.onClose, this);
48899 getResizeEl : function(){
48903 getPositionEl : function(){
48908 onRender : function(ct, position){
48910 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
48911 //if(this.inputValue !== undefined){
48912 this.wrap = this.el.wrap();
48914 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
48917 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
48920 if (this.bodyStyle) {
48921 this.viewEl.applyStyles(this.bodyStyle);
48923 //this.viewEl.setStyle('padding', '2px');
48925 this.setValue(this.value);
48930 initValue : Roo.emptyFn,
48935 onClick : function(){
48940 * Sets the checked state of the checkbox.
48941 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
48943 setValue : function(v){
48945 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
48946 // this might be called before we have a dom element..
48947 if (!this.viewEl) {
48950 this.viewEl.dom.innerHTML = html;
48951 Roo.form.DisplayField.superclass.setValue.call(this, v);
48955 onClose : function(e)
48957 e.preventDefault();
48959 this.fireEvent('close', this);
48968 * @class Roo.form.DayPicker
48969 * @extends Roo.form.Field
48970 * A Day picker show [M] [T] [W] ....
48972 * Creates a new Day Picker
48973 * @param {Object} config Configuration options
48975 Roo.form.DayPicker= function(config){
48976 Roo.form.DayPicker.superclass.constructor.call(this, config);
48980 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
48982 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48984 focusClass : undefined,
48986 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48988 fieldClass: "x-form-field",
48991 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48992 * {tag: "input", type: "checkbox", autocomplete: "off"})
48994 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
48997 actionMode : 'viewEl',
49001 inputType : 'hidden',
49004 inputElement: false, // real input element?
49005 basedOn: false, // ????
49007 isFormField: true, // not sure where this is needed!!!!
49009 onResize : function(){
49010 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49011 if(!this.boxLabel){
49012 this.el.alignTo(this.wrap, 'c-c');
49016 initEvents : function(){
49017 Roo.form.Checkbox.superclass.initEvents.call(this);
49018 this.el.on("click", this.onClick, this);
49019 this.el.on("change", this.onClick, this);
49023 getResizeEl : function(){
49027 getPositionEl : function(){
49033 onRender : function(ct, position){
49034 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49036 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49038 var r1 = '<table><tr>';
49039 var r2 = '<tr class="x-form-daypick-icons">';
49040 for (var i=0; i < 7; i++) {
49041 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49042 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49045 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49046 viewEl.select('img').on('click', this.onClick, this);
49047 this.viewEl = viewEl;
49050 // this will not work on Chrome!!!
49051 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49052 this.el.on('propertychange', this.setFromHidden, this); //ie
49060 initValue : Roo.emptyFn,
49063 * Returns the checked state of the checkbox.
49064 * @return {Boolean} True if checked, else false
49066 getValue : function(){
49067 return this.el.dom.value;
49072 onClick : function(e){
49073 //this.setChecked(!this.checked);
49074 Roo.get(e.target).toggleClass('x-menu-item-checked');
49075 this.refreshValue();
49076 //if(this.el.dom.checked != this.checked){
49077 // this.setValue(this.el.dom.checked);
49082 refreshValue : function()
49085 this.viewEl.select('img',true).each(function(e,i,n) {
49086 val += e.is(".x-menu-item-checked") ? String(n) : '';
49088 this.setValue(val, true);
49092 * Sets the checked state of the checkbox.
49093 * On is always based on a string comparison between inputValue and the param.
49094 * @param {Boolean/String} value - the value to set
49095 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49097 setValue : function(v,suppressEvent){
49098 if (!this.el.dom) {
49101 var old = this.el.dom.value ;
49102 this.el.dom.value = v;
49103 if (suppressEvent) {
49107 // update display..
49108 this.viewEl.select('img',true).each(function(e,i,n) {
49110 var on = e.is(".x-menu-item-checked");
49111 var newv = v.indexOf(String(n)) > -1;
49113 e.toggleClass('x-menu-item-checked');
49119 this.fireEvent('change', this, v, old);
49124 // handle setting of hidden value by some other method!!?!?
49125 setFromHidden: function()
49130 //console.log("SET FROM HIDDEN");
49131 //alert('setFrom hidden');
49132 this.setValue(this.el.dom.value);
49135 onDestroy : function()
49138 Roo.get(this.viewEl).remove();
49141 Roo.form.DayPicker.superclass.onDestroy.call(this);
49145 * RooJS Library 1.1.1
49146 * Copyright(c) 2008-2011 Alan Knowles
49153 * @class Roo.form.ComboCheck
49154 * @extends Roo.form.ComboBox
49155 * A combobox for multiple select items.
49157 * FIXME - could do with a reset button..
49160 * Create a new ComboCheck
49161 * @param {Object} config Configuration options
49163 Roo.form.ComboCheck = function(config){
49164 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49165 // should verify some data...
49167 // hiddenName = required..
49168 // displayField = required
49169 // valudField == required
49170 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49172 Roo.each(req, function(e) {
49173 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49174 throw "Roo.form.ComboCheck : missing value for: " + e;
49181 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49186 selectedClass: 'x-menu-item-checked',
49189 onRender : function(ct, position){
49195 var cls = 'x-combo-list';
49198 this.tpl = new Roo.Template({
49199 html : '<div class="'+cls+'-item x-menu-check-item">' +
49200 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49201 '<span>{' + this.displayField + '}</span>' +
49208 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49209 this.view.singleSelect = false;
49210 this.view.multiSelect = true;
49211 this.view.toggleSelect = true;
49212 this.pageTb.add(new Roo.Toolbar.Fill(), {
49215 handler: function()
49222 onViewOver : function(e, t){
49228 onViewClick : function(doFocus,index){
49232 select: function () {
49233 //Roo.log("SELECT CALLED");
49236 selectByValue : function(xv, scrollIntoView){
49237 var ar = this.getValueArray();
49240 Roo.each(ar, function(v) {
49241 if(v === undefined || v === null){
49244 var r = this.findRecord(this.valueField, v);
49246 sels.push(this.store.indexOf(r))
49250 this.view.select(sels);
49256 onSelect : function(record, index){
49257 // Roo.log("onselect Called");
49258 // this is only called by the clear button now..
49259 this.view.clearSelections();
49260 this.setValue('[]');
49261 if (this.value != this.valueBefore) {
49262 this.fireEvent('change', this, this.value, this.valueBefore);
49263 this.valueBefore = this.value;
49266 getValueArray : function()
49271 //Roo.log(this.value);
49272 if (typeof(this.value) == 'undefined') {
49275 var ar = Roo.decode(this.value);
49276 return ar instanceof Array ? ar : []; //?? valid?
49279 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49284 expand : function ()
49287 Roo.form.ComboCheck.superclass.expand.call(this);
49288 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49289 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49294 collapse : function(){
49295 Roo.form.ComboCheck.superclass.collapse.call(this);
49296 var sl = this.view.getSelectedIndexes();
49297 var st = this.store;
49301 Roo.each(sl, function(i) {
49303 nv.push(r.get(this.valueField));
49305 this.setValue(Roo.encode(nv));
49306 if (this.value != this.valueBefore) {
49308 this.fireEvent('change', this, this.value, this.valueBefore);
49309 this.valueBefore = this.value;
49314 setValue : function(v){
49318 var vals = this.getValueArray();
49320 Roo.each(vals, function(k) {
49321 var r = this.findRecord(this.valueField, k);
49323 tv.push(r.data[this.displayField]);
49324 }else if(this.valueNotFoundText !== undefined){
49325 tv.push( this.valueNotFoundText );
49330 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49331 this.hiddenField.value = v;
49337 * Ext JS Library 1.1.1
49338 * Copyright(c) 2006-2007, Ext JS, LLC.
49340 * Originally Released Under LGPL - original licence link has changed is not relivant.
49343 * <script type="text/javascript">
49347 * @class Roo.form.Signature
49348 * @extends Roo.form.Field
49352 * @param {Object} config Configuration options
49355 Roo.form.Signature = function(config){
49356 Roo.form.Signature.superclass.constructor.call(this, config);
49358 this.addEvents({// not in used??
49361 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49362 * @param {Roo.form.Signature} combo This combo box
49367 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49368 * @param {Roo.form.ComboBox} combo This combo box
49369 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49375 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49377 * @cfg {Object} labels Label to use when rendering a form.
49381 * confirm : "Confirm"
49386 confirm : "Confirm"
49389 * @cfg {Number} width The signature panel width (defaults to 300)
49393 * @cfg {Number} height The signature panel height (defaults to 100)
49397 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49399 allowBlank : false,
49402 // {Object} signPanel The signature SVG panel element (defaults to {})
49404 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49405 isMouseDown : false,
49406 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49407 isConfirmed : false,
49408 // {String} signatureTmp SVG mapping string (defaults to empty string)
49412 defaultAutoCreate : { // modified by initCompnoent..
49418 onRender : function(ct, position){
49420 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49422 this.wrap = this.el.wrap({
49423 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49426 this.createToolbar(this);
49427 this.signPanel = this.wrap.createChild({
49429 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49433 this.svgID = Roo.id();
49434 this.svgEl = this.signPanel.createChild({
49435 xmlns : 'http://www.w3.org/2000/svg',
49437 id : this.svgID + "-svg",
49439 height: this.height,
49440 viewBox: '0 0 '+this.width+' '+this.height,
49444 id: this.svgID + "-svg-r",
49446 height: this.height,
49451 id: this.svgID + "-svg-l",
49453 y1: (this.height*0.8), // start set the line in 80% of height
49454 x2: this.width, // end
49455 y2: (this.height*0.8), // end set the line in 80% of height
49457 'stroke-width': "1",
49458 'stroke-dasharray': "3",
49459 'shape-rendering': "crispEdges",
49460 'pointer-events': "none"
49464 id: this.svgID + "-svg-p",
49466 'stroke-width': "3",
49468 'pointer-events': 'none'
49473 this.svgBox = this.svgEl.dom.getScreenCTM();
49475 createSVG : function(){
49476 var svg = this.signPanel;
49477 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49480 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49481 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49482 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49483 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49484 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49485 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49486 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49489 isTouchEvent : function(e){
49490 return e.type.match(/^touch/);
49492 getCoords : function (e) {
49493 var pt = this.svgEl.dom.createSVGPoint();
49496 if (this.isTouchEvent(e)) {
49497 pt.x = e.targetTouches[0].clientX;
49498 pt.y = e.targetTouches[0].clientY;
49500 var a = this.svgEl.dom.getScreenCTM();
49501 var b = a.inverse();
49502 var mx = pt.matrixTransform(b);
49503 return mx.x + ',' + mx.y;
49505 //mouse event headler
49506 down : function (e) {
49507 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49508 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49510 this.isMouseDown = true;
49512 e.preventDefault();
49514 move : function (e) {
49515 if (this.isMouseDown) {
49516 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49517 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49520 e.preventDefault();
49522 up : function (e) {
49523 this.isMouseDown = false;
49524 var sp = this.signatureTmp.split(' ');
49527 if(!sp[sp.length-2].match(/^L/)){
49531 this.signatureTmp = sp.join(" ");
49534 if(this.getValue() != this.signatureTmp){
49535 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49536 this.isConfirmed = false;
49538 e.preventDefault();
49542 * Protected method that will not generally be called directly. It
49543 * is called when the editor creates its toolbar. Override this method if you need to
49544 * add custom toolbar buttons.
49545 * @param {HtmlEditor} editor
49547 createToolbar : function(editor){
49548 function btn(id, toggle, handler){
49549 var xid = fid + '-'+ id ;
49553 cls : 'x-btn-icon x-edit-'+id,
49554 enableToggle:toggle !== false,
49555 scope: editor, // was editor...
49556 handler:handler||editor.relayBtnCmd,
49557 clickEvent:'mousedown',
49558 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49564 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49568 cls : ' x-signature-btn x-signature-'+id,
49569 scope: editor, // was editor...
49570 handler: this.reset,
49571 clickEvent:'mousedown',
49572 text: this.labels.clear
49579 cls : ' x-signature-btn x-signature-'+id,
49580 scope: editor, // was editor...
49581 handler: this.confirmHandler,
49582 clickEvent:'mousedown',
49583 text: this.labels.confirm
49590 * when user is clicked confirm then show this image.....
49592 * @return {String} Image Data URI
49594 getImageDataURI : function(){
49595 var svg = this.svgEl.dom.parentNode.innerHTML;
49596 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49601 * @return {Boolean} this.isConfirmed
49603 getConfirmed : function(){
49604 return this.isConfirmed;
49608 * @return {Number} this.width
49610 getWidth : function(){
49615 * @return {Number} this.height
49617 getHeight : function(){
49618 return this.height;
49621 getSignature : function(){
49622 return this.signatureTmp;
49625 reset : function(){
49626 this.signatureTmp = '';
49627 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49628 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49629 this.isConfirmed = false;
49630 Roo.form.Signature.superclass.reset.call(this);
49632 setSignature : function(s){
49633 this.signatureTmp = s;
49634 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49635 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49637 this.isConfirmed = false;
49638 Roo.form.Signature.superclass.reset.call(this);
49641 // Roo.log(this.signPanel.dom.contentWindow.up())
49644 setConfirmed : function(){
49648 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49651 confirmHandler : function(){
49652 if(!this.getSignature()){
49656 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49657 this.setValue(this.getSignature());
49658 this.isConfirmed = true;
49660 this.fireEvent('confirm', this);
49663 // Subclasses should provide the validation implementation by overriding this
49664 validateValue : function(value){
49665 if(this.allowBlank){
49669 if(this.isConfirmed){
49676 * Ext JS Library 1.1.1
49677 * Copyright(c) 2006-2007, Ext JS, LLC.
49679 * Originally Released Under LGPL - original licence link has changed is not relivant.
49682 * <script type="text/javascript">
49687 * @class Roo.form.ComboBox
49688 * @extends Roo.form.TriggerField
49689 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49691 * Create a new ComboBox.
49692 * @param {Object} config Configuration options
49694 Roo.form.Select = function(config){
49695 Roo.form.Select.superclass.constructor.call(this, config);
49699 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49701 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49704 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49705 * rendering into an Roo.Editor, defaults to false)
49708 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49709 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49712 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49715 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49716 * the dropdown list (defaults to undefined, with no header element)
49720 * @cfg {String/Roo.Template} tpl The template to use to render the output
49724 defaultAutoCreate : {tag: "select" },
49726 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49728 listWidth: undefined,
49730 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49731 * mode = 'remote' or 'text' if mode = 'local')
49733 displayField: undefined,
49735 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49736 * mode = 'remote' or 'value' if mode = 'local').
49737 * Note: use of a valueField requires the user make a selection
49738 * in order for a value to be mapped.
49740 valueField: undefined,
49744 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49745 * field's data value (defaults to the underlying DOM element's name)
49747 hiddenName: undefined,
49749 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49753 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49755 selectedClass: 'x-combo-selected',
49757 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49758 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49759 * which displays a downward arrow icon).
49761 triggerClass : 'x-form-arrow-trigger',
49763 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49767 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49768 * anchor positions (defaults to 'tl-bl')
49770 listAlign: 'tl-bl?',
49772 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49776 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49777 * query specified by the allQuery config option (defaults to 'query')
49779 triggerAction: 'query',
49781 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49782 * (defaults to 4, does not apply if editable = false)
49786 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49787 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49791 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49792 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49796 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49797 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49801 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49802 * when editable = true (defaults to false)
49804 selectOnFocus:false,
49806 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49808 queryParam: 'query',
49810 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49811 * when mode = 'remote' (defaults to 'Loading...')
49813 loadingText: 'Loading...',
49815 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49819 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49823 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49824 * traditional select (defaults to true)
49828 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49832 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49836 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49837 * listWidth has a higher value)
49841 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49842 * allow the user to set arbitrary text into the field (defaults to false)
49844 forceSelection:false,
49846 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49847 * if typeAhead = true (defaults to 250)
49849 typeAheadDelay : 250,
49851 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
49852 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
49854 valueNotFoundText : undefined,
49857 * @cfg {String} defaultValue The value displayed after loading the store.
49862 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
49864 blockFocus : false,
49867 * @cfg {Boolean} disableClear Disable showing of clear button.
49869 disableClear : false,
49871 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
49873 alwaysQuery : false,
49879 // element that contains real text value.. (when hidden is used..)
49882 onRender : function(ct, position){
49883 Roo.form.Field.prototype.onRender.call(this, ct, position);
49886 this.store.on('beforeload', this.onBeforeLoad, this);
49887 this.store.on('load', this.onLoad, this);
49888 this.store.on('loadexception', this.onLoadException, this);
49889 this.store.load({});
49897 initEvents : function(){
49898 //Roo.form.ComboBox.superclass.initEvents.call(this);
49902 onDestroy : function(){
49905 this.store.un('beforeload', this.onBeforeLoad, this);
49906 this.store.un('load', this.onLoad, this);
49907 this.store.un('loadexception', this.onLoadException, this);
49909 //Roo.form.ComboBox.superclass.onDestroy.call(this);
49913 fireKey : function(e){
49914 if(e.isNavKeyPress() && !this.list.isVisible()){
49915 this.fireEvent("specialkey", this, e);
49920 onResize: function(w, h){
49928 * Allow or prevent the user from directly editing the field text. If false is passed,
49929 * the user will only be able to select from the items defined in the dropdown list. This method
49930 * is the runtime equivalent of setting the 'editable' config option at config time.
49931 * @param {Boolean} value True to allow the user to directly edit the field text
49933 setEditable : function(value){
49938 onBeforeLoad : function(){
49940 Roo.log("Select before load");
49943 this.innerList.update(this.loadingText ?
49944 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
49945 //this.restrictHeight();
49946 this.selectedIndex = -1;
49950 onLoad : function(){
49953 var dom = this.el.dom;
49954 dom.innerHTML = '';
49955 var od = dom.ownerDocument;
49957 if (this.emptyText) {
49958 var op = od.createElement('option');
49959 op.setAttribute('value', '');
49960 op.innerHTML = String.format('{0}', this.emptyText);
49961 dom.appendChild(op);
49963 if(this.store.getCount() > 0){
49965 var vf = this.valueField;
49966 var df = this.displayField;
49967 this.store.data.each(function(r) {
49968 // which colmsn to use... testing - cdoe / title..
49969 var op = od.createElement('option');
49970 op.setAttribute('value', r.data[vf]);
49971 op.innerHTML = String.format('{0}', r.data[df]);
49972 dom.appendChild(op);
49974 if (typeof(this.defaultValue != 'undefined')) {
49975 this.setValue(this.defaultValue);
49980 //this.onEmptyResults();
49985 onLoadException : function()
49987 dom.innerHTML = '';
49989 Roo.log("Select on load exception");
49993 Roo.log(this.store.reader.jsonData);
49994 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
49995 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50001 onTypeAhead : function(){
50006 onSelect : function(record, index){
50007 Roo.log('on select?');
50009 if(this.fireEvent('beforeselect', this, record, index) !== false){
50010 this.setFromData(index > -1 ? record.data : false);
50012 this.fireEvent('select', this, record, index);
50017 * Returns the currently selected field value or empty string if no value is set.
50018 * @return {String} value The selected value
50020 getValue : function(){
50021 var dom = this.el.dom;
50022 this.value = dom.options[dom.selectedIndex].value;
50028 * Clears any text/value currently set in the field
50030 clearValue : function(){
50032 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50037 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50038 * will be displayed in the field. If the value does not match the data value of an existing item,
50039 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50040 * Otherwise the field will be blank (although the value will still be set).
50041 * @param {String} value The value to match
50043 setValue : function(v){
50044 var d = this.el.dom;
50045 for (var i =0; i < d.options.length;i++) {
50046 if (v == d.options[i].value) {
50047 d.selectedIndex = i;
50055 * @property {Object} the last set data for the element
50060 * Sets the value of the field based on a object which is related to the record format for the store.
50061 * @param {Object} value the value to set as. or false on reset?
50063 setFromData : function(o){
50064 Roo.log('setfrom data?');
50070 reset : function(){
50074 findRecord : function(prop, value){
50079 if(this.store.getCount() > 0){
50080 this.store.each(function(r){
50081 if(r.data[prop] == value){
50091 getName: function()
50093 // returns hidden if it's set..
50094 if (!this.rendered) {return ''};
50095 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50103 onEmptyResults : function(){
50104 Roo.log('empty results');
50109 * Returns true if the dropdown list is expanded, else false.
50111 isExpanded : function(){
50116 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50117 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50118 * @param {String} value The data value of the item to select
50119 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50120 * selected item if it is not currently in view (defaults to true)
50121 * @return {Boolean} True if the value matched an item in the list, else false
50123 selectByValue : function(v, scrollIntoView){
50124 Roo.log('select By Value');
50127 if(v !== undefined && v !== null){
50128 var r = this.findRecord(this.valueField || this.displayField, v);
50130 this.select(this.store.indexOf(r), scrollIntoView);
50138 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50139 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50140 * @param {Number} index The zero-based index of the list item to select
50141 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50142 * selected item if it is not currently in view (defaults to true)
50144 select : function(index, scrollIntoView){
50145 Roo.log('select ');
50148 this.selectedIndex = index;
50149 this.view.select(index);
50150 if(scrollIntoView !== false){
50151 var el = this.view.getNode(index);
50153 this.innerList.scrollChildIntoView(el, false);
50161 validateBlur : function(){
50168 initQuery : function(){
50169 this.doQuery(this.getRawValue());
50173 doForce : function(){
50174 if(this.el.dom.value.length > 0){
50175 this.el.dom.value =
50176 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50182 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50183 * query allowing the query action to be canceled if needed.
50184 * @param {String} query The SQL query to execute
50185 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50186 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50187 * saved in the current store (defaults to false)
50189 doQuery : function(q, forceAll){
50191 Roo.log('doQuery?');
50192 if(q === undefined || q === null){
50197 forceAll: forceAll,
50201 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50205 forceAll = qe.forceAll;
50206 if(forceAll === true || (q.length >= this.minChars)){
50207 if(this.lastQuery != q || this.alwaysQuery){
50208 this.lastQuery = q;
50209 if(this.mode == 'local'){
50210 this.selectedIndex = -1;
50212 this.store.clearFilter();
50214 this.store.filter(this.displayField, q);
50218 this.store.baseParams[this.queryParam] = q;
50220 params: this.getParams(q)
50225 this.selectedIndex = -1;
50232 getParams : function(q){
50234 //p[this.queryParam] = q;
50237 p.limit = this.pageSize;
50243 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50245 collapse : function(){
50250 collapseIf : function(e){
50255 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50257 expand : function(){
50265 * @cfg {Boolean} grow
50269 * @cfg {Number} growMin
50273 * @cfg {Number} growMax
50281 setWidth : function()
50285 getResizeEl : function(){
50288 });//<script type="text/javasscript">
50292 * @class Roo.DDView
50293 * A DnD enabled version of Roo.View.
50294 * @param {Element/String} container The Element in which to create the View.
50295 * @param {String} tpl The template string used to create the markup for each element of the View
50296 * @param {Object} config The configuration properties. These include all the config options of
50297 * {@link Roo.View} plus some specific to this class.<br>
50299 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50300 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50302 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50303 .x-view-drag-insert-above {
50304 border-top:1px dotted #3366cc;
50306 .x-view-drag-insert-below {
50307 border-bottom:1px dotted #3366cc;
50313 Roo.DDView = function(container, tpl, config) {
50314 Roo.DDView.superclass.constructor.apply(this, arguments);
50315 this.getEl().setStyle("outline", "0px none");
50316 this.getEl().unselectable();
50317 if (this.dragGroup) {
50318 this.setDraggable(this.dragGroup.split(","));
50320 if (this.dropGroup) {
50321 this.setDroppable(this.dropGroup.split(","));
50323 if (this.deletable) {
50324 this.setDeletable();
50326 this.isDirtyFlag = false;
50332 Roo.extend(Roo.DDView, Roo.View, {
50333 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50334 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50335 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50336 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50340 reset: Roo.emptyFn,
50342 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50344 validate: function() {
50348 destroy: function() {
50349 this.purgeListeners();
50350 this.getEl.removeAllListeners();
50351 this.getEl().remove();
50352 if (this.dragZone) {
50353 if (this.dragZone.destroy) {
50354 this.dragZone.destroy();
50357 if (this.dropZone) {
50358 if (this.dropZone.destroy) {
50359 this.dropZone.destroy();
50364 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50365 getName: function() {
50369 /** Loads the View from a JSON string representing the Records to put into the Store. */
50370 setValue: function(v) {
50372 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50375 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50376 this.store.proxy = new Roo.data.MemoryProxy(data);
50380 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50381 getValue: function() {
50383 this.store.each(function(rec) {
50384 result += rec.id + ',';
50386 return result.substr(0, result.length - 1) + ')';
50389 getIds: function() {
50390 var i = 0, result = new Array(this.store.getCount());
50391 this.store.each(function(rec) {
50392 result[i++] = rec.id;
50397 isDirty: function() {
50398 return this.isDirtyFlag;
50402 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50403 * whole Element becomes the target, and this causes the drop gesture to append.
50405 getTargetFromEvent : function(e) {
50406 var target = e.getTarget();
50407 while ((target !== null) && (target.parentNode != this.el.dom)) {
50408 target = target.parentNode;
50411 target = this.el.dom.lastChild || this.el.dom;
50417 * Create the drag data which consists of an object which has the property "ddel" as
50418 * the drag proxy element.
50420 getDragData : function(e) {
50421 var target = this.findItemFromChild(e.getTarget());
50423 this.handleSelection(e);
50424 var selNodes = this.getSelectedNodes();
50427 copy: this.copy || (this.allowCopy && e.ctrlKey),
50431 var selectedIndices = this.getSelectedIndexes();
50432 for (var i = 0; i < selectedIndices.length; i++) {
50433 dragData.records.push(this.store.getAt(selectedIndices[i]));
50435 if (selNodes.length == 1) {
50436 dragData.ddel = target.cloneNode(true); // the div element
50438 var div = document.createElement('div'); // create the multi element drag "ghost"
50439 div.className = 'multi-proxy';
50440 for (var i = 0, len = selNodes.length; i < len; i++) {
50441 div.appendChild(selNodes[i].cloneNode(true));
50443 dragData.ddel = div;
50445 //console.log(dragData)
50446 //console.log(dragData.ddel.innerHTML)
50449 //console.log('nodragData')
50453 /** Specify to which ddGroup items in this DDView may be dragged. */
50454 setDraggable: function(ddGroup) {
50455 if (ddGroup instanceof Array) {
50456 Roo.each(ddGroup, this.setDraggable, this);
50459 if (this.dragZone) {
50460 this.dragZone.addToGroup(ddGroup);
50462 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50463 containerScroll: true,
50467 // Draggability implies selection. DragZone's mousedown selects the element.
50468 if (!this.multiSelect) { this.singleSelect = true; }
50470 // Wire the DragZone's handlers up to methods in *this*
50471 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50475 /** Specify from which ddGroup this DDView accepts drops. */
50476 setDroppable: function(ddGroup) {
50477 if (ddGroup instanceof Array) {
50478 Roo.each(ddGroup, this.setDroppable, this);
50481 if (this.dropZone) {
50482 this.dropZone.addToGroup(ddGroup);
50484 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50485 containerScroll: true,
50489 // Wire the DropZone's handlers up to methods in *this*
50490 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50491 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50492 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50493 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50494 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50498 /** Decide whether to drop above or below a View node. */
50499 getDropPoint : function(e, n, dd){
50500 if (n == this.el.dom) { return "above"; }
50501 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50502 var c = t + (b - t) / 2;
50503 var y = Roo.lib.Event.getPageY(e);
50511 onNodeEnter : function(n, dd, e, data){
50515 onNodeOver : function(n, dd, e, data){
50516 var pt = this.getDropPoint(e, n, dd);
50517 // set the insert point style on the target node
50518 var dragElClass = this.dropNotAllowed;
50521 if (pt == "above"){
50522 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50523 targetElClass = "x-view-drag-insert-above";
50525 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50526 targetElClass = "x-view-drag-insert-below";
50528 if (this.lastInsertClass != targetElClass){
50529 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50530 this.lastInsertClass = targetElClass;
50533 return dragElClass;
50536 onNodeOut : function(n, dd, e, data){
50537 this.removeDropIndicators(n);
50540 onNodeDrop : function(n, dd, e, data){
50541 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50544 var pt = this.getDropPoint(e, n, dd);
50545 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50546 if (pt == "below") { insertAt++; }
50547 for (var i = 0; i < data.records.length; i++) {
50548 var r = data.records[i];
50549 var dup = this.store.getById(r.id);
50550 if (dup && (dd != this.dragZone)) {
50551 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50554 this.store.insert(insertAt++, r.copy());
50556 data.source.isDirtyFlag = true;
50558 this.store.insert(insertAt++, r);
50560 this.isDirtyFlag = true;
50563 this.dragZone.cachedTarget = null;
50567 removeDropIndicators : function(n){
50569 Roo.fly(n).removeClass([
50570 "x-view-drag-insert-above",
50571 "x-view-drag-insert-below"]);
50572 this.lastInsertClass = "_noclass";
50577 * Utility method. Add a delete option to the DDView's context menu.
50578 * @param {String} imageUrl The URL of the "delete" icon image.
50580 setDeletable: function(imageUrl) {
50581 if (!this.singleSelect && !this.multiSelect) {
50582 this.singleSelect = true;
50584 var c = this.getContextMenu();
50585 this.contextMenu.on("itemclick", function(item) {
50588 this.remove(this.getSelectedIndexes());
50592 this.contextMenu.add({
50599 /** Return the context menu for this DDView. */
50600 getContextMenu: function() {
50601 if (!this.contextMenu) {
50602 // Create the View's context menu
50603 this.contextMenu = new Roo.menu.Menu({
50604 id: this.id + "-contextmenu"
50606 this.el.on("contextmenu", this.showContextMenu, this);
50608 return this.contextMenu;
50611 disableContextMenu: function() {
50612 if (this.contextMenu) {
50613 this.el.un("contextmenu", this.showContextMenu, this);
50617 showContextMenu: function(e, item) {
50618 item = this.findItemFromChild(e.getTarget());
50621 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50622 this.contextMenu.showAt(e.getXY());
50627 * Remove {@link Roo.data.Record}s at the specified indices.
50628 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50630 remove: function(selectedIndices) {
50631 selectedIndices = [].concat(selectedIndices);
50632 for (var i = 0; i < selectedIndices.length; i++) {
50633 var rec = this.store.getAt(selectedIndices[i]);
50634 this.store.remove(rec);
50639 * Double click fires the event, but also, if this is draggable, and there is only one other
50640 * related DropZone, it transfers the selected node.
50642 onDblClick : function(e){
50643 var item = this.findItemFromChild(e.getTarget());
50645 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50648 if (this.dragGroup) {
50649 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50650 while (targets.indexOf(this.dropZone) > -1) {
50651 targets.remove(this.dropZone);
50653 if (targets.length == 1) {
50654 this.dragZone.cachedTarget = null;
50655 var el = Roo.get(targets[0].getEl());
50656 var box = el.getBox(true);
50657 targets[0].onNodeDrop(el.dom, {
50659 xy: [box.x, box.y + box.height - 1]
50660 }, null, this.getDragData(e));
50666 handleSelection: function(e) {
50667 this.dragZone.cachedTarget = null;
50668 var item = this.findItemFromChild(e.getTarget());
50670 this.clearSelections(true);
50673 if (item && (this.multiSelect || this.singleSelect)){
50674 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50675 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50676 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50677 this.unselect(item);
50679 this.select(item, this.multiSelect && e.ctrlKey);
50680 this.lastSelection = item;
50685 onItemClick : function(item, index, e){
50686 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50692 unselect : function(nodeInfo, suppressEvent){
50693 var node = this.getNode(nodeInfo);
50694 if(node && this.isSelected(node)){
50695 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50696 Roo.fly(node).removeClass(this.selectedClass);
50697 this.selections.remove(node);
50698 if(!suppressEvent){
50699 this.fireEvent("selectionchange", this, this.selections);
50707 * Ext JS Library 1.1.1
50708 * Copyright(c) 2006-2007, Ext JS, LLC.
50710 * Originally Released Under LGPL - original licence link has changed is not relivant.
50713 * <script type="text/javascript">
50717 * @class Roo.LayoutManager
50718 * @extends Roo.util.Observable
50719 * Base class for layout managers.
50721 Roo.LayoutManager = function(container, config){
50722 Roo.LayoutManager.superclass.constructor.call(this);
50723 this.el = Roo.get(container);
50724 // ie scrollbar fix
50725 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50726 document.body.scroll = "no";
50727 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50728 this.el.position('relative');
50730 this.id = this.el.id;
50731 this.el.addClass("x-layout-container");
50732 /** false to disable window resize monitoring @type Boolean */
50733 this.monitorWindowResize = true;
50738 * Fires when a layout is performed.
50739 * @param {Roo.LayoutManager} this
50743 * @event regionresized
50744 * Fires when the user resizes a region.
50745 * @param {Roo.LayoutRegion} region The resized region
50746 * @param {Number} newSize The new size (width for east/west, height for north/south)
50748 "regionresized" : true,
50750 * @event regioncollapsed
50751 * Fires when a region is collapsed.
50752 * @param {Roo.LayoutRegion} region The collapsed region
50754 "regioncollapsed" : true,
50756 * @event regionexpanded
50757 * Fires when a region is expanded.
50758 * @param {Roo.LayoutRegion} region The expanded region
50760 "regionexpanded" : true
50762 this.updating = false;
50763 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50766 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50768 * Returns true if this layout is currently being updated
50769 * @return {Boolean}
50771 isUpdating : function(){
50772 return this.updating;
50776 * Suspend the LayoutManager from doing auto-layouts while
50777 * making multiple add or remove calls
50779 beginUpdate : function(){
50780 this.updating = true;
50784 * Restore auto-layouts and optionally disable the manager from performing a layout
50785 * @param {Boolean} noLayout true to disable a layout update
50787 endUpdate : function(noLayout){
50788 this.updating = false;
50794 layout: function(){
50798 onRegionResized : function(region, newSize){
50799 this.fireEvent("regionresized", region, newSize);
50803 onRegionCollapsed : function(region){
50804 this.fireEvent("regioncollapsed", region);
50807 onRegionExpanded : function(region){
50808 this.fireEvent("regionexpanded", region);
50812 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50813 * performs box-model adjustments.
50814 * @return {Object} The size as an object {width: (the width), height: (the height)}
50816 getViewSize : function(){
50818 if(this.el.dom != document.body){
50819 size = this.el.getSize();
50821 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50823 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50824 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50829 * Returns the Element this layout is bound to.
50830 * @return {Roo.Element}
50832 getEl : function(){
50837 * Returns the specified region.
50838 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50839 * @return {Roo.LayoutRegion}
50841 getRegion : function(target){
50842 return this.regions[target.toLowerCase()];
50845 onWindowResize : function(){
50846 if(this.monitorWindowResize){
50852 * Ext JS Library 1.1.1
50853 * Copyright(c) 2006-2007, Ext JS, LLC.
50855 * Originally Released Under LGPL - original licence link has changed is not relivant.
50858 * <script type="text/javascript">
50861 * @class Roo.BorderLayout
50862 * @extends Roo.LayoutManager
50863 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
50864 * please see: <br><br>
50865 * <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>
50866 * <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>
50869 var layout = new Roo.BorderLayout(document.body, {
50903 preferredTabWidth: 150
50908 var CP = Roo.ContentPanel;
50910 layout.beginUpdate();
50911 layout.add("north", new CP("north", "North"));
50912 layout.add("south", new CP("south", {title: "South", closable: true}));
50913 layout.add("west", new CP("west", {title: "West"}));
50914 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
50915 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
50916 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
50917 layout.getRegion("center").showPanel("center1");
50918 layout.endUpdate();
50921 <b>The container the layout is rendered into can be either the body element or any other element.
50922 If it is not the body element, the container needs to either be an absolute positioned element,
50923 or you will need to add "position:relative" to the css of the container. You will also need to specify
50924 the container size if it is not the body element.</b>
50927 * Create a new BorderLayout
50928 * @param {String/HTMLElement/Element} container The container this layout is bound to
50929 * @param {Object} config Configuration options
50931 Roo.BorderLayout = function(container, config){
50932 config = config || {};
50933 Roo.BorderLayout.superclass.constructor.call(this, container, config);
50934 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
50935 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
50936 var target = this.factory.validRegions[i];
50937 if(config[target]){
50938 this.addRegion(target, config[target]);
50943 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
50945 * Creates and adds a new region if it doesn't already exist.
50946 * @param {String} target The target region key (north, south, east, west or center).
50947 * @param {Object} config The regions config object
50948 * @return {BorderLayoutRegion} The new region
50950 addRegion : function(target, config){
50951 if(!this.regions[target]){
50952 var r = this.factory.create(target, this, config);
50953 this.bindRegion(target, r);
50955 return this.regions[target];
50959 bindRegion : function(name, r){
50960 this.regions[name] = r;
50961 r.on("visibilitychange", this.layout, this);
50962 r.on("paneladded", this.layout, this);
50963 r.on("panelremoved", this.layout, this);
50964 r.on("invalidated", this.layout, this);
50965 r.on("resized", this.onRegionResized, this);
50966 r.on("collapsed", this.onRegionCollapsed, this);
50967 r.on("expanded", this.onRegionExpanded, this);
50971 * Performs a layout update.
50973 layout : function(){
50974 if(this.updating) {
50977 var size = this.getViewSize();
50978 var w = size.width;
50979 var h = size.height;
50984 //var x = 0, y = 0;
50986 var rs = this.regions;
50987 var north = rs["north"];
50988 var south = rs["south"];
50989 var west = rs["west"];
50990 var east = rs["east"];
50991 var center = rs["center"];
50992 //if(this.hideOnLayout){ // not supported anymore
50993 //c.el.setStyle("display", "none");
50995 if(north && north.isVisible()){
50996 var b = north.getBox();
50997 var m = north.getMargins();
50998 b.width = w - (m.left+m.right);
51001 centerY = b.height + b.y + m.bottom;
51002 centerH -= centerY;
51003 north.updateBox(this.safeBox(b));
51005 if(south && south.isVisible()){
51006 var b = south.getBox();
51007 var m = south.getMargins();
51008 b.width = w - (m.left+m.right);
51010 var totalHeight = (b.height + m.top + m.bottom);
51011 b.y = h - totalHeight + m.top;
51012 centerH -= totalHeight;
51013 south.updateBox(this.safeBox(b));
51015 if(west && west.isVisible()){
51016 var b = west.getBox();
51017 var m = west.getMargins();
51018 b.height = centerH - (m.top+m.bottom);
51020 b.y = centerY + m.top;
51021 var totalWidth = (b.width + m.left + m.right);
51022 centerX += totalWidth;
51023 centerW -= totalWidth;
51024 west.updateBox(this.safeBox(b));
51026 if(east && east.isVisible()){
51027 var b = east.getBox();
51028 var m = east.getMargins();
51029 b.height = centerH - (m.top+m.bottom);
51030 var totalWidth = (b.width + m.left + m.right);
51031 b.x = w - totalWidth + m.left;
51032 b.y = centerY + m.top;
51033 centerW -= totalWidth;
51034 east.updateBox(this.safeBox(b));
51037 var m = center.getMargins();
51039 x: centerX + m.left,
51040 y: centerY + m.top,
51041 width: centerW - (m.left+m.right),
51042 height: centerH - (m.top+m.bottom)
51044 //if(this.hideOnLayout){
51045 //center.el.setStyle("display", "block");
51047 center.updateBox(this.safeBox(centerBox));
51050 this.fireEvent("layout", this);
51054 safeBox : function(box){
51055 box.width = Math.max(0, box.width);
51056 box.height = Math.max(0, box.height);
51061 * Adds a ContentPanel (or subclass) to this layout.
51062 * @param {String} target The target region key (north, south, east, west or center).
51063 * @param {Roo.ContentPanel} panel The panel to add
51064 * @return {Roo.ContentPanel} The added panel
51066 add : function(target, panel){
51068 target = target.toLowerCase();
51069 return this.regions[target].add(panel);
51073 * Remove a ContentPanel (or subclass) to this layout.
51074 * @param {String} target The target region key (north, south, east, west or center).
51075 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51076 * @return {Roo.ContentPanel} The removed panel
51078 remove : function(target, panel){
51079 target = target.toLowerCase();
51080 return this.regions[target].remove(panel);
51084 * Searches all regions for a panel with the specified id
51085 * @param {String} panelId
51086 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51088 findPanel : function(panelId){
51089 var rs = this.regions;
51090 for(var target in rs){
51091 if(typeof rs[target] != "function"){
51092 var p = rs[target].getPanel(panelId);
51102 * Searches all regions for a panel with the specified id and activates (shows) it.
51103 * @param {String/ContentPanel} panelId The panels id or the panel itself
51104 * @return {Roo.ContentPanel} The shown panel or null
51106 showPanel : function(panelId) {
51107 var rs = this.regions;
51108 for(var target in rs){
51109 var r = rs[target];
51110 if(typeof r != "function"){
51111 if(r.hasPanel(panelId)){
51112 return r.showPanel(panelId);
51120 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51121 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51123 restoreState : function(provider){
51125 provider = Roo.state.Manager;
51127 var sm = new Roo.LayoutStateManager();
51128 sm.init(this, provider);
51132 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51133 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51134 * a valid ContentPanel config object. Example:
51136 // Create the main layout
51137 var layout = new Roo.BorderLayout('main-ct', {
51148 // Create and add multiple ContentPanels at once via configs
51151 id: 'source-files',
51153 title:'Ext Source Files',
51166 * @param {Object} regions An object containing ContentPanel configs by region name
51168 batchAdd : function(regions){
51169 this.beginUpdate();
51170 for(var rname in regions){
51171 var lr = this.regions[rname];
51173 this.addTypedPanels(lr, regions[rname]);
51180 addTypedPanels : function(lr, ps){
51181 if(typeof ps == 'string'){
51182 lr.add(new Roo.ContentPanel(ps));
51184 else if(ps instanceof Array){
51185 for(var i =0, len = ps.length; i < len; i++){
51186 this.addTypedPanels(lr, ps[i]);
51189 else if(!ps.events){ // raw config?
51191 delete ps.el; // prevent conflict
51192 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51194 else { // panel object assumed!
51199 * Adds a xtype elements to the layout.
51203 xtype : 'ContentPanel',
51210 xtype : 'NestedLayoutPanel',
51216 items : [ ... list of content panels or nested layout panels.. ]
51220 * @param {Object} cfg Xtype definition of item to add.
51222 addxtype : function(cfg)
51224 // basically accepts a pannel...
51225 // can accept a layout region..!?!?
51226 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51228 if (!cfg.xtype.match(/Panel$/)) {
51233 if (typeof(cfg.region) == 'undefined') {
51234 Roo.log("Failed to add Panel, region was not set");
51238 var region = cfg.region;
51244 xitems = cfg.items;
51251 case 'ContentPanel': // ContentPanel (el, cfg)
51252 case 'ScrollPanel': // ContentPanel (el, cfg)
51254 if(cfg.autoCreate) {
51255 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51257 var el = this.el.createChild();
51258 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51261 this.add(region, ret);
51265 case 'TreePanel': // our new panel!
51266 cfg.el = this.el.createChild();
51267 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51268 this.add(region, ret);
51271 case 'NestedLayoutPanel':
51272 // create a new Layout (which is a Border Layout...
51273 var el = this.el.createChild();
51274 var clayout = cfg.layout;
51276 clayout.items = clayout.items || [];
51277 // replace this exitems with the clayout ones..
51278 xitems = clayout.items;
51281 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51282 cfg.background = false;
51284 var layout = new Roo.BorderLayout(el, clayout);
51286 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51287 //console.log('adding nested layout panel ' + cfg.toSource());
51288 this.add(region, ret);
51289 nb = {}; /// find first...
51294 // needs grid and region
51296 //var el = this.getRegion(region).el.createChild();
51297 var el = this.el.createChild();
51298 // create the grid first...
51300 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51302 if (region == 'center' && this.active ) {
51303 cfg.background = false;
51305 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51307 this.add(region, ret);
51308 if (cfg.background) {
51309 ret.on('activate', function(gp) {
51310 if (!gp.grid.rendered) {
51325 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51327 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51328 this.add(region, ret);
51331 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51335 // GridPanel (grid, cfg)
51338 this.beginUpdate();
51342 Roo.each(xitems, function(i) {
51343 region = nb && i.region ? i.region : false;
51345 var add = ret.addxtype(i);
51348 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51349 if (!i.background) {
51350 abn[region] = nb[region] ;
51357 // make the last non-background panel active..
51358 //if (nb) { Roo.log(abn); }
51361 for(var r in abn) {
51362 region = this.getRegion(r);
51364 // tried using nb[r], but it does not work..
51366 region.showPanel(abn[r]);
51377 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51378 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51379 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51380 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51383 var CP = Roo.ContentPanel;
51385 var layout = Roo.BorderLayout.create({
51389 panels: [new CP("north", "North")]
51398 panels: [new CP("west", {title: "West"})]
51407 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51416 panels: [new CP("south", {title: "South", closable: true})]
51423 preferredTabWidth: 150,
51425 new CP("center1", {title: "Close Me", closable: true}),
51426 new CP("center2", {title: "Center Panel", closable: false})
51431 layout.getRegion("center").showPanel("center1");
51436 Roo.BorderLayout.create = function(config, targetEl){
51437 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51438 layout.beginUpdate();
51439 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51440 for(var j = 0, jlen = regions.length; j < jlen; j++){
51441 var lr = regions[j];
51442 if(layout.regions[lr] && config[lr].panels){
51443 var r = layout.regions[lr];
51444 var ps = config[lr].panels;
51445 layout.addTypedPanels(r, ps);
51448 layout.endUpdate();
51453 Roo.BorderLayout.RegionFactory = {
51455 validRegions : ["north","south","east","west","center"],
51458 create : function(target, mgr, config){
51459 target = target.toLowerCase();
51460 if(config.lightweight || config.basic){
51461 return new Roo.BasicLayoutRegion(mgr, config, target);
51465 return new Roo.NorthLayoutRegion(mgr, config);
51467 return new Roo.SouthLayoutRegion(mgr, config);
51469 return new Roo.EastLayoutRegion(mgr, config);
51471 return new Roo.WestLayoutRegion(mgr, config);
51473 return new Roo.CenterLayoutRegion(mgr, config);
51475 throw 'Layout region "'+target+'" not supported.';
51479 * Ext JS Library 1.1.1
51480 * Copyright(c) 2006-2007, Ext JS, LLC.
51482 * Originally Released Under LGPL - original licence link has changed is not relivant.
51485 * <script type="text/javascript">
51489 * @class Roo.BasicLayoutRegion
51490 * @extends Roo.util.Observable
51491 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51492 * and does not have a titlebar, tabs or any other features. All it does is size and position
51493 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51495 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51497 this.position = pos;
51500 * @scope Roo.BasicLayoutRegion
51504 * @event beforeremove
51505 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51506 * @param {Roo.LayoutRegion} this
51507 * @param {Roo.ContentPanel} panel The panel
51508 * @param {Object} e The cancel event object
51510 "beforeremove" : true,
51512 * @event invalidated
51513 * Fires when the layout for this region is changed.
51514 * @param {Roo.LayoutRegion} this
51516 "invalidated" : true,
51518 * @event visibilitychange
51519 * Fires when this region is shown or hidden
51520 * @param {Roo.LayoutRegion} this
51521 * @param {Boolean} visibility true or false
51523 "visibilitychange" : true,
51525 * @event paneladded
51526 * Fires when a panel is added.
51527 * @param {Roo.LayoutRegion} this
51528 * @param {Roo.ContentPanel} panel The panel
51530 "paneladded" : true,
51532 * @event panelremoved
51533 * Fires when a panel is removed.
51534 * @param {Roo.LayoutRegion} this
51535 * @param {Roo.ContentPanel} panel The panel
51537 "panelremoved" : true,
51539 * @event beforecollapse
51540 * Fires when this region before collapse.
51541 * @param {Roo.LayoutRegion} this
51543 "beforecollapse" : true,
51546 * Fires when this region is collapsed.
51547 * @param {Roo.LayoutRegion} this
51549 "collapsed" : true,
51552 * Fires when this region is expanded.
51553 * @param {Roo.LayoutRegion} this
51558 * Fires when this region is slid into view.
51559 * @param {Roo.LayoutRegion} this
51561 "slideshow" : true,
51564 * Fires when this region slides out of view.
51565 * @param {Roo.LayoutRegion} this
51567 "slidehide" : true,
51569 * @event panelactivated
51570 * Fires when a panel is activated.
51571 * @param {Roo.LayoutRegion} this
51572 * @param {Roo.ContentPanel} panel The activated panel
51574 "panelactivated" : true,
51577 * Fires when the user resizes this region.
51578 * @param {Roo.LayoutRegion} this
51579 * @param {Number} newSize The new size (width for east/west, height for north/south)
51583 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51584 this.panels = new Roo.util.MixedCollection();
51585 this.panels.getKey = this.getPanelId.createDelegate(this);
51587 this.activePanel = null;
51588 // ensure listeners are added...
51590 if (config.listeners || config.events) {
51591 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51592 listeners : config.listeners || {},
51593 events : config.events || {}
51597 if(skipConfig !== true){
51598 this.applyConfig(config);
51602 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51603 getPanelId : function(p){
51607 applyConfig : function(config){
51608 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51609 this.config = config;
51614 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51615 * the width, for horizontal (north, south) the height.
51616 * @param {Number} newSize The new width or height
51618 resizeTo : function(newSize){
51619 var el = this.el ? this.el :
51620 (this.activePanel ? this.activePanel.getEl() : null);
51622 switch(this.position){
51625 el.setWidth(newSize);
51626 this.fireEvent("resized", this, newSize);
51630 el.setHeight(newSize);
51631 this.fireEvent("resized", this, newSize);
51637 getBox : function(){
51638 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51641 getMargins : function(){
51642 return this.margins;
51645 updateBox : function(box){
51647 var el = this.activePanel.getEl();
51648 el.dom.style.left = box.x + "px";
51649 el.dom.style.top = box.y + "px";
51650 this.activePanel.setSize(box.width, box.height);
51654 * Returns the container element for this region.
51655 * @return {Roo.Element}
51657 getEl : function(){
51658 return this.activePanel;
51662 * Returns true if this region is currently visible.
51663 * @return {Boolean}
51665 isVisible : function(){
51666 return this.activePanel ? true : false;
51669 setActivePanel : function(panel){
51670 panel = this.getPanel(panel);
51671 if(this.activePanel && this.activePanel != panel){
51672 this.activePanel.setActiveState(false);
51673 this.activePanel.getEl().setLeftTop(-10000,-10000);
51675 this.activePanel = panel;
51676 panel.setActiveState(true);
51678 panel.setSize(this.box.width, this.box.height);
51680 this.fireEvent("panelactivated", this, panel);
51681 this.fireEvent("invalidated");
51685 * Show the specified panel.
51686 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51687 * @return {Roo.ContentPanel} The shown panel or null
51689 showPanel : function(panel){
51690 if(panel = this.getPanel(panel)){
51691 this.setActivePanel(panel);
51697 * Get the active panel for this region.
51698 * @return {Roo.ContentPanel} The active panel or null
51700 getActivePanel : function(){
51701 return this.activePanel;
51705 * Add the passed ContentPanel(s)
51706 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51707 * @return {Roo.ContentPanel} The panel added (if only one was added)
51709 add : function(panel){
51710 if(arguments.length > 1){
51711 for(var i = 0, len = arguments.length; i < len; i++) {
51712 this.add(arguments[i]);
51716 if(this.hasPanel(panel)){
51717 this.showPanel(panel);
51720 var el = panel.getEl();
51721 if(el.dom.parentNode != this.mgr.el.dom){
51722 this.mgr.el.dom.appendChild(el.dom);
51724 if(panel.setRegion){
51725 panel.setRegion(this);
51727 this.panels.add(panel);
51728 el.setStyle("position", "absolute");
51729 if(!panel.background){
51730 this.setActivePanel(panel);
51731 if(this.config.initialSize && this.panels.getCount()==1){
51732 this.resizeTo(this.config.initialSize);
51735 this.fireEvent("paneladded", this, panel);
51740 * Returns true if the panel is in this region.
51741 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51742 * @return {Boolean}
51744 hasPanel : function(panel){
51745 if(typeof panel == "object"){ // must be panel obj
51746 panel = panel.getId();
51748 return this.getPanel(panel) ? true : false;
51752 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51753 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51754 * @param {Boolean} preservePanel Overrides the config preservePanel option
51755 * @return {Roo.ContentPanel} The panel that was removed
51757 remove : function(panel, preservePanel){
51758 panel = this.getPanel(panel);
51763 this.fireEvent("beforeremove", this, panel, e);
51764 if(e.cancel === true){
51767 var panelId = panel.getId();
51768 this.panels.removeKey(panelId);
51773 * Returns the panel specified or null if it's not in this region.
51774 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51775 * @return {Roo.ContentPanel}
51777 getPanel : function(id){
51778 if(typeof id == "object"){ // must be panel obj
51781 return this.panels.get(id);
51785 * Returns this regions position (north/south/east/west/center).
51788 getPosition: function(){
51789 return this.position;
51793 * Ext JS Library 1.1.1
51794 * Copyright(c) 2006-2007, Ext JS, LLC.
51796 * Originally Released Under LGPL - original licence link has changed is not relivant.
51799 * <script type="text/javascript">
51803 * @class Roo.LayoutRegion
51804 * @extends Roo.BasicLayoutRegion
51805 * This class represents a region in a layout manager.
51806 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51807 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51808 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51809 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51810 * @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})
51811 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51812 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51813 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51814 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51815 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51816 * @cfg {String} title The title for the region (overrides panel titles)
51817 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51818 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51819 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51820 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51821 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51822 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51823 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51824 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51825 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51826 * @cfg {Boolean} showPin True to show a pin button
51827 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51828 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51829 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51830 * @cfg {Number} width For East/West panels
51831 * @cfg {Number} height For North/South panels
51832 * @cfg {Boolean} split To show the splitter
51833 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51835 Roo.LayoutRegion = function(mgr, config, pos){
51836 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51837 var dh = Roo.DomHelper;
51838 /** This region's container element
51839 * @type Roo.Element */
51840 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51841 /** This region's title element
51842 * @type Roo.Element */
51844 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51845 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51846 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51848 this.titleEl.enableDisplayMode();
51849 /** This region's title text element
51850 * @type HTMLElement */
51851 this.titleTextEl = this.titleEl.dom.firstChild;
51852 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
51853 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
51854 this.closeBtn.enableDisplayMode();
51855 this.closeBtn.on("click", this.closeClicked, this);
51856 this.closeBtn.hide();
51858 this.createBody(config);
51859 this.visible = true;
51860 this.collapsed = false;
51862 if(config.hideWhenEmpty){
51864 this.on("paneladded", this.validateVisibility, this);
51865 this.on("panelremoved", this.validateVisibility, this);
51867 this.applyConfig(config);
51870 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
51872 createBody : function(){
51873 /** This region's body element
51874 * @type Roo.Element */
51875 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
51878 applyConfig : function(c){
51879 if(c.collapsible && this.position != "center" && !this.collapsedEl){
51880 var dh = Roo.DomHelper;
51881 if(c.titlebar !== false){
51882 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
51883 this.collapseBtn.on("click", this.collapse, this);
51884 this.collapseBtn.enableDisplayMode();
51886 if(c.showPin === true || this.showPin){
51887 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
51888 this.stickBtn.enableDisplayMode();
51889 this.stickBtn.on("click", this.expand, this);
51890 this.stickBtn.hide();
51893 /** This region's collapsed element
51894 * @type Roo.Element */
51895 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
51896 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
51898 if(c.floatable !== false){
51899 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
51900 this.collapsedEl.on("click", this.collapseClick, this);
51903 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
51904 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
51905 id: "message", unselectable: "on", style:{"float":"left"}});
51906 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
51908 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
51909 this.expandBtn.on("click", this.expand, this);
51911 if(this.collapseBtn){
51912 this.collapseBtn.setVisible(c.collapsible == true);
51914 this.cmargins = c.cmargins || this.cmargins ||
51915 (this.position == "west" || this.position == "east" ?
51916 {top: 0, left: 2, right:2, bottom: 0} :
51917 {top: 2, left: 0, right:0, bottom: 2});
51918 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51919 this.bottomTabs = c.tabPosition != "top";
51920 this.autoScroll = c.autoScroll || false;
51921 if(this.autoScroll){
51922 this.bodyEl.setStyle("overflow", "auto");
51924 this.bodyEl.setStyle("overflow", "hidden");
51926 //if(c.titlebar !== false){
51927 if((!c.titlebar && !c.title) || c.titlebar === false){
51928 this.titleEl.hide();
51930 this.titleEl.show();
51932 this.titleTextEl.innerHTML = c.title;
51936 this.duration = c.duration || .30;
51937 this.slideDuration = c.slideDuration || .45;
51940 this.collapse(true);
51947 * Returns true if this region is currently visible.
51948 * @return {Boolean}
51950 isVisible : function(){
51951 return this.visible;
51955 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
51956 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
51958 setCollapsedTitle : function(title){
51959 title = title || " ";
51960 if(this.collapsedTitleTextEl){
51961 this.collapsedTitleTextEl.innerHTML = title;
51965 getBox : function(){
51967 if(!this.collapsed){
51968 b = this.el.getBox(false, true);
51970 b = this.collapsedEl.getBox(false, true);
51975 getMargins : function(){
51976 return this.collapsed ? this.cmargins : this.margins;
51979 highlight : function(){
51980 this.el.addClass("x-layout-panel-dragover");
51983 unhighlight : function(){
51984 this.el.removeClass("x-layout-panel-dragover");
51987 updateBox : function(box){
51989 if(!this.collapsed){
51990 this.el.dom.style.left = box.x + "px";
51991 this.el.dom.style.top = box.y + "px";
51992 this.updateBody(box.width, box.height);
51994 this.collapsedEl.dom.style.left = box.x + "px";
51995 this.collapsedEl.dom.style.top = box.y + "px";
51996 this.collapsedEl.setSize(box.width, box.height);
51999 this.tabs.autoSizeTabs();
52003 updateBody : function(w, h){
52005 this.el.setWidth(w);
52006 w -= this.el.getBorderWidth("rl");
52007 if(this.config.adjustments){
52008 w += this.config.adjustments[0];
52012 this.el.setHeight(h);
52013 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52014 h -= this.el.getBorderWidth("tb");
52015 if(this.config.adjustments){
52016 h += this.config.adjustments[1];
52018 this.bodyEl.setHeight(h);
52020 h = this.tabs.syncHeight(h);
52023 if(this.panelSize){
52024 w = w !== null ? w : this.panelSize.width;
52025 h = h !== null ? h : this.panelSize.height;
52027 if(this.activePanel){
52028 var el = this.activePanel.getEl();
52029 w = w !== null ? w : el.getWidth();
52030 h = h !== null ? h : el.getHeight();
52031 this.panelSize = {width: w, height: h};
52032 this.activePanel.setSize(w, h);
52034 if(Roo.isIE && this.tabs){
52035 this.tabs.el.repaint();
52040 * Returns the container element for this region.
52041 * @return {Roo.Element}
52043 getEl : function(){
52048 * Hides this region.
52051 if(!this.collapsed){
52052 this.el.dom.style.left = "-2000px";
52055 this.collapsedEl.dom.style.left = "-2000px";
52056 this.collapsedEl.hide();
52058 this.visible = false;
52059 this.fireEvent("visibilitychange", this, false);
52063 * Shows this region if it was previously hidden.
52066 if(!this.collapsed){
52069 this.collapsedEl.show();
52071 this.visible = true;
52072 this.fireEvent("visibilitychange", this, true);
52075 closeClicked : function(){
52076 if(this.activePanel){
52077 this.remove(this.activePanel);
52081 collapseClick : function(e){
52083 e.stopPropagation();
52086 e.stopPropagation();
52092 * Collapses this region.
52093 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52095 collapse : function(skipAnim, skipCheck = false){
52096 if(this.collapsed) {
52100 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52102 this.collapsed = true;
52104 this.split.el.hide();
52106 if(this.config.animate && skipAnim !== true){
52107 this.fireEvent("invalidated", this);
52108 this.animateCollapse();
52110 this.el.setLocation(-20000,-20000);
52112 this.collapsedEl.show();
52113 this.fireEvent("collapsed", this);
52114 this.fireEvent("invalidated", this);
52120 animateCollapse : function(){
52125 * Expands this region if it was previously collapsed.
52126 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52127 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52129 expand : function(e, skipAnim){
52131 e.stopPropagation();
52133 if(!this.collapsed || this.el.hasActiveFx()) {
52137 this.afterSlideIn();
52140 this.collapsed = false;
52141 if(this.config.animate && skipAnim !== true){
52142 this.animateExpand();
52146 this.split.el.show();
52148 this.collapsedEl.setLocation(-2000,-2000);
52149 this.collapsedEl.hide();
52150 this.fireEvent("invalidated", this);
52151 this.fireEvent("expanded", this);
52155 animateExpand : function(){
52159 initTabs : function()
52161 this.bodyEl.setStyle("overflow", "hidden");
52162 var ts = new Roo.TabPanel(
52165 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52166 disableTooltips: this.config.disableTabTips,
52167 toolbar : this.config.toolbar
52170 if(this.config.hideTabs){
52171 ts.stripWrap.setDisplayed(false);
52174 ts.resizeTabs = this.config.resizeTabs === true;
52175 ts.minTabWidth = this.config.minTabWidth || 40;
52176 ts.maxTabWidth = this.config.maxTabWidth || 250;
52177 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52178 ts.monitorResize = false;
52179 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52180 ts.bodyEl.addClass('x-layout-tabs-body');
52181 this.panels.each(this.initPanelAsTab, this);
52184 initPanelAsTab : function(panel){
52185 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52186 this.config.closeOnTab && panel.isClosable());
52187 if(panel.tabTip !== undefined){
52188 ti.setTooltip(panel.tabTip);
52190 ti.on("activate", function(){
52191 this.setActivePanel(panel);
52193 if(this.config.closeOnTab){
52194 ti.on("beforeclose", function(t, e){
52196 this.remove(panel);
52202 updatePanelTitle : function(panel, title){
52203 if(this.activePanel == panel){
52204 this.updateTitle(title);
52207 var ti = this.tabs.getTab(panel.getEl().id);
52209 if(panel.tabTip !== undefined){
52210 ti.setTooltip(panel.tabTip);
52215 updateTitle : function(title){
52216 if(this.titleTextEl && !this.config.title){
52217 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52221 setActivePanel : function(panel){
52222 panel = this.getPanel(panel);
52223 if(this.activePanel && this.activePanel != panel){
52224 this.activePanel.setActiveState(false);
52226 this.activePanel = panel;
52227 panel.setActiveState(true);
52228 if(this.panelSize){
52229 panel.setSize(this.panelSize.width, this.panelSize.height);
52232 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52234 this.updateTitle(panel.getTitle());
52236 this.fireEvent("invalidated", this);
52238 this.fireEvent("panelactivated", this, panel);
52242 * Shows the specified panel.
52243 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52244 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52246 showPanel : function(panel)
52248 panel = this.getPanel(panel);
52251 var tab = this.tabs.getTab(panel.getEl().id);
52252 if(tab.isHidden()){
52253 this.tabs.unhideTab(tab.id);
52257 this.setActivePanel(panel);
52264 * Get the active panel for this region.
52265 * @return {Roo.ContentPanel} The active panel or null
52267 getActivePanel : function(){
52268 return this.activePanel;
52271 validateVisibility : function(){
52272 if(this.panels.getCount() < 1){
52273 this.updateTitle(" ");
52274 this.closeBtn.hide();
52277 if(!this.isVisible()){
52284 * Adds the passed ContentPanel(s) to this region.
52285 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52286 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52288 add : function(panel){
52289 if(arguments.length > 1){
52290 for(var i = 0, len = arguments.length; i < len; i++) {
52291 this.add(arguments[i]);
52295 if(this.hasPanel(panel)){
52296 this.showPanel(panel);
52299 panel.setRegion(this);
52300 this.panels.add(panel);
52301 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52302 this.bodyEl.dom.appendChild(panel.getEl().dom);
52303 if(panel.background !== true){
52304 this.setActivePanel(panel);
52306 this.fireEvent("paneladded", this, panel);
52312 this.initPanelAsTab(panel);
52314 if(panel.background !== true){
52315 this.tabs.activate(panel.getEl().id);
52317 this.fireEvent("paneladded", this, panel);
52322 * Hides the tab for the specified panel.
52323 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52325 hidePanel : function(panel){
52326 if(this.tabs && (panel = this.getPanel(panel))){
52327 this.tabs.hideTab(panel.getEl().id);
52332 * Unhides the tab for a previously hidden panel.
52333 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52335 unhidePanel : function(panel){
52336 if(this.tabs && (panel = this.getPanel(panel))){
52337 this.tabs.unhideTab(panel.getEl().id);
52341 clearPanels : function(){
52342 while(this.panels.getCount() > 0){
52343 this.remove(this.panels.first());
52348 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52349 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52350 * @param {Boolean} preservePanel Overrides the config preservePanel option
52351 * @return {Roo.ContentPanel} The panel that was removed
52353 remove : function(panel, preservePanel){
52354 panel = this.getPanel(panel);
52359 this.fireEvent("beforeremove", this, panel, e);
52360 if(e.cancel === true){
52363 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52364 var panelId = panel.getId();
52365 this.panels.removeKey(panelId);
52367 document.body.appendChild(panel.getEl().dom);
52370 this.tabs.removeTab(panel.getEl().id);
52371 }else if (!preservePanel){
52372 this.bodyEl.dom.removeChild(panel.getEl().dom);
52374 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52375 var p = this.panels.first();
52376 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52377 tempEl.appendChild(p.getEl().dom);
52378 this.bodyEl.update("");
52379 this.bodyEl.dom.appendChild(p.getEl().dom);
52381 this.updateTitle(p.getTitle());
52383 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52384 this.setActivePanel(p);
52386 panel.setRegion(null);
52387 if(this.activePanel == panel){
52388 this.activePanel = null;
52390 if(this.config.autoDestroy !== false && preservePanel !== true){
52391 try{panel.destroy();}catch(e){}
52393 this.fireEvent("panelremoved", this, panel);
52398 * Returns the TabPanel component used by this region
52399 * @return {Roo.TabPanel}
52401 getTabs : function(){
52405 createTool : function(parentEl, className){
52406 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52407 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52408 btn.addClassOnOver("x-layout-tools-button-over");
52413 * Ext JS Library 1.1.1
52414 * Copyright(c) 2006-2007, Ext JS, LLC.
52416 * Originally Released Under LGPL - original licence link has changed is not relivant.
52419 * <script type="text/javascript">
52425 * @class Roo.SplitLayoutRegion
52426 * @extends Roo.LayoutRegion
52427 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52429 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52430 this.cursor = cursor;
52431 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52434 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52435 splitTip : "Drag to resize.",
52436 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52437 useSplitTips : false,
52439 applyConfig : function(config){
52440 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52443 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52444 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52445 /** The SplitBar for this region
52446 * @type Roo.SplitBar */
52447 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52448 this.split.on("moved", this.onSplitMove, this);
52449 this.split.useShim = config.useShim === true;
52450 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52451 if(this.useSplitTips){
52452 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52454 if(config.collapsible){
52455 this.split.el.on("dblclick", this.collapse, this);
52458 if(typeof config.minSize != "undefined"){
52459 this.split.minSize = config.minSize;
52461 if(typeof config.maxSize != "undefined"){
52462 this.split.maxSize = config.maxSize;
52464 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52465 this.hideSplitter();
52470 getHMaxSize : function(){
52471 var cmax = this.config.maxSize || 10000;
52472 var center = this.mgr.getRegion("center");
52473 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52476 getVMaxSize : function(){
52477 var cmax = this.config.maxSize || 10000;
52478 var center = this.mgr.getRegion("center");
52479 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52482 onSplitMove : function(split, newSize){
52483 this.fireEvent("resized", this, newSize);
52487 * Returns the {@link Roo.SplitBar} for this region.
52488 * @return {Roo.SplitBar}
52490 getSplitBar : function(){
52495 this.hideSplitter();
52496 Roo.SplitLayoutRegion.superclass.hide.call(this);
52499 hideSplitter : function(){
52501 this.split.el.setLocation(-2000,-2000);
52502 this.split.el.hide();
52508 this.split.el.show();
52510 Roo.SplitLayoutRegion.superclass.show.call(this);
52513 beforeSlide: function(){
52514 if(Roo.isGecko){// firefox overflow auto bug workaround
52515 this.bodyEl.clip();
52517 this.tabs.bodyEl.clip();
52519 if(this.activePanel){
52520 this.activePanel.getEl().clip();
52522 if(this.activePanel.beforeSlide){
52523 this.activePanel.beforeSlide();
52529 afterSlide : function(){
52530 if(Roo.isGecko){// firefox overflow auto bug workaround
52531 this.bodyEl.unclip();
52533 this.tabs.bodyEl.unclip();
52535 if(this.activePanel){
52536 this.activePanel.getEl().unclip();
52537 if(this.activePanel.afterSlide){
52538 this.activePanel.afterSlide();
52544 initAutoHide : function(){
52545 if(this.autoHide !== false){
52546 if(!this.autoHideHd){
52547 var st = new Roo.util.DelayedTask(this.slideIn, this);
52548 this.autoHideHd = {
52549 "mouseout": function(e){
52550 if(!e.within(this.el, true)){
52554 "mouseover" : function(e){
52560 this.el.on(this.autoHideHd);
52564 clearAutoHide : function(){
52565 if(this.autoHide !== false){
52566 this.el.un("mouseout", this.autoHideHd.mouseout);
52567 this.el.un("mouseover", this.autoHideHd.mouseover);
52571 clearMonitor : function(){
52572 Roo.get(document).un("click", this.slideInIf, this);
52575 // these names are backwards but not changed for compat
52576 slideOut : function(){
52577 if(this.isSlid || this.el.hasActiveFx()){
52580 this.isSlid = true;
52581 if(this.collapseBtn){
52582 this.collapseBtn.hide();
52584 this.closeBtnState = this.closeBtn.getStyle('display');
52585 this.closeBtn.hide();
52587 this.stickBtn.show();
52590 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52591 this.beforeSlide();
52592 this.el.setStyle("z-index", 10001);
52593 this.el.slideIn(this.getSlideAnchor(), {
52594 callback: function(){
52596 this.initAutoHide();
52597 Roo.get(document).on("click", this.slideInIf, this);
52598 this.fireEvent("slideshow", this);
52605 afterSlideIn : function(){
52606 this.clearAutoHide();
52607 this.isSlid = false;
52608 this.clearMonitor();
52609 this.el.setStyle("z-index", "");
52610 if(this.collapseBtn){
52611 this.collapseBtn.show();
52613 this.closeBtn.setStyle('display', this.closeBtnState);
52615 this.stickBtn.hide();
52617 this.fireEvent("slidehide", this);
52620 slideIn : function(cb){
52621 if(!this.isSlid || this.el.hasActiveFx()){
52625 this.isSlid = false;
52626 this.beforeSlide();
52627 this.el.slideOut(this.getSlideAnchor(), {
52628 callback: function(){
52629 this.el.setLeftTop(-10000, -10000);
52631 this.afterSlideIn();
52639 slideInIf : function(e){
52640 if(!e.within(this.el)){
52645 animateCollapse : function(){
52646 this.beforeSlide();
52647 this.el.setStyle("z-index", 20000);
52648 var anchor = this.getSlideAnchor();
52649 this.el.slideOut(anchor, {
52650 callback : function(){
52651 this.el.setStyle("z-index", "");
52652 this.collapsedEl.slideIn(anchor, {duration:.3});
52654 this.el.setLocation(-10000,-10000);
52656 this.fireEvent("collapsed", this);
52663 animateExpand : function(){
52664 this.beforeSlide();
52665 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52666 this.el.setStyle("z-index", 20000);
52667 this.collapsedEl.hide({
52670 this.el.slideIn(this.getSlideAnchor(), {
52671 callback : function(){
52672 this.el.setStyle("z-index", "");
52675 this.split.el.show();
52677 this.fireEvent("invalidated", this);
52678 this.fireEvent("expanded", this);
52706 getAnchor : function(){
52707 return this.anchors[this.position];
52710 getCollapseAnchor : function(){
52711 return this.canchors[this.position];
52714 getSlideAnchor : function(){
52715 return this.sanchors[this.position];
52718 getAlignAdj : function(){
52719 var cm = this.cmargins;
52720 switch(this.position){
52736 getExpandAdj : function(){
52737 var c = this.collapsedEl, cm = this.cmargins;
52738 switch(this.position){
52740 return [-(cm.right+c.getWidth()+cm.left), 0];
52743 return [cm.right+c.getWidth()+cm.left, 0];
52746 return [0, -(cm.top+cm.bottom+c.getHeight())];
52749 return [0, cm.top+cm.bottom+c.getHeight()];
52755 * Ext JS Library 1.1.1
52756 * Copyright(c) 2006-2007, Ext JS, LLC.
52758 * Originally Released Under LGPL - original licence link has changed is not relivant.
52761 * <script type="text/javascript">
52764 * These classes are private internal classes
52766 Roo.CenterLayoutRegion = function(mgr, config){
52767 Roo.LayoutRegion.call(this, mgr, config, "center");
52768 this.visible = true;
52769 this.minWidth = config.minWidth || 20;
52770 this.minHeight = config.minHeight || 20;
52773 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52775 // center panel can't be hidden
52779 // center panel can't be hidden
52782 getMinWidth: function(){
52783 return this.minWidth;
52786 getMinHeight: function(){
52787 return this.minHeight;
52792 Roo.NorthLayoutRegion = function(mgr, config){
52793 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52795 this.split.placement = Roo.SplitBar.TOP;
52796 this.split.orientation = Roo.SplitBar.VERTICAL;
52797 this.split.el.addClass("x-layout-split-v");
52799 var size = config.initialSize || config.height;
52800 if(typeof size != "undefined"){
52801 this.el.setHeight(size);
52804 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52805 orientation: Roo.SplitBar.VERTICAL,
52806 getBox : function(){
52807 if(this.collapsed){
52808 return this.collapsedEl.getBox();
52810 var box = this.el.getBox();
52812 box.height += this.split.el.getHeight();
52817 updateBox : function(box){
52818 if(this.split && !this.collapsed){
52819 box.height -= this.split.el.getHeight();
52820 this.split.el.setLeft(box.x);
52821 this.split.el.setTop(box.y+box.height);
52822 this.split.el.setWidth(box.width);
52824 if(this.collapsed){
52825 this.updateBody(box.width, null);
52827 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52831 Roo.SouthLayoutRegion = function(mgr, config){
52832 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52834 this.split.placement = Roo.SplitBar.BOTTOM;
52835 this.split.orientation = Roo.SplitBar.VERTICAL;
52836 this.split.el.addClass("x-layout-split-v");
52838 var size = config.initialSize || config.height;
52839 if(typeof size != "undefined"){
52840 this.el.setHeight(size);
52843 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52844 orientation: Roo.SplitBar.VERTICAL,
52845 getBox : function(){
52846 if(this.collapsed){
52847 return this.collapsedEl.getBox();
52849 var box = this.el.getBox();
52851 var sh = this.split.el.getHeight();
52858 updateBox : function(box){
52859 if(this.split && !this.collapsed){
52860 var sh = this.split.el.getHeight();
52863 this.split.el.setLeft(box.x);
52864 this.split.el.setTop(box.y-sh);
52865 this.split.el.setWidth(box.width);
52867 if(this.collapsed){
52868 this.updateBody(box.width, null);
52870 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52874 Roo.EastLayoutRegion = function(mgr, config){
52875 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
52877 this.split.placement = Roo.SplitBar.RIGHT;
52878 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52879 this.split.el.addClass("x-layout-split-h");
52881 var size = config.initialSize || config.width;
52882 if(typeof size != "undefined"){
52883 this.el.setWidth(size);
52886 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
52887 orientation: Roo.SplitBar.HORIZONTAL,
52888 getBox : function(){
52889 if(this.collapsed){
52890 return this.collapsedEl.getBox();
52892 var box = this.el.getBox();
52894 var sw = this.split.el.getWidth();
52901 updateBox : function(box){
52902 if(this.split && !this.collapsed){
52903 var sw = this.split.el.getWidth();
52905 this.split.el.setLeft(box.x);
52906 this.split.el.setTop(box.y);
52907 this.split.el.setHeight(box.height);
52910 if(this.collapsed){
52911 this.updateBody(null, box.height);
52913 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52917 Roo.WestLayoutRegion = function(mgr, config){
52918 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
52920 this.split.placement = Roo.SplitBar.LEFT;
52921 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52922 this.split.el.addClass("x-layout-split-h");
52924 var size = config.initialSize || config.width;
52925 if(typeof size != "undefined"){
52926 this.el.setWidth(size);
52929 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
52930 orientation: Roo.SplitBar.HORIZONTAL,
52931 getBox : function(){
52932 if(this.collapsed){
52933 return this.collapsedEl.getBox();
52935 var box = this.el.getBox();
52937 box.width += this.split.el.getWidth();
52942 updateBox : function(box){
52943 if(this.split && !this.collapsed){
52944 var sw = this.split.el.getWidth();
52946 this.split.el.setLeft(box.x+box.width);
52947 this.split.el.setTop(box.y);
52948 this.split.el.setHeight(box.height);
52950 if(this.collapsed){
52951 this.updateBody(null, box.height);
52953 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52958 * Ext JS Library 1.1.1
52959 * Copyright(c) 2006-2007, Ext JS, LLC.
52961 * Originally Released Under LGPL - original licence link has changed is not relivant.
52964 * <script type="text/javascript">
52969 * Private internal class for reading and applying state
52971 Roo.LayoutStateManager = function(layout){
52972 // default empty state
52981 Roo.LayoutStateManager.prototype = {
52982 init : function(layout, provider){
52983 this.provider = provider;
52984 var state = provider.get(layout.id+"-layout-state");
52986 var wasUpdating = layout.isUpdating();
52988 layout.beginUpdate();
52990 for(var key in state){
52991 if(typeof state[key] != "function"){
52992 var rstate = state[key];
52993 var r = layout.getRegion(key);
52996 r.resizeTo(rstate.size);
52998 if(rstate.collapsed == true){
53001 r.expand(null, true);
53007 layout.endUpdate();
53009 this.state = state;
53011 this.layout = layout;
53012 layout.on("regionresized", this.onRegionResized, this);
53013 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53014 layout.on("regionexpanded", this.onRegionExpanded, this);
53017 storeState : function(){
53018 this.provider.set(this.layout.id+"-layout-state", this.state);
53021 onRegionResized : function(region, newSize){
53022 this.state[region.getPosition()].size = newSize;
53026 onRegionCollapsed : function(region){
53027 this.state[region.getPosition()].collapsed = true;
53031 onRegionExpanded : function(region){
53032 this.state[region.getPosition()].collapsed = false;
53037 * Ext JS Library 1.1.1
53038 * Copyright(c) 2006-2007, Ext JS, LLC.
53040 * Originally Released Under LGPL - original licence link has changed is not relivant.
53043 * <script type="text/javascript">
53046 * @class Roo.ContentPanel
53047 * @extends Roo.util.Observable
53048 * A basic ContentPanel element.
53049 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53050 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53051 * @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
53052 * @cfg {Boolean} closable True if the panel can be closed/removed
53053 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53054 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53055 * @cfg {Toolbar} toolbar A toolbar for this panel
53056 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53057 * @cfg {String} title The title for this panel
53058 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53059 * @cfg {String} url Calls {@link #setUrl} with this value
53060 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53061 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53062 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53063 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53066 * Create a new ContentPanel.
53067 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53068 * @param {String/Object} config A string to set only the title or a config object
53069 * @param {String} content (optional) Set the HTML content for this panel
53070 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53072 Roo.ContentPanel = function(el, config, content){
53076 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53080 if (config && config.parentLayout) {
53081 el = config.parentLayout.el.createChild();
53084 if(el.autoCreate){ // xtype is available if this is called from factory
53088 this.el = Roo.get(el);
53089 if(!this.el && config && config.autoCreate){
53090 if(typeof config.autoCreate == "object"){
53091 if(!config.autoCreate.id){
53092 config.autoCreate.id = config.id||el;
53094 this.el = Roo.DomHelper.append(document.body,
53095 config.autoCreate, true);
53097 this.el = Roo.DomHelper.append(document.body,
53098 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53101 this.closable = false;
53102 this.loaded = false;
53103 this.active = false;
53104 if(typeof config == "string"){
53105 this.title = config;
53107 Roo.apply(this, config);
53110 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53111 this.wrapEl = this.el.wrap();
53112 this.toolbar.container = this.el.insertSibling(false, 'before');
53113 this.toolbar = new Roo.Toolbar(this.toolbar);
53116 // xtype created footer. - not sure if will work as we normally have to render first..
53117 if (this.footer && !this.footer.el && this.footer.xtype) {
53118 if (!this.wrapEl) {
53119 this.wrapEl = this.el.wrap();
53122 this.footer.container = this.wrapEl.createChild();
53124 this.footer = Roo.factory(this.footer, Roo);
53129 this.resizeEl = Roo.get(this.resizeEl, true);
53131 this.resizeEl = this.el;
53133 // handle view.xtype
53141 * Fires when this panel is activated.
53142 * @param {Roo.ContentPanel} this
53146 * @event deactivate
53147 * Fires when this panel is activated.
53148 * @param {Roo.ContentPanel} this
53150 "deactivate" : true,
53154 * Fires when this panel is resized if fitToFrame is true.
53155 * @param {Roo.ContentPanel} this
53156 * @param {Number} width The width after any component adjustments
53157 * @param {Number} height The height after any component adjustments
53163 * Fires when this tab is created
53164 * @param {Roo.ContentPanel} this
53175 if(this.autoScroll){
53176 this.resizeEl.setStyle("overflow", "auto");
53178 // fix randome scrolling
53179 this.el.on('scroll', function() {
53180 Roo.log('fix random scolling');
53181 this.scrollTo('top',0);
53184 content = content || this.content;
53186 this.setContent(content);
53188 if(config && config.url){
53189 this.setUrl(this.url, this.params, this.loadOnce);
53194 Roo.ContentPanel.superclass.constructor.call(this);
53196 if (this.view && typeof(this.view.xtype) != 'undefined') {
53197 this.view.el = this.el.appendChild(document.createElement("div"));
53198 this.view = Roo.factory(this.view);
53199 this.view.render && this.view.render(false, '');
53203 this.fireEvent('render', this);
53206 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53208 setRegion : function(region){
53209 this.region = region;
53211 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53213 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53218 * Returns the toolbar for this Panel if one was configured.
53219 * @return {Roo.Toolbar}
53221 getToolbar : function(){
53222 return this.toolbar;
53225 setActiveState : function(active){
53226 this.active = active;
53228 this.fireEvent("deactivate", this);
53230 this.fireEvent("activate", this);
53234 * Updates this panel's element
53235 * @param {String} content The new content
53236 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53238 setContent : function(content, loadScripts){
53239 this.el.update(content, loadScripts);
53242 ignoreResize : function(w, h){
53243 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53246 this.lastSize = {width: w, height: h};
53251 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53252 * @return {Roo.UpdateManager} The UpdateManager
53254 getUpdateManager : function(){
53255 return this.el.getUpdateManager();
53258 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53259 * @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:
53262 url: "your-url.php",
53263 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53264 callback: yourFunction,
53265 scope: yourObject, //(optional scope)
53268 text: "Loading...",
53273 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53274 * 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.
53275 * @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}
53276 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53277 * @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.
53278 * @return {Roo.ContentPanel} this
53281 var um = this.el.getUpdateManager();
53282 um.update.apply(um, arguments);
53288 * 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.
53289 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53290 * @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)
53291 * @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)
53292 * @return {Roo.UpdateManager} The UpdateManager
53294 setUrl : function(url, params, loadOnce){
53295 if(this.refreshDelegate){
53296 this.removeListener("activate", this.refreshDelegate);
53298 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53299 this.on("activate", this.refreshDelegate);
53300 return this.el.getUpdateManager();
53303 _handleRefresh : function(url, params, loadOnce){
53304 if(!loadOnce || !this.loaded){
53305 var updater = this.el.getUpdateManager();
53306 updater.update(url, params, this._setLoaded.createDelegate(this));
53310 _setLoaded : function(){
53311 this.loaded = true;
53315 * Returns this panel's id
53318 getId : function(){
53323 * Returns this panel's element - used by regiosn to add.
53324 * @return {Roo.Element}
53326 getEl : function(){
53327 return this.wrapEl || this.el;
53330 adjustForComponents : function(width, height)
53332 //Roo.log('adjustForComponents ');
53333 if(this.resizeEl != this.el){
53334 width -= this.el.getFrameWidth('lr');
53335 height -= this.el.getFrameWidth('tb');
53338 var te = this.toolbar.getEl();
53339 height -= te.getHeight();
53340 te.setWidth(width);
53343 var te = this.footer.getEl();
53344 Roo.log("footer:" + te.getHeight());
53346 height -= te.getHeight();
53347 te.setWidth(width);
53351 if(this.adjustments){
53352 width += this.adjustments[0];
53353 height += this.adjustments[1];
53355 return {"width": width, "height": height};
53358 setSize : function(width, height){
53359 if(this.fitToFrame && !this.ignoreResize(width, height)){
53360 if(this.fitContainer && this.resizeEl != this.el){
53361 this.el.setSize(width, height);
53363 var size = this.adjustForComponents(width, height);
53364 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53365 this.fireEvent('resize', this, size.width, size.height);
53370 * Returns this panel's title
53373 getTitle : function(){
53378 * Set this panel's title
53379 * @param {String} title
53381 setTitle : function(title){
53382 this.title = title;
53384 this.region.updatePanelTitle(this, title);
53389 * Returns true is this panel was configured to be closable
53390 * @return {Boolean}
53392 isClosable : function(){
53393 return this.closable;
53396 beforeSlide : function(){
53398 this.resizeEl.clip();
53401 afterSlide : function(){
53403 this.resizeEl.unclip();
53407 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53408 * Will fail silently if the {@link #setUrl} method has not been called.
53409 * This does not activate the panel, just updates its content.
53411 refresh : function(){
53412 if(this.refreshDelegate){
53413 this.loaded = false;
53414 this.refreshDelegate();
53419 * Destroys this panel
53421 destroy : function(){
53422 this.el.removeAllListeners();
53423 var tempEl = document.createElement("span");
53424 tempEl.appendChild(this.el.dom);
53425 tempEl.innerHTML = "";
53431 * form - if the content panel contains a form - this is a reference to it.
53432 * @type {Roo.form.Form}
53436 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53437 * This contains a reference to it.
53443 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53453 * @param {Object} cfg Xtype definition of item to add.
53456 addxtype : function(cfg) {
53458 if (cfg.xtype.match(/^Form$/)) {
53461 //if (this.footer) {
53462 // el = this.footer.container.insertSibling(false, 'before');
53464 el = this.el.createChild();
53467 this.form = new Roo.form.Form(cfg);
53470 if ( this.form.allItems.length) {
53471 this.form.render(el.dom);
53475 // should only have one of theses..
53476 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53477 // views.. should not be just added - used named prop 'view''
53479 cfg.el = this.el.appendChild(document.createElement("div"));
53482 var ret = new Roo.factory(cfg);
53484 ret.render && ret.render(false, ''); // render blank..
53493 * @class Roo.GridPanel
53494 * @extends Roo.ContentPanel
53496 * Create a new GridPanel.
53497 * @param {Roo.grid.Grid} grid The grid for this panel
53498 * @param {String/Object} config A string to set only the panel's title, or a config object
53500 Roo.GridPanel = function(grid, config){
53503 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53504 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53506 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53508 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53511 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53513 // xtype created footer. - not sure if will work as we normally have to render first..
53514 if (this.footer && !this.footer.el && this.footer.xtype) {
53516 this.footer.container = this.grid.getView().getFooterPanel(true);
53517 this.footer.dataSource = this.grid.dataSource;
53518 this.footer = Roo.factory(this.footer, Roo);
53522 grid.monitorWindowResize = false; // turn off autosizing
53523 grid.autoHeight = false;
53524 grid.autoWidth = false;
53526 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53529 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53530 getId : function(){
53531 return this.grid.id;
53535 * Returns the grid for this panel
53536 * @return {Roo.grid.Grid}
53538 getGrid : function(){
53542 setSize : function(width, height){
53543 if(!this.ignoreResize(width, height)){
53544 var grid = this.grid;
53545 var size = this.adjustForComponents(width, height);
53546 grid.getGridEl().setSize(size.width, size.height);
53551 beforeSlide : function(){
53552 this.grid.getView().scroller.clip();
53555 afterSlide : function(){
53556 this.grid.getView().scroller.unclip();
53559 destroy : function(){
53560 this.grid.destroy();
53562 Roo.GridPanel.superclass.destroy.call(this);
53568 * @class Roo.NestedLayoutPanel
53569 * @extends Roo.ContentPanel
53571 * Create a new NestedLayoutPanel.
53574 * @param {Roo.BorderLayout} layout The layout for this panel
53575 * @param {String/Object} config A string to set only the title or a config object
53577 Roo.NestedLayoutPanel = function(layout, config)
53579 // construct with only one argument..
53580 /* FIXME - implement nicer consturctors
53581 if (layout.layout) {
53583 layout = config.layout;
53584 delete config.layout;
53586 if (layout.xtype && !layout.getEl) {
53587 // then layout needs constructing..
53588 layout = Roo.factory(layout, Roo);
53593 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53595 layout.monitorWindowResize = false; // turn off autosizing
53596 this.layout = layout;
53597 this.layout.getEl().addClass("x-layout-nested-layout");
53604 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53606 setSize : function(width, height){
53607 if(!this.ignoreResize(width, height)){
53608 var size = this.adjustForComponents(width, height);
53609 var el = this.layout.getEl();
53610 el.setSize(size.width, size.height);
53611 var touch = el.dom.offsetWidth;
53612 this.layout.layout();
53613 // ie requires a double layout on the first pass
53614 if(Roo.isIE && !this.initialized){
53615 this.initialized = true;
53616 this.layout.layout();
53621 // activate all subpanels if not currently active..
53623 setActiveState : function(active){
53624 this.active = active;
53626 this.fireEvent("deactivate", this);
53630 this.fireEvent("activate", this);
53631 // not sure if this should happen before or after..
53632 if (!this.layout) {
53633 return; // should not happen..
53636 for (var r in this.layout.regions) {
53637 reg = this.layout.getRegion(r);
53638 if (reg.getActivePanel()) {
53639 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53640 reg.setActivePanel(reg.getActivePanel());
53643 if (!reg.panels.length) {
53646 reg.showPanel(reg.getPanel(0));
53655 * Returns the nested BorderLayout for this panel
53656 * @return {Roo.BorderLayout}
53658 getLayout : function(){
53659 return this.layout;
53663 * Adds a xtype elements to the layout of the nested panel
53667 xtype : 'ContentPanel',
53674 xtype : 'NestedLayoutPanel',
53680 items : [ ... list of content panels or nested layout panels.. ]
53684 * @param {Object} cfg Xtype definition of item to add.
53686 addxtype : function(cfg) {
53687 return this.layout.addxtype(cfg);
53692 Roo.ScrollPanel = function(el, config, content){
53693 config = config || {};
53694 config.fitToFrame = true;
53695 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53697 this.el.dom.style.overflow = "hidden";
53698 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53699 this.el.removeClass("x-layout-inactive-content");
53700 this.el.on("mousewheel", this.onWheel, this);
53702 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53703 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53704 up.unselectable(); down.unselectable();
53705 up.on("click", this.scrollUp, this);
53706 down.on("click", this.scrollDown, this);
53707 up.addClassOnOver("x-scroller-btn-over");
53708 down.addClassOnOver("x-scroller-btn-over");
53709 up.addClassOnClick("x-scroller-btn-click");
53710 down.addClassOnClick("x-scroller-btn-click");
53711 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53713 this.resizeEl = this.el;
53714 this.el = wrap; this.up = up; this.down = down;
53717 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53719 wheelIncrement : 5,
53720 scrollUp : function(){
53721 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53724 scrollDown : function(){
53725 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53728 afterScroll : function(){
53729 var el = this.resizeEl;
53730 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53731 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53732 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53735 setSize : function(){
53736 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53737 this.afterScroll();
53740 onWheel : function(e){
53741 var d = e.getWheelDelta();
53742 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53743 this.afterScroll();
53747 setContent : function(content, loadScripts){
53748 this.resizeEl.update(content, loadScripts);
53762 * @class Roo.TreePanel
53763 * @extends Roo.ContentPanel
53765 * Create a new TreePanel. - defaults to fit/scoll contents.
53766 * @param {String/Object} config A string to set only the panel's title, or a config object
53767 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53769 Roo.TreePanel = function(config){
53770 var el = config.el;
53771 var tree = config.tree;
53772 delete config.tree;
53773 delete config.el; // hopefull!
53775 // wrapper for IE7 strict & safari scroll issue
53777 var treeEl = el.createChild();
53778 config.resizeEl = treeEl;
53782 Roo.TreePanel.superclass.constructor.call(this, el, config);
53785 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53786 //console.log(tree);
53787 this.on('activate', function()
53789 if (this.tree.rendered) {
53792 //console.log('render tree');
53793 this.tree.render();
53795 // this should not be needed.. - it's actually the 'el' that resizes?
53796 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53798 //this.on('resize', function (cp, w, h) {
53799 // this.tree.innerCt.setWidth(w);
53800 // this.tree.innerCt.setHeight(h);
53801 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53808 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53825 * Ext JS Library 1.1.1
53826 * Copyright(c) 2006-2007, Ext JS, LLC.
53828 * Originally Released Under LGPL - original licence link has changed is not relivant.
53831 * <script type="text/javascript">
53836 * @class Roo.ReaderLayout
53837 * @extends Roo.BorderLayout
53838 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53839 * center region containing two nested regions (a top one for a list view and one for item preview below),
53840 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53841 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53842 * expedites the setup of the overall layout and regions for this common application style.
53845 var reader = new Roo.ReaderLayout();
53846 var CP = Roo.ContentPanel; // shortcut for adding
53848 reader.beginUpdate();
53849 reader.add("north", new CP("north", "North"));
53850 reader.add("west", new CP("west", {title: "West"}));
53851 reader.add("east", new CP("east", {title: "East"}));
53853 reader.regions.listView.add(new CP("listView", "List"));
53854 reader.regions.preview.add(new CP("preview", "Preview"));
53855 reader.endUpdate();
53858 * Create a new ReaderLayout
53859 * @param {Object} config Configuration options
53860 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
53861 * document.body if omitted)
53863 Roo.ReaderLayout = function(config, renderTo){
53864 var c = config || {size:{}};
53865 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
53866 north: c.north !== false ? Roo.apply({
53870 }, c.north) : false,
53871 west: c.west !== false ? Roo.apply({
53879 margins:{left:5,right:0,bottom:5,top:5},
53880 cmargins:{left:5,right:5,bottom:5,top:5}
53881 }, c.west) : false,
53882 east: c.east !== false ? Roo.apply({
53890 margins:{left:0,right:5,bottom:5,top:5},
53891 cmargins:{left:5,right:5,bottom:5,top:5}
53892 }, c.east) : false,
53893 center: Roo.apply({
53894 tabPosition: 'top',
53898 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
53902 this.el.addClass('x-reader');
53904 this.beginUpdate();
53906 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
53907 south: c.preview !== false ? Roo.apply({
53914 cmargins:{top:5,left:0, right:0, bottom:0}
53915 }, c.preview) : false,
53916 center: Roo.apply({
53922 this.add('center', new Roo.NestedLayoutPanel(inner,
53923 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
53927 this.regions.preview = inner.getRegion('south');
53928 this.regions.listView = inner.getRegion('center');
53931 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
53933 * Ext JS Library 1.1.1
53934 * Copyright(c) 2006-2007, Ext JS, LLC.
53936 * Originally Released Under LGPL - original licence link has changed is not relivant.
53939 * <script type="text/javascript">
53943 * @class Roo.grid.Grid
53944 * @extends Roo.util.Observable
53945 * This class represents the primary interface of a component based grid control.
53946 * <br><br>Usage:<pre><code>
53947 var grid = new Roo.grid.Grid("my-container-id", {
53950 selModel: mySelectionModel,
53951 autoSizeColumns: true,
53952 monitorWindowResize: false,
53953 trackMouseOver: true
53958 * <b>Common Problems:</b><br/>
53959 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
53960 * element will correct this<br/>
53961 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
53962 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
53963 * are unpredictable.<br/>
53964 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
53965 * grid to calculate dimensions/offsets.<br/>
53967 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53968 * The container MUST have some type of size defined for the grid to fill. The container will be
53969 * automatically set to position relative if it isn't already.
53970 * @param {Object} config A config object that sets properties on this grid.
53972 Roo.grid.Grid = function(container, config){
53973 // initialize the container
53974 this.container = Roo.get(container);
53975 this.container.update("");
53976 this.container.setStyle("overflow", "hidden");
53977 this.container.addClass('x-grid-container');
53979 this.id = this.container.id;
53981 Roo.apply(this, config);
53982 // check and correct shorthanded configs
53984 this.dataSource = this.ds;
53988 this.colModel = this.cm;
53992 this.selModel = this.sm;
53996 if (this.selModel) {
53997 this.selModel = Roo.factory(this.selModel, Roo.grid);
53998 this.sm = this.selModel;
53999 this.sm.xmodule = this.xmodule || false;
54001 if (typeof(this.colModel.config) == 'undefined') {
54002 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54003 this.cm = this.colModel;
54004 this.cm.xmodule = this.xmodule || false;
54006 if (this.dataSource) {
54007 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54008 this.ds = this.dataSource;
54009 this.ds.xmodule = this.xmodule || false;
54016 this.container.setWidth(this.width);
54020 this.container.setHeight(this.height);
54027 * The raw click event for the entire grid.
54028 * @param {Roo.EventObject} e
54033 * The raw dblclick event for the entire grid.
54034 * @param {Roo.EventObject} e
54038 * @event contextmenu
54039 * The raw contextmenu event for the entire grid.
54040 * @param {Roo.EventObject} e
54042 "contextmenu" : true,
54045 * The raw mousedown event for the entire grid.
54046 * @param {Roo.EventObject} e
54048 "mousedown" : true,
54051 * The raw mouseup event for the entire grid.
54052 * @param {Roo.EventObject} e
54057 * The raw mouseover event for the entire grid.
54058 * @param {Roo.EventObject} e
54060 "mouseover" : true,
54063 * The raw mouseout event for the entire grid.
54064 * @param {Roo.EventObject} e
54069 * The raw keypress event for the entire grid.
54070 * @param {Roo.EventObject} e
54075 * The raw keydown event for the entire grid.
54076 * @param {Roo.EventObject} e
54084 * Fires when a cell is clicked
54085 * @param {Grid} this
54086 * @param {Number} rowIndex
54087 * @param {Number} columnIndex
54088 * @param {Roo.EventObject} e
54090 "cellclick" : true,
54092 * @event celldblclick
54093 * Fires when a cell is double clicked
54094 * @param {Grid} this
54095 * @param {Number} rowIndex
54096 * @param {Number} columnIndex
54097 * @param {Roo.EventObject} e
54099 "celldblclick" : true,
54102 * Fires when a row is clicked
54103 * @param {Grid} this
54104 * @param {Number} rowIndex
54105 * @param {Roo.EventObject} e
54109 * @event rowdblclick
54110 * Fires when a row is double clicked
54111 * @param {Grid} this
54112 * @param {Number} rowIndex
54113 * @param {Roo.EventObject} e
54115 "rowdblclick" : true,
54117 * @event headerclick
54118 * Fires when a header is clicked
54119 * @param {Grid} this
54120 * @param {Number} columnIndex
54121 * @param {Roo.EventObject} e
54123 "headerclick" : true,
54125 * @event headerdblclick
54126 * Fires when a header cell is double clicked
54127 * @param {Grid} this
54128 * @param {Number} columnIndex
54129 * @param {Roo.EventObject} e
54131 "headerdblclick" : true,
54133 * @event rowcontextmenu
54134 * Fires when a row is right clicked
54135 * @param {Grid} this
54136 * @param {Number} rowIndex
54137 * @param {Roo.EventObject} e
54139 "rowcontextmenu" : true,
54141 * @event cellcontextmenu
54142 * Fires when a cell is right clicked
54143 * @param {Grid} this
54144 * @param {Number} rowIndex
54145 * @param {Number} cellIndex
54146 * @param {Roo.EventObject} e
54148 "cellcontextmenu" : true,
54150 * @event headercontextmenu
54151 * Fires when a header is right clicked
54152 * @param {Grid} this
54153 * @param {Number} columnIndex
54154 * @param {Roo.EventObject} e
54156 "headercontextmenu" : true,
54158 * @event bodyscroll
54159 * Fires when the body element is scrolled
54160 * @param {Number} scrollLeft
54161 * @param {Number} scrollTop
54163 "bodyscroll" : true,
54165 * @event columnresize
54166 * Fires when the user resizes a column
54167 * @param {Number} columnIndex
54168 * @param {Number} newSize
54170 "columnresize" : true,
54172 * @event columnmove
54173 * Fires when the user moves a column
54174 * @param {Number} oldIndex
54175 * @param {Number} newIndex
54177 "columnmove" : true,
54180 * Fires when row(s) start being dragged
54181 * @param {Grid} this
54182 * @param {Roo.GridDD} dd The drag drop object
54183 * @param {event} e The raw browser event
54185 "startdrag" : true,
54188 * Fires when a drag operation is complete
54189 * @param {Grid} this
54190 * @param {Roo.GridDD} dd The drag drop object
54191 * @param {event} e The raw browser event
54196 * Fires when dragged row(s) are dropped on a valid DD target
54197 * @param {Grid} this
54198 * @param {Roo.GridDD} dd The drag drop object
54199 * @param {String} targetId The target drag drop object
54200 * @param {event} e The raw browser event
54205 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54206 * @param {Grid} this
54207 * @param {Roo.GridDD} dd The drag drop object
54208 * @param {String} targetId The target drag drop object
54209 * @param {event} e The raw browser event
54214 * Fires when the dragged row(s) first cross another DD target while being dragged
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
54220 "dragenter" : true,
54223 * Fires when the dragged row(s) leave another DD target while being dragged
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 a row is rendered, so you can change add a style to it.
54233 * @param {GridView} gridview The grid view
54234 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54240 * Fires when the grid is rendered
54241 * @param {Grid} grid
54246 Roo.grid.Grid.superclass.constructor.call(this);
54248 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54251 * @cfg {String} ddGroup - drag drop group.
54255 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54257 minColumnWidth : 25,
54260 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54261 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54262 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54264 autoSizeColumns : false,
54267 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54269 autoSizeHeaders : true,
54272 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54274 monitorWindowResize : true,
54277 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54278 * rows measured to get a columns size. Default is 0 (all rows).
54280 maxRowsToMeasure : 0,
54283 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54285 trackMouseOver : true,
54288 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54292 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54294 enableDragDrop : false,
54297 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54299 enableColumnMove : true,
54302 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54304 enableColumnHide : true,
54307 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54309 enableRowHeightSync : false,
54312 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54317 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54319 autoHeight : false,
54322 * @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.
54324 autoExpandColumn : false,
54327 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54330 autoExpandMin : 50,
54333 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54335 autoExpandMax : 1000,
54338 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54343 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54347 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54357 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54358 * of a fixed width. Default is false.
54361 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54364 * Called once after all setup has been completed and the grid is ready to be rendered.
54365 * @return {Roo.grid.Grid} this
54367 render : function()
54369 var c = this.container;
54370 // try to detect autoHeight/width mode
54371 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54372 this.autoHeight = true;
54374 var view = this.getView();
54377 c.on("click", this.onClick, this);
54378 c.on("dblclick", this.onDblClick, this);
54379 c.on("contextmenu", this.onContextMenu, this);
54380 c.on("keydown", this.onKeyDown, this);
54382 c.on("touchstart", this.onTouchStart, this);
54385 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54387 this.getSelectionModel().init(this);
54392 this.loadMask = new Roo.LoadMask(this.container,
54393 Roo.apply({store:this.dataSource}, this.loadMask));
54397 if (this.toolbar && this.toolbar.xtype) {
54398 this.toolbar.container = this.getView().getHeaderPanel(true);
54399 this.toolbar = new Roo.Toolbar(this.toolbar);
54401 if (this.footer && this.footer.xtype) {
54402 this.footer.dataSource = this.getDataSource();
54403 this.footer.container = this.getView().getFooterPanel(true);
54404 this.footer = Roo.factory(this.footer, Roo);
54406 if (this.dropTarget && this.dropTarget.xtype) {
54407 delete this.dropTarget.xtype;
54408 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54412 this.rendered = true;
54413 this.fireEvent('render', this);
54418 * Reconfigures the grid to use a different Store and Column Model.
54419 * The View will be bound to the new objects and refreshed.
54420 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54421 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54423 reconfigure : function(dataSource, colModel){
54425 this.loadMask.destroy();
54426 this.loadMask = new Roo.LoadMask(this.container,
54427 Roo.apply({store:dataSource}, this.loadMask));
54429 this.view.bind(dataSource, colModel);
54430 this.dataSource = dataSource;
54431 this.colModel = colModel;
54432 this.view.refresh(true);
54436 onKeyDown : function(e){
54437 this.fireEvent("keydown", e);
54441 * Destroy this grid.
54442 * @param {Boolean} removeEl True to remove the element
54444 destroy : function(removeEl, keepListeners){
54446 this.loadMask.destroy();
54448 var c = this.container;
54449 c.removeAllListeners();
54450 this.view.destroy();
54451 this.colModel.purgeListeners();
54452 if(!keepListeners){
54453 this.purgeListeners();
54456 if(removeEl === true){
54462 processEvent : function(name, e){
54463 // does this fire select???
54464 //Roo.log('grid:processEvent ' + name);
54466 if (name != 'touchstart' ) {
54467 this.fireEvent(name, e);
54470 var t = e.getTarget();
54472 var header = v.findHeaderIndex(t);
54473 if(header !== false){
54474 var ename = name == 'touchstart' ? 'click' : name;
54476 this.fireEvent("header" + ename, this, header, e);
54478 var row = v.findRowIndex(t);
54479 var cell = v.findCellIndex(t);
54480 if (name == 'touchstart') {
54481 // first touch is always a click.
54482 // hopefull this happens after selection is updated.?
54485 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54486 var cs = this.selModel.getSelectedCell();
54487 if (row == cs[0] && cell == cs[1]){
54491 if (typeof(this.selModel.getSelections) != 'undefined') {
54492 var cs = this.selModel.getSelections();
54493 var ds = this.dataSource;
54494 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54505 this.fireEvent("row" + name, this, row, e);
54506 if(cell !== false){
54507 this.fireEvent("cell" + name, this, row, cell, e);
54514 onClick : function(e){
54515 this.processEvent("click", e);
54518 onTouchStart : function(e){
54519 this.processEvent("touchstart", e);
54523 onContextMenu : function(e, t){
54524 this.processEvent("contextmenu", e);
54528 onDblClick : function(e){
54529 this.processEvent("dblclick", e);
54533 walkCells : function(row, col, step, fn, scope){
54534 var cm = this.colModel, clen = cm.getColumnCount();
54535 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54547 if(fn.call(scope || this, row, col, cm) === true){
54565 if(fn.call(scope || this, row, col, cm) === true){
54577 getSelections : function(){
54578 return this.selModel.getSelections();
54582 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54583 * but if manual update is required this method will initiate it.
54585 autoSize : function(){
54587 this.view.layout();
54588 if(this.view.adjustForScroll){
54589 this.view.adjustForScroll();
54595 * Returns the grid's underlying element.
54596 * @return {Element} The element
54598 getGridEl : function(){
54599 return this.container;
54602 // private for compatibility, overridden by editor grid
54603 stopEditing : function(){},
54606 * Returns the grid's SelectionModel.
54607 * @return {SelectionModel}
54609 getSelectionModel : function(){
54610 if(!this.selModel){
54611 this.selModel = new Roo.grid.RowSelectionModel();
54613 return this.selModel;
54617 * Returns the grid's DataSource.
54618 * @return {DataSource}
54620 getDataSource : function(){
54621 return this.dataSource;
54625 * Returns the grid's ColumnModel.
54626 * @return {ColumnModel}
54628 getColumnModel : function(){
54629 return this.colModel;
54633 * Returns the grid's GridView object.
54634 * @return {GridView}
54636 getView : function(){
54638 this.view = new Roo.grid.GridView(this.viewConfig);
54643 * Called to get grid's drag proxy text, by default returns this.ddText.
54646 getDragDropText : function(){
54647 var count = this.selModel.getCount();
54648 return String.format(this.ddText, count, count == 1 ? '' : 's');
54652 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54653 * %0 is replaced with the number of selected rows.
54656 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54658 * Ext JS Library 1.1.1
54659 * Copyright(c) 2006-2007, Ext JS, LLC.
54661 * Originally Released Under LGPL - original licence link has changed is not relivant.
54664 * <script type="text/javascript">
54667 Roo.grid.AbstractGridView = function(){
54671 "beforerowremoved" : true,
54672 "beforerowsinserted" : true,
54673 "beforerefresh" : true,
54674 "rowremoved" : true,
54675 "rowsinserted" : true,
54676 "rowupdated" : true,
54679 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54682 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54683 rowClass : "x-grid-row",
54684 cellClass : "x-grid-cell",
54685 tdClass : "x-grid-td",
54686 hdClass : "x-grid-hd",
54687 splitClass : "x-grid-hd-split",
54689 init: function(grid){
54691 var cid = this.grid.getGridEl().id;
54692 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54693 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54694 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54695 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54698 getColumnRenderers : function(){
54699 var renderers = [];
54700 var cm = this.grid.colModel;
54701 var colCount = cm.getColumnCount();
54702 for(var i = 0; i < colCount; i++){
54703 renderers[i] = cm.getRenderer(i);
54708 getColumnIds : function(){
54710 var cm = this.grid.colModel;
54711 var colCount = cm.getColumnCount();
54712 for(var i = 0; i < colCount; i++){
54713 ids[i] = cm.getColumnId(i);
54718 getDataIndexes : function(){
54719 if(!this.indexMap){
54720 this.indexMap = this.buildIndexMap();
54722 return this.indexMap.colToData;
54725 getColumnIndexByDataIndex : function(dataIndex){
54726 if(!this.indexMap){
54727 this.indexMap = this.buildIndexMap();
54729 return this.indexMap.dataToCol[dataIndex];
54733 * Set a css style for a column dynamically.
54734 * @param {Number} colIndex The index of the column
54735 * @param {String} name The css property name
54736 * @param {String} value The css value
54738 setCSSStyle : function(colIndex, name, value){
54739 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54740 Roo.util.CSS.updateRule(selector, name, value);
54743 generateRules : function(cm){
54744 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54745 Roo.util.CSS.removeStyleSheet(rulesId);
54746 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54747 var cid = cm.getColumnId(i);
54748 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54749 this.tdSelector, cid, " {\n}\n",
54750 this.hdSelector, cid, " {\n}\n",
54751 this.splitSelector, cid, " {\n}\n");
54753 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54757 * Ext JS Library 1.1.1
54758 * Copyright(c) 2006-2007, Ext JS, LLC.
54760 * Originally Released Under LGPL - original licence link has changed is not relivant.
54763 * <script type="text/javascript">
54767 // This is a support class used internally by the Grid components
54768 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54770 this.view = grid.getView();
54771 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54772 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54774 this.setHandleElId(Roo.id(hd));
54775 this.setOuterHandleElId(Roo.id(hd2));
54777 this.scroll = false;
54779 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54781 getDragData : function(e){
54782 var t = Roo.lib.Event.getTarget(e);
54783 var h = this.view.findHeaderCell(t);
54785 return {ddel: h.firstChild, header:h};
54790 onInitDrag : function(e){
54791 this.view.headersDisabled = true;
54792 var clone = this.dragData.ddel.cloneNode(true);
54793 clone.id = Roo.id();
54794 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54795 this.proxy.update(clone);
54799 afterValidDrop : function(){
54801 setTimeout(function(){
54802 v.headersDisabled = false;
54806 afterInvalidDrop : function(){
54808 setTimeout(function(){
54809 v.headersDisabled = false;
54815 * Ext JS Library 1.1.1
54816 * Copyright(c) 2006-2007, Ext JS, LLC.
54818 * Originally Released Under LGPL - original licence link has changed is not relivant.
54821 * <script type="text/javascript">
54824 // This is a support class used internally by the Grid components
54825 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54827 this.view = grid.getView();
54828 // split the proxies so they don't interfere with mouse events
54829 this.proxyTop = Roo.DomHelper.append(document.body, {
54830 cls:"col-move-top", html:" "
54832 this.proxyBottom = Roo.DomHelper.append(document.body, {
54833 cls:"col-move-bottom", html:" "
54835 this.proxyTop.hide = this.proxyBottom.hide = function(){
54836 this.setLeftTop(-100,-100);
54837 this.setStyle("visibility", "hidden");
54839 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54840 // temporarily disabled
54841 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54842 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54844 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54845 proxyOffsets : [-4, -9],
54846 fly: Roo.Element.fly,
54848 getTargetFromEvent : function(e){
54849 var t = Roo.lib.Event.getTarget(e);
54850 var cindex = this.view.findCellIndex(t);
54851 if(cindex !== false){
54852 return this.view.getHeaderCell(cindex);
54857 nextVisible : function(h){
54858 var v = this.view, cm = this.grid.colModel;
54861 if(!cm.isHidden(v.getCellIndex(h))){
54869 prevVisible : function(h){
54870 var v = this.view, cm = this.grid.colModel;
54873 if(!cm.isHidden(v.getCellIndex(h))){
54881 positionIndicator : function(h, n, e){
54882 var x = Roo.lib.Event.getPageX(e);
54883 var r = Roo.lib.Dom.getRegion(n.firstChild);
54884 var px, pt, py = r.top + this.proxyOffsets[1];
54885 if((r.right - x) <= (r.right-r.left)/2){
54886 px = r.right+this.view.borderWidth;
54892 var oldIndex = this.view.getCellIndex(h);
54893 var newIndex = this.view.getCellIndex(n);
54895 if(this.grid.colModel.isFixed(newIndex)){
54899 var locked = this.grid.colModel.isLocked(newIndex);
54904 if(oldIndex < newIndex){
54907 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
54910 px += this.proxyOffsets[0];
54911 this.proxyTop.setLeftTop(px, py);
54912 this.proxyTop.show();
54913 if(!this.bottomOffset){
54914 this.bottomOffset = this.view.mainHd.getHeight();
54916 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
54917 this.proxyBottom.show();
54921 onNodeEnter : function(n, dd, e, data){
54922 if(data.header != n){
54923 this.positionIndicator(data.header, n, e);
54927 onNodeOver : function(n, dd, e, data){
54928 var result = false;
54929 if(data.header != n){
54930 result = this.positionIndicator(data.header, n, e);
54933 this.proxyTop.hide();
54934 this.proxyBottom.hide();
54936 return result ? this.dropAllowed : this.dropNotAllowed;
54939 onNodeOut : function(n, dd, e, data){
54940 this.proxyTop.hide();
54941 this.proxyBottom.hide();
54944 onNodeDrop : function(n, dd, e, data){
54945 var h = data.header;
54947 var cm = this.grid.colModel;
54948 var x = Roo.lib.Event.getPageX(e);
54949 var r = Roo.lib.Dom.getRegion(n.firstChild);
54950 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
54951 var oldIndex = this.view.getCellIndex(h);
54952 var newIndex = this.view.getCellIndex(n);
54953 var locked = cm.isLocked(newIndex);
54957 if(oldIndex < newIndex){
54960 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
54963 cm.setLocked(oldIndex, locked, true);
54964 cm.moveColumn(oldIndex, newIndex);
54965 this.grid.fireEvent("columnmove", oldIndex, newIndex);
54973 * Ext JS Library 1.1.1
54974 * Copyright(c) 2006-2007, Ext JS, LLC.
54976 * Originally Released Under LGPL - original licence link has changed is not relivant.
54979 * <script type="text/javascript">
54983 * @class Roo.grid.GridView
54984 * @extends Roo.util.Observable
54987 * @param {Object} config
54989 Roo.grid.GridView = function(config){
54990 Roo.grid.GridView.superclass.constructor.call(this);
54993 Roo.apply(this, config);
54996 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
54998 unselectable : 'unselectable="on"',
54999 unselectableCls : 'x-unselectable',
55002 rowClass : "x-grid-row",
55004 cellClass : "x-grid-col",
55006 tdClass : "x-grid-td",
55008 hdClass : "x-grid-hd",
55010 splitClass : "x-grid-split",
55012 sortClasses : ["sort-asc", "sort-desc"],
55014 enableMoveAnim : false,
55018 dh : Roo.DomHelper,
55020 fly : Roo.Element.fly,
55022 css : Roo.util.CSS,
55028 scrollIncrement : 22,
55030 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55032 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55034 bind : function(ds, cm){
55036 this.ds.un("load", this.onLoad, this);
55037 this.ds.un("datachanged", this.onDataChange, this);
55038 this.ds.un("add", this.onAdd, this);
55039 this.ds.un("remove", this.onRemove, this);
55040 this.ds.un("update", this.onUpdate, this);
55041 this.ds.un("clear", this.onClear, this);
55044 ds.on("load", this.onLoad, this);
55045 ds.on("datachanged", this.onDataChange, this);
55046 ds.on("add", this.onAdd, this);
55047 ds.on("remove", this.onRemove, this);
55048 ds.on("update", this.onUpdate, this);
55049 ds.on("clear", this.onClear, this);
55054 this.cm.un("widthchange", this.onColWidthChange, this);
55055 this.cm.un("headerchange", this.onHeaderChange, this);
55056 this.cm.un("hiddenchange", this.onHiddenChange, this);
55057 this.cm.un("columnmoved", this.onColumnMove, this);
55058 this.cm.un("columnlockchange", this.onColumnLock, this);
55061 this.generateRules(cm);
55062 cm.on("widthchange", this.onColWidthChange, this);
55063 cm.on("headerchange", this.onHeaderChange, this);
55064 cm.on("hiddenchange", this.onHiddenChange, this);
55065 cm.on("columnmoved", this.onColumnMove, this);
55066 cm.on("columnlockchange", this.onColumnLock, this);
55071 init: function(grid){
55072 Roo.grid.GridView.superclass.init.call(this, grid);
55074 this.bind(grid.dataSource, grid.colModel);
55076 grid.on("headerclick", this.handleHeaderClick, this);
55078 if(grid.trackMouseOver){
55079 grid.on("mouseover", this.onRowOver, this);
55080 grid.on("mouseout", this.onRowOut, this);
55082 grid.cancelTextSelection = function(){};
55083 this.gridId = grid.id;
55085 var tpls = this.templates || {};
55088 tpls.master = new Roo.Template(
55089 '<div class="x-grid" hidefocus="true">',
55090 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55091 '<div class="x-grid-topbar"></div>',
55092 '<div class="x-grid-scroller"><div></div></div>',
55093 '<div class="x-grid-locked">',
55094 '<div class="x-grid-header">{lockedHeader}</div>',
55095 '<div class="x-grid-body">{lockedBody}</div>',
55097 '<div class="x-grid-viewport">',
55098 '<div class="x-grid-header">{header}</div>',
55099 '<div class="x-grid-body">{body}</div>',
55101 '<div class="x-grid-bottombar"></div>',
55103 '<div class="x-grid-resize-proxy"> </div>',
55106 tpls.master.disableformats = true;
55110 tpls.header = new Roo.Template(
55111 '<table border="0" cellspacing="0" cellpadding="0">',
55112 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55115 tpls.header.disableformats = true;
55117 tpls.header.compile();
55120 tpls.hcell = new Roo.Template(
55121 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55122 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55125 tpls.hcell.disableFormats = true;
55127 tpls.hcell.compile();
55130 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55131 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55132 tpls.hsplit.disableFormats = true;
55134 tpls.hsplit.compile();
55137 tpls.body = new Roo.Template(
55138 '<table border="0" cellspacing="0" cellpadding="0">',
55139 "<tbody>{rows}</tbody>",
55142 tpls.body.disableFormats = true;
55144 tpls.body.compile();
55147 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55148 tpls.row.disableFormats = true;
55150 tpls.row.compile();
55153 tpls.cell = new Roo.Template(
55154 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55155 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55156 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55159 tpls.cell.disableFormats = true;
55161 tpls.cell.compile();
55163 this.templates = tpls;
55166 // remap these for backwards compat
55167 onColWidthChange : function(){
55168 this.updateColumns.apply(this, arguments);
55170 onHeaderChange : function(){
55171 this.updateHeaders.apply(this, arguments);
55173 onHiddenChange : function(){
55174 this.handleHiddenChange.apply(this, arguments);
55176 onColumnMove : function(){
55177 this.handleColumnMove.apply(this, arguments);
55179 onColumnLock : function(){
55180 this.handleLockChange.apply(this, arguments);
55183 onDataChange : function(){
55185 this.updateHeaderSortState();
55188 onClear : function(){
55192 onUpdate : function(ds, record){
55193 this.refreshRow(record);
55196 refreshRow : function(record){
55197 var ds = this.ds, index;
55198 if(typeof record == 'number'){
55200 record = ds.getAt(index);
55202 index = ds.indexOf(record);
55204 this.insertRows(ds, index, index, true);
55205 this.onRemove(ds, record, index+1, true);
55206 this.syncRowHeights(index, index);
55208 this.fireEvent("rowupdated", this, index, record);
55211 onAdd : function(ds, records, index){
55212 this.insertRows(ds, index, index + (records.length-1));
55215 onRemove : function(ds, record, index, isUpdate){
55216 if(isUpdate !== true){
55217 this.fireEvent("beforerowremoved", this, index, record);
55219 var bt = this.getBodyTable(), lt = this.getLockedTable();
55220 if(bt.rows[index]){
55221 bt.firstChild.removeChild(bt.rows[index]);
55223 if(lt.rows[index]){
55224 lt.firstChild.removeChild(lt.rows[index]);
55226 if(isUpdate !== true){
55227 this.stripeRows(index);
55228 this.syncRowHeights(index, index);
55230 this.fireEvent("rowremoved", this, index, record);
55234 onLoad : function(){
55235 this.scrollToTop();
55239 * Scrolls the grid to the top
55241 scrollToTop : function(){
55243 this.scroller.dom.scrollTop = 0;
55249 * Gets a panel in the header of the grid that can be used for toolbars etc.
55250 * After modifying the contents of this panel a call to grid.autoSize() may be
55251 * required to register any changes in size.
55252 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55253 * @return Roo.Element
55255 getHeaderPanel : function(doShow){
55257 this.headerPanel.show();
55259 return this.headerPanel;
55263 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55264 * After modifying the contents of this panel a call to grid.autoSize() may be
55265 * required to register any changes in size.
55266 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55267 * @return Roo.Element
55269 getFooterPanel : function(doShow){
55271 this.footerPanel.show();
55273 return this.footerPanel;
55276 initElements : function(){
55277 var E = Roo.Element;
55278 var el = this.grid.getGridEl().dom.firstChild;
55279 var cs = el.childNodes;
55281 this.el = new E(el);
55283 this.focusEl = new E(el.firstChild);
55284 this.focusEl.swallowEvent("click", true);
55286 this.headerPanel = new E(cs[1]);
55287 this.headerPanel.enableDisplayMode("block");
55289 this.scroller = new E(cs[2]);
55290 this.scrollSizer = new E(this.scroller.dom.firstChild);
55292 this.lockedWrap = new E(cs[3]);
55293 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55294 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55296 this.mainWrap = new E(cs[4]);
55297 this.mainHd = new E(this.mainWrap.dom.firstChild);
55298 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55300 this.footerPanel = new E(cs[5]);
55301 this.footerPanel.enableDisplayMode("block");
55303 this.resizeProxy = new E(cs[6]);
55305 this.headerSelector = String.format(
55306 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55307 this.lockedHd.id, this.mainHd.id
55310 this.splitterSelector = String.format(
55311 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55312 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55315 idToCssName : function(s)
55317 return s.replace(/[^a-z0-9]+/ig, '-');
55320 getHeaderCell : function(index){
55321 return Roo.DomQuery.select(this.headerSelector)[index];
55324 getHeaderCellMeasure : function(index){
55325 return this.getHeaderCell(index).firstChild;
55328 getHeaderCellText : function(index){
55329 return this.getHeaderCell(index).firstChild.firstChild;
55332 getLockedTable : function(){
55333 return this.lockedBody.dom.firstChild;
55336 getBodyTable : function(){
55337 return this.mainBody.dom.firstChild;
55340 getLockedRow : function(index){
55341 return this.getLockedTable().rows[index];
55344 getRow : function(index){
55345 return this.getBodyTable().rows[index];
55348 getRowComposite : function(index){
55350 this.rowEl = new Roo.CompositeElementLite();
55352 var els = [], lrow, mrow;
55353 if(lrow = this.getLockedRow(index)){
55356 if(mrow = this.getRow(index)){
55359 this.rowEl.elements = els;
55363 * Gets the 'td' of the cell
55365 * @param {Integer} rowIndex row to select
55366 * @param {Integer} colIndex column to select
55370 getCell : function(rowIndex, colIndex){
55371 var locked = this.cm.getLockedCount();
55373 if(colIndex < locked){
55374 source = this.lockedBody.dom.firstChild;
55376 source = this.mainBody.dom.firstChild;
55377 colIndex -= locked;
55379 return source.rows[rowIndex].childNodes[colIndex];
55382 getCellText : function(rowIndex, colIndex){
55383 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55386 getCellBox : function(cell){
55387 var b = this.fly(cell).getBox();
55388 if(Roo.isOpera){ // opera fails to report the Y
55389 b.y = cell.offsetTop + this.mainBody.getY();
55394 getCellIndex : function(cell){
55395 var id = String(cell.className).match(this.cellRE);
55397 return parseInt(id[1], 10);
55402 findHeaderIndex : function(n){
55403 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55404 return r ? this.getCellIndex(r) : false;
55407 findHeaderCell : function(n){
55408 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55409 return r ? r : false;
55412 findRowIndex : function(n){
55416 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55417 return r ? r.rowIndex : false;
55420 findCellIndex : function(node){
55421 var stop = this.el.dom;
55422 while(node && node != stop){
55423 if(this.findRE.test(node.className)){
55424 return this.getCellIndex(node);
55426 node = node.parentNode;
55431 getColumnId : function(index){
55432 return this.cm.getColumnId(index);
55435 getSplitters : function()
55437 if(this.splitterSelector){
55438 return Roo.DomQuery.select(this.splitterSelector);
55444 getSplitter : function(index){
55445 return this.getSplitters()[index];
55448 onRowOver : function(e, t){
55450 if((row = this.findRowIndex(t)) !== false){
55451 this.getRowComposite(row).addClass("x-grid-row-over");
55455 onRowOut : function(e, t){
55457 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55458 this.getRowComposite(row).removeClass("x-grid-row-over");
55462 renderHeaders : function(){
55464 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55465 var cb = [], lb = [], sb = [], lsb = [], p = {};
55466 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55467 p.cellId = "x-grid-hd-0-" + i;
55468 p.splitId = "x-grid-csplit-0-" + i;
55469 p.id = cm.getColumnId(i);
55470 p.value = cm.getColumnHeader(i) || "";
55471 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55472 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55473 if(!cm.isLocked(i)){
55474 cb[cb.length] = ct.apply(p);
55475 sb[sb.length] = st.apply(p);
55477 lb[lb.length] = ct.apply(p);
55478 lsb[lsb.length] = st.apply(p);
55481 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55482 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55485 updateHeaders : function(){
55486 var html = this.renderHeaders();
55487 this.lockedHd.update(html[0]);
55488 this.mainHd.update(html[1]);
55492 * Focuses the specified row.
55493 * @param {Number} row The row index
55495 focusRow : function(row)
55497 //Roo.log('GridView.focusRow');
55498 var x = this.scroller.dom.scrollLeft;
55499 this.focusCell(row, 0, false);
55500 this.scroller.dom.scrollLeft = x;
55504 * Focuses the specified cell.
55505 * @param {Number} row The row index
55506 * @param {Number} col The column index
55507 * @param {Boolean} hscroll false to disable horizontal scrolling
55509 focusCell : function(row, col, hscroll)
55511 //Roo.log('GridView.focusCell');
55512 var el = this.ensureVisible(row, col, hscroll);
55513 this.focusEl.alignTo(el, "tl-tl");
55515 this.focusEl.focus();
55517 this.focusEl.focus.defer(1, this.focusEl);
55522 * Scrolls the specified cell into view
55523 * @param {Number} row The row index
55524 * @param {Number} col The column index
55525 * @param {Boolean} hscroll false to disable horizontal scrolling
55527 ensureVisible : function(row, col, hscroll)
55529 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55530 //return null; //disable for testing.
55531 if(typeof row != "number"){
55532 row = row.rowIndex;
55534 if(row < 0 && row >= this.ds.getCount()){
55537 col = (col !== undefined ? col : 0);
55538 var cm = this.grid.colModel;
55539 while(cm.isHidden(col)){
55543 var el = this.getCell(row, col);
55547 var c = this.scroller.dom;
55549 var ctop = parseInt(el.offsetTop, 10);
55550 var cleft = parseInt(el.offsetLeft, 10);
55551 var cbot = ctop + el.offsetHeight;
55552 var cright = cleft + el.offsetWidth;
55554 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55555 var stop = parseInt(c.scrollTop, 10);
55556 var sleft = parseInt(c.scrollLeft, 10);
55557 var sbot = stop + ch;
55558 var sright = sleft + c.clientWidth;
55560 Roo.log('GridView.ensureVisible:' +
55562 ' c.clientHeight:' + c.clientHeight +
55563 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55571 c.scrollTop = ctop;
55572 //Roo.log("set scrolltop to ctop DISABLE?");
55573 }else if(cbot > sbot){
55574 //Roo.log("set scrolltop to cbot-ch");
55575 c.scrollTop = cbot-ch;
55578 if(hscroll !== false){
55580 c.scrollLeft = cleft;
55581 }else if(cright > sright){
55582 c.scrollLeft = cright-c.clientWidth;
55589 updateColumns : function(){
55590 this.grid.stopEditing();
55591 var cm = this.grid.colModel, colIds = this.getColumnIds();
55592 //var totalWidth = cm.getTotalWidth();
55594 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55595 //if(cm.isHidden(i)) continue;
55596 var w = cm.getColumnWidth(i);
55597 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55598 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55600 this.updateSplitters();
55603 generateRules : function(cm){
55604 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55605 Roo.util.CSS.removeStyleSheet(rulesId);
55606 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55607 var cid = cm.getColumnId(i);
55609 if(cm.config[i].align){
55610 align = 'text-align:'+cm.config[i].align+';';
55613 if(cm.isHidden(i)){
55614 hidden = 'display:none;';
55616 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55618 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55619 this.hdSelector, cid, " {\n", align, width, "}\n",
55620 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55621 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55623 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55626 updateSplitters : function(){
55627 var cm = this.cm, s = this.getSplitters();
55628 if(s){ // splitters not created yet
55629 var pos = 0, locked = true;
55630 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55631 if(cm.isHidden(i)) {
55634 var w = cm.getColumnWidth(i); // make sure it's a number
55635 if(!cm.isLocked(i) && locked){
55640 s[i].style.left = (pos-this.splitOffset) + "px";
55645 handleHiddenChange : function(colModel, colIndex, hidden){
55647 this.hideColumn(colIndex);
55649 this.unhideColumn(colIndex);
55653 hideColumn : function(colIndex){
55654 var cid = this.getColumnId(colIndex);
55655 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55656 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55658 this.updateHeaders();
55660 this.updateSplitters();
55664 unhideColumn : function(colIndex){
55665 var cid = this.getColumnId(colIndex);
55666 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55667 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55670 this.updateHeaders();
55672 this.updateSplitters();
55676 insertRows : function(dm, firstRow, lastRow, isUpdate){
55677 if(firstRow == 0 && lastRow == dm.getCount()-1){
55681 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55683 var s = this.getScrollState();
55684 var markup = this.renderRows(firstRow, lastRow);
55685 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55686 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55687 this.restoreScroll(s);
55689 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55690 this.syncRowHeights(firstRow, lastRow);
55691 this.stripeRows(firstRow);
55697 bufferRows : function(markup, target, index){
55698 var before = null, trows = target.rows, tbody = target.tBodies[0];
55699 if(index < trows.length){
55700 before = trows[index];
55702 var b = document.createElement("div");
55703 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55704 var rows = b.firstChild.rows;
55705 for(var i = 0, len = rows.length; i < len; i++){
55707 tbody.insertBefore(rows[0], before);
55709 tbody.appendChild(rows[0]);
55716 deleteRows : function(dm, firstRow, lastRow){
55717 if(dm.getRowCount()<1){
55718 this.fireEvent("beforerefresh", this);
55719 this.mainBody.update("");
55720 this.lockedBody.update("");
55721 this.fireEvent("refresh", this);
55723 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55724 var bt = this.getBodyTable();
55725 var tbody = bt.firstChild;
55726 var rows = bt.rows;
55727 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55728 tbody.removeChild(rows[firstRow]);
55730 this.stripeRows(firstRow);
55731 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55735 updateRows : function(dataSource, firstRow, lastRow){
55736 var s = this.getScrollState();
55738 this.restoreScroll(s);
55741 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55745 this.updateHeaderSortState();
55748 getScrollState : function(){
55750 var sb = this.scroller.dom;
55751 return {left: sb.scrollLeft, top: sb.scrollTop};
55754 stripeRows : function(startRow){
55755 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55758 startRow = startRow || 0;
55759 var rows = this.getBodyTable().rows;
55760 var lrows = this.getLockedTable().rows;
55761 var cls = ' x-grid-row-alt ';
55762 for(var i = startRow, len = rows.length; i < len; i++){
55763 var row = rows[i], lrow = lrows[i];
55764 var isAlt = ((i+1) % 2 == 0);
55765 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55766 if(isAlt == hasAlt){
55770 row.className += " x-grid-row-alt";
55772 row.className = row.className.replace("x-grid-row-alt", "");
55775 lrow.className = row.className;
55780 restoreScroll : function(state){
55781 //Roo.log('GridView.restoreScroll');
55782 var sb = this.scroller.dom;
55783 sb.scrollLeft = state.left;
55784 sb.scrollTop = state.top;
55788 syncScroll : function(){
55789 //Roo.log('GridView.syncScroll');
55790 var sb = this.scroller.dom;
55791 var sh = this.mainHd.dom;
55792 var bs = this.mainBody.dom;
55793 var lv = this.lockedBody.dom;
55794 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55795 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55798 handleScroll : function(e){
55800 var sb = this.scroller.dom;
55801 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55805 handleWheel : function(e){
55806 var d = e.getWheelDelta();
55807 this.scroller.dom.scrollTop -= d*22;
55808 // set this here to prevent jumpy scrolling on large tables
55809 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55813 renderRows : function(startRow, endRow){
55814 // pull in all the crap needed to render rows
55815 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55816 var colCount = cm.getColumnCount();
55818 if(ds.getCount() < 1){
55822 // build a map for all the columns
55824 for(var i = 0; i < colCount; i++){
55825 var name = cm.getDataIndex(i);
55827 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55828 renderer : cm.getRenderer(i),
55829 id : cm.getColumnId(i),
55830 locked : cm.isLocked(i),
55831 has_editor : cm.isCellEditable(i)
55835 startRow = startRow || 0;
55836 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55838 // records to render
55839 var rs = ds.getRange(startRow, endRow);
55841 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55844 // As much as I hate to duplicate code, this was branched because FireFox really hates
55845 // [].join("") on strings. The performance difference was substantial enough to
55846 // branch this function
55847 doRender : Roo.isGecko ?
55848 function(cs, rs, ds, startRow, colCount, stripe){
55849 var ts = this.templates, ct = ts.cell, rt = ts.row;
55851 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55853 var hasListener = this.grid.hasListener('rowclass');
55855 for(var j = 0, len = rs.length; j < len; j++){
55856 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
55857 for(var i = 0; i < colCount; i++){
55859 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55861 p.css = p.attr = "";
55862 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55863 if(p.value == undefined || p.value === "") {
55864 p.value = " ";
55867 p.css += ' x-grid-editable-cell';
55869 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
55870 p.css += ' x-grid-dirty-cell';
55872 var markup = ct.apply(p);
55880 if(stripe && ((rowIndex+1) % 2 == 0)){
55881 alt.push("x-grid-row-alt")
55884 alt.push( " x-grid-dirty-row");
55887 if(this.getRowClass){
55888 alt.push(this.getRowClass(r, rowIndex));
55894 rowIndex : rowIndex,
55897 this.grid.fireEvent('rowclass', this, rowcfg);
55898 alt.push(rowcfg.rowClass);
55900 rp.alt = alt.join(" ");
55901 lbuf+= rt.apply(rp);
55903 buf+= rt.apply(rp);
55905 return [lbuf, buf];
55907 function(cs, rs, ds, startRow, colCount, stripe){
55908 var ts = this.templates, ct = ts.cell, rt = ts.row;
55910 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55911 var hasListener = this.grid.hasListener('rowclass');
55914 for(var j = 0, len = rs.length; j < len; j++){
55915 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
55916 for(var i = 0; i < colCount; i++){
55918 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55920 p.css = p.attr = "";
55921 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55922 if(p.value == undefined || p.value === "") {
55923 p.value = " ";
55927 p.css += ' x-grid-editable-cell';
55929 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
55930 p.css += ' x-grid-dirty-cell'
55933 var markup = ct.apply(p);
55935 cb[cb.length] = markup;
55937 lcb[lcb.length] = markup;
55941 if(stripe && ((rowIndex+1) % 2 == 0)){
55942 alt.push( "x-grid-row-alt");
55945 alt.push(" x-grid-dirty-row");
55948 if(this.getRowClass){
55949 alt.push( this.getRowClass(r, rowIndex));
55955 rowIndex : rowIndex,
55958 this.grid.fireEvent('rowclass', this, rowcfg);
55959 alt.push(rowcfg.rowClass);
55962 rp.alt = alt.join(" ");
55963 rp.cells = lcb.join("");
55964 lbuf[lbuf.length] = rt.apply(rp);
55965 rp.cells = cb.join("");
55966 buf[buf.length] = rt.apply(rp);
55968 return [lbuf.join(""), buf.join("")];
55971 renderBody : function(){
55972 var markup = this.renderRows();
55973 var bt = this.templates.body;
55974 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
55978 * Refreshes the grid
55979 * @param {Boolean} headersToo
55981 refresh : function(headersToo){
55982 this.fireEvent("beforerefresh", this);
55983 this.grid.stopEditing();
55984 var result = this.renderBody();
55985 this.lockedBody.update(result[0]);
55986 this.mainBody.update(result[1]);
55987 if(headersToo === true){
55988 this.updateHeaders();
55989 this.updateColumns();
55990 this.updateSplitters();
55991 this.updateHeaderSortState();
55993 this.syncRowHeights();
55995 this.fireEvent("refresh", this);
55998 handleColumnMove : function(cm, oldIndex, newIndex){
55999 this.indexMap = null;
56000 var s = this.getScrollState();
56001 this.refresh(true);
56002 this.restoreScroll(s);
56003 this.afterMove(newIndex);
56006 afterMove : function(colIndex){
56007 if(this.enableMoveAnim && Roo.enableFx){
56008 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56010 // if multisort - fix sortOrder, and reload..
56011 if (this.grid.dataSource.multiSort) {
56012 // the we can call sort again..
56013 var dm = this.grid.dataSource;
56014 var cm = this.grid.colModel;
56016 for(var i = 0; i < cm.config.length; i++ ) {
56018 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56019 continue; // dont' bother, it's not in sort list or being set.
56022 so.push(cm.config[i].dataIndex);
56025 dm.load(dm.lastOptions);
56032 updateCell : function(dm, rowIndex, dataIndex){
56033 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56034 if(typeof colIndex == "undefined"){ // not present in grid
56037 var cm = this.grid.colModel;
56038 var cell = this.getCell(rowIndex, colIndex);
56039 var cellText = this.getCellText(rowIndex, colIndex);
56042 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56043 id : cm.getColumnId(colIndex),
56044 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56046 var renderer = cm.getRenderer(colIndex);
56047 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56048 if(typeof val == "undefined" || val === "") {
56051 cellText.innerHTML = val;
56052 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56053 this.syncRowHeights(rowIndex, rowIndex);
56056 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56058 if(this.grid.autoSizeHeaders){
56059 var h = this.getHeaderCellMeasure(colIndex);
56060 maxWidth = Math.max(maxWidth, h.scrollWidth);
56063 if(this.cm.isLocked(colIndex)){
56064 tb = this.getLockedTable();
56067 tb = this.getBodyTable();
56068 index = colIndex - this.cm.getLockedCount();
56071 var rows = tb.rows;
56072 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56073 for(var i = 0; i < stopIndex; i++){
56074 var cell = rows[i].childNodes[index].firstChild;
56075 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56078 return maxWidth + /*margin for error in IE*/ 5;
56081 * Autofit a column to its content.
56082 * @param {Number} colIndex
56083 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56085 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56086 if(this.cm.isHidden(colIndex)){
56087 return; // can't calc a hidden column
56090 var cid = this.cm.getColumnId(colIndex);
56091 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56092 if(this.grid.autoSizeHeaders){
56093 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56096 var newWidth = this.calcColumnWidth(colIndex);
56097 this.cm.setColumnWidth(colIndex,
56098 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56099 if(!suppressEvent){
56100 this.grid.fireEvent("columnresize", colIndex, newWidth);
56105 * Autofits all columns to their content and then expands to fit any extra space in the grid
56107 autoSizeColumns : function(){
56108 var cm = this.grid.colModel;
56109 var colCount = cm.getColumnCount();
56110 for(var i = 0; i < colCount; i++){
56111 this.autoSizeColumn(i, true, true);
56113 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56116 this.updateColumns();
56122 * Autofits all columns to the grid's width proportionate with their current size
56123 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56125 fitColumns : function(reserveScrollSpace){
56126 var cm = this.grid.colModel;
56127 var colCount = cm.getColumnCount();
56131 for (i = 0; i < colCount; i++){
56132 if(!cm.isHidden(i) && !cm.isFixed(i)){
56133 w = cm.getColumnWidth(i);
56139 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56140 if(reserveScrollSpace){
56143 var frac = (avail - cm.getTotalWidth())/width;
56144 while (cols.length){
56147 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56149 this.updateColumns();
56153 onRowSelect : function(rowIndex){
56154 var row = this.getRowComposite(rowIndex);
56155 row.addClass("x-grid-row-selected");
56158 onRowDeselect : function(rowIndex){
56159 var row = this.getRowComposite(rowIndex);
56160 row.removeClass("x-grid-row-selected");
56163 onCellSelect : function(row, col){
56164 var cell = this.getCell(row, col);
56166 Roo.fly(cell).addClass("x-grid-cell-selected");
56170 onCellDeselect : function(row, col){
56171 var cell = this.getCell(row, col);
56173 Roo.fly(cell).removeClass("x-grid-cell-selected");
56177 updateHeaderSortState : function(){
56179 // sort state can be single { field: xxx, direction : yyy}
56180 // or { xxx=>ASC , yyy : DESC ..... }
56183 if (!this.ds.multiSort) {
56184 var state = this.ds.getSortState();
56188 mstate[state.field] = state.direction;
56189 // FIXME... - this is not used here.. but might be elsewhere..
56190 this.sortState = state;
56193 mstate = this.ds.sortToggle;
56195 //remove existing sort classes..
56197 var sc = this.sortClasses;
56198 var hds = this.el.select(this.headerSelector).removeClass(sc);
56200 for(var f in mstate) {
56202 var sortColumn = this.cm.findColumnIndex(f);
56204 if(sortColumn != -1){
56205 var sortDir = mstate[f];
56206 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56215 handleHeaderClick : function(g, index,e){
56217 Roo.log("header click");
56220 // touch events on header are handled by context
56221 this.handleHdCtx(g,index,e);
56226 if(this.headersDisabled){
56229 var dm = g.dataSource, cm = g.colModel;
56230 if(!cm.isSortable(index)){
56235 if (dm.multiSort) {
56236 // update the sortOrder
56238 for(var i = 0; i < cm.config.length; i++ ) {
56240 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56241 continue; // dont' bother, it's not in sort list or being set.
56244 so.push(cm.config[i].dataIndex);
56250 dm.sort(cm.getDataIndex(index));
56254 destroy : function(){
56256 this.colMenu.removeAll();
56257 Roo.menu.MenuMgr.unregister(this.colMenu);
56258 this.colMenu.getEl().remove();
56259 delete this.colMenu;
56262 this.hmenu.removeAll();
56263 Roo.menu.MenuMgr.unregister(this.hmenu);
56264 this.hmenu.getEl().remove();
56267 if(this.grid.enableColumnMove){
56268 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56270 for(var dd in dds){
56271 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56272 var elid = dds[dd].dragElId;
56274 Roo.get(elid).remove();
56275 } else if(dds[dd].config.isTarget){
56276 dds[dd].proxyTop.remove();
56277 dds[dd].proxyBottom.remove();
56280 if(Roo.dd.DDM.locationCache[dd]){
56281 delete Roo.dd.DDM.locationCache[dd];
56284 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56287 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56288 this.bind(null, null);
56289 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56292 handleLockChange : function(){
56293 this.refresh(true);
56296 onDenyColumnLock : function(){
56300 onDenyColumnHide : function(){
56304 handleHdMenuClick : function(item){
56305 var index = this.hdCtxIndex;
56306 var cm = this.cm, ds = this.ds;
56309 ds.sort(cm.getDataIndex(index), "ASC");
56312 ds.sort(cm.getDataIndex(index), "DESC");
56315 var lc = cm.getLockedCount();
56316 if(cm.getColumnCount(true) <= lc+1){
56317 this.onDenyColumnLock();
56321 cm.setLocked(index, true, true);
56322 cm.moveColumn(index, lc);
56323 this.grid.fireEvent("columnmove", index, lc);
56325 cm.setLocked(index, true);
56329 var lc = cm.getLockedCount();
56330 if((lc-1) != index){
56331 cm.setLocked(index, false, true);
56332 cm.moveColumn(index, lc-1);
56333 this.grid.fireEvent("columnmove", index, lc-1);
56335 cm.setLocked(index, false);
56338 case 'wider': // used to expand cols on touch..
56340 var cw = cm.getColumnWidth(index);
56341 cw += (item.id == 'wider' ? 1 : -1) * 50;
56342 cw = Math.max(0, cw);
56343 cw = Math.min(cw,4000);
56344 cm.setColumnWidth(index, cw);
56348 index = cm.getIndexById(item.id.substr(4));
56350 if(item.checked && cm.getColumnCount(true) <= 1){
56351 this.onDenyColumnHide();
56354 cm.setHidden(index, item.checked);
56360 beforeColMenuShow : function(){
56361 var cm = this.cm, colCount = cm.getColumnCount();
56362 this.colMenu.removeAll();
56363 for(var i = 0; i < colCount; i++){
56364 this.colMenu.add(new Roo.menu.CheckItem({
56365 id: "col-"+cm.getColumnId(i),
56366 text: cm.getColumnHeader(i),
56367 checked: !cm.isHidden(i),
56373 handleHdCtx : function(g, index, e){
56375 var hd = this.getHeaderCell(index);
56376 this.hdCtxIndex = index;
56377 var ms = this.hmenu.items, cm = this.cm;
56378 ms.get("asc").setDisabled(!cm.isSortable(index));
56379 ms.get("desc").setDisabled(!cm.isSortable(index));
56380 if(this.grid.enableColLock !== false){
56381 ms.get("lock").setDisabled(cm.isLocked(index));
56382 ms.get("unlock").setDisabled(!cm.isLocked(index));
56384 this.hmenu.show(hd, "tl-bl");
56387 handleHdOver : function(e){
56388 var hd = this.findHeaderCell(e.getTarget());
56389 if(hd && !this.headersDisabled){
56390 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56391 this.fly(hd).addClass("x-grid-hd-over");
56396 handleHdOut : function(e){
56397 var hd = this.findHeaderCell(e.getTarget());
56399 this.fly(hd).removeClass("x-grid-hd-over");
56403 handleSplitDblClick : function(e, t){
56404 var i = this.getCellIndex(t);
56405 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56406 this.autoSizeColumn(i, true);
56411 render : function(){
56414 var colCount = cm.getColumnCount();
56416 if(this.grid.monitorWindowResize === true){
56417 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56419 var header = this.renderHeaders();
56420 var body = this.templates.body.apply({rows:""});
56421 var html = this.templates.master.apply({
56424 lockedHeader: header[0],
56428 //this.updateColumns();
56430 this.grid.getGridEl().dom.innerHTML = html;
56432 this.initElements();
56434 // a kludge to fix the random scolling effect in webkit
56435 this.el.on("scroll", function() {
56436 this.el.dom.scrollTop=0; // hopefully not recursive..
56439 this.scroller.on("scroll", this.handleScroll, this);
56440 this.lockedBody.on("mousewheel", this.handleWheel, this);
56441 this.mainBody.on("mousewheel", this.handleWheel, this);
56443 this.mainHd.on("mouseover", this.handleHdOver, this);
56444 this.mainHd.on("mouseout", this.handleHdOut, this);
56445 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56446 {delegate: "."+this.splitClass});
56448 this.lockedHd.on("mouseover", this.handleHdOver, this);
56449 this.lockedHd.on("mouseout", this.handleHdOut, this);
56450 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56451 {delegate: "."+this.splitClass});
56453 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56454 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56457 this.updateSplitters();
56459 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56460 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56461 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56464 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56465 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56467 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56468 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56470 if(this.grid.enableColLock !== false){
56471 this.hmenu.add('-',
56472 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56473 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56477 this.hmenu.add('-',
56478 {id:"wider", text: this.columnsWiderText},
56479 {id:"narrow", text: this.columnsNarrowText }
56485 if(this.grid.enableColumnHide !== false){
56487 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56488 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56489 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56491 this.hmenu.add('-',
56492 {id:"columns", text: this.columnsText, menu: this.colMenu}
56495 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56497 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56500 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56501 this.dd = new Roo.grid.GridDragZone(this.grid, {
56502 ddGroup : this.grid.ddGroup || 'GridDD'
56508 for(var i = 0; i < colCount; i++){
56509 if(cm.isHidden(i)){
56510 this.hideColumn(i);
56512 if(cm.config[i].align){
56513 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56514 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56518 this.updateHeaderSortState();
56520 this.beforeInitialResize();
56523 // two part rendering gives faster view to the user
56524 this.renderPhase2.defer(1, this);
56527 renderPhase2 : function(){
56528 // render the rows now
56530 if(this.grid.autoSizeColumns){
56531 this.autoSizeColumns();
56535 beforeInitialResize : function(){
56539 onColumnSplitterMoved : function(i, w){
56540 this.userResized = true;
56541 var cm = this.grid.colModel;
56542 cm.setColumnWidth(i, w, true);
56543 var cid = cm.getColumnId(i);
56544 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56545 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56546 this.updateSplitters();
56548 this.grid.fireEvent("columnresize", i, w);
56551 syncRowHeights : function(startIndex, endIndex){
56552 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56553 startIndex = startIndex || 0;
56554 var mrows = this.getBodyTable().rows;
56555 var lrows = this.getLockedTable().rows;
56556 var len = mrows.length-1;
56557 endIndex = Math.min(endIndex || len, len);
56558 for(var i = startIndex; i <= endIndex; i++){
56559 var m = mrows[i], l = lrows[i];
56560 var h = Math.max(m.offsetHeight, l.offsetHeight);
56561 m.style.height = l.style.height = h + "px";
56566 layout : function(initialRender, is2ndPass){
56568 var auto = g.autoHeight;
56569 var scrollOffset = 16;
56570 var c = g.getGridEl(), cm = this.cm,
56571 expandCol = g.autoExpandColumn,
56573 //c.beginMeasure();
56575 if(!c.dom.offsetWidth){ // display:none?
56577 this.lockedWrap.show();
56578 this.mainWrap.show();
56583 var hasLock = this.cm.isLocked(0);
56585 var tbh = this.headerPanel.getHeight();
56586 var bbh = this.footerPanel.getHeight();
56589 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56590 var newHeight = ch + c.getBorderWidth("tb");
56592 newHeight = Math.min(g.maxHeight, newHeight);
56594 c.setHeight(newHeight);
56598 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56601 var s = this.scroller;
56603 var csize = c.getSize(true);
56605 this.el.setSize(csize.width, csize.height);
56607 this.headerPanel.setWidth(csize.width);
56608 this.footerPanel.setWidth(csize.width);
56610 var hdHeight = this.mainHd.getHeight();
56611 var vw = csize.width;
56612 var vh = csize.height - (tbh + bbh);
56616 var bt = this.getBodyTable();
56618 if(cm.getLockedCount() == cm.config.length){
56619 bt = this.getLockedTable();
56622 var ltWidth = hasLock ?
56623 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56625 var scrollHeight = bt.offsetHeight;
56626 var scrollWidth = ltWidth + bt.offsetWidth;
56627 var vscroll = false, hscroll = false;
56629 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56631 var lw = this.lockedWrap, mw = this.mainWrap;
56632 var lb = this.lockedBody, mb = this.mainBody;
56634 setTimeout(function(){
56635 var t = s.dom.offsetTop;
56636 var w = s.dom.clientWidth,
56637 h = s.dom.clientHeight;
56640 lw.setSize(ltWidth, h);
56642 mw.setLeftTop(ltWidth, t);
56643 mw.setSize(w-ltWidth, h);
56645 lb.setHeight(h-hdHeight);
56646 mb.setHeight(h-hdHeight);
56648 if(is2ndPass !== true && !gv.userResized && expandCol){
56649 // high speed resize without full column calculation
56651 var ci = cm.getIndexById(expandCol);
56653 ci = cm.findColumnIndex(expandCol);
56655 ci = Math.max(0, ci); // make sure it's got at least the first col.
56656 var expandId = cm.getColumnId(ci);
56657 var tw = cm.getTotalWidth(false);
56658 var currentWidth = cm.getColumnWidth(ci);
56659 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56660 if(currentWidth != cw){
56661 cm.setColumnWidth(ci, cw, true);
56662 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56663 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56664 gv.updateSplitters();
56665 gv.layout(false, true);
56677 onWindowResize : function(){
56678 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56684 appendFooter : function(parentEl){
56688 sortAscText : "Sort Ascending",
56689 sortDescText : "Sort Descending",
56690 lockText : "Lock Column",
56691 unlockText : "Unlock Column",
56692 columnsText : "Columns",
56694 columnsWiderText : "Wider",
56695 columnsNarrowText : "Thinner"
56699 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56700 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56701 this.proxy.el.addClass('x-grid3-col-dd');
56704 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56705 handleMouseDown : function(e){
56709 callHandleMouseDown : function(e){
56710 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56715 * Ext JS Library 1.1.1
56716 * Copyright(c) 2006-2007, Ext JS, LLC.
56718 * Originally Released Under LGPL - original licence link has changed is not relivant.
56721 * <script type="text/javascript">
56725 // This is a support class used internally by the Grid components
56726 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56728 this.view = grid.getView();
56729 this.proxy = this.view.resizeProxy;
56730 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56731 "gridSplitters" + this.grid.getGridEl().id, {
56732 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56734 this.setHandleElId(Roo.id(hd));
56735 this.setOuterHandleElId(Roo.id(hd2));
56736 this.scroll = false;
56738 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56739 fly: Roo.Element.fly,
56741 b4StartDrag : function(x, y){
56742 this.view.headersDisabled = true;
56743 this.proxy.setHeight(this.view.mainWrap.getHeight());
56744 var w = this.cm.getColumnWidth(this.cellIndex);
56745 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56746 this.resetConstraints();
56747 this.setXConstraint(minw, 1000);
56748 this.setYConstraint(0, 0);
56749 this.minX = x - minw;
56750 this.maxX = x + 1000;
56752 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56756 handleMouseDown : function(e){
56757 ev = Roo.EventObject.setEvent(e);
56758 var t = this.fly(ev.getTarget());
56759 if(t.hasClass("x-grid-split")){
56760 this.cellIndex = this.view.getCellIndex(t.dom);
56761 this.split = t.dom;
56762 this.cm = this.grid.colModel;
56763 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56764 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56769 endDrag : function(e){
56770 this.view.headersDisabled = false;
56771 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56772 var diff = endX - this.startPos;
56773 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56776 autoOffset : function(){
56777 this.setDelta(0,0);
56781 * Ext JS Library 1.1.1
56782 * Copyright(c) 2006-2007, Ext JS, LLC.
56784 * Originally Released Under LGPL - original licence link has changed is not relivant.
56787 * <script type="text/javascript">
56791 // This is a support class used internally by the Grid components
56792 Roo.grid.GridDragZone = function(grid, config){
56793 this.view = grid.getView();
56794 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56795 if(this.view.lockedBody){
56796 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56797 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56799 this.scroll = false;
56801 this.ddel = document.createElement('div');
56802 this.ddel.className = 'x-grid-dd-wrap';
56805 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56806 ddGroup : "GridDD",
56808 getDragData : function(e){
56809 var t = Roo.lib.Event.getTarget(e);
56810 var rowIndex = this.view.findRowIndex(t);
56811 var sm = this.grid.selModel;
56813 //Roo.log(rowIndex);
56815 if (sm.getSelectedCell) {
56816 // cell selection..
56817 if (!sm.getSelectedCell()) {
56820 if (rowIndex != sm.getSelectedCell()[0]) {
56826 if(rowIndex !== false){
56831 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56833 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56836 if (e.hasModifier()){
56837 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56840 Roo.log("getDragData");
56845 rowIndex: rowIndex,
56846 selections:sm.getSelections ? sm.getSelections() : (
56847 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
56854 onInitDrag : function(e){
56855 var data = this.dragData;
56856 this.ddel.innerHTML = this.grid.getDragDropText();
56857 this.proxy.update(this.ddel);
56858 // fire start drag?
56861 afterRepair : function(){
56862 this.dragging = false;
56865 getRepairXY : function(e, data){
56869 onEndDrag : function(data, e){
56873 onValidDrop : function(dd, e, id){
56878 beforeInvalidDrop : function(e, id){
56883 * Ext JS Library 1.1.1
56884 * Copyright(c) 2006-2007, Ext JS, LLC.
56886 * Originally Released Under LGPL - original licence link has changed is not relivant.
56889 * <script type="text/javascript">
56894 * @class Roo.grid.ColumnModel
56895 * @extends Roo.util.Observable
56896 * This is the default implementation of a ColumnModel used by the Grid. It defines
56897 * the columns in the grid.
56900 var colModel = new Roo.grid.ColumnModel([
56901 {header: "Ticker", width: 60, sortable: true, locked: true},
56902 {header: "Company Name", width: 150, sortable: true},
56903 {header: "Market Cap.", width: 100, sortable: true},
56904 {header: "$ Sales", width: 100, sortable: true, renderer: money},
56905 {header: "Employees", width: 100, sortable: true, resizable: false}
56910 * The config options listed for this class are options which may appear in each
56911 * individual column definition.
56912 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
56914 * @param {Object} config An Array of column config objects. See this class's
56915 * config objects for details.
56917 Roo.grid.ColumnModel = function(config){
56919 * The config passed into the constructor
56921 this.config = config;
56924 // if no id, create one
56925 // if the column does not have a dataIndex mapping,
56926 // map it to the order it is in the config
56927 for(var i = 0, len = config.length; i < len; i++){
56929 if(typeof c.dataIndex == "undefined"){
56932 if(typeof c.renderer == "string"){
56933 c.renderer = Roo.util.Format[c.renderer];
56935 if(typeof c.id == "undefined"){
56938 if(c.editor && c.editor.xtype){
56939 c.editor = Roo.factory(c.editor, Roo.grid);
56941 if(c.editor && c.editor.isFormField){
56942 c.editor = new Roo.grid.GridEditor(c.editor);
56944 this.lookup[c.id] = c;
56948 * The width of columns which have no width specified (defaults to 100)
56951 this.defaultWidth = 100;
56954 * Default sortable of columns which have no sortable specified (defaults to false)
56957 this.defaultSortable = false;
56961 * @event widthchange
56962 * Fires when the width of a column changes.
56963 * @param {ColumnModel} this
56964 * @param {Number} columnIndex The column index
56965 * @param {Number} newWidth The new width
56967 "widthchange": true,
56969 * @event headerchange
56970 * Fires when the text of a header changes.
56971 * @param {ColumnModel} this
56972 * @param {Number} columnIndex The column index
56973 * @param {Number} newText The new header text
56975 "headerchange": true,
56977 * @event hiddenchange
56978 * Fires when a column is hidden or "unhidden".
56979 * @param {ColumnModel} this
56980 * @param {Number} columnIndex The column index
56981 * @param {Boolean} hidden true if hidden, false otherwise
56983 "hiddenchange": true,
56985 * @event columnmoved
56986 * Fires when a column is moved.
56987 * @param {ColumnModel} this
56988 * @param {Number} oldIndex
56989 * @param {Number} newIndex
56991 "columnmoved" : true,
56993 * @event columlockchange
56994 * Fires when a column's locked state is changed
56995 * @param {ColumnModel} this
56996 * @param {Number} colIndex
56997 * @param {Boolean} locked true if locked
56999 "columnlockchange" : true
57001 Roo.grid.ColumnModel.superclass.constructor.call(this);
57003 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57005 * @cfg {String} header The header text to display in the Grid view.
57008 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57009 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57010 * specified, the column's index is used as an index into the Record's data Array.
57013 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57014 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57017 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57018 * Defaults to the value of the {@link #defaultSortable} property.
57019 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57022 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57025 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57028 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57031 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57034 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57035 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57036 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57037 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57040 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57043 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57046 * @cfg {String} cursor (Optional)
57049 * @cfg {String} tooltip (Optional)
57052 * @cfg {Number} xs (Optional)
57055 * @cfg {Number} sm (Optional)
57058 * @cfg {Number} md (Optional)
57061 * @cfg {Number} lg (Optional)
57064 * Returns the id of the column at the specified index.
57065 * @param {Number} index The column index
57066 * @return {String} the id
57068 getColumnId : function(index){
57069 return this.config[index].id;
57073 * Returns the column for a specified id.
57074 * @param {String} id The column id
57075 * @return {Object} the column
57077 getColumnById : function(id){
57078 return this.lookup[id];
57083 * Returns the column for a specified dataIndex.
57084 * @param {String} dataIndex The column dataIndex
57085 * @return {Object|Boolean} the column or false if not found
57087 getColumnByDataIndex: function(dataIndex){
57088 var index = this.findColumnIndex(dataIndex);
57089 return index > -1 ? this.config[index] : false;
57093 * Returns the index for a specified column id.
57094 * @param {String} id The column id
57095 * @return {Number} the index, or -1 if not found
57097 getIndexById : function(id){
57098 for(var i = 0, len = this.config.length; i < len; i++){
57099 if(this.config[i].id == id){
57107 * Returns the index for a specified column dataIndex.
57108 * @param {String} dataIndex The column dataIndex
57109 * @return {Number} the index, or -1 if not found
57112 findColumnIndex : function(dataIndex){
57113 for(var i = 0, len = this.config.length; i < len; i++){
57114 if(this.config[i].dataIndex == dataIndex){
57122 moveColumn : function(oldIndex, newIndex){
57123 var c = this.config[oldIndex];
57124 this.config.splice(oldIndex, 1);
57125 this.config.splice(newIndex, 0, c);
57126 this.dataMap = null;
57127 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57130 isLocked : function(colIndex){
57131 return this.config[colIndex].locked === true;
57134 setLocked : function(colIndex, value, suppressEvent){
57135 if(this.isLocked(colIndex) == value){
57138 this.config[colIndex].locked = value;
57139 if(!suppressEvent){
57140 this.fireEvent("columnlockchange", this, colIndex, value);
57144 getTotalLockedWidth : function(){
57145 var totalWidth = 0;
57146 for(var i = 0; i < this.config.length; i++){
57147 if(this.isLocked(i) && !this.isHidden(i)){
57148 this.totalWidth += this.getColumnWidth(i);
57154 getLockedCount : function(){
57155 for(var i = 0, len = this.config.length; i < len; i++){
57156 if(!this.isLocked(i)){
57161 return this.config.length;
57165 * Returns the number of columns.
57168 getColumnCount : function(visibleOnly){
57169 if(visibleOnly === true){
57171 for(var i = 0, len = this.config.length; i < len; i++){
57172 if(!this.isHidden(i)){
57178 return this.config.length;
57182 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57183 * @param {Function} fn
57184 * @param {Object} scope (optional)
57185 * @return {Array} result
57187 getColumnsBy : function(fn, scope){
57189 for(var i = 0, len = this.config.length; i < len; i++){
57190 var c = this.config[i];
57191 if(fn.call(scope||this, c, i) === true){
57199 * Returns true if the specified column is sortable.
57200 * @param {Number} col The column index
57201 * @return {Boolean}
57203 isSortable : function(col){
57204 if(typeof this.config[col].sortable == "undefined"){
57205 return this.defaultSortable;
57207 return this.config[col].sortable;
57211 * Returns the rendering (formatting) function defined for the column.
57212 * @param {Number} col The column index.
57213 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57215 getRenderer : function(col){
57216 if(!this.config[col].renderer){
57217 return Roo.grid.ColumnModel.defaultRenderer;
57219 return this.config[col].renderer;
57223 * Sets the rendering (formatting) function for a column.
57224 * @param {Number} col The column index
57225 * @param {Function} fn The function to use to process the cell's raw data
57226 * to return HTML markup for the grid view. The render function is called with
57227 * the following parameters:<ul>
57228 * <li>Data value.</li>
57229 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57230 * <li>css A CSS style string to apply to the table cell.</li>
57231 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57232 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57233 * <li>Row index</li>
57234 * <li>Column index</li>
57235 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57237 setRenderer : function(col, fn){
57238 this.config[col].renderer = fn;
57242 * Returns the width for the specified column.
57243 * @param {Number} col The column index
57246 getColumnWidth : function(col){
57247 return this.config[col].width * 1 || this.defaultWidth;
57251 * Sets the width for a column.
57252 * @param {Number} col The column index
57253 * @param {Number} width The new width
57255 setColumnWidth : function(col, width, suppressEvent){
57256 this.config[col].width = width;
57257 this.totalWidth = null;
57258 if(!suppressEvent){
57259 this.fireEvent("widthchange", this, col, width);
57264 * Returns the total width of all columns.
57265 * @param {Boolean} includeHidden True to include hidden column widths
57268 getTotalWidth : function(includeHidden){
57269 if(!this.totalWidth){
57270 this.totalWidth = 0;
57271 for(var i = 0, len = this.config.length; i < len; i++){
57272 if(includeHidden || !this.isHidden(i)){
57273 this.totalWidth += this.getColumnWidth(i);
57277 return this.totalWidth;
57281 * Returns the header for the specified column.
57282 * @param {Number} col The column index
57285 getColumnHeader : function(col){
57286 return this.config[col].header;
57290 * Sets the header for a column.
57291 * @param {Number} col The column index
57292 * @param {String} header The new header
57294 setColumnHeader : function(col, header){
57295 this.config[col].header = header;
57296 this.fireEvent("headerchange", this, col, header);
57300 * Returns the tooltip for the specified column.
57301 * @param {Number} col The column index
57304 getColumnTooltip : function(col){
57305 return this.config[col].tooltip;
57308 * Sets the tooltip for a column.
57309 * @param {Number} col The column index
57310 * @param {String} tooltip The new tooltip
57312 setColumnTooltip : function(col, tooltip){
57313 this.config[col].tooltip = tooltip;
57317 * Returns the dataIndex for the specified column.
57318 * @param {Number} col The column index
57321 getDataIndex : function(col){
57322 return this.config[col].dataIndex;
57326 * Sets the dataIndex for a column.
57327 * @param {Number} col The column index
57328 * @param {Number} dataIndex The new dataIndex
57330 setDataIndex : function(col, dataIndex){
57331 this.config[col].dataIndex = dataIndex;
57337 * Returns true if the cell is editable.
57338 * @param {Number} colIndex The column index
57339 * @param {Number} rowIndex The row index - this is nto actually used..?
57340 * @return {Boolean}
57342 isCellEditable : function(colIndex, rowIndex){
57343 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57347 * Returns the editor defined for the cell/column.
57348 * return false or null to disable editing.
57349 * @param {Number} colIndex The column index
57350 * @param {Number} rowIndex The row index
57353 getCellEditor : function(colIndex, rowIndex){
57354 return this.config[colIndex].editor;
57358 * Sets if a column is editable.
57359 * @param {Number} col The column index
57360 * @param {Boolean} editable True if the column is editable
57362 setEditable : function(col, editable){
57363 this.config[col].editable = editable;
57368 * Returns true if the column is hidden.
57369 * @param {Number} colIndex The column index
57370 * @return {Boolean}
57372 isHidden : function(colIndex){
57373 return this.config[colIndex].hidden;
57378 * Returns true if the column width cannot be changed
57380 isFixed : function(colIndex){
57381 return this.config[colIndex].fixed;
57385 * Returns true if the column can be resized
57386 * @return {Boolean}
57388 isResizable : function(colIndex){
57389 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57392 * Sets if a column is hidden.
57393 * @param {Number} colIndex The column index
57394 * @param {Boolean} hidden True if the column is hidden
57396 setHidden : function(colIndex, hidden){
57397 this.config[colIndex].hidden = hidden;
57398 this.totalWidth = null;
57399 this.fireEvent("hiddenchange", this, colIndex, hidden);
57403 * Sets the editor for a column.
57404 * @param {Number} col The column index
57405 * @param {Object} editor The editor object
57407 setEditor : function(col, editor){
57408 this.config[col].editor = editor;
57412 Roo.grid.ColumnModel.defaultRenderer = function(value)
57414 if(typeof value == "object") {
57417 if(typeof value == "string" && value.length < 1){
57421 return String.format("{0}", value);
57424 // Alias for backwards compatibility
57425 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57428 * Ext JS Library 1.1.1
57429 * Copyright(c) 2006-2007, Ext JS, LLC.
57431 * Originally Released Under LGPL - original licence link has changed is not relivant.
57434 * <script type="text/javascript">
57438 * @class Roo.grid.AbstractSelectionModel
57439 * @extends Roo.util.Observable
57440 * Abstract base class for grid SelectionModels. It provides the interface that should be
57441 * implemented by descendant classes. This class should not be directly instantiated.
57444 Roo.grid.AbstractSelectionModel = function(){
57445 this.locked = false;
57446 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57449 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57450 /** @ignore Called by the grid automatically. Do not call directly. */
57451 init : function(grid){
57457 * Locks the selections.
57460 this.locked = true;
57464 * Unlocks the selections.
57466 unlock : function(){
57467 this.locked = false;
57471 * Returns true if the selections are locked.
57472 * @return {Boolean}
57474 isLocked : function(){
57475 return this.locked;
57479 * Ext JS Library 1.1.1
57480 * Copyright(c) 2006-2007, Ext JS, LLC.
57482 * Originally Released Under LGPL - original licence link has changed is not relivant.
57485 * <script type="text/javascript">
57488 * @extends Roo.grid.AbstractSelectionModel
57489 * @class Roo.grid.RowSelectionModel
57490 * The default SelectionModel used by {@link Roo.grid.Grid}.
57491 * It supports multiple selections and keyboard selection/navigation.
57493 * @param {Object} config
57495 Roo.grid.RowSelectionModel = function(config){
57496 Roo.apply(this, config);
57497 this.selections = new Roo.util.MixedCollection(false, function(o){
57502 this.lastActive = false;
57506 * @event selectionchange
57507 * Fires when the selection changes
57508 * @param {SelectionModel} this
57510 "selectionchange" : true,
57512 * @event afterselectionchange
57513 * Fires after the selection changes (eg. by key press or clicking)
57514 * @param {SelectionModel} this
57516 "afterselectionchange" : true,
57518 * @event beforerowselect
57519 * Fires when a row is selected being selected, return false to cancel.
57520 * @param {SelectionModel} this
57521 * @param {Number} rowIndex The selected index
57522 * @param {Boolean} keepExisting False if other selections will be cleared
57524 "beforerowselect" : true,
57527 * Fires when a row is selected.
57528 * @param {SelectionModel} this
57529 * @param {Number} rowIndex The selected index
57530 * @param {Roo.data.Record} r The record
57532 "rowselect" : true,
57534 * @event rowdeselect
57535 * Fires when a row is deselected.
57536 * @param {SelectionModel} this
57537 * @param {Number} rowIndex The selected index
57539 "rowdeselect" : true
57541 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57542 this.locked = false;
57545 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57547 * @cfg {Boolean} singleSelect
57548 * True to allow selection of only one row at a time (defaults to false)
57550 singleSelect : false,
57553 initEvents : function(){
57555 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57556 this.grid.on("mousedown", this.handleMouseDown, this);
57557 }else{ // allow click to work like normal
57558 this.grid.on("rowclick", this.handleDragableRowClick, this);
57561 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57562 "up" : function(e){
57564 this.selectPrevious(e.shiftKey);
57565 }else if(this.last !== false && this.lastActive !== false){
57566 var last = this.last;
57567 this.selectRange(this.last, this.lastActive-1);
57568 this.grid.getView().focusRow(this.lastActive);
57569 if(last !== false){
57573 this.selectFirstRow();
57575 this.fireEvent("afterselectionchange", this);
57577 "down" : function(e){
57579 this.selectNext(e.shiftKey);
57580 }else if(this.last !== false && this.lastActive !== false){
57581 var last = this.last;
57582 this.selectRange(this.last, this.lastActive+1);
57583 this.grid.getView().focusRow(this.lastActive);
57584 if(last !== false){
57588 this.selectFirstRow();
57590 this.fireEvent("afterselectionchange", this);
57595 var view = this.grid.view;
57596 view.on("refresh", this.onRefresh, this);
57597 view.on("rowupdated", this.onRowUpdated, this);
57598 view.on("rowremoved", this.onRemove, this);
57602 onRefresh : function(){
57603 var ds = this.grid.dataSource, i, v = this.grid.view;
57604 var s = this.selections;
57605 s.each(function(r){
57606 if((i = ds.indexOfId(r.id)) != -1){
57608 s.add(ds.getAt(i)); // updating the selection relate data
57616 onRemove : function(v, index, r){
57617 this.selections.remove(r);
57621 onRowUpdated : function(v, index, r){
57622 if(this.isSelected(r)){
57623 v.onRowSelect(index);
57629 * @param {Array} records The records to select
57630 * @param {Boolean} keepExisting (optional) True to keep existing selections
57632 selectRecords : function(records, keepExisting){
57634 this.clearSelections();
57636 var ds = this.grid.dataSource;
57637 for(var i = 0, len = records.length; i < len; i++){
57638 this.selectRow(ds.indexOf(records[i]), true);
57643 * Gets the number of selected rows.
57646 getCount : function(){
57647 return this.selections.length;
57651 * Selects the first row in the grid.
57653 selectFirstRow : function(){
57658 * Select the last row.
57659 * @param {Boolean} keepExisting (optional) True to keep existing selections
57661 selectLastRow : function(keepExisting){
57662 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57666 * Selects the row immediately following the last selected row.
57667 * @param {Boolean} keepExisting (optional) True to keep existing selections
57669 selectNext : function(keepExisting){
57670 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57671 this.selectRow(this.last+1, keepExisting);
57672 this.grid.getView().focusRow(this.last);
57677 * Selects the row that precedes the last selected row.
57678 * @param {Boolean} keepExisting (optional) True to keep existing selections
57680 selectPrevious : function(keepExisting){
57682 this.selectRow(this.last-1, keepExisting);
57683 this.grid.getView().focusRow(this.last);
57688 * Returns the selected records
57689 * @return {Array} Array of selected records
57691 getSelections : function(){
57692 return [].concat(this.selections.items);
57696 * Returns the first selected record.
57699 getSelected : function(){
57700 return this.selections.itemAt(0);
57705 * Clears all selections.
57707 clearSelections : function(fast){
57712 var ds = this.grid.dataSource;
57713 var s = this.selections;
57714 s.each(function(r){
57715 this.deselectRow(ds.indexOfId(r.id));
57719 this.selections.clear();
57726 * Selects all rows.
57728 selectAll : function(){
57732 this.selections.clear();
57733 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57734 this.selectRow(i, true);
57739 * Returns True if there is a selection.
57740 * @return {Boolean}
57742 hasSelection : function(){
57743 return this.selections.length > 0;
57747 * Returns True if the specified row is selected.
57748 * @param {Number/Record} record The record or index of the record to check
57749 * @return {Boolean}
57751 isSelected : function(index){
57752 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57753 return (r && this.selections.key(r.id) ? true : false);
57757 * Returns True if the specified record id is selected.
57758 * @param {String} id The id of record to check
57759 * @return {Boolean}
57761 isIdSelected : function(id){
57762 return (this.selections.key(id) ? true : false);
57766 handleMouseDown : function(e, t){
57767 var view = this.grid.getView(), rowIndex;
57768 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57771 if(e.shiftKey && this.last !== false){
57772 var last = this.last;
57773 this.selectRange(last, rowIndex, e.ctrlKey);
57774 this.last = last; // reset the last
57775 view.focusRow(rowIndex);
57777 var isSelected = this.isSelected(rowIndex);
57778 if(e.button !== 0 && isSelected){
57779 view.focusRow(rowIndex);
57780 }else if(e.ctrlKey && isSelected){
57781 this.deselectRow(rowIndex);
57782 }else if(!isSelected){
57783 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57784 view.focusRow(rowIndex);
57787 this.fireEvent("afterselectionchange", this);
57790 handleDragableRowClick : function(grid, rowIndex, e)
57792 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57793 this.selectRow(rowIndex, false);
57794 grid.view.focusRow(rowIndex);
57795 this.fireEvent("afterselectionchange", this);
57800 * Selects multiple rows.
57801 * @param {Array} rows Array of the indexes of the row to select
57802 * @param {Boolean} keepExisting (optional) True to keep existing selections
57804 selectRows : function(rows, keepExisting){
57806 this.clearSelections();
57808 for(var i = 0, len = rows.length; i < len; i++){
57809 this.selectRow(rows[i], true);
57814 * Selects a range of rows. All rows in between startRow and endRow are also selected.
57815 * @param {Number} startRow The index of the first row in the range
57816 * @param {Number} endRow The index of the last row in the range
57817 * @param {Boolean} keepExisting (optional) True to retain existing selections
57819 selectRange : function(startRow, endRow, keepExisting){
57824 this.clearSelections();
57826 if(startRow <= endRow){
57827 for(var i = startRow; i <= endRow; i++){
57828 this.selectRow(i, true);
57831 for(var i = startRow; i >= endRow; i--){
57832 this.selectRow(i, true);
57838 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57839 * @param {Number} startRow The index of the first row in the range
57840 * @param {Number} endRow The index of the last row in the range
57842 deselectRange : function(startRow, endRow, preventViewNotify){
57846 for(var i = startRow; i <= endRow; i++){
57847 this.deselectRow(i, preventViewNotify);
57853 * @param {Number} row The index of the row to select
57854 * @param {Boolean} keepExisting (optional) True to keep existing selections
57856 selectRow : function(index, keepExisting, preventViewNotify){
57857 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
57860 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
57861 if(!keepExisting || this.singleSelect){
57862 this.clearSelections();
57864 var r = this.grid.dataSource.getAt(index);
57865 this.selections.add(r);
57866 this.last = this.lastActive = index;
57867 if(!preventViewNotify){
57868 this.grid.getView().onRowSelect(index);
57870 this.fireEvent("rowselect", this, index, r);
57871 this.fireEvent("selectionchange", this);
57877 * @param {Number} row The index of the row to deselect
57879 deselectRow : function(index, preventViewNotify){
57883 if(this.last == index){
57886 if(this.lastActive == index){
57887 this.lastActive = false;
57889 var r = this.grid.dataSource.getAt(index);
57890 this.selections.remove(r);
57891 if(!preventViewNotify){
57892 this.grid.getView().onRowDeselect(index);
57894 this.fireEvent("rowdeselect", this, index);
57895 this.fireEvent("selectionchange", this);
57899 restoreLast : function(){
57901 this.last = this._last;
57906 acceptsNav : function(row, col, cm){
57907 return !cm.isHidden(col) && cm.isCellEditable(col, row);
57911 onEditorKey : function(field, e){
57912 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
57917 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
57919 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
57921 }else if(k == e.ENTER && !e.ctrlKey){
57925 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
57927 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
57929 }else if(k == e.ESC){
57933 g.startEditing(newCell[0], newCell[1]);
57938 * Ext JS Library 1.1.1
57939 * Copyright(c) 2006-2007, Ext JS, LLC.
57941 * Originally Released Under LGPL - original licence link has changed is not relivant.
57944 * <script type="text/javascript">
57947 * @class Roo.grid.CellSelectionModel
57948 * @extends Roo.grid.AbstractSelectionModel
57949 * This class provides the basic implementation for cell selection in a grid.
57951 * @param {Object} config The object containing the configuration of this model.
57952 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
57954 Roo.grid.CellSelectionModel = function(config){
57955 Roo.apply(this, config);
57957 this.selection = null;
57961 * @event beforerowselect
57962 * Fires before a cell is selected.
57963 * @param {SelectionModel} this
57964 * @param {Number} rowIndex The selected row index
57965 * @param {Number} colIndex The selected cell index
57967 "beforecellselect" : true,
57969 * @event cellselect
57970 * Fires when a cell is selected.
57971 * @param {SelectionModel} this
57972 * @param {Number} rowIndex The selected row index
57973 * @param {Number} colIndex The selected cell index
57975 "cellselect" : true,
57977 * @event selectionchange
57978 * Fires when the active selection changes.
57979 * @param {SelectionModel} this
57980 * @param {Object} selection null for no selection or an object (o) with two properties
57982 <li>o.record: the record object for the row the selection is in</li>
57983 <li>o.cell: An array of [rowIndex, columnIndex]</li>
57986 "selectionchange" : true,
57989 * Fires when the tab (or enter) was pressed on the last editable cell
57990 * You can use this to trigger add new row.
57991 * @param {SelectionModel} this
57995 * @event beforeeditnext
57996 * Fires before the next editable sell is made active
57997 * You can use this to skip to another cell or fire the tabend
57998 * if you set cell to false
57999 * @param {Object} eventdata object : { cell : [ row, col ] }
58001 "beforeeditnext" : true
58003 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58006 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58008 enter_is_tab: false,
58011 initEvents : function(){
58012 this.grid.on("mousedown", this.handleMouseDown, this);
58013 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58014 var view = this.grid.view;
58015 view.on("refresh", this.onViewChange, this);
58016 view.on("rowupdated", this.onRowUpdated, this);
58017 view.on("beforerowremoved", this.clearSelections, this);
58018 view.on("beforerowsinserted", this.clearSelections, this);
58019 if(this.grid.isEditor){
58020 this.grid.on("beforeedit", this.beforeEdit, this);
58025 beforeEdit : function(e){
58026 this.select(e.row, e.column, false, true, e.record);
58030 onRowUpdated : function(v, index, r){
58031 if(this.selection && this.selection.record == r){
58032 v.onCellSelect(index, this.selection.cell[1]);
58037 onViewChange : function(){
58038 this.clearSelections(true);
58042 * Returns the currently selected cell,.
58043 * @return {Array} The selected cell (row, column) or null if none selected.
58045 getSelectedCell : function(){
58046 return this.selection ? this.selection.cell : null;
58050 * Clears all selections.
58051 * @param {Boolean} true to prevent the gridview from being notified about the change.
58053 clearSelections : function(preventNotify){
58054 var s = this.selection;
58056 if(preventNotify !== true){
58057 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58059 this.selection = null;
58060 this.fireEvent("selectionchange", this, null);
58065 * Returns true if there is a selection.
58066 * @return {Boolean}
58068 hasSelection : function(){
58069 return this.selection ? true : false;
58073 handleMouseDown : function(e, t){
58074 var v = this.grid.getView();
58075 if(this.isLocked()){
58078 var row = v.findRowIndex(t);
58079 var cell = v.findCellIndex(t);
58080 if(row !== false && cell !== false){
58081 this.select(row, cell);
58087 * @param {Number} rowIndex
58088 * @param {Number} collIndex
58090 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58091 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58092 this.clearSelections();
58093 r = r || this.grid.dataSource.getAt(rowIndex);
58096 cell : [rowIndex, colIndex]
58098 if(!preventViewNotify){
58099 var v = this.grid.getView();
58100 v.onCellSelect(rowIndex, colIndex);
58101 if(preventFocus !== true){
58102 v.focusCell(rowIndex, colIndex);
58105 this.fireEvent("cellselect", this, rowIndex, colIndex);
58106 this.fireEvent("selectionchange", this, this.selection);
58111 isSelectable : function(rowIndex, colIndex, cm){
58112 return !cm.isHidden(colIndex);
58116 handleKeyDown : function(e){
58117 //Roo.log('Cell Sel Model handleKeyDown');
58118 if(!e.isNavKeyPress()){
58121 var g = this.grid, s = this.selection;
58124 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58126 this.select(cell[0], cell[1]);
58131 var walk = function(row, col, step){
58132 return g.walkCells(row, col, step, sm.isSelectable, sm);
58134 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58141 // handled by onEditorKey
58142 if (g.isEditor && g.editing) {
58146 newCell = walk(r, c-1, -1);
58148 newCell = walk(r, c+1, 1);
58153 newCell = walk(r+1, c, 1);
58157 newCell = walk(r-1, c, -1);
58161 newCell = walk(r, c+1, 1);
58165 newCell = walk(r, c-1, -1);
58170 if(g.isEditor && !g.editing){
58171 g.startEditing(r, c);
58180 this.select(newCell[0], newCell[1]);
58186 acceptsNav : function(row, col, cm){
58187 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58191 * @param {Number} field (not used) - as it's normally used as a listener
58192 * @param {Number} e - event - fake it by using
58194 * var e = Roo.EventObjectImpl.prototype;
58195 * e.keyCode = e.TAB
58199 onEditorKey : function(field, e){
58201 var k = e.getKey(),
58204 ed = g.activeEditor,
58206 ///Roo.log('onEditorKey' + k);
58209 if (this.enter_is_tab && k == e.ENTER) {
58215 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58217 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58223 } else if(k == e.ENTER && !e.ctrlKey){
58226 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58228 } else if(k == e.ESC){
58233 var ecall = { cell : newCell, forward : forward };
58234 this.fireEvent('beforeeditnext', ecall );
58235 newCell = ecall.cell;
58236 forward = ecall.forward;
58240 //Roo.log('next cell after edit');
58241 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58242 } else if (forward) {
58243 // tabbed past last
58244 this.fireEvent.defer(100, this, ['tabend',this]);
58249 * Ext JS Library 1.1.1
58250 * Copyright(c) 2006-2007, Ext JS, LLC.
58252 * Originally Released Under LGPL - original licence link has changed is not relivant.
58255 * <script type="text/javascript">
58259 * @class Roo.grid.EditorGrid
58260 * @extends Roo.grid.Grid
58261 * Class for creating and editable grid.
58262 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58263 * The container MUST have some type of size defined for the grid to fill. The container will be
58264 * automatically set to position relative if it isn't already.
58265 * @param {Object} dataSource The data model to bind to
58266 * @param {Object} colModel The column model with info about this grid's columns
58268 Roo.grid.EditorGrid = function(container, config){
58269 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58270 this.getGridEl().addClass("xedit-grid");
58272 if(!this.selModel){
58273 this.selModel = new Roo.grid.CellSelectionModel();
58276 this.activeEditor = null;
58280 * @event beforeedit
58281 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58282 * <ul style="padding:5px;padding-left:16px;">
58283 * <li>grid - This grid</li>
58284 * <li>record - The record being edited</li>
58285 * <li>field - The field name being edited</li>
58286 * <li>value - The value for the field being edited.</li>
58287 * <li>row - The grid row index</li>
58288 * <li>column - The grid column index</li>
58289 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58291 * @param {Object} e An edit event (see above for description)
58293 "beforeedit" : true,
58296 * Fires after a cell is edited. <br />
58297 * <ul style="padding:5px;padding-left:16px;">
58298 * <li>grid - This grid</li>
58299 * <li>record - The record being edited</li>
58300 * <li>field - The field name being edited</li>
58301 * <li>value - The value being set</li>
58302 * <li>originalValue - The original value for the field, before the edit.</li>
58303 * <li>row - The grid row index</li>
58304 * <li>column - The grid column index</li>
58306 * @param {Object} e An edit event (see above for description)
58308 "afteredit" : true,
58310 * @event validateedit
58311 * Fires after a cell is edited, but before the value is set in the record.
58312 * You can use this to modify the value being set in the field, Return false
58313 * to cancel the change. The edit event object has the following properties <br />
58314 * <ul style="padding:5px;padding-left:16px;">
58315 * <li>editor - This editor</li>
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>
58323 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58325 * @param {Object} e An edit event (see above for description)
58327 "validateedit" : true
58329 this.on("bodyscroll", this.stopEditing, this);
58330 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58333 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58335 * @cfg {Number} clicksToEdit
58336 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58343 trackMouseOver: false, // causes very odd FF errors
58345 onCellDblClick : function(g, row, col){
58346 this.startEditing(row, col);
58349 onEditComplete : function(ed, value, startValue){
58350 this.editing = false;
58351 this.activeEditor = null;
58352 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58354 var field = this.colModel.getDataIndex(ed.col);
58359 originalValue: startValue,
58366 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58369 if(String(value) !== String(startValue)){
58371 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58372 r.set(field, e.value);
58373 // if we are dealing with a combo box..
58374 // then we also set the 'name' colum to be the displayField
58375 if (ed.field.displayField && ed.field.name) {
58376 r.set(ed.field.name, ed.field.el.dom.value);
58379 delete e.cancel; //?? why!!!
58380 this.fireEvent("afteredit", e);
58383 this.fireEvent("afteredit", e); // always fire it!
58385 this.view.focusCell(ed.row, ed.col);
58389 * Starts editing the specified for the specified row/column
58390 * @param {Number} rowIndex
58391 * @param {Number} colIndex
58393 startEditing : function(row, col){
58394 this.stopEditing();
58395 if(this.colModel.isCellEditable(col, row)){
58396 this.view.ensureVisible(row, col, true);
58398 var r = this.dataSource.getAt(row);
58399 var field = this.colModel.getDataIndex(col);
58400 var cell = Roo.get(this.view.getCell(row,col));
58405 value: r.data[field],
58410 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58411 this.editing = true;
58412 var ed = this.colModel.getCellEditor(col, row);
58418 ed.render(ed.parentEl || document.body);
58424 (function(){ // complex but required for focus issues in safari, ie and opera
58428 ed.on("complete", this.onEditComplete, this, {single: true});
58429 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58430 this.activeEditor = ed;
58431 var v = r.data[field];
58432 ed.startEdit(this.view.getCell(row, col), v);
58433 // combo's with 'displayField and name set
58434 if (ed.field.displayField && ed.field.name) {
58435 ed.field.el.dom.value = r.data[ed.field.name];
58439 }).defer(50, this);
58445 * Stops any active editing
58447 stopEditing : function(){
58448 if(this.activeEditor){
58449 this.activeEditor.completeEdit();
58451 this.activeEditor = null;
58455 * Called to get grid's drag proxy text, by default returns this.ddText.
58458 getDragDropText : function(){
58459 var count = this.selModel.getSelectedCell() ? 1 : 0;
58460 return String.format(this.ddText, count, count == 1 ? '' : 's');
58465 * Ext JS Library 1.1.1
58466 * Copyright(c) 2006-2007, Ext JS, LLC.
58468 * Originally Released Under LGPL - original licence link has changed is not relivant.
58471 * <script type="text/javascript">
58474 // private - not really -- you end up using it !
58475 // This is a support class used internally by the Grid components
58478 * @class Roo.grid.GridEditor
58479 * @extends Roo.Editor
58480 * Class for creating and editable grid elements.
58481 * @param {Object} config any settings (must include field)
58483 Roo.grid.GridEditor = function(field, config){
58484 if (!config && field.field) {
58486 field = Roo.factory(config.field, Roo.form);
58488 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58489 field.monitorTab = false;
58492 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58495 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58498 alignment: "tl-tl",
58501 cls: "x-small-editor x-grid-editor",
58506 * Ext JS Library 1.1.1
58507 * Copyright(c) 2006-2007, Ext JS, LLC.
58509 * Originally Released Under LGPL - original licence link has changed is not relivant.
58512 * <script type="text/javascript">
58517 Roo.grid.PropertyRecord = Roo.data.Record.create([
58518 {name:'name',type:'string'}, 'value'
58522 Roo.grid.PropertyStore = function(grid, source){
58524 this.store = new Roo.data.Store({
58525 recordType : Roo.grid.PropertyRecord
58527 this.store.on('update', this.onUpdate, this);
58529 this.setSource(source);
58531 Roo.grid.PropertyStore.superclass.constructor.call(this);
58536 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58537 setSource : function(o){
58539 this.store.removeAll();
58542 if(this.isEditableValue(o[k])){
58543 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58546 this.store.loadRecords({records: data}, {}, true);
58549 onUpdate : function(ds, record, type){
58550 if(type == Roo.data.Record.EDIT){
58551 var v = record.data['value'];
58552 var oldValue = record.modified['value'];
58553 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58554 this.source[record.id] = v;
58556 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58563 getProperty : function(row){
58564 return this.store.getAt(row);
58567 isEditableValue: function(val){
58568 if(val && val instanceof Date){
58570 }else if(typeof val == 'object' || typeof val == 'function'){
58576 setValue : function(prop, value){
58577 this.source[prop] = value;
58578 this.store.getById(prop).set('value', value);
58581 getSource : function(){
58582 return this.source;
58586 Roo.grid.PropertyColumnModel = function(grid, store){
58589 g.PropertyColumnModel.superclass.constructor.call(this, [
58590 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58591 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58593 this.store = store;
58594 this.bselect = Roo.DomHelper.append(document.body, {
58595 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58596 {tag: 'option', value: 'true', html: 'true'},
58597 {tag: 'option', value: 'false', html: 'false'}
58600 Roo.id(this.bselect);
58603 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58604 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58605 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58606 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58607 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58609 this.renderCellDelegate = this.renderCell.createDelegate(this);
58610 this.renderPropDelegate = this.renderProp.createDelegate(this);
58613 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58617 valueText : 'Value',
58619 dateFormat : 'm/j/Y',
58622 renderDate : function(dateVal){
58623 return dateVal.dateFormat(this.dateFormat);
58626 renderBool : function(bVal){
58627 return bVal ? 'true' : 'false';
58630 isCellEditable : function(colIndex, rowIndex){
58631 return colIndex == 1;
58634 getRenderer : function(col){
58636 this.renderCellDelegate : this.renderPropDelegate;
58639 renderProp : function(v){
58640 return this.getPropertyName(v);
58643 renderCell : function(val){
58645 if(val instanceof Date){
58646 rv = this.renderDate(val);
58647 }else if(typeof val == 'boolean'){
58648 rv = this.renderBool(val);
58650 return Roo.util.Format.htmlEncode(rv);
58653 getPropertyName : function(name){
58654 var pn = this.grid.propertyNames;
58655 return pn && pn[name] ? pn[name] : name;
58658 getCellEditor : function(colIndex, rowIndex){
58659 var p = this.store.getProperty(rowIndex);
58660 var n = p.data['name'], val = p.data['value'];
58662 if(typeof(this.grid.customEditors[n]) == 'string'){
58663 return this.editors[this.grid.customEditors[n]];
58665 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58666 return this.grid.customEditors[n];
58668 if(val instanceof Date){
58669 return this.editors['date'];
58670 }else if(typeof val == 'number'){
58671 return this.editors['number'];
58672 }else if(typeof val == 'boolean'){
58673 return this.editors['boolean'];
58675 return this.editors['string'];
58681 * @class Roo.grid.PropertyGrid
58682 * @extends Roo.grid.EditorGrid
58683 * This class represents the interface of a component based property grid control.
58684 * <br><br>Usage:<pre><code>
58685 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58693 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58694 * The container MUST have some type of size defined for the grid to fill. The container will be
58695 * automatically set to position relative if it isn't already.
58696 * @param {Object} config A config object that sets properties on this grid.
58698 Roo.grid.PropertyGrid = function(container, config){
58699 config = config || {};
58700 var store = new Roo.grid.PropertyStore(this);
58701 this.store = store;
58702 var cm = new Roo.grid.PropertyColumnModel(this, store);
58703 store.store.sort('name', 'ASC');
58704 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58707 enableColLock:false,
58708 enableColumnMove:false,
58710 trackMouseOver: false,
58713 this.getGridEl().addClass('x-props-grid');
58714 this.lastEditRow = null;
58715 this.on('columnresize', this.onColumnResize, this);
58718 * @event beforepropertychange
58719 * Fires before a property changes (return false to stop?)
58720 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58721 * @param {String} id Record Id
58722 * @param {String} newval New Value
58723 * @param {String} oldval Old Value
58725 "beforepropertychange": true,
58727 * @event propertychange
58728 * Fires after a property changes
58729 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58730 * @param {String} id Record Id
58731 * @param {String} newval New Value
58732 * @param {String} oldval Old Value
58734 "propertychange": true
58736 this.customEditors = this.customEditors || {};
58738 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58741 * @cfg {Object} customEditors map of colnames=> custom editors.
58742 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58743 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58744 * false disables editing of the field.
58748 * @cfg {Object} propertyNames map of property Names to their displayed value
58751 render : function(){
58752 Roo.grid.PropertyGrid.superclass.render.call(this);
58753 this.autoSize.defer(100, this);
58756 autoSize : function(){
58757 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58759 this.view.fitColumns();
58763 onColumnResize : function(){
58764 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58768 * Sets the data for the Grid
58769 * accepts a Key => Value object of all the elements avaiable.
58770 * @param {Object} data to appear in grid.
58772 setSource : function(source){
58773 this.store.setSource(source);
58777 * Gets all the data from the grid.
58778 * @return {Object} data data stored in grid
58780 getSource : function(){
58781 return this.store.getSource();
58790 * @class Roo.grid.Calendar
58791 * @extends Roo.util.Grid
58792 * This class extends the Grid to provide a calendar widget
58793 * <br><br>Usage:<pre><code>
58794 var grid = new Roo.grid.Calendar("my-container-id", {
58797 selModel: mySelectionModel,
58798 autoSizeColumns: true,
58799 monitorWindowResize: false,
58800 trackMouseOver: true
58801 eventstore : real data store..
58807 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58808 * The container MUST have some type of size defined for the grid to fill. The container will be
58809 * automatically set to position relative if it isn't already.
58810 * @param {Object} config A config object that sets properties on this grid.
58812 Roo.grid.Calendar = function(container, config){
58813 // initialize the container
58814 this.container = Roo.get(container);
58815 this.container.update("");
58816 this.container.setStyle("overflow", "hidden");
58817 this.container.addClass('x-grid-container');
58819 this.id = this.container.id;
58821 Roo.apply(this, config);
58822 // check and correct shorthanded configs
58826 for (var r = 0;r < 6;r++) {
58829 for (var c =0;c < 7;c++) {
58833 if (this.eventStore) {
58834 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58835 this.eventStore.on('load',this.onLoad, this);
58836 this.eventStore.on('beforeload',this.clearEvents, this);
58840 this.dataSource = new Roo.data.Store({
58841 proxy: new Roo.data.MemoryProxy(rows),
58842 reader: new Roo.data.ArrayReader({}, [
58843 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58846 this.dataSource.load();
58847 this.ds = this.dataSource;
58848 this.ds.xmodule = this.xmodule || false;
58851 var cellRender = function(v,x,r)
58853 return String.format(
58854 '<div class="fc-day fc-widget-content"><div>' +
58855 '<div class="fc-event-container"></div>' +
58856 '<div class="fc-day-number">{0}</div>'+
58858 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
58859 '</div></div>', v);
58864 this.colModel = new Roo.grid.ColumnModel( [
58866 xtype: 'ColumnModel',
58868 dataIndex : 'weekday0',
58870 renderer : cellRender
58873 xtype: 'ColumnModel',
58875 dataIndex : 'weekday1',
58877 renderer : cellRender
58880 xtype: 'ColumnModel',
58882 dataIndex : 'weekday2',
58883 header : 'Tuesday',
58884 renderer : cellRender
58887 xtype: 'ColumnModel',
58889 dataIndex : 'weekday3',
58890 header : 'Wednesday',
58891 renderer : cellRender
58894 xtype: 'ColumnModel',
58896 dataIndex : 'weekday4',
58897 header : 'Thursday',
58898 renderer : cellRender
58901 xtype: 'ColumnModel',
58903 dataIndex : 'weekday5',
58905 renderer : cellRender
58908 xtype: 'ColumnModel',
58910 dataIndex : 'weekday6',
58911 header : 'Saturday',
58912 renderer : cellRender
58915 this.cm = this.colModel;
58916 this.cm.xmodule = this.xmodule || false;
58920 //this.selModel = new Roo.grid.CellSelectionModel();
58921 //this.sm = this.selModel;
58922 //this.selModel.init(this);
58926 this.container.setWidth(this.width);
58930 this.container.setHeight(this.height);
58937 * The raw click event for the entire grid.
58938 * @param {Roo.EventObject} e
58943 * The raw dblclick event for the entire grid.
58944 * @param {Roo.EventObject} e
58948 * @event contextmenu
58949 * The raw contextmenu event for the entire grid.
58950 * @param {Roo.EventObject} e
58952 "contextmenu" : true,
58955 * The raw mousedown event for the entire grid.
58956 * @param {Roo.EventObject} e
58958 "mousedown" : true,
58961 * The raw mouseup event for the entire grid.
58962 * @param {Roo.EventObject} e
58967 * The raw mouseover event for the entire grid.
58968 * @param {Roo.EventObject} e
58970 "mouseover" : true,
58973 * The raw mouseout event for the entire grid.
58974 * @param {Roo.EventObject} e
58979 * The raw keypress event for the entire grid.
58980 * @param {Roo.EventObject} e
58985 * The raw keydown event for the entire grid.
58986 * @param {Roo.EventObject} e
58994 * Fires when a cell is clicked
58995 * @param {Grid} this
58996 * @param {Number} rowIndex
58997 * @param {Number} columnIndex
58998 * @param {Roo.EventObject} e
59000 "cellclick" : true,
59002 * @event celldblclick
59003 * Fires when a cell is double clicked
59004 * @param {Grid} this
59005 * @param {Number} rowIndex
59006 * @param {Number} columnIndex
59007 * @param {Roo.EventObject} e
59009 "celldblclick" : true,
59012 * Fires when a row is clicked
59013 * @param {Grid} this
59014 * @param {Number} rowIndex
59015 * @param {Roo.EventObject} e
59019 * @event rowdblclick
59020 * Fires when a row is double clicked
59021 * @param {Grid} this
59022 * @param {Number} rowIndex
59023 * @param {Roo.EventObject} e
59025 "rowdblclick" : true,
59027 * @event headerclick
59028 * Fires when a header is clicked
59029 * @param {Grid} this
59030 * @param {Number} columnIndex
59031 * @param {Roo.EventObject} e
59033 "headerclick" : true,
59035 * @event headerdblclick
59036 * Fires when a header cell is double clicked
59037 * @param {Grid} this
59038 * @param {Number} columnIndex
59039 * @param {Roo.EventObject} e
59041 "headerdblclick" : true,
59043 * @event rowcontextmenu
59044 * Fires when a row is right clicked
59045 * @param {Grid} this
59046 * @param {Number} rowIndex
59047 * @param {Roo.EventObject} e
59049 "rowcontextmenu" : true,
59051 * @event cellcontextmenu
59052 * Fires when a cell is right clicked
59053 * @param {Grid} this
59054 * @param {Number} rowIndex
59055 * @param {Number} cellIndex
59056 * @param {Roo.EventObject} e
59058 "cellcontextmenu" : true,
59060 * @event headercontextmenu
59061 * Fires when a header is right clicked
59062 * @param {Grid} this
59063 * @param {Number} columnIndex
59064 * @param {Roo.EventObject} e
59066 "headercontextmenu" : true,
59068 * @event bodyscroll
59069 * Fires when the body element is scrolled
59070 * @param {Number} scrollLeft
59071 * @param {Number} scrollTop
59073 "bodyscroll" : true,
59075 * @event columnresize
59076 * Fires when the user resizes a column
59077 * @param {Number} columnIndex
59078 * @param {Number} newSize
59080 "columnresize" : true,
59082 * @event columnmove
59083 * Fires when the user moves a column
59084 * @param {Number} oldIndex
59085 * @param {Number} newIndex
59087 "columnmove" : true,
59090 * Fires when row(s) start being dragged
59091 * @param {Grid} this
59092 * @param {Roo.GridDD} dd The drag drop object
59093 * @param {event} e The raw browser event
59095 "startdrag" : true,
59098 * Fires when a drag operation is complete
59099 * @param {Grid} this
59100 * @param {Roo.GridDD} dd The drag drop object
59101 * @param {event} e The raw browser event
59106 * Fires when dragged row(s) are dropped on a valid DD target
59107 * @param {Grid} this
59108 * @param {Roo.GridDD} dd The drag drop object
59109 * @param {String} targetId The target drag drop object
59110 * @param {event} e The raw browser event
59115 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59116 * @param {Grid} this
59117 * @param {Roo.GridDD} dd The drag drop object
59118 * @param {String} targetId The target drag drop object
59119 * @param {event} e The raw browser event
59124 * Fires when the dragged row(s) first cross another DD target while being dragged
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
59130 "dragenter" : true,
59133 * Fires when the dragged row(s) leave another DD target while being dragged
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 a row is rendered, so you can change add a style to it.
59143 * @param {GridView} gridview The grid view
59144 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59150 * Fires when the grid is rendered
59151 * @param {Grid} grid
59156 * Fires when a date is selected
59157 * @param {DatePicker} this
59158 * @param {Date} date The selected date
59162 * @event monthchange
59163 * Fires when the displayed month changes
59164 * @param {DatePicker} this
59165 * @param {Date} date The selected month
59167 'monthchange': true,
59169 * @event evententer
59170 * Fires when mouse over an event
59171 * @param {Calendar} this
59172 * @param {event} Event
59174 'evententer': true,
59176 * @event eventleave
59177 * Fires when the mouse leaves an
59178 * @param {Calendar} this
59181 'eventleave': true,
59183 * @event eventclick
59184 * Fires when the mouse click an
59185 * @param {Calendar} this
59188 'eventclick': true,
59190 * @event eventrender
59191 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59192 * @param {Calendar} this
59193 * @param {data} data to be modified
59195 'eventrender': true
59199 Roo.grid.Grid.superclass.constructor.call(this);
59200 this.on('render', function() {
59201 this.view.el.addClass('x-grid-cal');
59203 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59207 if (!Roo.grid.Calendar.style) {
59208 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59211 '.x-grid-cal .x-grid-col' : {
59212 height: 'auto !important',
59213 'vertical-align': 'top'
59215 '.x-grid-cal .fc-event-hori' : {
59226 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59228 * @cfg {Store} eventStore The store that loads events.
59233 activeDate : false,
59236 monitorWindowResize : false,
59239 resizeColumns : function() {
59240 var col = (this.view.el.getWidth() / 7) - 3;
59241 // loop through cols, and setWidth
59242 for(var i =0 ; i < 7 ; i++){
59243 this.cm.setColumnWidth(i, col);
59246 setDate :function(date) {
59248 Roo.log('setDate?');
59250 this.resizeColumns();
59251 var vd = this.activeDate;
59252 this.activeDate = date;
59253 // if(vd && this.el){
59254 // var t = date.getTime();
59255 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59256 // Roo.log('using add remove');
59258 // this.fireEvent('monthchange', this, date);
59260 // this.cells.removeClass("fc-state-highlight");
59261 // this.cells.each(function(c){
59262 // if(c.dateValue == t){
59263 // c.addClass("fc-state-highlight");
59264 // setTimeout(function(){
59265 // try{c.dom.firstChild.focus();}catch(e){}
59275 var days = date.getDaysInMonth();
59277 var firstOfMonth = date.getFirstDateOfMonth();
59278 var startingPos = firstOfMonth.getDay()-this.startDay;
59280 if(startingPos < this.startDay){
59284 var pm = date.add(Date.MONTH, -1);
59285 var prevStart = pm.getDaysInMonth()-startingPos;
59289 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59291 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59292 //this.cells.addClassOnOver('fc-state-hover');
59294 var cells = this.cells.elements;
59295 var textEls = this.textNodes;
59297 //Roo.each(cells, function(cell){
59298 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59301 days += startingPos;
59303 // convert everything to numbers so it's fast
59304 var day = 86400000;
59305 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59308 //Roo.log(prevStart);
59310 var today = new Date().clearTime().getTime();
59311 var sel = date.clearTime().getTime();
59312 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59313 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59314 var ddMatch = this.disabledDatesRE;
59315 var ddText = this.disabledDatesText;
59316 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59317 var ddaysText = this.disabledDaysText;
59318 var format = this.format;
59320 var setCellClass = function(cal, cell){
59322 //Roo.log('set Cell Class');
59324 var t = d.getTime();
59329 cell.dateValue = t;
59331 cell.className += " fc-today";
59332 cell.className += " fc-state-highlight";
59333 cell.title = cal.todayText;
59336 // disable highlight in other month..
59337 cell.className += " fc-state-highlight";
59342 //cell.className = " fc-state-disabled";
59343 cell.title = cal.minText;
59347 //cell.className = " fc-state-disabled";
59348 cell.title = cal.maxText;
59352 if(ddays.indexOf(d.getDay()) != -1){
59353 // cell.title = ddaysText;
59354 // cell.className = " fc-state-disabled";
59357 if(ddMatch && format){
59358 var fvalue = d.dateFormat(format);
59359 if(ddMatch.test(fvalue)){
59360 cell.title = ddText.replace("%0", fvalue);
59361 cell.className = " fc-state-disabled";
59365 if (!cell.initialClassName) {
59366 cell.initialClassName = cell.dom.className;
59369 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59374 for(; i < startingPos; i++) {
59375 cells[i].dayName = (++prevStart);
59376 Roo.log(textEls[i]);
59377 d.setDate(d.getDate()+1);
59379 //cells[i].className = "fc-past fc-other-month";
59380 setCellClass(this, cells[i]);
59385 for(; i < days; i++){
59386 intDay = i - startingPos + 1;
59387 cells[i].dayName = (intDay);
59388 d.setDate(d.getDate()+1);
59390 cells[i].className = ''; // "x-date-active";
59391 setCellClass(this, cells[i]);
59395 for(; i < 42; i++) {
59396 //textEls[i].innerHTML = (++extraDays);
59398 d.setDate(d.getDate()+1);
59399 cells[i].dayName = (++extraDays);
59400 cells[i].className = "fc-future fc-other-month";
59401 setCellClass(this, cells[i]);
59404 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59406 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59408 // this will cause all the cells to mis
59411 for (var r = 0;r < 6;r++) {
59412 for (var c =0;c < 7;c++) {
59413 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59417 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59418 for(i=0;i<cells.length;i++) {
59420 this.cells.elements[i].dayName = cells[i].dayName ;
59421 this.cells.elements[i].className = cells[i].className;
59422 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59423 this.cells.elements[i].title = cells[i].title ;
59424 this.cells.elements[i].dateValue = cells[i].dateValue ;
59430 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59431 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59433 ////if(totalRows != 6){
59434 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59435 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59438 this.fireEvent('monthchange', this, date);
59443 * Returns the grid's SelectionModel.
59444 * @return {SelectionModel}
59446 getSelectionModel : function(){
59447 if(!this.selModel){
59448 this.selModel = new Roo.grid.CellSelectionModel();
59450 return this.selModel;
59454 this.eventStore.load()
59460 findCell : function(dt) {
59461 dt = dt.clearTime().getTime();
59463 this.cells.each(function(c){
59464 //Roo.log("check " +c.dateValue + '?=' + dt);
59465 if(c.dateValue == dt){
59475 findCells : function(rec) {
59476 var s = rec.data.start_dt.clone().clearTime().getTime();
59478 var e= rec.data.end_dt.clone().clearTime().getTime();
59481 this.cells.each(function(c){
59482 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59484 if(c.dateValue > e){
59487 if(c.dateValue < s){
59496 findBestRow: function(cells)
59500 for (var i =0 ; i < cells.length;i++) {
59501 ret = Math.max(cells[i].rows || 0,ret);
59508 addItem : function(rec)
59510 // look for vertical location slot in
59511 var cells = this.findCells(rec);
59513 rec.row = this.findBestRow(cells);
59515 // work out the location.
59519 for(var i =0; i < cells.length; i++) {
59527 if (crow.start.getY() == cells[i].getY()) {
59529 crow.end = cells[i];
59545 for (var i = 0; i < cells.length;i++) {
59546 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59553 clearEvents: function() {
59555 if (!this.eventStore.getCount()) {
59558 // reset number of rows in cells.
59559 Roo.each(this.cells.elements, function(c){
59563 this.eventStore.each(function(e) {
59564 this.clearEvent(e);
59569 clearEvent : function(ev)
59572 Roo.each(ev.els, function(el) {
59573 el.un('mouseenter' ,this.onEventEnter, this);
59574 el.un('mouseleave' ,this.onEventLeave, this);
59582 renderEvent : function(ev,ctr) {
59584 ctr = this.view.el.select('.fc-event-container',true).first();
59588 this.clearEvent(ev);
59594 var cells = ev.cells;
59595 var rows = ev.rows;
59596 this.fireEvent('eventrender', this, ev);
59598 for(var i =0; i < rows.length; i++) {
59602 cls += ' fc-event-start';
59604 if ((i+1) == rows.length) {
59605 cls += ' fc-event-end';
59608 //Roo.log(ev.data);
59609 // how many rows should it span..
59610 var cg = this.eventTmpl.append(ctr,Roo.apply({
59613 }, ev.data) , true);
59616 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59617 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59618 cg.on('click', this.onEventClick, this, ev);
59622 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59623 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59626 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59627 cg.setWidth(ebox.right - sbox.x -2);
59631 renderEvents: function()
59633 // first make sure there is enough space..
59635 if (!this.eventTmpl) {
59636 this.eventTmpl = new Roo.Template(
59637 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59638 '<div class="fc-event-inner">' +
59639 '<span class="fc-event-time">{time}</span>' +
59640 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59642 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59650 this.cells.each(function(c) {
59651 //Roo.log(c.select('.fc-day-content div',true).first());
59652 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59655 var ctr = this.view.el.select('.fc-event-container',true).first();
59658 this.eventStore.each(function(ev){
59660 this.renderEvent(ev);
59664 this.view.layout();
59668 onEventEnter: function (e, el,event,d) {
59669 this.fireEvent('evententer', this, el, event);
59672 onEventLeave: function (e, el,event,d) {
59673 this.fireEvent('eventleave', this, el, event);
59676 onEventClick: function (e, el,event,d) {
59677 this.fireEvent('eventclick', this, el, event);
59680 onMonthChange: function () {
59684 onLoad: function () {
59686 //Roo.log('calendar onload');
59688 if(this.eventStore.getCount() > 0){
59692 this.eventStore.each(function(d){
59697 if (typeof(add.end_dt) == 'undefined') {
59698 Roo.log("Missing End time in calendar data: ");
59702 if (typeof(add.start_dt) == 'undefined') {
59703 Roo.log("Missing Start time in calendar data: ");
59707 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59708 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59709 add.id = add.id || d.id;
59710 add.title = add.title || '??';
59718 this.renderEvents();
59728 render : function ()
59732 if (!this.view.el.hasClass('course-timesheet')) {
59733 this.view.el.addClass('course-timesheet');
59735 if (this.tsStyle) {
59740 Roo.log(_this.grid.view.el.getWidth());
59743 this.tsStyle = Roo.util.CSS.createStyleSheet({
59744 '.course-timesheet .x-grid-row' : {
59747 '.x-grid-row td' : {
59748 'vertical-align' : 0
59750 '.course-edit-link' : {
59752 'text-overflow' : 'ellipsis',
59753 'overflow' : 'hidden',
59754 'white-space' : 'nowrap',
59755 'cursor' : 'pointer'
59760 '.de-act-sup-link' : {
59761 'color' : 'purple',
59762 'text-decoration' : 'line-through'
59766 'text-decoration' : 'line-through'
59768 '.course-timesheet .course-highlight' : {
59769 'border-top-style': 'dashed !important',
59770 'border-bottom-bottom': 'dashed !important'
59772 '.course-timesheet .course-item' : {
59773 'font-family' : 'tahoma, arial, helvetica',
59774 'font-size' : '11px',
59775 'overflow' : 'hidden',
59776 'padding-left' : '10px',
59777 'padding-right' : '10px',
59778 'padding-top' : '10px'
59786 monitorWindowResize : false,
59787 cellrenderer : function(v,x,r)
59792 xtype: 'CellSelectionModel',
59799 beforeload : function (_self, options)
59801 options.params = options.params || {};
59802 options.params._month = _this.monthField.getValue();
59803 options.params.limit = 9999;
59804 options.params['sort'] = 'when_dt';
59805 options.params['dir'] = 'ASC';
59806 this.proxy.loadResponse = this.loadResponse;
59808 //this.addColumns();
59810 load : function (_self, records, options)
59812 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59813 // if you click on the translation.. you can edit it...
59814 var el = Roo.get(this);
59815 var id = el.dom.getAttribute('data-id');
59816 var d = el.dom.getAttribute('data-date');
59817 var t = el.dom.getAttribute('data-time');
59818 //var id = this.child('span').dom.textContent;
59821 Pman.Dialog.CourseCalendar.show({
59825 productitem_active : id ? 1 : 0
59827 _this.grid.ds.load({});
59832 _this.panel.fireEvent('resize', [ '', '' ]);
59835 loadResponse : function(o, success, response){
59836 // this is overridden on before load..
59838 Roo.log("our code?");
59839 //Roo.log(success);
59840 //Roo.log(response)
59841 delete this.activeRequest;
59843 this.fireEvent("loadexception", this, o, response);
59844 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59849 result = o.reader.read(response);
59851 Roo.log("load exception?");
59852 this.fireEvent("loadexception", this, o, response, e);
59853 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59856 Roo.log("ready...");
59857 // loop through result.records;
59858 // and set this.tdate[date] = [] << array of records..
59860 Roo.each(result.records, function(r){
59862 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
59863 _this.tdata[r.data.when_dt.format('j')] = [];
59865 _this.tdata[r.data.when_dt.format('j')].push(r.data);
59868 //Roo.log(_this.tdata);
59870 result.records = [];
59871 result.totalRecords = 6;
59873 // let's generate some duumy records for the rows.
59874 //var st = _this.dateField.getValue();
59876 // work out monday..
59877 //st = st.add(Date.DAY, -1 * st.format('w'));
59879 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59881 var firstOfMonth = date.getFirstDayOfMonth();
59882 var days = date.getDaysInMonth();
59884 var firstAdded = false;
59885 for (var i = 0; i < result.totalRecords ; i++) {
59886 //var d= st.add(Date.DAY, i);
59889 for(var w = 0 ; w < 7 ; w++){
59890 if(!firstAdded && firstOfMonth != w){
59897 var dd = (d > 0 && d < 10) ? "0"+d : d;
59898 row['weekday'+w] = String.format(
59899 '<span style="font-size: 16px;"><b>{0}</b></span>'+
59900 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
59902 date.format('Y-m-')+dd
59905 if(typeof(_this.tdata[d]) != 'undefined'){
59906 Roo.each(_this.tdata[d], function(r){
59910 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
59911 if(r.parent_id*1>0){
59912 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
59915 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
59916 deactive = 'de-act-link';
59919 row['weekday'+w] += String.format(
59920 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
59922 r.product_id_name, //1
59923 r.when_dt.format('h:ia'), //2
59933 // only do this if something added..
59935 result.records.push(_this.grid.dataSource.reader.newRow(row));
59939 // push it twice. (second one with an hour..
59943 this.fireEvent("load", this, o, o.request.arg);
59944 o.request.callback.call(o.request.scope, result, o.request.arg, true);
59946 sortInfo : {field: 'when_dt', direction : 'ASC' },
59948 xtype: 'HttpProxy',
59951 url : baseURL + '/Roo/Shop_course.php'
59954 xtype: 'JsonReader',
59971 'name': 'parent_id',
59975 'name': 'product_id',
59979 'name': 'productitem_id',
59997 click : function (_self, e)
59999 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60000 sd.setMonth(sd.getMonth()-1);
60001 _this.monthField.setValue(sd.format('Y-m-d'));
60002 _this.grid.ds.load({});
60008 xtype: 'Separator',
60012 xtype: 'MonthField',
60015 render : function (_self)
60017 _this.monthField = _self;
60018 // _this.monthField.set today
60020 select : function (combo, date)
60022 _this.grid.ds.load({});
60025 value : (function() { return new Date(); })()
60028 xtype: 'Separator',
60034 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60044 click : function (_self, e)
60046 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60047 sd.setMonth(sd.getMonth()+1);
60048 _this.monthField.setValue(sd.format('Y-m-d'));
60049 _this.grid.ds.load({});
60062 * Ext JS Library 1.1.1
60063 * Copyright(c) 2006-2007, Ext JS, LLC.
60065 * Originally Released Under LGPL - original licence link has changed is not relivant.
60068 * <script type="text/javascript">
60072 * @class Roo.LoadMask
60073 * A simple utility class for generically masking elements while loading data. If the element being masked has
60074 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60075 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60076 * element's UpdateManager load indicator and will be destroyed after the initial load.
60078 * Create a new LoadMask
60079 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60080 * @param {Object} config The config object
60082 Roo.LoadMask = function(el, config){
60083 this.el = Roo.get(el);
60084 Roo.apply(this, config);
60086 this.store.on('beforeload', this.onBeforeLoad, this);
60087 this.store.on('load', this.onLoad, this);
60088 this.store.on('loadexception', this.onLoadException, this);
60089 this.removeMask = false;
60091 var um = this.el.getUpdateManager();
60092 um.showLoadIndicator = false; // disable the default indicator
60093 um.on('beforeupdate', this.onBeforeLoad, this);
60094 um.on('update', this.onLoad, this);
60095 um.on('failure', this.onLoad, this);
60096 this.removeMask = true;
60100 Roo.LoadMask.prototype = {
60102 * @cfg {Boolean} removeMask
60103 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60104 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60107 * @cfg {String} msg
60108 * The text to display in a centered loading message box (defaults to 'Loading...')
60110 msg : 'Loading...',
60112 * @cfg {String} msgCls
60113 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60115 msgCls : 'x-mask-loading',
60118 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60124 * Disables the mask to prevent it from being displayed
60126 disable : function(){
60127 this.disabled = true;
60131 * Enables the mask so that it can be displayed
60133 enable : function(){
60134 this.disabled = false;
60137 onLoadException : function()
60139 Roo.log(arguments);
60141 if (typeof(arguments[3]) != 'undefined') {
60142 Roo.MessageBox.alert("Error loading",arguments[3]);
60146 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60147 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60156 this.el.unmask(this.removeMask);
60159 onLoad : function()
60161 this.el.unmask(this.removeMask);
60165 onBeforeLoad : function(){
60166 if(!this.disabled){
60167 this.el.mask(this.msg, this.msgCls);
60172 destroy : function(){
60174 this.store.un('beforeload', this.onBeforeLoad, this);
60175 this.store.un('load', this.onLoad, this);
60176 this.store.un('loadexception', this.onLoadException, this);
60178 var um = this.el.getUpdateManager();
60179 um.un('beforeupdate', this.onBeforeLoad, this);
60180 um.un('update', this.onLoad, this);
60181 um.un('failure', this.onLoad, this);
60186 * Ext JS Library 1.1.1
60187 * Copyright(c) 2006-2007, Ext JS, LLC.
60189 * Originally Released Under LGPL - original licence link has changed is not relivant.
60192 * <script type="text/javascript">
60197 * @class Roo.XTemplate
60198 * @extends Roo.Template
60199 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60201 var t = new Roo.XTemplate(
60202 '<select name="{name}">',
60203 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60207 // then append, applying the master template values
60210 * Supported features:
60215 {a_variable} - output encoded.
60216 {a_variable.format:("Y-m-d")} - call a method on the variable
60217 {a_variable:raw} - unencoded output
60218 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60219 {a_variable:this.method_on_template(...)} - call a method on the template object.
60224 <tpl for="a_variable or condition.."></tpl>
60225 <tpl if="a_variable or condition"></tpl>
60226 <tpl exec="some javascript"></tpl>
60227 <tpl name="named_template"></tpl> (experimental)
60229 <tpl for="."></tpl> - just iterate the property..
60230 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60234 Roo.XTemplate = function()
60236 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60243 Roo.extend(Roo.XTemplate, Roo.Template, {
60246 * The various sub templates
60251 * basic tag replacing syntax
60254 * // you can fake an object call by doing this
60258 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60261 * compile the template
60263 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60266 compile: function()
60270 s = ['<tpl>', s, '</tpl>'].join('');
60272 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60273 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60274 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60275 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60276 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60281 while(true == !!(m = s.match(re))){
60282 var forMatch = m[0].match(nameRe),
60283 ifMatch = m[0].match(ifRe),
60284 execMatch = m[0].match(execRe),
60285 namedMatch = m[0].match(namedRe),
60290 name = forMatch && forMatch[1] ? forMatch[1] : '';
60293 // if - puts fn into test..
60294 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60296 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60301 // exec - calls a function... returns empty if true is returned.
60302 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60304 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60312 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60313 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60314 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60317 var uid = namedMatch ? namedMatch[1] : id;
60321 id: namedMatch ? namedMatch[1] : id,
60328 s = s.replace(m[0], '');
60330 s = s.replace(m[0], '{xtpl'+ id + '}');
60335 for(var i = tpls.length-1; i >= 0; --i){
60336 this.compileTpl(tpls[i]);
60337 this.tpls[tpls[i].id] = tpls[i];
60339 this.master = tpls[tpls.length-1];
60343 * same as applyTemplate, except it's done to one of the subTemplates
60344 * when using named templates, you can do:
60346 * var str = pl.applySubTemplate('your-name', values);
60349 * @param {Number} id of the template
60350 * @param {Object} values to apply to template
60351 * @param {Object} parent (normaly the instance of this object)
60353 applySubTemplate : function(id, values, parent)
60357 var t = this.tpls[id];
60361 if(t.test && !t.test.call(this, values, parent)){
60365 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60366 Roo.log(e.toString());
60372 if(t.exec && t.exec.call(this, values, parent)){
60376 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60377 Roo.log(e.toString());
60382 var vs = t.target ? t.target.call(this, values, parent) : values;
60383 parent = t.target ? values : parent;
60384 if(t.target && vs instanceof Array){
60386 for(var i = 0, len = vs.length; i < len; i++){
60387 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60389 return buf.join('');
60391 return t.compiled.call(this, vs, parent);
60393 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60394 Roo.log(e.toString());
60395 Roo.log(t.compiled);
60400 compileTpl : function(tpl)
60402 var fm = Roo.util.Format;
60403 var useF = this.disableFormats !== true;
60404 var sep = Roo.isGecko ? "+" : ",";
60405 var undef = function(str) {
60406 Roo.log("Property not found :" + str);
60410 var fn = function(m, name, format, args)
60412 //Roo.log(arguments);
60413 args = args ? args.replace(/\\'/g,"'") : args;
60414 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60415 if (typeof(format) == 'undefined') {
60416 format= 'htmlEncode';
60418 if (format == 'raw' ) {
60422 if(name.substr(0, 4) == 'xtpl'){
60423 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60426 // build an array of options to determine if value is undefined..
60428 // basically get 'xxxx.yyyy' then do
60429 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60430 // (function () { Roo.log("Property not found"); return ''; })() :
60435 Roo.each(name.split('.'), function(st) {
60436 lookfor += (lookfor.length ? '.': '') + st;
60437 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60440 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60443 if(format && useF){
60445 args = args ? ',' + args : "";
60447 if(format.substr(0, 5) != "this."){
60448 format = "fm." + format + '(';
60450 format = 'this.call("'+ format.substr(5) + '", ';
60454 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60458 // called with xxyx.yuu:(test,test)
60460 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60462 // raw.. - :raw modifier..
60463 return "'"+ sep + udef_st + name + ")"+sep+"'";
60467 // branched to use + in gecko and [].join() in others
60469 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60470 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60473 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60474 body.push(tpl.body.replace(/(\r\n|\n)/g,
60475 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60476 body.push("'].join('');};};");
60477 body = body.join('');
60480 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60482 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60488 applyTemplate : function(values){
60489 return this.master.compiled.call(this, values, {});
60490 //var s = this.subs;
60493 apply : function(){
60494 return this.applyTemplate.apply(this, arguments);
60499 Roo.XTemplate.from = function(el){
60500 el = Roo.getDom(el);
60501 return new Roo.XTemplate(el.value || el.innerHTML);