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 */
6780 setEvent : function(e){
6781 if(e == this || (e && e.browserEvent)){ // already wrapped
6784 this.browserEvent = e;
6786 // normalize buttons
6787 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6788 if(e.type == 'click' && this.button == -1){
6792 this.shiftKey = e.shiftKey;
6793 // mac metaKey behaves like ctrlKey
6794 this.ctrlKey = e.ctrlKey || e.metaKey;
6795 this.altKey = e.altKey;
6796 // in getKey these will be normalized for the mac
6797 this.keyCode = e.keyCode;
6798 // keyup warnings on firefox.
6799 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6800 // cache the target for the delayed and or buffered events
6801 this.target = E.getTarget(e);
6803 this.xy = E.getXY(e);
6806 this.shiftKey = false;
6807 this.ctrlKey = false;
6808 this.altKey = false;
6818 * Stop the event (preventDefault and stopPropagation)
6820 stopEvent : function(){
6821 if(this.browserEvent){
6822 if(this.browserEvent.type == 'mousedown'){
6823 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6825 E.stopEvent(this.browserEvent);
6830 * Prevents the browsers default handling of the event.
6832 preventDefault : function(){
6833 if(this.browserEvent){
6834 E.preventDefault(this.browserEvent);
6839 isNavKeyPress : function(){
6840 var k = this.keyCode;
6841 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6842 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6845 isSpecialKey : function(){
6846 var k = this.keyCode;
6847 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6848 (k == 16) || (k == 17) ||
6849 (k >= 18 && k <= 20) ||
6850 (k >= 33 && k <= 35) ||
6851 (k >= 36 && k <= 39) ||
6852 (k >= 44 && k <= 45);
6855 * Cancels bubbling of the event.
6857 stopPropagation : function(){
6858 if(this.browserEvent){
6859 if(this.type == 'mousedown'){
6860 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6862 E.stopPropagation(this.browserEvent);
6867 * Gets the key code for the event.
6870 getCharCode : function(){
6871 return this.charCode || this.keyCode;
6875 * Returns a normalized keyCode for the event.
6876 * @return {Number} The key code
6878 getKey : function(){
6879 var k = this.keyCode || this.charCode;
6880 return Roo.isSafari ? (safariKeys[k] || k) : k;
6884 * Gets the x coordinate of the event.
6887 getPageX : function(){
6892 * Gets the y coordinate of the event.
6895 getPageY : function(){
6900 * Gets the time of the event.
6903 getTime : function(){
6904 if(this.browserEvent){
6905 return E.getTime(this.browserEvent);
6911 * Gets the page coordinates of the event.
6912 * @return {Array} The xy values like [x, y]
6919 * Gets the target for the event.
6920 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6921 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6922 search as a number or element (defaults to 10 || document.body)
6923 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6924 * @return {HTMLelement}
6926 getTarget : function(selector, maxDepth, returnEl){
6927 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6930 * Gets the related target.
6931 * @return {HTMLElement}
6933 getRelatedTarget : function(){
6934 if(this.browserEvent){
6935 return E.getRelatedTarget(this.browserEvent);
6941 * Normalizes mouse wheel delta across browsers
6942 * @return {Number} The delta
6944 getWheelDelta : function(){
6945 var e = this.browserEvent;
6947 if(e.wheelDelta){ /* IE/Opera. */
6948 delta = e.wheelDelta/120;
6949 }else if(e.detail){ /* Mozilla case. */
6950 delta = -e.detail/3;
6956 * Returns true if the control, meta, shift or alt key was pressed during this event.
6959 hasModifier : function(){
6960 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6964 * Returns true if the target of this event equals el or is a child of el
6965 * @param {String/HTMLElement/Element} el
6966 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6969 within : function(el, related){
6970 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6971 return t && Roo.fly(el).contains(t);
6974 getPoint : function(){
6975 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6979 return new Roo.EventObjectImpl();
6984 * Ext JS Library 1.1.1
6985 * Copyright(c) 2006-2007, Ext JS, LLC.
6987 * Originally Released Under LGPL - original licence link has changed is not relivant.
6990 * <script type="text/javascript">
6994 // was in Composite Element!??!?!
6997 var D = Roo.lib.Dom;
6998 var E = Roo.lib.Event;
6999 var A = Roo.lib.Anim;
7001 // local style camelizing for speed
7003 var camelRe = /(-[a-z])/gi;
7004 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7005 var view = document.defaultView;
7008 * @class Roo.Element
7009 * Represents an Element in the DOM.<br><br>
7012 var el = Roo.get("my-div");
7015 var el = getEl("my-div");
7017 // or with a DOM element
7018 var el = Roo.get(myDivElement);
7020 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7021 * each call instead of constructing a new one.<br><br>
7022 * <b>Animations</b><br />
7023 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7024 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7026 Option Default Description
7027 --------- -------- ---------------------------------------------
7028 duration .35 The duration of the animation in seconds
7029 easing easeOut The YUI easing method
7030 callback none A function to execute when the anim completes
7031 scope this The scope (this) of the callback function
7033 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7034 * manipulate the animation. Here's an example:
7036 var el = Roo.get("my-div");
7041 // default animation
7042 el.setWidth(100, true);
7044 // animation with some options set
7051 // using the "anim" property to get the Anim object
7057 el.setWidth(100, opt);
7059 if(opt.anim.isAnimated()){
7063 * <b> Composite (Collections of) Elements</b><br />
7064 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7065 * @constructor Create a new Element directly.
7066 * @param {String/HTMLElement} element
7067 * @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).
7069 Roo.Element = function(element, forceNew){
7070 var dom = typeof element == "string" ?
7071 document.getElementById(element) : element;
7072 if(!dom){ // invalid id/element
7076 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7077 return Roo.Element.cache[id];
7087 * The DOM element ID
7090 this.id = id || Roo.id(dom);
7093 var El = Roo.Element;
7097 * The element's default display mode (defaults to "")
7100 originalDisplay : "",
7104 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7110 * Sets the element's visibility mode. When setVisible() is called it
7111 * will use this to determine whether to set the visibility or the display property.
7112 * @param visMode Element.VISIBILITY or Element.DISPLAY
7113 * @return {Roo.Element} this
7115 setVisibilityMode : function(visMode){
7116 this.visibilityMode = visMode;
7120 * Convenience method for setVisibilityMode(Element.DISPLAY)
7121 * @param {String} display (optional) What to set display to when visible
7122 * @return {Roo.Element} this
7124 enableDisplayMode : function(display){
7125 this.setVisibilityMode(El.DISPLAY);
7126 if(typeof display != "undefined") { this.originalDisplay = display; }
7131 * 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)
7132 * @param {String} selector The simple selector to test
7133 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7134 search as a number or element (defaults to 10 || document.body)
7135 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7136 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7138 findParent : function(simpleSelector, maxDepth, returnEl){
7139 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7140 maxDepth = maxDepth || 50;
7141 if(typeof maxDepth != "number"){
7142 stopEl = Roo.getDom(maxDepth);
7145 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7146 if(dq.is(p, simpleSelector)){
7147 return returnEl ? Roo.get(p) : p;
7157 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7158 * @param {String} selector The simple selector to test
7159 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7160 search as a number or element (defaults to 10 || document.body)
7161 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7162 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7164 findParentNode : function(simpleSelector, maxDepth, returnEl){
7165 var p = Roo.fly(this.dom.parentNode, '_internal');
7166 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7170 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7171 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7172 * @param {String} selector The simple selector to test
7173 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7174 search as a number or element (defaults to 10 || document.body)
7175 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7177 up : function(simpleSelector, maxDepth){
7178 return this.findParentNode(simpleSelector, maxDepth, true);
7184 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7185 * @param {String} selector The simple selector to test
7186 * @return {Boolean} True if this element matches the selector, else false
7188 is : function(simpleSelector){
7189 return Roo.DomQuery.is(this.dom, simpleSelector);
7193 * Perform animation on this element.
7194 * @param {Object} args The YUI animation control args
7195 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7196 * @param {Function} onComplete (optional) Function to call when animation completes
7197 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7198 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7199 * @return {Roo.Element} this
7201 animate : function(args, duration, onComplete, easing, animType){
7202 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7207 * @private Internal animation call
7209 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7210 animType = animType || 'run';
7212 var anim = Roo.lib.Anim[animType](
7214 (opt.duration || defaultDur) || .35,
7215 (opt.easing || defaultEase) || 'easeOut',
7217 Roo.callback(cb, this);
7218 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7226 // private legacy anim prep
7227 preanim : function(a, i){
7228 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7232 * Removes worthless text nodes
7233 * @param {Boolean} forceReclean (optional) By default the element
7234 * keeps track if it has been cleaned already so
7235 * you can call this over and over. However, if you update the element and
7236 * need to force a reclean, you can pass true.
7238 clean : function(forceReclean){
7239 if(this.isCleaned && forceReclean !== true){
7243 var d = this.dom, n = d.firstChild, ni = -1;
7245 var nx = n.nextSibling;
7246 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7253 this.isCleaned = true;
7258 calcOffsetsTo : function(el){
7261 var restorePos = false;
7262 if(el.getStyle('position') == 'static'){
7263 el.position('relative');
7268 while(op && op != d && op.tagName != 'HTML'){
7271 op = op.offsetParent;
7274 el.position('static');
7280 * Scrolls this element into view within the passed container.
7281 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7282 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7283 * @return {Roo.Element} this
7285 scrollIntoView : function(container, hscroll){
7286 var c = Roo.getDom(container) || document.body;
7289 var o = this.calcOffsetsTo(c),
7292 b = t+el.offsetHeight,
7293 r = l+el.offsetWidth;
7295 var ch = c.clientHeight;
7296 var ct = parseInt(c.scrollTop, 10);
7297 var cl = parseInt(c.scrollLeft, 10);
7299 var cr = cl + c.clientWidth;
7307 if(hscroll !== false){
7311 c.scrollLeft = r-c.clientWidth;
7318 scrollChildIntoView : function(child, hscroll){
7319 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7323 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7324 * the new height may not be available immediately.
7325 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7326 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7327 * @param {Function} onComplete (optional) Function to call when animation completes
7328 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7329 * @return {Roo.Element} this
7331 autoHeight : function(animate, duration, onComplete, easing){
7332 var oldHeight = this.getHeight();
7334 this.setHeight(1); // force clipping
7335 setTimeout(function(){
7336 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7338 this.setHeight(height);
7340 if(typeof onComplete == "function"){
7344 this.setHeight(oldHeight); // restore original height
7345 this.setHeight(height, animate, duration, function(){
7347 if(typeof onComplete == "function") { onComplete(); }
7348 }.createDelegate(this), easing);
7350 }.createDelegate(this), 0);
7355 * Returns true if this element is an ancestor of the passed element
7356 * @param {HTMLElement/String} el The element to check
7357 * @return {Boolean} True if this element is an ancestor of el, else false
7359 contains : function(el){
7360 if(!el){return false;}
7361 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7365 * Checks whether the element is currently visible using both visibility and display properties.
7366 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7367 * @return {Boolean} True if the element is currently visible, else false
7369 isVisible : function(deep) {
7370 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7371 if(deep !== true || !vis){
7374 var p = this.dom.parentNode;
7375 while(p && p.tagName.toLowerCase() != "body"){
7376 if(!Roo.fly(p, '_isVisible').isVisible()){
7385 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7386 * @param {String} selector The CSS selector
7387 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7388 * @return {CompositeElement/CompositeElementLite} The composite element
7390 select : function(selector, unique){
7391 return El.select(selector, unique, this.dom);
7395 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7396 * @param {String} selector The CSS selector
7397 * @return {Array} An array of the matched nodes
7399 query : function(selector, unique){
7400 return Roo.DomQuery.select(selector, this.dom);
7404 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7405 * @param {String} selector The CSS selector
7406 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7407 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7409 child : function(selector, returnDom){
7410 var n = Roo.DomQuery.selectNode(selector, this.dom);
7411 return returnDom ? n : Roo.get(n);
7415 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7416 * @param {String} selector The CSS selector
7417 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7418 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7420 down : function(selector, returnDom){
7421 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7422 return returnDom ? n : Roo.get(n);
7426 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7427 * @param {String} group The group the DD object is member of
7428 * @param {Object} config The DD config object
7429 * @param {Object} overrides An object containing methods to override/implement on the DD object
7430 * @return {Roo.dd.DD} The DD object
7432 initDD : function(group, config, overrides){
7433 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7434 return Roo.apply(dd, overrides);
7438 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7439 * @param {String} group The group the DDProxy object is member of
7440 * @param {Object} config The DDProxy config object
7441 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7442 * @return {Roo.dd.DDProxy} The DDProxy object
7444 initDDProxy : function(group, config, overrides){
7445 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7446 return Roo.apply(dd, overrides);
7450 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7451 * @param {String} group The group the DDTarget object is member of
7452 * @param {Object} config The DDTarget config object
7453 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7454 * @return {Roo.dd.DDTarget} The DDTarget object
7456 initDDTarget : function(group, config, overrides){
7457 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7458 return Roo.apply(dd, overrides);
7462 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7463 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7464 * @param {Boolean} visible Whether the element is visible
7465 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7466 * @return {Roo.Element} this
7468 setVisible : function(visible, animate){
7470 if(this.visibilityMode == El.DISPLAY){
7471 this.setDisplayed(visible);
7474 this.dom.style.visibility = visible ? "visible" : "hidden";
7477 // closure for composites
7479 var visMode = this.visibilityMode;
7481 this.setOpacity(.01);
7482 this.setVisible(true);
7484 this.anim({opacity: { to: (visible?1:0) }},
7485 this.preanim(arguments, 1),
7486 null, .35, 'easeIn', function(){
7488 if(visMode == El.DISPLAY){
7489 dom.style.display = "none";
7491 dom.style.visibility = "hidden";
7493 Roo.get(dom).setOpacity(1);
7501 * Returns true if display is not "none"
7504 isDisplayed : function() {
7505 return this.getStyle("display") != "none";
7509 * Toggles the element's visibility or display, depending on visibility mode.
7510 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7511 * @return {Roo.Element} this
7513 toggle : function(animate){
7514 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7519 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7520 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7521 * @return {Roo.Element} this
7523 setDisplayed : function(value) {
7524 if(typeof value == "boolean"){
7525 value = value ? this.originalDisplay : "none";
7527 this.setStyle("display", value);
7532 * Tries to focus the element. Any exceptions are caught and ignored.
7533 * @return {Roo.Element} this
7535 focus : function() {
7543 * Tries to blur the element. Any exceptions are caught and ignored.
7544 * @return {Roo.Element} this
7554 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7555 * @param {String/Array} className The CSS class to add, or an array of classes
7556 * @return {Roo.Element} this
7558 addClass : function(className){
7559 if(className instanceof Array){
7560 for(var i = 0, len = className.length; i < len; i++) {
7561 this.addClass(className[i]);
7564 if(className && !this.hasClass(className)){
7565 this.dom.className = this.dom.className + " " + className;
7572 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7573 * @param {String/Array} className The CSS class to add, or an array of classes
7574 * @return {Roo.Element} this
7576 radioClass : function(className){
7577 var siblings = this.dom.parentNode.childNodes;
7578 for(var i = 0; i < siblings.length; i++) {
7579 var s = siblings[i];
7580 if(s.nodeType == 1){
7581 Roo.get(s).removeClass(className);
7584 this.addClass(className);
7589 * Removes one or more CSS classes from the element.
7590 * @param {String/Array} className The CSS class to remove, or an array of classes
7591 * @return {Roo.Element} this
7593 removeClass : function(className){
7594 if(!className || !this.dom.className){
7597 if(className instanceof Array){
7598 for(var i = 0, len = className.length; i < len; i++) {
7599 this.removeClass(className[i]);
7602 if(this.hasClass(className)){
7603 var re = this.classReCache[className];
7605 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7606 this.classReCache[className] = re;
7608 this.dom.className =
7609 this.dom.className.replace(re, " ");
7619 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7620 * @param {String} className The CSS class to toggle
7621 * @return {Roo.Element} this
7623 toggleClass : function(className){
7624 if(this.hasClass(className)){
7625 this.removeClass(className);
7627 this.addClass(className);
7633 * Checks if the specified CSS class exists on this element's DOM node.
7634 * @param {String} className The CSS class to check for
7635 * @return {Boolean} True if the class exists, else false
7637 hasClass : function(className){
7638 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7642 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7643 * @param {String} oldClassName The CSS class to replace
7644 * @param {String} newClassName The replacement CSS class
7645 * @return {Roo.Element} this
7647 replaceClass : function(oldClassName, newClassName){
7648 this.removeClass(oldClassName);
7649 this.addClass(newClassName);
7654 * Returns an object with properties matching the styles requested.
7655 * For example, el.getStyles('color', 'font-size', 'width') might return
7656 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7657 * @param {String} style1 A style name
7658 * @param {String} style2 A style name
7659 * @param {String} etc.
7660 * @return {Object} The style object
7662 getStyles : function(){
7663 var a = arguments, len = a.length, r = {};
7664 for(var i = 0; i < len; i++){
7665 r[a[i]] = this.getStyle(a[i]);
7671 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7672 * @param {String} property The style property whose value is returned.
7673 * @return {String} The current value of the style property for this element.
7675 getStyle : function(){
7676 return view && view.getComputedStyle ?
7678 var el = this.dom, v, cs, camel;
7679 if(prop == 'float'){
7682 if(el.style && (v = el.style[prop])){
7685 if(cs = view.getComputedStyle(el, "")){
7686 if(!(camel = propCache[prop])){
7687 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7694 var el = this.dom, v, cs, camel;
7695 if(prop == 'opacity'){
7696 if(typeof el.style.filter == 'string'){
7697 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7699 var fv = parseFloat(m[1]);
7701 return fv ? fv / 100 : 0;
7706 }else if(prop == 'float'){
7707 prop = "styleFloat";
7709 if(!(camel = propCache[prop])){
7710 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7712 if(v = el.style[camel]){
7715 if(cs = el.currentStyle){
7723 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7724 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7725 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7726 * @return {Roo.Element} this
7728 setStyle : function(prop, value){
7729 if(typeof prop == "string"){
7731 if (prop == 'float') {
7732 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7737 if(!(camel = propCache[prop])){
7738 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7741 if(camel == 'opacity') {
7742 this.setOpacity(value);
7744 this.dom.style[camel] = value;
7747 for(var style in prop){
7748 if(typeof prop[style] != "function"){
7749 this.setStyle(style, prop[style]);
7757 * More flexible version of {@link #setStyle} for setting style properties.
7758 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7759 * a function which returns such a specification.
7760 * @return {Roo.Element} this
7762 applyStyles : function(style){
7763 Roo.DomHelper.applyStyles(this.dom, style);
7768 * 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).
7769 * @return {Number} The X position of the element
7772 return D.getX(this.dom);
7776 * 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).
7777 * @return {Number} The Y position of the element
7780 return D.getY(this.dom);
7784 * 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).
7785 * @return {Array} The XY position of the element
7788 return D.getXY(this.dom);
7792 * 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).
7793 * @param {Number} The X position of the element
7794 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7795 * @return {Roo.Element} this
7797 setX : function(x, animate){
7799 D.setX(this.dom, x);
7801 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7807 * 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).
7808 * @param {Number} The Y position of the element
7809 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7810 * @return {Roo.Element} this
7812 setY : function(y, animate){
7814 D.setY(this.dom, y);
7816 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7822 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7823 * @param {String} left The left CSS property value
7824 * @return {Roo.Element} this
7826 setLeft : function(left){
7827 this.setStyle("left", this.addUnits(left));
7832 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7833 * @param {String} top The top CSS property value
7834 * @return {Roo.Element} this
7836 setTop : function(top){
7837 this.setStyle("top", this.addUnits(top));
7842 * Sets the element's CSS right style.
7843 * @param {String} right The right CSS property value
7844 * @return {Roo.Element} this
7846 setRight : function(right){
7847 this.setStyle("right", this.addUnits(right));
7852 * Sets the element's CSS bottom style.
7853 * @param {String} bottom The bottom CSS property value
7854 * @return {Roo.Element} this
7856 setBottom : function(bottom){
7857 this.setStyle("bottom", this.addUnits(bottom));
7862 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7863 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7864 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7865 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7866 * @return {Roo.Element} this
7868 setXY : function(pos, animate){
7870 D.setXY(this.dom, pos);
7872 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7878 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7879 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7880 * @param {Number} x X value for new position (coordinates are page-based)
7881 * @param {Number} y Y value for new position (coordinates are page-based)
7882 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7883 * @return {Roo.Element} this
7885 setLocation : function(x, y, animate){
7886 this.setXY([x, y], this.preanim(arguments, 2));
7891 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7892 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7893 * @param {Number} x X value for new position (coordinates are page-based)
7894 * @param {Number} y Y value for new position (coordinates are page-based)
7895 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7896 * @return {Roo.Element} this
7898 moveTo : function(x, y, animate){
7899 this.setXY([x, y], this.preanim(arguments, 2));
7904 * Returns the region of the given element.
7905 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7906 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7908 getRegion : function(){
7909 return D.getRegion(this.dom);
7913 * Returns the offset height of the element
7914 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7915 * @return {Number} The element's height
7917 getHeight : function(contentHeight){
7918 var h = this.dom.offsetHeight || 0;
7919 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7923 * Returns the offset width of the element
7924 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7925 * @return {Number} The element's width
7927 getWidth : function(contentWidth){
7928 var w = this.dom.offsetWidth || 0;
7929 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7933 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7934 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7935 * if a height has not been set using CSS.
7938 getComputedHeight : function(){
7939 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7941 h = parseInt(this.getStyle('height'), 10) || 0;
7942 if(!this.isBorderBox()){
7943 h += this.getFrameWidth('tb');
7950 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7951 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7952 * if a width has not been set using CSS.
7955 getComputedWidth : function(){
7956 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7958 w = parseInt(this.getStyle('width'), 10) || 0;
7959 if(!this.isBorderBox()){
7960 w += this.getFrameWidth('lr');
7967 * Returns the size of the element.
7968 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7969 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7971 getSize : function(contentSize){
7972 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7976 * Returns the width and height of the viewport.
7977 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7979 getViewSize : function(){
7980 var d = this.dom, doc = document, aw = 0, ah = 0;
7981 if(d == doc || d == doc.body){
7982 return {width : D.getViewWidth(), height: D.getViewHeight()};
7985 width : d.clientWidth,
7986 height: d.clientHeight
7992 * Returns the value of the "value" attribute
7993 * @param {Boolean} asNumber true to parse the value as a number
7994 * @return {String/Number}
7996 getValue : function(asNumber){
7997 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8001 adjustWidth : function(width){
8002 if(typeof width == "number"){
8003 if(this.autoBoxAdjust && !this.isBorderBox()){
8004 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8014 adjustHeight : function(height){
8015 if(typeof height == "number"){
8016 if(this.autoBoxAdjust && !this.isBorderBox()){
8017 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8027 * Set the width of the element
8028 * @param {Number} width The new width
8029 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8030 * @return {Roo.Element} this
8032 setWidth : function(width, animate){
8033 width = this.adjustWidth(width);
8035 this.dom.style.width = this.addUnits(width);
8037 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8043 * Set the height of the element
8044 * @param {Number} height The new height
8045 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8046 * @return {Roo.Element} this
8048 setHeight : function(height, animate){
8049 height = this.adjustHeight(height);
8051 this.dom.style.height = this.addUnits(height);
8053 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8059 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8060 * @param {Number} width The new width
8061 * @param {Number} height The new height
8062 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8063 * @return {Roo.Element} this
8065 setSize : function(width, height, animate){
8066 if(typeof width == "object"){ // in case of object from getSize()
8067 height = width.height; width = width.width;
8069 width = this.adjustWidth(width); height = this.adjustHeight(height);
8071 this.dom.style.width = this.addUnits(width);
8072 this.dom.style.height = this.addUnits(height);
8074 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8080 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8081 * @param {Number} x X value for new position (coordinates are page-based)
8082 * @param {Number} y Y value for new position (coordinates are page-based)
8083 * @param {Number} width The new width
8084 * @param {Number} height The new height
8085 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8086 * @return {Roo.Element} this
8088 setBounds : function(x, y, width, height, animate){
8090 this.setSize(width, height);
8091 this.setLocation(x, y);
8093 width = this.adjustWidth(width); height = this.adjustHeight(height);
8094 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8095 this.preanim(arguments, 4), 'motion');
8101 * 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.
8102 * @param {Roo.lib.Region} region The region to fill
8103 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8104 * @return {Roo.Element} this
8106 setRegion : function(region, animate){
8107 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8112 * Appends an event handler
8114 * @param {String} eventName The type of event to append
8115 * @param {Function} fn The method the event invokes
8116 * @param {Object} scope (optional) The scope (this object) of the fn
8117 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8119 addListener : function(eventName, fn, scope, options){
8121 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8126 * Removes an event handler from this element
8127 * @param {String} eventName the type of event to remove
8128 * @param {Function} fn the method the event invokes
8129 * @return {Roo.Element} this
8131 removeListener : function(eventName, fn){
8132 Roo.EventManager.removeListener(this.dom, eventName, fn);
8137 * Removes all previous added listeners from this element
8138 * @return {Roo.Element} this
8140 removeAllListeners : function(){
8141 E.purgeElement(this.dom);
8145 relayEvent : function(eventName, observable){
8146 this.on(eventName, function(e){
8147 observable.fireEvent(eventName, e);
8152 * Set the opacity of the element
8153 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8154 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8155 * @return {Roo.Element} this
8157 setOpacity : function(opacity, animate){
8159 var s = this.dom.style;
8162 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8163 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8165 s.opacity = opacity;
8168 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8174 * Gets the left X coordinate
8175 * @param {Boolean} local True to get the local css position instead of page coordinate
8178 getLeft : function(local){
8182 return parseInt(this.getStyle("left"), 10) || 0;
8187 * Gets the right X coordinate of the element (element X position + element width)
8188 * @param {Boolean} local True to get the local css position instead of page coordinate
8191 getRight : function(local){
8193 return this.getX() + this.getWidth();
8195 return (this.getLeft(true) + this.getWidth()) || 0;
8200 * Gets the top Y coordinate
8201 * @param {Boolean} local True to get the local css position instead of page coordinate
8204 getTop : function(local) {
8208 return parseInt(this.getStyle("top"), 10) || 0;
8213 * Gets the bottom Y coordinate of the element (element Y position + element height)
8214 * @param {Boolean} local True to get the local css position instead of page coordinate
8217 getBottom : function(local){
8219 return this.getY() + this.getHeight();
8221 return (this.getTop(true) + this.getHeight()) || 0;
8226 * Initializes positioning on this element. If a desired position is not passed, it will make the
8227 * the element positioned relative IF it is not already positioned.
8228 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8229 * @param {Number} zIndex (optional) The zIndex to apply
8230 * @param {Number} x (optional) Set the page X position
8231 * @param {Number} y (optional) Set the page Y position
8233 position : function(pos, zIndex, x, y){
8235 if(this.getStyle('position') == 'static'){
8236 this.setStyle('position', 'relative');
8239 this.setStyle("position", pos);
8242 this.setStyle("z-index", zIndex);
8244 if(x !== undefined && y !== undefined){
8246 }else if(x !== undefined){
8248 }else if(y !== undefined){
8254 * Clear positioning back to the default when the document was loaded
8255 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8256 * @return {Roo.Element} this
8258 clearPositioning : function(value){
8266 "position" : "static"
8272 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8273 * snapshot before performing an update and then restoring the element.
8276 getPositioning : function(){
8277 var l = this.getStyle("left");
8278 var t = this.getStyle("top");
8280 "position" : this.getStyle("position"),
8282 "right" : l ? "" : this.getStyle("right"),
8284 "bottom" : t ? "" : this.getStyle("bottom"),
8285 "z-index" : this.getStyle("z-index")
8290 * Gets the width of the border(s) for the specified side(s)
8291 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8292 * passing lr would get the border (l)eft width + the border (r)ight width.
8293 * @return {Number} The width of the sides passed added together
8295 getBorderWidth : function(side){
8296 return this.addStyles(side, El.borders);
8300 * Gets the width of the padding(s) for the specified side(s)
8301 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8302 * passing lr would get the padding (l)eft + the padding (r)ight.
8303 * @return {Number} The padding of the sides passed added together
8305 getPadding : function(side){
8306 return this.addStyles(side, El.paddings);
8310 * Set positioning with an object returned by getPositioning().
8311 * @param {Object} posCfg
8312 * @return {Roo.Element} this
8314 setPositioning : function(pc){
8315 this.applyStyles(pc);
8316 if(pc.right == "auto"){
8317 this.dom.style.right = "";
8319 if(pc.bottom == "auto"){
8320 this.dom.style.bottom = "";
8326 fixDisplay : function(){
8327 if(this.getStyle("display") == "none"){
8328 this.setStyle("visibility", "hidden");
8329 this.setStyle("display", this.originalDisplay); // first try reverting to default
8330 if(this.getStyle("display") == "none"){ // if that fails, default to block
8331 this.setStyle("display", "block");
8337 * Quick set left and top adding default units
8338 * @param {String} left The left CSS property value
8339 * @param {String} top The top CSS property value
8340 * @return {Roo.Element} this
8342 setLeftTop : function(left, top){
8343 this.dom.style.left = this.addUnits(left);
8344 this.dom.style.top = this.addUnits(top);
8349 * Move this element relative to its current position.
8350 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8351 * @param {Number} distance How far to move the element in pixels
8352 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8353 * @return {Roo.Element} this
8355 move : function(direction, distance, animate){
8356 var xy = this.getXY();
8357 direction = direction.toLowerCase();
8361 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8365 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8370 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8375 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8382 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8383 * @return {Roo.Element} this
8386 if(!this.isClipped){
8387 this.isClipped = true;
8388 this.originalClip = {
8389 "o": this.getStyle("overflow"),
8390 "x": this.getStyle("overflow-x"),
8391 "y": this.getStyle("overflow-y")
8393 this.setStyle("overflow", "hidden");
8394 this.setStyle("overflow-x", "hidden");
8395 this.setStyle("overflow-y", "hidden");
8401 * Return clipping (overflow) to original clipping before clip() was called
8402 * @return {Roo.Element} this
8404 unclip : function(){
8406 this.isClipped = false;
8407 var o = this.originalClip;
8408 if(o.o){this.setStyle("overflow", o.o);}
8409 if(o.x){this.setStyle("overflow-x", o.x);}
8410 if(o.y){this.setStyle("overflow-y", o.y);}
8417 * Gets the x,y coordinates specified by the anchor position on the element.
8418 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8419 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8420 * {width: (target width), height: (target height)} (defaults to the element's current size)
8421 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8422 * @return {Array} [x, y] An array containing the element's x and y coordinates
8424 getAnchorXY : function(anchor, local, s){
8425 //Passing a different size is useful for pre-calculating anchors,
8426 //especially for anchored animations that change the el size.
8428 var w, h, vp = false;
8431 if(d == document.body || d == document){
8433 w = D.getViewWidth(); h = D.getViewHeight();
8435 w = this.getWidth(); h = this.getHeight();
8438 w = s.width; h = s.height;
8440 var x = 0, y = 0, r = Math.round;
8441 switch((anchor || "tl").toLowerCase()){
8483 var sc = this.getScroll();
8484 return [x + sc.left, y + sc.top];
8486 //Add the element's offset xy
8487 var o = this.getXY();
8488 return [x+o[0], y+o[1]];
8492 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8493 * supported position values.
8494 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8495 * @param {String} position The position to align to.
8496 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8497 * @return {Array} [x, y]
8499 getAlignToXY : function(el, p, o){
8503 throw "Element.alignTo with an element that doesn't exist";
8505 var c = false; //constrain to viewport
8506 var p1 = "", p2 = "";
8513 }else if(p.indexOf("-") == -1){
8516 p = p.toLowerCase();
8517 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8519 throw "Element.alignTo with an invalid alignment " + p;
8521 p1 = m[1]; p2 = m[2]; c = !!m[3];
8523 //Subtract the aligned el's internal xy from the target's offset xy
8524 //plus custom offset to get the aligned el's new offset xy
8525 var a1 = this.getAnchorXY(p1, true);
8526 var a2 = el.getAnchorXY(p2, false);
8527 var x = a2[0] - a1[0] + o[0];
8528 var y = a2[1] - a1[1] + o[1];
8530 //constrain the aligned el to viewport if necessary
8531 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8532 // 5px of margin for ie
8533 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8535 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8536 //perpendicular to the vp border, allow the aligned el to slide on that border,
8537 //otherwise swap the aligned el to the opposite border of the target.
8538 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8539 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8540 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8541 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8544 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8545 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8547 if((x+w) > dw + scrollX){
8548 x = swapX ? r.left-w : dw+scrollX-w;
8551 x = swapX ? r.right : scrollX;
8553 if((y+h) > dh + scrollY){
8554 y = swapY ? r.top-h : dh+scrollY-h;
8557 y = swapY ? r.bottom : scrollY;
8564 getConstrainToXY : function(){
8565 var os = {top:0, left:0, bottom:0, right: 0};
8567 return function(el, local, offsets, proposedXY){
8569 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8571 var vw, vh, vx = 0, vy = 0;
8572 if(el.dom == document.body || el.dom == document){
8573 vw = Roo.lib.Dom.getViewWidth();
8574 vh = Roo.lib.Dom.getViewHeight();
8576 vw = el.dom.clientWidth;
8577 vh = el.dom.clientHeight;
8579 var vxy = el.getXY();
8585 var s = el.getScroll();
8587 vx += offsets.left + s.left;
8588 vy += offsets.top + s.top;
8590 vw -= offsets.right;
8591 vh -= offsets.bottom;
8596 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8597 var x = xy[0], y = xy[1];
8598 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8600 // only move it if it needs it
8603 // first validate right/bottom
8612 // then make sure top/left isn't negative
8621 return moved ? [x, y] : false;
8626 adjustForConstraints : function(xy, parent, offsets){
8627 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8631 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8632 * document it aligns it to the viewport.
8633 * The position parameter is optional, and can be specified in any one of the following formats:
8635 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8636 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8637 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8638 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8639 * <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
8640 * element's anchor point, and the second value is used as the target's anchor point.</li>
8642 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8643 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8644 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8645 * that specified in order to enforce the viewport constraints.
8646 * Following are all of the supported anchor positions:
8649 ----- -----------------------------
8650 tl The top left corner (default)
8651 t The center of the top edge
8652 tr The top right corner
8653 l The center of the left edge
8654 c In the center of the element
8655 r The center of the right edge
8656 bl The bottom left corner
8657 b The center of the bottom edge
8658 br The bottom right corner
8662 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8663 el.alignTo("other-el");
8665 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8666 el.alignTo("other-el", "tr?");
8668 // align the bottom right corner of el with the center left edge of other-el
8669 el.alignTo("other-el", "br-l?");
8671 // align the center of el with the bottom left corner of other-el and
8672 // adjust the x position by -6 pixels (and the y position by 0)
8673 el.alignTo("other-el", "c-bl", [-6, 0]);
8675 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8676 * @param {String} position The position to align to.
8677 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8678 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8679 * @return {Roo.Element} this
8681 alignTo : function(element, position, offsets, animate){
8682 var xy = this.getAlignToXY(element, position, offsets);
8683 this.setXY(xy, this.preanim(arguments, 3));
8688 * Anchors an element to another element and realigns it when the window is resized.
8689 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8690 * @param {String} position The position to align to.
8691 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8692 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8693 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8694 * is a number, it is used as the buffer delay (defaults to 50ms).
8695 * @param {Function} callback The function to call after the animation finishes
8696 * @return {Roo.Element} this
8698 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8699 var action = function(){
8700 this.alignTo(el, alignment, offsets, animate);
8701 Roo.callback(callback, this);
8703 Roo.EventManager.onWindowResize(action, this);
8704 var tm = typeof monitorScroll;
8705 if(tm != 'undefined'){
8706 Roo.EventManager.on(window, 'scroll', action, this,
8707 {buffer: tm == 'number' ? monitorScroll : 50});
8709 action.call(this); // align immediately
8713 * Clears any opacity settings from this element. Required in some cases for IE.
8714 * @return {Roo.Element} this
8716 clearOpacity : function(){
8717 if (window.ActiveXObject) {
8718 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8719 this.dom.style.filter = "";
8722 this.dom.style.opacity = "";
8723 this.dom.style["-moz-opacity"] = "";
8724 this.dom.style["-khtml-opacity"] = "";
8730 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8731 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8732 * @return {Roo.Element} this
8734 hide : function(animate){
8735 this.setVisible(false, this.preanim(arguments, 0));
8740 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8741 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8742 * @return {Roo.Element} this
8744 show : function(animate){
8745 this.setVisible(true, this.preanim(arguments, 0));
8750 * @private Test if size has a unit, otherwise appends the default
8752 addUnits : function(size){
8753 return Roo.Element.addUnits(size, this.defaultUnit);
8757 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8758 * @return {Roo.Element} this
8760 beginMeasure : function(){
8762 if(el.offsetWidth || el.offsetHeight){
8763 return this; // offsets work already
8766 var p = this.dom, b = document.body; // start with this element
8767 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8768 var pe = Roo.get(p);
8769 if(pe.getStyle('display') == 'none'){
8770 changed.push({el: p, visibility: pe.getStyle("visibility")});
8771 p.style.visibility = "hidden";
8772 p.style.display = "block";
8776 this._measureChanged = changed;
8782 * Restores displays to before beginMeasure was called
8783 * @return {Roo.Element} this
8785 endMeasure : function(){
8786 var changed = this._measureChanged;
8788 for(var i = 0, len = changed.length; i < len; i++) {
8790 r.el.style.visibility = r.visibility;
8791 r.el.style.display = "none";
8793 this._measureChanged = null;
8799 * Update the innerHTML of this element, optionally searching for and processing scripts
8800 * @param {String} html The new HTML
8801 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8802 * @param {Function} callback For async script loading you can be noticed when the update completes
8803 * @return {Roo.Element} this
8805 update : function(html, loadScripts, callback){
8806 if(typeof html == "undefined"){
8809 if(loadScripts !== true){
8810 this.dom.innerHTML = html;
8811 if(typeof callback == "function"){
8819 html += '<span id="' + id + '"></span>';
8821 E.onAvailable(id, function(){
8822 var hd = document.getElementsByTagName("head")[0];
8823 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8824 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8825 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8828 while(match = re.exec(html)){
8829 var attrs = match[1];
8830 var srcMatch = attrs ? attrs.match(srcRe) : false;
8831 if(srcMatch && srcMatch[2]){
8832 var s = document.createElement("script");
8833 s.src = srcMatch[2];
8834 var typeMatch = attrs.match(typeRe);
8835 if(typeMatch && typeMatch[2]){
8836 s.type = typeMatch[2];
8839 }else if(match[2] && match[2].length > 0){
8840 if(window.execScript) {
8841 window.execScript(match[2]);
8849 window.eval(match[2]);
8853 var el = document.getElementById(id);
8854 if(el){el.parentNode.removeChild(el);}
8855 if(typeof callback == "function"){
8859 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8864 * Direct access to the UpdateManager update() method (takes the same parameters).
8865 * @param {String/Function} url The url for this request or a function to call to get the url
8866 * @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}
8867 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8868 * @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.
8869 * @return {Roo.Element} this
8872 var um = this.getUpdateManager();
8873 um.update.apply(um, arguments);
8878 * Gets this element's UpdateManager
8879 * @return {Roo.UpdateManager} The UpdateManager
8881 getUpdateManager : function(){
8882 if(!this.updateManager){
8883 this.updateManager = new Roo.UpdateManager(this);
8885 return this.updateManager;
8889 * Disables text selection for this element (normalized across browsers)
8890 * @return {Roo.Element} this
8892 unselectable : function(){
8893 this.dom.unselectable = "on";
8894 this.swallowEvent("selectstart", true);
8895 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8896 this.addClass("x-unselectable");
8901 * Calculates the x, y to center this element on the screen
8902 * @return {Array} The x, y values [x, y]
8904 getCenterXY : function(){
8905 return this.getAlignToXY(document, 'c-c');
8909 * Centers the Element in either the viewport, or another Element.
8910 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8912 center : function(centerIn){
8913 this.alignTo(centerIn || document, 'c-c');
8918 * Tests various css rules/browsers to determine if this element uses a border box
8921 isBorderBox : function(){
8922 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8926 * Return a box {x, y, width, height} that can be used to set another elements
8927 * size/location to match this element.
8928 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8929 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8930 * @return {Object} box An object in the format {x, y, width, height}
8932 getBox : function(contentBox, local){
8937 var left = parseInt(this.getStyle("left"), 10) || 0;
8938 var top = parseInt(this.getStyle("top"), 10) || 0;
8941 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8943 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8945 var l = this.getBorderWidth("l")+this.getPadding("l");
8946 var r = this.getBorderWidth("r")+this.getPadding("r");
8947 var t = this.getBorderWidth("t")+this.getPadding("t");
8948 var b = this.getBorderWidth("b")+this.getPadding("b");
8949 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)};
8951 bx.right = bx.x + bx.width;
8952 bx.bottom = bx.y + bx.height;
8957 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8958 for more information about the sides.
8959 * @param {String} sides
8962 getFrameWidth : function(sides, onlyContentBox){
8963 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8967 * 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.
8968 * @param {Object} box The box to fill {x, y, width, height}
8969 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8970 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8971 * @return {Roo.Element} this
8973 setBox : function(box, adjust, animate){
8974 var w = box.width, h = box.height;
8975 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8976 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8977 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8979 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8984 * Forces the browser to repaint this element
8985 * @return {Roo.Element} this
8987 repaint : function(){
8989 this.addClass("x-repaint");
8990 setTimeout(function(){
8991 Roo.get(dom).removeClass("x-repaint");
8997 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8998 * then it returns the calculated width of the sides (see getPadding)
8999 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9000 * @return {Object/Number}
9002 getMargins : function(side){
9005 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9006 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9007 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9008 right: parseInt(this.getStyle("margin-right"), 10) || 0
9011 return this.addStyles(side, El.margins);
9016 addStyles : function(sides, styles){
9018 for(var i = 0, len = sides.length; i < len; i++){
9019 v = this.getStyle(styles[sides.charAt(i)]);
9021 w = parseInt(v, 10);
9029 * Creates a proxy element of this element
9030 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9031 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9032 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9033 * @return {Roo.Element} The new proxy element
9035 createProxy : function(config, renderTo, matchBox){
9037 renderTo = Roo.getDom(renderTo);
9039 renderTo = document.body;
9041 config = typeof config == "object" ?
9042 config : {tag : "div", cls: config};
9043 var proxy = Roo.DomHelper.append(renderTo, config, true);
9045 proxy.setBox(this.getBox());
9051 * Puts a mask over this element to disable user interaction. Requires core.css.
9052 * This method can only be applied to elements which accept child nodes.
9053 * @param {String} msg (optional) A message to display in the mask
9054 * @param {String} msgCls (optional) A css class to apply to the msg element
9055 * @return {Element} The mask element
9057 mask : function(msg, msgCls)
9059 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9060 this.setStyle("position", "relative");
9063 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9065 this.addClass("x-masked");
9066 this._mask.setDisplayed(true);
9071 while (dom && dom.style) {
9072 if (!isNaN(parseInt(dom.style.zIndex))) {
9073 z = Math.max(z, parseInt(dom.style.zIndex));
9075 dom = dom.parentNode;
9077 // if we are masking the body - then it hides everything..
9078 if (this.dom == document.body) {
9080 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9081 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9084 if(typeof msg == 'string'){
9086 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9088 var mm = this._maskMsg;
9089 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9090 if (mm.dom.firstChild) { // weird IE issue?
9091 mm.dom.firstChild.innerHTML = msg;
9093 mm.setDisplayed(true);
9095 mm.setStyle('z-index', z + 102);
9097 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9098 this._mask.setHeight(this.getHeight());
9100 this._mask.setStyle('z-index', z + 100);
9106 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9107 * it is cached for reuse.
9109 unmask : function(removeEl){
9111 if(removeEl === true){
9112 this._mask.remove();
9115 this._maskMsg.remove();
9116 delete this._maskMsg;
9119 this._mask.setDisplayed(false);
9121 this._maskMsg.setDisplayed(false);
9125 this.removeClass("x-masked");
9129 * Returns true if this element is masked
9132 isMasked : function(){
9133 return this._mask && this._mask.isVisible();
9137 * Creates an iframe shim for this element to keep selects and other windowed objects from
9139 * @return {Roo.Element} The new shim element
9141 createShim : function(){
9142 var el = document.createElement('iframe');
9143 el.frameBorder = 'no';
9144 el.className = 'roo-shim';
9145 if(Roo.isIE && Roo.isSecure){
9146 el.src = Roo.SSL_SECURE_URL;
9148 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9149 shim.autoBoxAdjust = false;
9154 * Removes this element from the DOM and deletes it from the cache
9156 remove : function(){
9157 if(this.dom.parentNode){
9158 this.dom.parentNode.removeChild(this.dom);
9160 delete El.cache[this.dom.id];
9164 * Sets up event handlers to add and remove a css class when the mouse is over this element
9165 * @param {String} className
9166 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9167 * mouseout events for children elements
9168 * @return {Roo.Element} this
9170 addClassOnOver : function(className, preventFlicker){
9171 this.on("mouseover", function(){
9172 Roo.fly(this, '_internal').addClass(className);
9174 var removeFn = function(e){
9175 if(preventFlicker !== true || !e.within(this, true)){
9176 Roo.fly(this, '_internal').removeClass(className);
9179 this.on("mouseout", removeFn, this.dom);
9184 * Sets up event handlers to add and remove a css class when this element has the focus
9185 * @param {String} className
9186 * @return {Roo.Element} this
9188 addClassOnFocus : function(className){
9189 this.on("focus", function(){
9190 Roo.fly(this, '_internal').addClass(className);
9192 this.on("blur", function(){
9193 Roo.fly(this, '_internal').removeClass(className);
9198 * 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)
9199 * @param {String} className
9200 * @return {Roo.Element} this
9202 addClassOnClick : function(className){
9204 this.on("mousedown", function(){
9205 Roo.fly(dom, '_internal').addClass(className);
9206 var d = Roo.get(document);
9207 var fn = function(){
9208 Roo.fly(dom, '_internal').removeClass(className);
9209 d.removeListener("mouseup", fn);
9211 d.on("mouseup", fn);
9217 * Stops the specified event from bubbling and optionally prevents the default action
9218 * @param {String} eventName
9219 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9220 * @return {Roo.Element} this
9222 swallowEvent : function(eventName, preventDefault){
9223 var fn = function(e){
9224 e.stopPropagation();
9229 if(eventName instanceof Array){
9230 for(var i = 0, len = eventName.length; i < len; i++){
9231 this.on(eventName[i], fn);
9235 this.on(eventName, fn);
9242 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9245 * Sizes this element to its parent element's dimensions performing
9246 * neccessary box adjustments.
9247 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9248 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9249 * @return {Roo.Element} this
9251 fitToParent : function(monitorResize, targetParent) {
9252 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9253 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9254 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9257 var p = Roo.get(targetParent || this.dom.parentNode);
9258 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9259 if (monitorResize === true) {
9260 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9261 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9267 * Gets the next sibling, skipping text nodes
9268 * @return {HTMLElement} The next sibling or null
9270 getNextSibling : function(){
9271 var n = this.dom.nextSibling;
9272 while(n && n.nodeType != 1){
9279 * Gets the previous sibling, skipping text nodes
9280 * @return {HTMLElement} The previous sibling or null
9282 getPrevSibling : function(){
9283 var n = this.dom.previousSibling;
9284 while(n && n.nodeType != 1){
9285 n = n.previousSibling;
9292 * Appends the passed element(s) to this element
9293 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9294 * @return {Roo.Element} this
9296 appendChild: function(el){
9303 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9304 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9305 * automatically generated with the specified attributes.
9306 * @param {HTMLElement} insertBefore (optional) a child element of this element
9307 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9308 * @return {Roo.Element} The new child element
9310 createChild: function(config, insertBefore, returnDom){
9311 config = config || {tag:'div'};
9313 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9315 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9319 * Appends this element to the passed element
9320 * @param {String/HTMLElement/Element} el The new parent element
9321 * @return {Roo.Element} this
9323 appendTo: function(el){
9324 el = Roo.getDom(el);
9325 el.appendChild(this.dom);
9330 * Inserts this element before the passed element in the DOM
9331 * @param {String/HTMLElement/Element} el The element to insert before
9332 * @return {Roo.Element} this
9334 insertBefore: function(el){
9335 el = Roo.getDom(el);
9336 el.parentNode.insertBefore(this.dom, el);
9341 * Inserts this element after the passed element in the DOM
9342 * @param {String/HTMLElement/Element} el The element to insert after
9343 * @return {Roo.Element} this
9345 insertAfter: function(el){
9346 el = Roo.getDom(el);
9347 el.parentNode.insertBefore(this.dom, el.nextSibling);
9352 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9353 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9354 * @return {Roo.Element} The new child
9356 insertFirst: function(el, returnDom){
9358 if(typeof el == 'object' && !el.nodeType){ // dh config
9359 return this.createChild(el, this.dom.firstChild, returnDom);
9361 el = Roo.getDom(el);
9362 this.dom.insertBefore(el, this.dom.firstChild);
9363 return !returnDom ? Roo.get(el) : el;
9368 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9369 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9370 * @param {String} where (optional) 'before' or 'after' defaults to before
9371 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9372 * @return {Roo.Element} the inserted Element
9374 insertSibling: function(el, where, returnDom){
9375 where = where ? where.toLowerCase() : 'before';
9377 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9379 if(typeof el == 'object' && !el.nodeType){ // dh config
9380 if(where == 'after' && !this.dom.nextSibling){
9381 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9383 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9387 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9388 where == 'before' ? this.dom : this.dom.nextSibling);
9397 * Creates and wraps this element with another element
9398 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9399 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9400 * @return {HTMLElement/Element} The newly created wrapper element
9402 wrap: function(config, returnDom){
9404 config = {tag: "div"};
9406 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9407 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9412 * Replaces the passed element with this element
9413 * @param {String/HTMLElement/Element} el The element to replace
9414 * @return {Roo.Element} this
9416 replace: function(el){
9418 this.insertBefore(el);
9424 * Inserts an html fragment into this element
9425 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9426 * @param {String} html The HTML fragment
9427 * @param {Boolean} returnEl True to return an Roo.Element
9428 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9430 insertHtml : function(where, html, returnEl){
9431 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9432 return returnEl ? Roo.get(el) : el;
9436 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9437 * @param {Object} o The object with the attributes
9438 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9439 * @return {Roo.Element} this
9441 set : function(o, useSet){
9443 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9445 if(attr == "style" || typeof o[attr] == "function") { continue; }
9447 el.className = o["cls"];
9450 el.setAttribute(attr, o[attr]);
9457 Roo.DomHelper.applyStyles(el, o.style);
9463 * Convenience method for constructing a KeyMap
9464 * @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:
9465 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9466 * @param {Function} fn The function to call
9467 * @param {Object} scope (optional) The scope of the function
9468 * @return {Roo.KeyMap} The KeyMap created
9470 addKeyListener : function(key, fn, scope){
9472 if(typeof key != "object" || key instanceof Array){
9488 return new Roo.KeyMap(this, config);
9492 * Creates a KeyMap for this element
9493 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9494 * @return {Roo.KeyMap} The KeyMap created
9496 addKeyMap : function(config){
9497 return new Roo.KeyMap(this, config);
9501 * Returns true if this element is scrollable.
9504 isScrollable : function(){
9506 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9510 * 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().
9511 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9512 * @param {Number} value The new scroll value
9513 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9514 * @return {Element} this
9517 scrollTo : function(side, value, animate){
9518 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9520 this.dom[prop] = value;
9522 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9523 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9529 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9530 * within this element's scrollable range.
9531 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9532 * @param {Number} distance How far to scroll the element in pixels
9533 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9534 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9535 * was scrolled as far as it could go.
9537 scroll : function(direction, distance, animate){
9538 if(!this.isScrollable()){
9542 var l = el.scrollLeft, t = el.scrollTop;
9543 var w = el.scrollWidth, h = el.scrollHeight;
9544 var cw = el.clientWidth, ch = el.clientHeight;
9545 direction = direction.toLowerCase();
9546 var scrolled = false;
9547 var a = this.preanim(arguments, 2);
9552 var v = Math.min(l + distance, w-cw);
9553 this.scrollTo("left", v, a);
9560 var v = Math.max(l - distance, 0);
9561 this.scrollTo("left", v, a);
9569 var v = Math.max(t - distance, 0);
9570 this.scrollTo("top", v, a);
9578 var v = Math.min(t + distance, h-ch);
9579 this.scrollTo("top", v, a);
9588 * Translates the passed page coordinates into left/top css values for this element
9589 * @param {Number/Array} x The page x or an array containing [x, y]
9590 * @param {Number} y The page y
9591 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9593 translatePoints : function(x, y){
9594 if(typeof x == 'object' || x instanceof Array){
9597 var p = this.getStyle('position');
9598 var o = this.getXY();
9600 var l = parseInt(this.getStyle('left'), 10);
9601 var t = parseInt(this.getStyle('top'), 10);
9604 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9607 t = (p == "relative") ? 0 : this.dom.offsetTop;
9610 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9614 * Returns the current scroll position of the element.
9615 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9617 getScroll : function(){
9618 var d = this.dom, doc = document;
9619 if(d == doc || d == doc.body){
9620 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9621 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9622 return {left: l, top: t};
9624 return {left: d.scrollLeft, top: d.scrollTop};
9629 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9630 * are convert to standard 6 digit hex color.
9631 * @param {String} attr The css attribute
9632 * @param {String} defaultValue The default value to use when a valid color isn't found
9633 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9636 getColor : function(attr, defaultValue, prefix){
9637 var v = this.getStyle(attr);
9638 if(!v || v == "transparent" || v == "inherit") {
9639 return defaultValue;
9641 var color = typeof prefix == "undefined" ? "#" : prefix;
9642 if(v.substr(0, 4) == "rgb("){
9643 var rvs = v.slice(4, v.length -1).split(",");
9644 for(var i = 0; i < 3; i++){
9645 var h = parseInt(rvs[i]).toString(16);
9652 if(v.substr(0, 1) == "#"){
9654 for(var i = 1; i < 4; i++){
9655 var c = v.charAt(i);
9658 }else if(v.length == 7){
9659 color += v.substr(1);
9663 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9667 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9668 * gradient background, rounded corners and a 4-way shadow.
9669 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9670 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9671 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9672 * @return {Roo.Element} this
9674 boxWrap : function(cls){
9675 cls = cls || 'x-box';
9676 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9677 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9682 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9683 * @param {String} namespace The namespace in which to look for the attribute
9684 * @param {String} name The attribute name
9685 * @return {String} The attribute value
9687 getAttributeNS : Roo.isIE ? function(ns, name){
9689 var type = typeof d[ns+":"+name];
9690 if(type != 'undefined' && type != 'unknown'){
9691 return d[ns+":"+name];
9694 } : function(ns, name){
9696 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9701 * Sets or Returns the value the dom attribute value
9702 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9703 * @param {String} value (optional) The value to set the attribute to
9704 * @return {String} The attribute value
9706 attr : function(name){
9707 if (arguments.length > 1) {
9708 this.dom.setAttribute(name, arguments[1]);
9709 return arguments[1];
9711 if (typeof(name) == 'object') {
9712 for(var i in name) {
9713 this.attr(i, name[i]);
9719 if (!this.dom.hasAttribute(name)) {
9722 return this.dom.getAttribute(name);
9729 var ep = El.prototype;
9732 * Appends an event handler (Shorthand for addListener)
9733 * @param {String} eventName The type of event to append
9734 * @param {Function} fn The method the event invokes
9735 * @param {Object} scope (optional) The scope (this object) of the fn
9736 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9739 ep.on = ep.addListener;
9741 ep.mon = ep.addListener;
9744 * Removes an event handler from this element (shorthand for removeListener)
9745 * @param {String} eventName the type of event to remove
9746 * @param {Function} fn the method the event invokes
9747 * @return {Roo.Element} this
9750 ep.un = ep.removeListener;
9753 * true to automatically adjust width and height settings for box-model issues (default to true)
9755 ep.autoBoxAdjust = true;
9758 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9761 El.addUnits = function(v, defaultUnit){
9762 if(v === "" || v == "auto"){
9765 if(v === undefined){
9768 if(typeof v == "number" || !El.unitPattern.test(v)){
9769 return v + (defaultUnit || 'px');
9774 // special markup used throughout Roo when box wrapping elements
9775 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>';
9777 * Visibility mode constant - Use visibility to hide element
9783 * Visibility mode constant - Use display to hide element
9789 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9790 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9791 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9803 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9804 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9805 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9806 * @return {Element} The Element object
9809 El.get = function(el){
9811 if(!el){ return null; }
9812 if(typeof el == "string"){ // element id
9813 if(!(elm = document.getElementById(el))){
9816 if(ex = El.cache[el]){
9819 ex = El.cache[el] = new El(elm);
9822 }else if(el.tagName){ // dom element
9826 if(ex = El.cache[id]){
9829 ex = El.cache[id] = new El(el);
9832 }else if(el instanceof El){
9834 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9835 // catch case where it hasn't been appended
9836 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9839 }else if(el.isComposite){
9841 }else if(el instanceof Array){
9842 return El.select(el);
9843 }else if(el == document){
9844 // create a bogus element object representing the document object
9846 var f = function(){};
9847 f.prototype = El.prototype;
9849 docEl.dom = document;
9857 El.uncache = function(el){
9858 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9860 delete El.cache[a[i].id || a[i]];
9866 // Garbage collection - uncache elements/purge listeners on orphaned elements
9867 // so we don't hold a reference and cause the browser to retain them
9868 El.garbageCollect = function(){
9869 if(!Roo.enableGarbageCollector){
9870 clearInterval(El.collectorThread);
9873 for(var eid in El.cache){
9874 var el = El.cache[eid], d = el.dom;
9875 // -------------------------------------------------------
9876 // Determining what is garbage:
9877 // -------------------------------------------------------
9879 // dom node is null, definitely garbage
9880 // -------------------------------------------------------
9882 // no parentNode == direct orphan, definitely garbage
9883 // -------------------------------------------------------
9884 // !d.offsetParent && !document.getElementById(eid)
9885 // display none elements have no offsetParent so we will
9886 // also try to look it up by it's id. However, check
9887 // offsetParent first so we don't do unneeded lookups.
9888 // This enables collection of elements that are not orphans
9889 // directly, but somewhere up the line they have an orphan
9891 // -------------------------------------------------------
9892 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9893 delete El.cache[eid];
9894 if(d && Roo.enableListenerCollection){
9900 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9904 El.Flyweight = function(dom){
9907 El.Flyweight.prototype = El.prototype;
9909 El._flyweights = {};
9911 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9912 * the dom node can be overwritten by other code.
9913 * @param {String/HTMLElement} el The dom node or id
9914 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9915 * prevent conflicts (e.g. internally Roo uses "_internal")
9917 * @return {Element} The shared Element object
9919 El.fly = function(el, named){
9920 named = named || '_global';
9921 el = Roo.getDom(el);
9925 if(!El._flyweights[named]){
9926 El._flyweights[named] = new El.Flyweight();
9928 El._flyweights[named].dom = el;
9929 return El._flyweights[named];
9933 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9934 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9935 * Shorthand of {@link Roo.Element#get}
9936 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9937 * @return {Element} The Element object
9943 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9944 * the dom node can be overwritten by other code.
9945 * Shorthand of {@link Roo.Element#fly}
9946 * @param {String/HTMLElement} el The dom node or id
9947 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9948 * prevent conflicts (e.g. internally Roo uses "_internal")
9950 * @return {Element} The shared Element object
9956 // speedy lookup for elements never to box adjust
9957 var noBoxAdjust = Roo.isStrict ? {
9960 input:1, select:1, textarea:1
9962 if(Roo.isIE || Roo.isGecko){
9963 noBoxAdjust['button'] = 1;
9967 Roo.EventManager.on(window, 'unload', function(){
9969 delete El._flyweights;
9977 Roo.Element.selectorFunction = Roo.DomQuery.select;
9980 Roo.Element.select = function(selector, unique, root){
9982 if(typeof selector == "string"){
9983 els = Roo.Element.selectorFunction(selector, root);
9984 }else if(selector.length !== undefined){
9987 throw "Invalid selector";
9989 if(unique === true){
9990 return new Roo.CompositeElement(els);
9992 return new Roo.CompositeElementLite(els);
9996 * Selects elements based on the passed CSS selector to enable working on them as 1.
9997 * @param {String/Array} selector The CSS selector or an array of elements
9998 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9999 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10000 * @return {CompositeElementLite/CompositeElement}
10004 Roo.select = Roo.Element.select;
10021 * Ext JS Library 1.1.1
10022 * Copyright(c) 2006-2007, Ext JS, LLC.
10024 * Originally Released Under LGPL - original licence link has changed is not relivant.
10027 * <script type="text/javascript">
10032 //Notifies Element that fx methods are available
10033 Roo.enableFx = true;
10037 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10038 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10039 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10040 * Element effects to work.</p><br/>
10042 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10043 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10044 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10045 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10046 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10047 * expected results and should be done with care.</p><br/>
10049 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10050 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10053 ----- -----------------------------
10054 tl The top left corner
10055 t The center of the top edge
10056 tr The top right corner
10057 l The center of the left edge
10058 r The center of the right edge
10059 bl The bottom left corner
10060 b The center of the bottom edge
10061 br The bottom right corner
10063 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10064 * below are common options that can be passed to any Fx method.</b>
10065 * @cfg {Function} callback A function called when the effect is finished
10066 * @cfg {Object} scope The scope of the effect function
10067 * @cfg {String} easing A valid Easing value for the effect
10068 * @cfg {String} afterCls A css class to apply after the effect
10069 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10070 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10071 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10072 * effects that end with the element being visually hidden, ignored otherwise)
10073 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10074 * a function which returns such a specification that will be applied to the Element after the effect finishes
10075 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10076 * @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
10077 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10081 * Slides the element into view. An anchor point can be optionally passed to set the point of
10082 * origin for the slide effect. This function automatically handles wrapping the element with
10083 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10086 // default: slide the element in from the top
10089 // custom: slide the element in from the right with a 2-second duration
10090 el.slideIn('r', { duration: 2 });
10092 // common config options shown with default values
10098 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10099 * @param {Object} options (optional) Object literal with any of the Fx config options
10100 * @return {Roo.Element} The Element
10102 slideIn : function(anchor, o){
10103 var el = this.getFxEl();
10106 el.queueFx(o, function(){
10108 anchor = anchor || "t";
10110 // fix display to visibility
10113 // restore values after effect
10114 var r = this.getFxRestore();
10115 var b = this.getBox();
10116 // fixed size for slide
10120 var wrap = this.fxWrap(r.pos, o, "hidden");
10122 var st = this.dom.style;
10123 st.visibility = "visible";
10124 st.position = "absolute";
10126 // clear out temp styles after slide and unwrap
10127 var after = function(){
10128 el.fxUnwrap(wrap, r.pos, o);
10129 st.width = r.width;
10130 st.height = r.height;
10133 // time to calc the positions
10134 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10136 switch(anchor.toLowerCase()){
10138 wrap.setSize(b.width, 0);
10139 st.left = st.bottom = "0";
10143 wrap.setSize(0, b.height);
10144 st.right = st.top = "0";
10148 wrap.setSize(0, b.height);
10149 wrap.setX(b.right);
10150 st.left = st.top = "0";
10151 a = {width: bw, points: pt};
10154 wrap.setSize(b.width, 0);
10155 wrap.setY(b.bottom);
10156 st.left = st.top = "0";
10157 a = {height: bh, points: pt};
10160 wrap.setSize(0, 0);
10161 st.right = st.bottom = "0";
10162 a = {width: bw, height: bh};
10165 wrap.setSize(0, 0);
10166 wrap.setY(b.y+b.height);
10167 st.right = st.top = "0";
10168 a = {width: bw, height: bh, points: pt};
10171 wrap.setSize(0, 0);
10172 wrap.setXY([b.right, b.bottom]);
10173 st.left = st.top = "0";
10174 a = {width: bw, height: bh, points: pt};
10177 wrap.setSize(0, 0);
10178 wrap.setX(b.x+b.width);
10179 st.left = st.bottom = "0";
10180 a = {width: bw, height: bh, points: pt};
10183 this.dom.style.visibility = "visible";
10186 arguments.callee.anim = wrap.fxanim(a,
10196 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10197 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10198 * 'hidden') but block elements will still take up space in the document. The element must be removed
10199 * from the DOM using the 'remove' config option if desired. This function automatically handles
10200 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10203 // default: slide the element out to the top
10206 // custom: slide the element out to the right with a 2-second duration
10207 el.slideOut('r', { duration: 2 });
10209 // common config options shown with default values
10217 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10218 * @param {Object} options (optional) Object literal with any of the Fx config options
10219 * @return {Roo.Element} The Element
10221 slideOut : function(anchor, o){
10222 var el = this.getFxEl();
10225 el.queueFx(o, function(){
10227 anchor = anchor || "t";
10229 // restore values after effect
10230 var r = this.getFxRestore();
10232 var b = this.getBox();
10233 // fixed size for slide
10237 var wrap = this.fxWrap(r.pos, o, "visible");
10239 var st = this.dom.style;
10240 st.visibility = "visible";
10241 st.position = "absolute";
10245 var after = function(){
10247 el.setDisplayed(false);
10252 el.fxUnwrap(wrap, r.pos, o);
10254 st.width = r.width;
10255 st.height = r.height;
10260 var a, zero = {to: 0};
10261 switch(anchor.toLowerCase()){
10263 st.left = st.bottom = "0";
10264 a = {height: zero};
10267 st.right = st.top = "0";
10271 st.left = st.top = "0";
10272 a = {width: zero, points: {to:[b.right, b.y]}};
10275 st.left = st.top = "0";
10276 a = {height: zero, points: {to:[b.x, b.bottom]}};
10279 st.right = st.bottom = "0";
10280 a = {width: zero, height: zero};
10283 st.right = st.top = "0";
10284 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10287 st.left = st.top = "0";
10288 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10291 st.left = st.bottom = "0";
10292 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10296 arguments.callee.anim = wrap.fxanim(a,
10306 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10307 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10308 * The element must be removed from the DOM using the 'remove' config option if desired.
10314 // common config options shown with default values
10322 * @param {Object} options (optional) Object literal with any of the Fx config options
10323 * @return {Roo.Element} The Element
10325 puff : function(o){
10326 var el = this.getFxEl();
10329 el.queueFx(o, function(){
10330 this.clearOpacity();
10333 // restore values after effect
10334 var r = this.getFxRestore();
10335 var st = this.dom.style;
10337 var after = function(){
10339 el.setDisplayed(false);
10346 el.setPositioning(r.pos);
10347 st.width = r.width;
10348 st.height = r.height;
10353 var width = this.getWidth();
10354 var height = this.getHeight();
10356 arguments.callee.anim = this.fxanim({
10357 width : {to: this.adjustWidth(width * 2)},
10358 height : {to: this.adjustHeight(height * 2)},
10359 points : {by: [-(width * .5), -(height * .5)]},
10361 fontSize: {to:200, unit: "%"}
10372 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10373 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10374 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10380 // all config options shown with default values
10388 * @param {Object} options (optional) Object literal with any of the Fx config options
10389 * @return {Roo.Element} The Element
10391 switchOff : function(o){
10392 var el = this.getFxEl();
10395 el.queueFx(o, function(){
10396 this.clearOpacity();
10399 // restore values after effect
10400 var r = this.getFxRestore();
10401 var st = this.dom.style;
10403 var after = function(){
10405 el.setDisplayed(false);
10411 el.setPositioning(r.pos);
10412 st.width = r.width;
10413 st.height = r.height;
10418 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10419 this.clearOpacity();
10423 points:{by:[0, this.getHeight() * .5]}
10424 }, o, 'motion', 0.3, 'easeIn', after);
10425 }).defer(100, this);
10432 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10433 * changed using the "attr" config option) and then fading back to the original color. If no original
10434 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10437 // default: highlight background to yellow
10440 // custom: highlight foreground text to blue for 2 seconds
10441 el.highlight("0000ff", { attr: 'color', duration: 2 });
10443 // common config options shown with default values
10444 el.highlight("ffff9c", {
10445 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10446 endColor: (current color) or "ffffff",
10451 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10452 * @param {Object} options (optional) Object literal with any of the Fx config options
10453 * @return {Roo.Element} The Element
10455 highlight : function(color, o){
10456 var el = this.getFxEl();
10459 el.queueFx(o, function(){
10460 color = color || "ffff9c";
10461 attr = o.attr || "backgroundColor";
10463 this.clearOpacity();
10466 var origColor = this.getColor(attr);
10467 var restoreColor = this.dom.style[attr];
10468 endColor = (o.endColor || origColor) || "ffffff";
10470 var after = function(){
10471 el.dom.style[attr] = restoreColor;
10476 a[attr] = {from: color, to: endColor};
10477 arguments.callee.anim = this.fxanim(a,
10487 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10490 // default: a single light blue ripple
10493 // custom: 3 red ripples lasting 3 seconds total
10494 el.frame("ff0000", 3, { duration: 3 });
10496 // common config options shown with default values
10497 el.frame("C3DAF9", 1, {
10498 duration: 1 //duration of entire animation (not each individual ripple)
10499 // Note: Easing is not configurable and will be ignored if included
10502 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10503 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10504 * @param {Object} options (optional) Object literal with any of the Fx config options
10505 * @return {Roo.Element} The Element
10507 frame : function(color, count, o){
10508 var el = this.getFxEl();
10511 el.queueFx(o, function(){
10512 color = color || "#C3DAF9";
10513 if(color.length == 6){
10514 color = "#" + color;
10516 count = count || 1;
10517 duration = o.duration || 1;
10520 var b = this.getBox();
10521 var animFn = function(){
10522 var proxy = this.createProxy({
10525 visbility:"hidden",
10526 position:"absolute",
10527 "z-index":"35000", // yee haw
10528 border:"0px solid " + color
10531 var scale = Roo.isBorderBox ? 2 : 1;
10533 top:{from:b.y, to:b.y - 20},
10534 left:{from:b.x, to:b.x - 20},
10535 borderWidth:{from:0, to:10},
10536 opacity:{from:1, to:0},
10537 height:{from:b.height, to:(b.height + (20*scale))},
10538 width:{from:b.width, to:(b.width + (20*scale))}
10539 }, duration, function(){
10543 animFn.defer((duration/2)*1000, this);
10554 * Creates a pause before any subsequent queued effects begin. If there are
10555 * no effects queued after the pause it will have no effect.
10560 * @param {Number} seconds The length of time to pause (in seconds)
10561 * @return {Roo.Element} The Element
10563 pause : function(seconds){
10564 var el = this.getFxEl();
10567 el.queueFx(o, function(){
10568 setTimeout(function(){
10570 }, seconds * 1000);
10576 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10577 * using the "endOpacity" config option.
10580 // default: fade in from opacity 0 to 100%
10583 // custom: fade in from opacity 0 to 75% over 2 seconds
10584 el.fadeIn({ endOpacity: .75, duration: 2});
10586 // common config options shown with default values
10588 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10593 * @param {Object} options (optional) Object literal with any of the Fx config options
10594 * @return {Roo.Element} The Element
10596 fadeIn : function(o){
10597 var el = this.getFxEl();
10599 el.queueFx(o, function(){
10600 this.setOpacity(0);
10602 this.dom.style.visibility = 'visible';
10603 var to = o.endOpacity || 1;
10604 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10605 o, null, .5, "easeOut", function(){
10607 this.clearOpacity();
10616 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10617 * using the "endOpacity" config option.
10620 // default: fade out from the element's current opacity to 0
10623 // custom: fade out from the element's current opacity to 25% over 2 seconds
10624 el.fadeOut({ endOpacity: .25, duration: 2});
10626 // common config options shown with default values
10628 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10635 * @param {Object} options (optional) Object literal with any of the Fx config options
10636 * @return {Roo.Element} The Element
10638 fadeOut : function(o){
10639 var el = this.getFxEl();
10641 el.queueFx(o, function(){
10642 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10643 o, null, .5, "easeOut", function(){
10644 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10645 this.dom.style.display = "none";
10647 this.dom.style.visibility = "hidden";
10649 this.clearOpacity();
10657 * Animates the transition of an element's dimensions from a starting height/width
10658 * to an ending height/width.
10661 // change height and width to 100x100 pixels
10662 el.scale(100, 100);
10664 // common config options shown with default values. The height and width will default to
10665 // the element's existing values if passed as null.
10668 [element's height], {
10673 * @param {Number} width The new width (pass undefined to keep the original width)
10674 * @param {Number} height The new height (pass undefined to keep the original height)
10675 * @param {Object} options (optional) Object literal with any of the Fx config options
10676 * @return {Roo.Element} The Element
10678 scale : function(w, h, o){
10679 this.shift(Roo.apply({}, o, {
10687 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10688 * Any of these properties not specified in the config object will not be changed. This effect
10689 * requires that at least one new dimension, position or opacity setting must be passed in on
10690 * the config object in order for the function to have any effect.
10693 // slide the element horizontally to x position 200 while changing the height and opacity
10694 el.shift({ x: 200, height: 50, opacity: .8 });
10696 // common config options shown with default values.
10698 width: [element's width],
10699 height: [element's height],
10700 x: [element's x position],
10701 y: [element's y position],
10702 opacity: [element's opacity],
10707 * @param {Object} options Object literal with any of the Fx config options
10708 * @return {Roo.Element} The Element
10710 shift : function(o){
10711 var el = this.getFxEl();
10713 el.queueFx(o, function(){
10714 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10715 if(w !== undefined){
10716 a.width = {to: this.adjustWidth(w)};
10718 if(h !== undefined){
10719 a.height = {to: this.adjustHeight(h)};
10721 if(x !== undefined || y !== undefined){
10723 x !== undefined ? x : this.getX(),
10724 y !== undefined ? y : this.getY()
10727 if(op !== undefined){
10728 a.opacity = {to: op};
10730 if(o.xy !== undefined){
10731 a.points = {to: o.xy};
10733 arguments.callee.anim = this.fxanim(a,
10734 o, 'motion', .35, "easeOut", function(){
10742 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10743 * ending point of the effect.
10746 // default: slide the element downward while fading out
10749 // custom: slide the element out to the right with a 2-second duration
10750 el.ghost('r', { duration: 2 });
10752 // common config options shown with default values
10760 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10761 * @param {Object} options (optional) Object literal with any of the Fx config options
10762 * @return {Roo.Element} The Element
10764 ghost : function(anchor, o){
10765 var el = this.getFxEl();
10768 el.queueFx(o, function(){
10769 anchor = anchor || "b";
10771 // restore values after effect
10772 var r = this.getFxRestore();
10773 var w = this.getWidth(),
10774 h = this.getHeight();
10776 var st = this.dom.style;
10778 var after = function(){
10780 el.setDisplayed(false);
10786 el.setPositioning(r.pos);
10787 st.width = r.width;
10788 st.height = r.height;
10793 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10794 switch(anchor.toLowerCase()){
10821 arguments.callee.anim = this.fxanim(a,
10831 * Ensures that all effects queued after syncFx is called on the element are
10832 * run concurrently. This is the opposite of {@link #sequenceFx}.
10833 * @return {Roo.Element} The Element
10835 syncFx : function(){
10836 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10845 * Ensures that all effects queued after sequenceFx is called on the element are
10846 * run in sequence. This is the opposite of {@link #syncFx}.
10847 * @return {Roo.Element} The Element
10849 sequenceFx : function(){
10850 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10852 concurrent : false,
10859 nextFx : function(){
10860 var ef = this.fxQueue[0];
10867 * Returns true if the element has any effects actively running or queued, else returns false.
10868 * @return {Boolean} True if element has active effects, else false
10870 hasActiveFx : function(){
10871 return this.fxQueue && this.fxQueue[0];
10875 * Stops any running effects and clears the element's internal effects queue if it contains
10876 * any additional effects that haven't started yet.
10877 * @return {Roo.Element} The Element
10879 stopFx : function(){
10880 if(this.hasActiveFx()){
10881 var cur = this.fxQueue[0];
10882 if(cur && cur.anim && cur.anim.isAnimated()){
10883 this.fxQueue = [cur]; // clear out others
10884 cur.anim.stop(true);
10891 beforeFx : function(o){
10892 if(this.hasActiveFx() && !o.concurrent){
10903 * Returns true if the element is currently blocking so that no other effect can be queued
10904 * until this effect is finished, else returns false if blocking is not set. This is commonly
10905 * used to ensure that an effect initiated by a user action runs to completion prior to the
10906 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10907 * @return {Boolean} True if blocking, else false
10909 hasFxBlock : function(){
10910 var q = this.fxQueue;
10911 return q && q[0] && q[0].block;
10915 queueFx : function(o, fn){
10919 if(!this.hasFxBlock()){
10920 Roo.applyIf(o, this.fxDefaults);
10922 var run = this.beforeFx(o);
10923 fn.block = o.block;
10924 this.fxQueue.push(fn);
10936 fxWrap : function(pos, o, vis){
10938 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10941 wrapXY = this.getXY();
10943 var div = document.createElement("div");
10944 div.style.visibility = vis;
10945 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10946 wrap.setPositioning(pos);
10947 if(wrap.getStyle("position") == "static"){
10948 wrap.position("relative");
10950 this.clearPositioning('auto');
10952 wrap.dom.appendChild(this.dom);
10954 wrap.setXY(wrapXY);
10961 fxUnwrap : function(wrap, pos, o){
10962 this.clearPositioning();
10963 this.setPositioning(pos);
10965 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10971 getFxRestore : function(){
10972 var st = this.dom.style;
10973 return {pos: this.getPositioning(), width: st.width, height : st.height};
10977 afterFx : function(o){
10979 this.applyStyles(o.afterStyle);
10982 this.addClass(o.afterCls);
10984 if(o.remove === true){
10987 Roo.callback(o.callback, o.scope, [this]);
10989 this.fxQueue.shift();
10995 getFxEl : function(){ // support for composite element fx
10996 return Roo.get(this.dom);
11000 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11001 animType = animType || 'run';
11003 var anim = Roo.lib.Anim[animType](
11005 (opt.duration || defaultDur) || .35,
11006 (opt.easing || defaultEase) || 'easeOut',
11008 Roo.callback(cb, this);
11017 // backwords compat
11018 Roo.Fx.resize = Roo.Fx.scale;
11020 //When included, Roo.Fx is automatically applied to Element so that all basic
11021 //effects are available directly via the Element API
11022 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11024 * Ext JS Library 1.1.1
11025 * Copyright(c) 2006-2007, Ext JS, LLC.
11027 * Originally Released Under LGPL - original licence link has changed is not relivant.
11030 * <script type="text/javascript">
11035 * @class Roo.CompositeElement
11036 * Standard composite class. Creates a Roo.Element for every element in the collection.
11038 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11039 * actions will be performed on all the elements in this collection.</b>
11041 * All methods return <i>this</i> and can be chained.
11043 var els = Roo.select("#some-el div.some-class", true);
11044 // or select directly from an existing element
11045 var el = Roo.get('some-el');
11046 el.select('div.some-class', true);
11048 els.setWidth(100); // all elements become 100 width
11049 els.hide(true); // all elements fade out and hide
11051 els.setWidth(100).hide(true);
11054 Roo.CompositeElement = function(els){
11055 this.elements = [];
11056 this.addElements(els);
11058 Roo.CompositeElement.prototype = {
11060 addElements : function(els){
11064 if(typeof els == "string"){
11065 els = Roo.Element.selectorFunction(els);
11067 var yels = this.elements;
11068 var index = yels.length-1;
11069 for(var i = 0, len = els.length; i < len; i++) {
11070 yels[++index] = Roo.get(els[i]);
11076 * Clears this composite and adds the elements returned by the passed selector.
11077 * @param {String/Array} els A string CSS selector, an array of elements or an element
11078 * @return {CompositeElement} this
11080 fill : function(els){
11081 this.elements = [];
11087 * Filters this composite to only elements that match the passed selector.
11088 * @param {String} selector A string CSS selector
11089 * @param {Boolean} inverse return inverse filter (not matches)
11090 * @return {CompositeElement} this
11092 filter : function(selector, inverse){
11094 inverse = inverse || false;
11095 this.each(function(el){
11096 var match = inverse ? !el.is(selector) : el.is(selector);
11098 els[els.length] = el.dom;
11105 invoke : function(fn, args){
11106 var els = this.elements;
11107 for(var i = 0, len = els.length; i < len; i++) {
11108 Roo.Element.prototype[fn].apply(els[i], args);
11113 * Adds elements to this composite.
11114 * @param {String/Array} els A string CSS selector, an array of elements or an element
11115 * @return {CompositeElement} this
11117 add : function(els){
11118 if(typeof els == "string"){
11119 this.addElements(Roo.Element.selectorFunction(els));
11120 }else if(els.length !== undefined){
11121 this.addElements(els);
11123 this.addElements([els]);
11128 * Calls the passed function passing (el, this, index) for each element in this composite.
11129 * @param {Function} fn The function to call
11130 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11131 * @return {CompositeElement} this
11133 each : function(fn, scope){
11134 var els = this.elements;
11135 for(var i = 0, len = els.length; i < len; i++){
11136 if(fn.call(scope || els[i], els[i], this, i) === false) {
11144 * Returns the Element object at the specified index
11145 * @param {Number} index
11146 * @return {Roo.Element}
11148 item : function(index){
11149 return this.elements[index] || null;
11153 * Returns the first Element
11154 * @return {Roo.Element}
11156 first : function(){
11157 return this.item(0);
11161 * Returns the last Element
11162 * @return {Roo.Element}
11165 return this.item(this.elements.length-1);
11169 * Returns the number of elements in this composite
11172 getCount : function(){
11173 return this.elements.length;
11177 * Returns true if this composite contains the passed element
11180 contains : function(el){
11181 return this.indexOf(el) !== -1;
11185 * Returns true if this composite contains the passed element
11188 indexOf : function(el){
11189 return this.elements.indexOf(Roo.get(el));
11194 * Removes the specified element(s).
11195 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11196 * or an array of any of those.
11197 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11198 * @return {CompositeElement} this
11200 removeElement : function(el, removeDom){
11201 if(el instanceof Array){
11202 for(var i = 0, len = el.length; i < len; i++){
11203 this.removeElement(el[i]);
11207 var index = typeof el == 'number' ? el : this.indexOf(el);
11210 var d = this.elements[index];
11214 d.parentNode.removeChild(d);
11217 this.elements.splice(index, 1);
11223 * Replaces the specified element with the passed element.
11224 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11226 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11227 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11228 * @return {CompositeElement} this
11230 replaceElement : function(el, replacement, domReplace){
11231 var index = typeof el == 'number' ? el : this.indexOf(el);
11234 this.elements[index].replaceWith(replacement);
11236 this.elements.splice(index, 1, Roo.get(replacement))
11243 * Removes all elements.
11245 clear : function(){
11246 this.elements = [];
11250 Roo.CompositeElement.createCall = function(proto, fnName){
11251 if(!proto[fnName]){
11252 proto[fnName] = function(){
11253 return this.invoke(fnName, arguments);
11257 for(var fnName in Roo.Element.prototype){
11258 if(typeof Roo.Element.prototype[fnName] == "function"){
11259 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11265 * Ext JS Library 1.1.1
11266 * Copyright(c) 2006-2007, Ext JS, LLC.
11268 * Originally Released Under LGPL - original licence link has changed is not relivant.
11271 * <script type="text/javascript">
11275 * @class Roo.CompositeElementLite
11276 * @extends Roo.CompositeElement
11277 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11279 var els = Roo.select("#some-el div.some-class");
11280 // or select directly from an existing element
11281 var el = Roo.get('some-el');
11282 el.select('div.some-class');
11284 els.setWidth(100); // all elements become 100 width
11285 els.hide(true); // all elements fade out and hide
11287 els.setWidth(100).hide(true);
11288 </code></pre><br><br>
11289 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11290 * actions will be performed on all the elements in this collection.</b>
11292 Roo.CompositeElementLite = function(els){
11293 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11294 this.el = new Roo.Element.Flyweight();
11296 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11297 addElements : function(els){
11299 if(els instanceof Array){
11300 this.elements = this.elements.concat(els);
11302 var yels = this.elements;
11303 var index = yels.length-1;
11304 for(var i = 0, len = els.length; i < len; i++) {
11305 yels[++index] = els[i];
11311 invoke : function(fn, args){
11312 var els = this.elements;
11314 for(var i = 0, len = els.length; i < len; i++) {
11316 Roo.Element.prototype[fn].apply(el, args);
11321 * Returns a flyweight Element of the dom element object at the specified index
11322 * @param {Number} index
11323 * @return {Roo.Element}
11325 item : function(index){
11326 if(!this.elements[index]){
11329 this.el.dom = this.elements[index];
11333 // fixes scope with flyweight
11334 addListener : function(eventName, handler, scope, opt){
11335 var els = this.elements;
11336 for(var i = 0, len = els.length; i < len; i++) {
11337 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11343 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11344 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11345 * a reference to the dom node, use el.dom.</b>
11346 * @param {Function} fn The function to call
11347 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11348 * @return {CompositeElement} this
11350 each : function(fn, scope){
11351 var els = this.elements;
11353 for(var i = 0, len = els.length; i < len; i++){
11355 if(fn.call(scope || el, el, this, i) === false){
11362 indexOf : function(el){
11363 return this.elements.indexOf(Roo.getDom(el));
11366 replaceElement : function(el, replacement, domReplace){
11367 var index = typeof el == 'number' ? el : this.indexOf(el);
11369 replacement = Roo.getDom(replacement);
11371 var d = this.elements[index];
11372 d.parentNode.insertBefore(replacement, d);
11373 d.parentNode.removeChild(d);
11375 this.elements.splice(index, 1, replacement);
11380 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11384 * Ext JS Library 1.1.1
11385 * Copyright(c) 2006-2007, Ext JS, LLC.
11387 * Originally Released Under LGPL - original licence link has changed is not relivant.
11390 * <script type="text/javascript">
11396 * @class Roo.data.Connection
11397 * @extends Roo.util.Observable
11398 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11399 * either to a configured URL, or to a URL specified at request time.<br><br>
11401 * Requests made by this class are asynchronous, and will return immediately. No data from
11402 * the server will be available to the statement immediately following the {@link #request} call.
11403 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11405 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11406 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11407 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11408 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11409 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11410 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11411 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11412 * standard DOM methods.
11414 * @param {Object} config a configuration object.
11416 Roo.data.Connection = function(config){
11417 Roo.apply(this, config);
11420 * @event beforerequest
11421 * Fires before a network request is made to retrieve a data object.
11422 * @param {Connection} conn This Connection object.
11423 * @param {Object} options The options config object passed to the {@link #request} method.
11425 "beforerequest" : true,
11427 * @event requestcomplete
11428 * Fires if the request was successfully completed.
11429 * @param {Connection} conn This Connection object.
11430 * @param {Object} response The XHR object containing the response data.
11431 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11432 * @param {Object} options The options config object passed to the {@link #request} method.
11434 "requestcomplete" : true,
11436 * @event requestexception
11437 * Fires if an error HTTP status was returned from the server.
11438 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11439 * @param {Connection} conn This Connection object.
11440 * @param {Object} response The XHR object containing the response data.
11441 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11442 * @param {Object} options The options config object passed to the {@link #request} method.
11444 "requestexception" : true
11446 Roo.data.Connection.superclass.constructor.call(this);
11449 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11451 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11454 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11455 * extra parameters to each request made by this object. (defaults to undefined)
11458 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11459 * to each request made by this object. (defaults to undefined)
11462 * @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)
11465 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11469 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11475 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11478 disableCaching: true,
11481 * Sends an HTTP request to a remote server.
11482 * @param {Object} options An object which may contain the following properties:<ul>
11483 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11484 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11485 * request, a url encoded string or a function to call to get either.</li>
11486 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11487 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11488 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11489 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11490 * <li>options {Object} The parameter to the request call.</li>
11491 * <li>success {Boolean} True if the request succeeded.</li>
11492 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11494 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11495 * The callback is passed the following parameters:<ul>
11496 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11497 * <li>options {Object} The parameter to the request call.</li>
11499 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11500 * The callback is passed the following parameters:<ul>
11501 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11502 * <li>options {Object} The parameter to the request call.</li>
11504 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11505 * for the callback function. Defaults to the browser window.</li>
11506 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11507 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11508 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11509 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11510 * params for the post data. Any params will be appended to the URL.</li>
11511 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11513 * @return {Number} transactionId
11515 request : function(o){
11516 if(this.fireEvent("beforerequest", this, o) !== false){
11519 if(typeof p == "function"){
11520 p = p.call(o.scope||window, o);
11522 if(typeof p == "object"){
11523 p = Roo.urlEncode(o.params);
11525 if(this.extraParams){
11526 var extras = Roo.urlEncode(this.extraParams);
11527 p = p ? (p + '&' + extras) : extras;
11530 var url = o.url || this.url;
11531 if(typeof url == 'function'){
11532 url = url.call(o.scope||window, o);
11536 var form = Roo.getDom(o.form);
11537 url = url || form.action;
11539 var enctype = form.getAttribute("enctype");
11540 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11541 return this.doFormUpload(o, p, url);
11543 var f = Roo.lib.Ajax.serializeForm(form);
11544 p = p ? (p + '&' + f) : f;
11547 var hs = o.headers;
11548 if(this.defaultHeaders){
11549 hs = Roo.apply(hs || {}, this.defaultHeaders);
11556 success: this.handleResponse,
11557 failure: this.handleFailure,
11559 argument: {options: o},
11560 timeout : o.timeout || this.timeout
11563 var method = o.method||this.method||(p ? "POST" : "GET");
11565 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11566 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11569 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11573 }else if(this.autoAbort !== false){
11577 if((method == 'GET' && p) || o.xmlData){
11578 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11581 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11582 return this.transId;
11584 Roo.callback(o.callback, o.scope, [o, null, null]);
11590 * Determine whether this object has a request outstanding.
11591 * @param {Number} transactionId (Optional) defaults to the last transaction
11592 * @return {Boolean} True if there is an outstanding request.
11594 isLoading : function(transId){
11596 return Roo.lib.Ajax.isCallInProgress(transId);
11598 return this.transId ? true : false;
11603 * Aborts any outstanding request.
11604 * @param {Number} transactionId (Optional) defaults to the last transaction
11606 abort : function(transId){
11607 if(transId || this.isLoading()){
11608 Roo.lib.Ajax.abort(transId || this.transId);
11613 handleResponse : function(response){
11614 this.transId = false;
11615 var options = response.argument.options;
11616 response.argument = options ? options.argument : null;
11617 this.fireEvent("requestcomplete", this, response, options);
11618 Roo.callback(options.success, options.scope, [response, options]);
11619 Roo.callback(options.callback, options.scope, [options, true, response]);
11623 handleFailure : function(response, e){
11624 this.transId = false;
11625 var options = response.argument.options;
11626 response.argument = options ? options.argument : null;
11627 this.fireEvent("requestexception", this, response, options, e);
11628 Roo.callback(options.failure, options.scope, [response, options]);
11629 Roo.callback(options.callback, options.scope, [options, false, response]);
11633 doFormUpload : function(o, ps, url){
11635 var frame = document.createElement('iframe');
11638 frame.className = 'x-hidden';
11640 frame.src = Roo.SSL_SECURE_URL;
11642 document.body.appendChild(frame);
11645 document.frames[id].name = id;
11648 var form = Roo.getDom(o.form);
11650 form.method = 'POST';
11651 form.enctype = form.encoding = 'multipart/form-data';
11657 if(ps){ // add dynamic params
11659 ps = Roo.urlDecode(ps, false);
11661 if(ps.hasOwnProperty(k)){
11662 hd = document.createElement('input');
11663 hd.type = 'hidden';
11666 form.appendChild(hd);
11673 var r = { // bogus response object
11678 r.argument = o ? o.argument : null;
11683 doc = frame.contentWindow.document;
11685 doc = (frame.contentDocument || window.frames[id].document);
11687 if(doc && doc.body){
11688 r.responseText = doc.body.innerHTML;
11690 if(doc && doc.XMLDocument){
11691 r.responseXML = doc.XMLDocument;
11693 r.responseXML = doc;
11700 Roo.EventManager.removeListener(frame, 'load', cb, this);
11702 this.fireEvent("requestcomplete", this, r, o);
11703 Roo.callback(o.success, o.scope, [r, o]);
11704 Roo.callback(o.callback, o.scope, [o, true, r]);
11706 setTimeout(function(){document.body.removeChild(frame);}, 100);
11709 Roo.EventManager.on(frame, 'load', cb, this);
11712 if(hiddens){ // remove dynamic params
11713 for(var i = 0, len = hiddens.length; i < len; i++){
11714 form.removeChild(hiddens[i]);
11721 * Ext JS Library 1.1.1
11722 * Copyright(c) 2006-2007, Ext JS, LLC.
11724 * Originally Released Under LGPL - original licence link has changed is not relivant.
11727 * <script type="text/javascript">
11731 * Global Ajax request class.
11734 * @extends Roo.data.Connection
11737 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11738 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11739 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11740 * @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)
11741 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11742 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11743 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11745 Roo.Ajax = new Roo.data.Connection({
11754 * Serialize the passed form into a url encoded string
11756 * @param {String/HTMLElement} form
11759 serializeForm : function(form){
11760 return Roo.lib.Ajax.serializeForm(form);
11764 * Ext JS Library 1.1.1
11765 * Copyright(c) 2006-2007, Ext JS, LLC.
11767 * Originally Released Under LGPL - original licence link has changed is not relivant.
11770 * <script type="text/javascript">
11775 * @class Roo.UpdateManager
11776 * @extends Roo.util.Observable
11777 * Provides AJAX-style update for Element object.<br><br>
11780 * // Get it from a Roo.Element object
11781 * var el = Roo.get("foo");
11782 * var mgr = el.getUpdateManager();
11783 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11785 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11787 * // or directly (returns the same UpdateManager instance)
11788 * var mgr = new Roo.UpdateManager("myElementId");
11789 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11790 * mgr.on("update", myFcnNeedsToKnow);
11792 // short handed call directly from the element object
11793 Roo.get("foo").load({
11797 text: "Loading Foo..."
11801 * Create new UpdateManager directly.
11802 * @param {String/HTMLElement/Roo.Element} el The element to update
11803 * @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).
11805 Roo.UpdateManager = function(el, forceNew){
11807 if(!forceNew && el.updateManager){
11808 return el.updateManager;
11811 * The Element object
11812 * @type Roo.Element
11816 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11819 this.defaultUrl = null;
11823 * @event beforeupdate
11824 * Fired before an update is made, return false from your handler and the update is cancelled.
11825 * @param {Roo.Element} el
11826 * @param {String/Object/Function} url
11827 * @param {String/Object} params
11829 "beforeupdate": true,
11832 * Fired after successful update is made.
11833 * @param {Roo.Element} el
11834 * @param {Object} oResponseObject The response Object
11839 * Fired on update failure.
11840 * @param {Roo.Element} el
11841 * @param {Object} oResponseObject The response Object
11845 var d = Roo.UpdateManager.defaults;
11847 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11850 this.sslBlankUrl = d.sslBlankUrl;
11852 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11855 this.disableCaching = d.disableCaching;
11857 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11860 this.indicatorText = d.indicatorText;
11862 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11865 this.showLoadIndicator = d.showLoadIndicator;
11867 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11870 this.timeout = d.timeout;
11873 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11876 this.loadScripts = d.loadScripts;
11879 * Transaction object of current executing transaction
11881 this.transaction = null;
11886 this.autoRefreshProcId = null;
11888 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11891 this.refreshDelegate = this.refresh.createDelegate(this);
11893 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11896 this.updateDelegate = this.update.createDelegate(this);
11898 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11901 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11905 this.successDelegate = this.processSuccess.createDelegate(this);
11909 this.failureDelegate = this.processFailure.createDelegate(this);
11911 if(!this.renderer){
11913 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11915 this.renderer = new Roo.UpdateManager.BasicRenderer();
11918 Roo.UpdateManager.superclass.constructor.call(this);
11921 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11923 * Get the Element this UpdateManager is bound to
11924 * @return {Roo.Element} The element
11926 getEl : function(){
11930 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11931 * @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:
11934 url: "your-url.php",<br/>
11935 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11936 callback: yourFunction,<br/>
11937 scope: yourObject, //(optional scope) <br/>
11938 discardUrl: false, <br/>
11939 nocache: false,<br/>
11940 text: "Loading...",<br/>
11942 scripts: false<br/>
11945 * The only required property is url. The optional properties nocache, text and scripts
11946 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11947 * @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}
11948 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11949 * @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.
11951 update : function(url, params, callback, discardUrl){
11952 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11953 var method = this.method,
11955 if(typeof url == "object"){ // must be config object
11958 params = params || cfg.params;
11959 callback = callback || cfg.callback;
11960 discardUrl = discardUrl || cfg.discardUrl;
11961 if(callback && cfg.scope){
11962 callback = callback.createDelegate(cfg.scope);
11964 if(typeof cfg.method != "undefined"){method = cfg.method;};
11965 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11966 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11967 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11968 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11970 this.showLoading();
11972 this.defaultUrl = url;
11974 if(typeof url == "function"){
11975 url = url.call(this);
11978 method = method || (params ? "POST" : "GET");
11979 if(method == "GET"){
11980 url = this.prepareUrl(url);
11983 var o = Roo.apply(cfg ||{}, {
11986 success: this.successDelegate,
11987 failure: this.failureDelegate,
11988 callback: undefined,
11989 timeout: (this.timeout*1000),
11990 argument: {"url": url, "form": null, "callback": callback, "params": params}
11992 Roo.log("updated manager called with timeout of " + o.timeout);
11993 this.transaction = Roo.Ajax.request(o);
11998 * 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.
11999 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12000 * @param {String/HTMLElement} form The form Id or form element
12001 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12002 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12003 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12005 formUpdate : function(form, url, reset, callback){
12006 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12007 if(typeof url == "function"){
12008 url = url.call(this);
12010 form = Roo.getDom(form);
12011 this.transaction = Roo.Ajax.request({
12014 success: this.successDelegate,
12015 failure: this.failureDelegate,
12016 timeout: (this.timeout*1000),
12017 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12019 this.showLoading.defer(1, this);
12024 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12025 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12027 refresh : function(callback){
12028 if(this.defaultUrl == null){
12031 this.update(this.defaultUrl, null, callback, true);
12035 * Set this element to auto refresh.
12036 * @param {Number} interval How often to update (in seconds).
12037 * @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)
12038 * @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}
12039 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12040 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12042 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12044 this.update(url || this.defaultUrl, params, callback, true);
12046 if(this.autoRefreshProcId){
12047 clearInterval(this.autoRefreshProcId);
12049 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12053 * Stop auto refresh on this element.
12055 stopAutoRefresh : function(){
12056 if(this.autoRefreshProcId){
12057 clearInterval(this.autoRefreshProcId);
12058 delete this.autoRefreshProcId;
12062 isAutoRefreshing : function(){
12063 return this.autoRefreshProcId ? true : false;
12066 * Called to update the element to "Loading" state. Override to perform custom action.
12068 showLoading : function(){
12069 if(this.showLoadIndicator){
12070 this.el.update(this.indicatorText);
12075 * Adds unique parameter to query string if disableCaching = true
12078 prepareUrl : function(url){
12079 if(this.disableCaching){
12080 var append = "_dc=" + (new Date().getTime());
12081 if(url.indexOf("?") !== -1){
12082 url += "&" + append;
12084 url += "?" + append;
12093 processSuccess : function(response){
12094 this.transaction = null;
12095 if(response.argument.form && response.argument.reset){
12096 try{ // put in try/catch since some older FF releases had problems with this
12097 response.argument.form.reset();
12100 if(this.loadScripts){
12101 this.renderer.render(this.el, response, this,
12102 this.updateComplete.createDelegate(this, [response]));
12104 this.renderer.render(this.el, response, this);
12105 this.updateComplete(response);
12109 updateComplete : function(response){
12110 this.fireEvent("update", this.el, response);
12111 if(typeof response.argument.callback == "function"){
12112 response.argument.callback(this.el, true, response);
12119 processFailure : function(response){
12120 this.transaction = null;
12121 this.fireEvent("failure", this.el, response);
12122 if(typeof response.argument.callback == "function"){
12123 response.argument.callback(this.el, false, response);
12128 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12129 * @param {Object} renderer The object implementing the render() method
12131 setRenderer : function(renderer){
12132 this.renderer = renderer;
12135 getRenderer : function(){
12136 return this.renderer;
12140 * Set the defaultUrl used for updates
12141 * @param {String/Function} defaultUrl The url or a function to call to get the url
12143 setDefaultUrl : function(defaultUrl){
12144 this.defaultUrl = defaultUrl;
12148 * Aborts the executing transaction
12150 abort : function(){
12151 if(this.transaction){
12152 Roo.Ajax.abort(this.transaction);
12157 * Returns true if an update is in progress
12158 * @return {Boolean}
12160 isUpdating : function(){
12161 if(this.transaction){
12162 return Roo.Ajax.isLoading(this.transaction);
12169 * @class Roo.UpdateManager.defaults
12170 * @static (not really - but it helps the doc tool)
12171 * The defaults collection enables customizing the default properties of UpdateManager
12173 Roo.UpdateManager.defaults = {
12175 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12181 * True to process scripts by default (Defaults to false).
12184 loadScripts : false,
12187 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12190 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12192 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12195 disableCaching : false,
12197 * Whether to show indicatorText when loading (Defaults to true).
12200 showLoadIndicator : true,
12202 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12205 indicatorText : '<div class="loading-indicator">Loading...</div>'
12209 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12211 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12212 * @param {String/HTMLElement/Roo.Element} el The element to update
12213 * @param {String} url The url
12214 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12215 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12218 * @member Roo.UpdateManager
12220 Roo.UpdateManager.updateElement = function(el, url, params, options){
12221 var um = Roo.get(el, true).getUpdateManager();
12222 Roo.apply(um, options);
12223 um.update(url, params, options ? options.callback : null);
12225 // alias for backwards compat
12226 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12228 * @class Roo.UpdateManager.BasicRenderer
12229 * Default Content renderer. Updates the elements innerHTML with the responseText.
12231 Roo.UpdateManager.BasicRenderer = function(){};
12233 Roo.UpdateManager.BasicRenderer.prototype = {
12235 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12236 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12237 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12238 * @param {Roo.Element} el The element being rendered
12239 * @param {Object} response The YUI Connect response object
12240 * @param {UpdateManager} updateManager The calling update manager
12241 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12243 render : function(el, response, updateManager, callback){
12244 el.update(response.responseText, updateManager.loadScripts, callback);
12250 * (c)) Alan Knowles
12256 * @class Roo.DomTemplate
12257 * @extends Roo.Template
12258 * An effort at a dom based template engine..
12260 * Similar to XTemplate, except it uses dom parsing to create the template..
12262 * Supported features:
12267 {a_variable} - output encoded.
12268 {a_variable.format:("Y-m-d")} - call a method on the variable
12269 {a_variable:raw} - unencoded output
12270 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12271 {a_variable:this.method_on_template(...)} - call a method on the template object.
12276 <div roo-for="a_variable or condition.."></div>
12277 <div roo-if="a_variable or condition"></div>
12278 <div roo-exec="some javascript"></div>
12279 <div roo-name="named_template"></div>
12284 Roo.DomTemplate = function()
12286 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12293 Roo.extend(Roo.DomTemplate, Roo.Template, {
12295 * id counter for sub templates.
12299 * flag to indicate if dom parser is inside a pre,
12300 * it will strip whitespace if not.
12305 * The various sub templates
12313 * basic tag replacing syntax
12316 * // you can fake an object call by doing this
12320 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12321 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12323 iterChild : function (node, method) {
12325 var oldPre = this.inPre;
12326 if (node.tagName == 'PRE') {
12329 for( var i = 0; i < node.childNodes.length; i++) {
12330 method.call(this, node.childNodes[i]);
12332 this.inPre = oldPre;
12338 * compile the template
12340 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12343 compile: function()
12347 // covert the html into DOM...
12351 doc = document.implementation.createHTMLDocument("");
12352 doc.documentElement.innerHTML = this.html ;
12353 div = doc.documentElement;
12355 // old IE... - nasty -- it causes all sorts of issues.. with
12356 // images getting pulled from server..
12357 div = document.createElement('div');
12358 div.innerHTML = this.html;
12360 //doc.documentElement.innerHTML = htmlBody
12366 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12368 var tpls = this.tpls;
12370 // create a top level template from the snippet..
12372 //Roo.log(div.innerHTML);
12379 body : div.innerHTML,
12392 Roo.each(tpls, function(tp){
12393 this.compileTpl(tp);
12394 this.tpls[tp.id] = tp;
12397 this.master = tpls[0];
12403 compileNode : function(node, istop) {
12408 // skip anything not a tag..
12409 if (node.nodeType != 1) {
12410 if (node.nodeType == 3 && !this.inPre) {
12411 // reduce white space..
12412 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12435 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12436 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12437 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12438 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12444 // just itterate children..
12445 this.iterChild(node,this.compileNode);
12448 tpl.uid = this.id++;
12449 tpl.value = node.getAttribute('roo-' + tpl.attr);
12450 node.removeAttribute('roo-'+ tpl.attr);
12451 if (tpl.attr != 'name') {
12452 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12453 node.parentNode.replaceChild(placeholder, node);
12456 var placeholder = document.createElement('span');
12457 placeholder.className = 'roo-tpl-' + tpl.value;
12458 node.parentNode.replaceChild(placeholder, node);
12461 // parent now sees '{domtplXXXX}
12462 this.iterChild(node,this.compileNode);
12464 // we should now have node body...
12465 var div = document.createElement('div');
12466 div.appendChild(node);
12468 // this has the unfortunate side effect of converting tagged attributes
12469 // eg. href="{...}" into %7C...%7D
12470 // this has been fixed by searching for those combo's although it's a bit hacky..
12473 tpl.body = div.innerHTML;
12480 switch (tpl.value) {
12481 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12482 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12483 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12488 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12492 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12496 tpl.id = tpl.value; // replace non characters???
12502 this.tpls.push(tpl);
12512 * Compile a segment of the template into a 'sub-template'
12518 compileTpl : function(tpl)
12520 var fm = Roo.util.Format;
12521 var useF = this.disableFormats !== true;
12523 var sep = Roo.isGecko ? "+\n" : ",\n";
12525 var undef = function(str) {
12526 Roo.debug && Roo.log("Property not found :" + str);
12530 //Roo.log(tpl.body);
12534 var fn = function(m, lbrace, name, format, args)
12537 //Roo.log(arguments);
12538 args = args ? args.replace(/\\'/g,"'") : args;
12539 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12540 if (typeof(format) == 'undefined') {
12541 format = 'htmlEncode';
12543 if (format == 'raw' ) {
12547 if(name.substr(0, 6) == 'domtpl'){
12548 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12551 // build an array of options to determine if value is undefined..
12553 // basically get 'xxxx.yyyy' then do
12554 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12555 // (function () { Roo.log("Property not found"); return ''; })() :
12560 Roo.each(name.split('.'), function(st) {
12561 lookfor += (lookfor.length ? '.': '') + st;
12562 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12565 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12568 if(format && useF){
12570 args = args ? ',' + args : "";
12572 if(format.substr(0, 5) != "this."){
12573 format = "fm." + format + '(';
12575 format = 'this.call("'+ format.substr(5) + '", ';
12579 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12582 if (args && args.length) {
12583 // called with xxyx.yuu:(test,test)
12585 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12587 // raw.. - :raw modifier..
12588 return "'"+ sep + udef_st + name + ")"+sep+"'";
12592 // branched to use + in gecko and [].join() in others
12594 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12595 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12598 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12599 body.push(tpl.body.replace(/(\r\n|\n)/g,
12600 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12601 body.push("'].join('');};};");
12602 body = body.join('');
12605 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12607 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12614 * same as applyTemplate, except it's done to one of the subTemplates
12615 * when using named templates, you can do:
12617 * var str = pl.applySubTemplate('your-name', values);
12620 * @param {Number} id of the template
12621 * @param {Object} values to apply to template
12622 * @param {Object} parent (normaly the instance of this object)
12624 applySubTemplate : function(id, values, parent)
12628 var t = this.tpls[id];
12632 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12633 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12637 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12644 if(t.execCall && t.execCall.call(this, values, parent)){
12648 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12654 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12655 parent = t.target ? values : parent;
12656 if(t.forCall && vs instanceof Array){
12658 for(var i = 0, len = vs.length; i < len; i++){
12660 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12662 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12664 //Roo.log(t.compiled);
12668 return buf.join('');
12671 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12676 return t.compiled.call(this, vs, parent);
12678 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12680 //Roo.log(t.compiled);
12688 applyTemplate : function(values){
12689 return this.master.compiled.call(this, values, {});
12690 //var s = this.subs;
12693 apply : function(){
12694 return this.applyTemplate.apply(this, arguments);
12699 Roo.DomTemplate.from = function(el){
12700 el = Roo.getDom(el);
12701 return new Roo.Domtemplate(el.value || el.innerHTML);
12704 * Ext JS Library 1.1.1
12705 * Copyright(c) 2006-2007, Ext JS, LLC.
12707 * Originally Released Under LGPL - original licence link has changed is not relivant.
12710 * <script type="text/javascript">
12714 * @class Roo.util.DelayedTask
12715 * Provides a convenient method of performing setTimeout where a new
12716 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12717 * You can use this class to buffer
12718 * the keypress events for a certain number of milliseconds, and perform only if they stop
12719 * for that amount of time.
12720 * @constructor The parameters to this constructor serve as defaults and are not required.
12721 * @param {Function} fn (optional) The default function to timeout
12722 * @param {Object} scope (optional) The default scope of that timeout
12723 * @param {Array} args (optional) The default Array of arguments
12725 Roo.util.DelayedTask = function(fn, scope, args){
12726 var id = null, d, t;
12728 var call = function(){
12729 var now = new Date().getTime();
12733 fn.apply(scope, args || []);
12737 * Cancels any pending timeout and queues a new one
12738 * @param {Number} delay The milliseconds to delay
12739 * @param {Function} newFn (optional) Overrides function passed to constructor
12740 * @param {Object} newScope (optional) Overrides scope passed to constructor
12741 * @param {Array} newArgs (optional) Overrides args passed to constructor
12743 this.delay = function(delay, newFn, newScope, newArgs){
12744 if(id && delay != d){
12748 t = new Date().getTime();
12750 scope = newScope || scope;
12751 args = newArgs || args;
12753 id = setInterval(call, d);
12758 * Cancel the last queued timeout
12760 this.cancel = function(){
12768 * Ext JS Library 1.1.1
12769 * Copyright(c) 2006-2007, Ext JS, LLC.
12771 * Originally Released Under LGPL - original licence link has changed is not relivant.
12774 * <script type="text/javascript">
12778 Roo.util.TaskRunner = function(interval){
12779 interval = interval || 10;
12780 var tasks = [], removeQueue = [];
12782 var running = false;
12784 var stopThread = function(){
12790 var startThread = function(){
12793 id = setInterval(runTasks, interval);
12797 var removeTask = function(task){
12798 removeQueue.push(task);
12804 var runTasks = function(){
12805 if(removeQueue.length > 0){
12806 for(var i = 0, len = removeQueue.length; i < len; i++){
12807 tasks.remove(removeQueue[i]);
12810 if(tasks.length < 1){
12815 var now = new Date().getTime();
12816 for(var i = 0, len = tasks.length; i < len; ++i){
12818 var itime = now - t.taskRunTime;
12819 if(t.interval <= itime){
12820 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12821 t.taskRunTime = now;
12822 if(rt === false || t.taskRunCount === t.repeat){
12827 if(t.duration && t.duration <= (now - t.taskStartTime)){
12834 * Queues a new task.
12835 * @param {Object} task
12837 this.start = function(task){
12839 task.taskStartTime = new Date().getTime();
12840 task.taskRunTime = 0;
12841 task.taskRunCount = 0;
12846 this.stop = function(task){
12851 this.stopAll = function(){
12853 for(var i = 0, len = tasks.length; i < len; i++){
12854 if(tasks[i].onStop){
12863 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12865 * Ext JS Library 1.1.1
12866 * Copyright(c) 2006-2007, Ext JS, LLC.
12868 * Originally Released Under LGPL - original licence link has changed is not relivant.
12871 * <script type="text/javascript">
12876 * @class Roo.util.MixedCollection
12877 * @extends Roo.util.Observable
12878 * A Collection class that maintains both numeric indexes and keys and exposes events.
12880 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12881 * collection (defaults to false)
12882 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12883 * and return the key value for that item. This is used when available to look up the key on items that
12884 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12885 * equivalent to providing an implementation for the {@link #getKey} method.
12887 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12895 * Fires when the collection is cleared.
12900 * Fires when an item is added to the collection.
12901 * @param {Number} index The index at which the item was added.
12902 * @param {Object} o The item added.
12903 * @param {String} key The key associated with the added item.
12908 * Fires when an item is replaced in the collection.
12909 * @param {String} key he key associated with the new added.
12910 * @param {Object} old The item being replaced.
12911 * @param {Object} new The new item.
12916 * Fires when an item is removed from the collection.
12917 * @param {Object} o The item being removed.
12918 * @param {String} key (optional) The key associated with the removed item.
12923 this.allowFunctions = allowFunctions === true;
12925 this.getKey = keyFn;
12927 Roo.util.MixedCollection.superclass.constructor.call(this);
12930 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12931 allowFunctions : false,
12934 * Adds an item to the collection.
12935 * @param {String} key The key to associate with the item
12936 * @param {Object} o The item to add.
12937 * @return {Object} The item added.
12939 add : function(key, o){
12940 if(arguments.length == 1){
12942 key = this.getKey(o);
12944 if(typeof key == "undefined" || key === null){
12946 this.items.push(o);
12947 this.keys.push(null);
12949 var old = this.map[key];
12951 return this.replace(key, o);
12954 this.items.push(o);
12956 this.keys.push(key);
12958 this.fireEvent("add", this.length-1, o, key);
12963 * MixedCollection has a generic way to fetch keys if you implement getKey.
12966 var mc = new Roo.util.MixedCollection();
12967 mc.add(someEl.dom.id, someEl);
12968 mc.add(otherEl.dom.id, otherEl);
12972 var mc = new Roo.util.MixedCollection();
12973 mc.getKey = function(el){
12979 // or via the constructor
12980 var mc = new Roo.util.MixedCollection(false, function(el){
12986 * @param o {Object} The item for which to find the key.
12987 * @return {Object} The key for the passed item.
12989 getKey : function(o){
12994 * Replaces an item in the collection.
12995 * @param {String} key The key associated with the item to replace, or the item to replace.
12996 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12997 * @return {Object} The new item.
12999 replace : function(key, o){
13000 if(arguments.length == 1){
13002 key = this.getKey(o);
13004 var old = this.item(key);
13005 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13006 return this.add(key, o);
13008 var index = this.indexOfKey(key);
13009 this.items[index] = o;
13011 this.fireEvent("replace", key, old, o);
13016 * Adds all elements of an Array or an Object to the collection.
13017 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13018 * an Array of values, each of which are added to the collection.
13020 addAll : function(objs){
13021 if(arguments.length > 1 || objs instanceof Array){
13022 var args = arguments.length > 1 ? arguments : objs;
13023 for(var i = 0, len = args.length; i < len; i++){
13027 for(var key in objs){
13028 if(this.allowFunctions || typeof objs[key] != "function"){
13029 this.add(key, objs[key]);
13036 * Executes the specified function once for every item in the collection, passing each
13037 * item as the first and only parameter. returning false from the function will stop the iteration.
13038 * @param {Function} fn The function to execute for each item.
13039 * @param {Object} scope (optional) The scope in which to execute the function.
13041 each : function(fn, scope){
13042 var items = [].concat(this.items); // each safe for removal
13043 for(var i = 0, len = items.length; i < len; i++){
13044 if(fn.call(scope || items[i], items[i], i, len) === false){
13051 * Executes the specified function once for every key in the collection, passing each
13052 * key, and its associated item as the first two parameters.
13053 * @param {Function} fn The function to execute for each item.
13054 * @param {Object} scope (optional) The scope in which to execute the function.
13056 eachKey : function(fn, scope){
13057 for(var i = 0, len = this.keys.length; i < len; i++){
13058 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13063 * Returns the first item in the collection which elicits a true return value from the
13064 * passed selection function.
13065 * @param {Function} fn The selection function to execute for each item.
13066 * @param {Object} scope (optional) The scope in which to execute the function.
13067 * @return {Object} The first item in the collection which returned true from the selection function.
13069 find : function(fn, scope){
13070 for(var i = 0, len = this.items.length; i < len; i++){
13071 if(fn.call(scope || window, this.items[i], this.keys[i])){
13072 return this.items[i];
13079 * Inserts an item at the specified index in the collection.
13080 * @param {Number} index The index to insert the item at.
13081 * @param {String} key The key to associate with the new item, or the item itself.
13082 * @param {Object} o (optional) If the second parameter was a key, the new item.
13083 * @return {Object} The item inserted.
13085 insert : function(index, key, o){
13086 if(arguments.length == 2){
13088 key = this.getKey(o);
13090 if(index >= this.length){
13091 return this.add(key, o);
13094 this.items.splice(index, 0, o);
13095 if(typeof key != "undefined" && key != null){
13098 this.keys.splice(index, 0, key);
13099 this.fireEvent("add", index, o, key);
13104 * Removed an item from the collection.
13105 * @param {Object} o The item to remove.
13106 * @return {Object} The item removed.
13108 remove : function(o){
13109 return this.removeAt(this.indexOf(o));
13113 * Remove an item from a specified index in the collection.
13114 * @param {Number} index The index within the collection of the item to remove.
13116 removeAt : function(index){
13117 if(index < this.length && index >= 0){
13119 var o = this.items[index];
13120 this.items.splice(index, 1);
13121 var key = this.keys[index];
13122 if(typeof key != "undefined"){
13123 delete this.map[key];
13125 this.keys.splice(index, 1);
13126 this.fireEvent("remove", o, key);
13131 * Removed an item associated with the passed key fom the collection.
13132 * @param {String} key The key of the item to remove.
13134 removeKey : function(key){
13135 return this.removeAt(this.indexOfKey(key));
13139 * Returns the number of items in the collection.
13140 * @return {Number} the number of items in the collection.
13142 getCount : function(){
13143 return this.length;
13147 * Returns index within the collection of the passed Object.
13148 * @param {Object} o The item to find the index of.
13149 * @return {Number} index of the item.
13151 indexOf : function(o){
13152 if(!this.items.indexOf){
13153 for(var i = 0, len = this.items.length; i < len; i++){
13154 if(this.items[i] == o) {
13160 return this.items.indexOf(o);
13165 * Returns index within the collection of the passed key.
13166 * @param {String} key The key to find the index of.
13167 * @return {Number} index of the key.
13169 indexOfKey : function(key){
13170 if(!this.keys.indexOf){
13171 for(var i = 0, len = this.keys.length; i < len; i++){
13172 if(this.keys[i] == key) {
13178 return this.keys.indexOf(key);
13183 * Returns the item associated with the passed key OR index. Key has priority over index.
13184 * @param {String/Number} key The key or index of the item.
13185 * @return {Object} The item associated with the passed key.
13187 item : function(key){
13188 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13189 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13193 * Returns the item at the specified index.
13194 * @param {Number} index The index of the item.
13197 itemAt : function(index){
13198 return this.items[index];
13202 * Returns the item associated with the passed key.
13203 * @param {String/Number} key The key of the item.
13204 * @return {Object} The item associated with the passed key.
13206 key : function(key){
13207 return this.map[key];
13211 * Returns true if the collection contains the passed Object as an item.
13212 * @param {Object} o The Object to look for in the collection.
13213 * @return {Boolean} True if the collection contains the Object as an item.
13215 contains : function(o){
13216 return this.indexOf(o) != -1;
13220 * Returns true if the collection contains the passed Object as a key.
13221 * @param {String} key The key to look for in the collection.
13222 * @return {Boolean} True if the collection contains the Object as a key.
13224 containsKey : function(key){
13225 return typeof this.map[key] != "undefined";
13229 * Removes all items from the collection.
13231 clear : function(){
13236 this.fireEvent("clear");
13240 * Returns the first item in the collection.
13241 * @return {Object} the first item in the collection..
13243 first : function(){
13244 return this.items[0];
13248 * Returns the last item in the collection.
13249 * @return {Object} the last item in the collection..
13252 return this.items[this.length-1];
13255 _sort : function(property, dir, fn){
13256 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13257 fn = fn || function(a, b){
13260 var c = [], k = this.keys, items = this.items;
13261 for(var i = 0, len = items.length; i < len; i++){
13262 c[c.length] = {key: k[i], value: items[i], index: i};
13264 c.sort(function(a, b){
13265 var v = fn(a[property], b[property]) * dsc;
13267 v = (a.index < b.index ? -1 : 1);
13271 for(var i = 0, len = c.length; i < len; i++){
13272 items[i] = c[i].value;
13275 this.fireEvent("sort", this);
13279 * Sorts this collection with the passed comparison function
13280 * @param {String} direction (optional) "ASC" or "DESC"
13281 * @param {Function} fn (optional) comparison function
13283 sort : function(dir, fn){
13284 this._sort("value", dir, fn);
13288 * Sorts this collection by keys
13289 * @param {String} direction (optional) "ASC" or "DESC"
13290 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13292 keySort : function(dir, fn){
13293 this._sort("key", dir, fn || function(a, b){
13294 return String(a).toUpperCase()-String(b).toUpperCase();
13299 * Returns a range of items in this collection
13300 * @param {Number} startIndex (optional) defaults to 0
13301 * @param {Number} endIndex (optional) default to the last item
13302 * @return {Array} An array of items
13304 getRange : function(start, end){
13305 var items = this.items;
13306 if(items.length < 1){
13309 start = start || 0;
13310 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13313 for(var i = start; i <= end; i++) {
13314 r[r.length] = items[i];
13317 for(var i = start; i >= end; i--) {
13318 r[r.length] = items[i];
13325 * Filter the <i>objects</i> in this collection by a specific property.
13326 * Returns a new collection that has been filtered.
13327 * @param {String} property A property on your objects
13328 * @param {String/RegExp} value Either string that the property values
13329 * should start with or a RegExp to test against the property
13330 * @return {MixedCollection} The new filtered collection
13332 filter : function(property, value){
13333 if(!value.exec){ // not a regex
13334 value = String(value);
13335 if(value.length == 0){
13336 return this.clone();
13338 value = new RegExp("^" + Roo.escapeRe(value), "i");
13340 return this.filterBy(function(o){
13341 return o && value.test(o[property]);
13346 * Filter by a function. * Returns a new collection that has been filtered.
13347 * The passed function will be called with each
13348 * object in the collection. If the function returns true, the value is included
13349 * otherwise it is filtered.
13350 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13351 * @param {Object} scope (optional) The scope of the function (defaults to this)
13352 * @return {MixedCollection} The new filtered collection
13354 filterBy : function(fn, scope){
13355 var r = new Roo.util.MixedCollection();
13356 r.getKey = this.getKey;
13357 var k = this.keys, it = this.items;
13358 for(var i = 0, len = it.length; i < len; i++){
13359 if(fn.call(scope||this, it[i], k[i])){
13360 r.add(k[i], it[i]);
13367 * Creates a duplicate of this collection
13368 * @return {MixedCollection}
13370 clone : function(){
13371 var r = new Roo.util.MixedCollection();
13372 var k = this.keys, it = this.items;
13373 for(var i = 0, len = it.length; i < len; i++){
13374 r.add(k[i], it[i]);
13376 r.getKey = this.getKey;
13381 * Returns the item associated with the passed key or index.
13383 * @param {String/Number} key The key or index of the item.
13384 * @return {Object} The item associated with the passed key.
13386 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13388 * Ext JS Library 1.1.1
13389 * Copyright(c) 2006-2007, Ext JS, LLC.
13391 * Originally Released Under LGPL - original licence link has changed is not relivant.
13394 * <script type="text/javascript">
13397 * @class Roo.util.JSON
13398 * Modified version of Douglas Crockford"s json.js that doesn"t
13399 * mess with the Object prototype
13400 * http://www.json.org/js.html
13403 Roo.util.JSON = new (function(){
13404 var useHasOwn = {}.hasOwnProperty ? true : false;
13406 // crashes Safari in some instances
13407 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13409 var pad = function(n) {
13410 return n < 10 ? "0" + n : n;
13423 var encodeString = function(s){
13424 if (/["\\\x00-\x1f]/.test(s)) {
13425 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13430 c = b.charCodeAt();
13432 Math.floor(c / 16).toString(16) +
13433 (c % 16).toString(16);
13436 return '"' + s + '"';
13439 var encodeArray = function(o){
13440 var a = ["["], b, i, l = o.length, v;
13441 for (i = 0; i < l; i += 1) {
13443 switch (typeof v) {
13452 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13460 var encodeDate = function(o){
13461 return '"' + o.getFullYear() + "-" +
13462 pad(o.getMonth() + 1) + "-" +
13463 pad(o.getDate()) + "T" +
13464 pad(o.getHours()) + ":" +
13465 pad(o.getMinutes()) + ":" +
13466 pad(o.getSeconds()) + '"';
13470 * Encodes an Object, Array or other value
13471 * @param {Mixed} o The variable to encode
13472 * @return {String} The JSON string
13474 this.encode = function(o)
13476 // should this be extended to fully wrap stringify..
13478 if(typeof o == "undefined" || o === null){
13480 }else if(o instanceof Array){
13481 return encodeArray(o);
13482 }else if(o instanceof Date){
13483 return encodeDate(o);
13484 }else if(typeof o == "string"){
13485 return encodeString(o);
13486 }else if(typeof o == "number"){
13487 return isFinite(o) ? String(o) : "null";
13488 }else if(typeof o == "boolean"){
13491 var a = ["{"], b, i, v;
13493 if(!useHasOwn || o.hasOwnProperty(i)) {
13495 switch (typeof v) {
13504 a.push(this.encode(i), ":",
13505 v === null ? "null" : this.encode(v));
13516 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13517 * @param {String} json The JSON string
13518 * @return {Object} The resulting object
13520 this.decode = function(json){
13522 return /** eval:var:json */ eval("(" + json + ')');
13526 * Shorthand for {@link Roo.util.JSON#encode}
13527 * @member Roo encode
13529 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13531 * Shorthand for {@link Roo.util.JSON#decode}
13532 * @member Roo decode
13534 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13537 * Ext JS Library 1.1.1
13538 * Copyright(c) 2006-2007, Ext JS, LLC.
13540 * Originally Released Under LGPL - original licence link has changed is not relivant.
13543 * <script type="text/javascript">
13547 * @class Roo.util.Format
13548 * Reusable data formatting functions
13551 Roo.util.Format = function(){
13552 var trimRe = /^\s+|\s+$/g;
13555 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13556 * @param {String} value The string to truncate
13557 * @param {Number} length The maximum length to allow before truncating
13558 * @return {String} The converted text
13560 ellipsis : function(value, len){
13561 if(value && value.length > len){
13562 return value.substr(0, len-3)+"...";
13568 * Checks a reference and converts it to empty string if it is undefined
13569 * @param {Mixed} value Reference to check
13570 * @return {Mixed} Empty string if converted, otherwise the original value
13572 undef : function(value){
13573 return typeof value != "undefined" ? value : "";
13577 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13578 * @param {String} value The string to encode
13579 * @return {String} The encoded text
13581 htmlEncode : function(value){
13582 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13586 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13587 * @param {String} value The string to decode
13588 * @return {String} The decoded text
13590 htmlDecode : function(value){
13591 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13595 * Trims any whitespace from either side of a string
13596 * @param {String} value The text to trim
13597 * @return {String} The trimmed text
13599 trim : function(value){
13600 return String(value).replace(trimRe, "");
13604 * Returns a substring from within an original string
13605 * @param {String} value The original text
13606 * @param {Number} start The start index of the substring
13607 * @param {Number} length The length of the substring
13608 * @return {String} The substring
13610 substr : function(value, start, length){
13611 return String(value).substr(start, length);
13615 * Converts a string to all lower case letters
13616 * @param {String} value The text to convert
13617 * @return {String} The converted text
13619 lowercase : function(value){
13620 return String(value).toLowerCase();
13624 * Converts a string to all upper case letters
13625 * @param {String} value The text to convert
13626 * @return {String} The converted text
13628 uppercase : function(value){
13629 return String(value).toUpperCase();
13633 * Converts the first character only of a string to upper case
13634 * @param {String} value The text to convert
13635 * @return {String} The converted text
13637 capitalize : function(value){
13638 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13642 call : function(value, fn){
13643 if(arguments.length > 2){
13644 var args = Array.prototype.slice.call(arguments, 2);
13645 args.unshift(value);
13647 return /** eval:var:value */ eval(fn).apply(window, args);
13649 /** eval:var:value */
13650 return /** eval:var:value */ eval(fn).call(window, value);
13656 * safer version of Math.toFixed..??/
13657 * @param {Number/String} value The numeric value to format
13658 * @param {Number/String} value Decimal places
13659 * @return {String} The formatted currency string
13661 toFixed : function(v, n)
13663 // why not use to fixed - precision is buggered???
13665 return Math.round(v-0);
13667 var fact = Math.pow(10,n+1);
13668 v = (Math.round((v-0)*fact))/fact;
13669 var z = (''+fact).substring(2);
13670 if (v == Math.floor(v)) {
13671 return Math.floor(v) + '.' + z;
13674 // now just padd decimals..
13675 var ps = String(v).split('.');
13676 var fd = (ps[1] + z);
13677 var r = fd.substring(0,n);
13678 var rm = fd.substring(n);
13680 return ps[0] + '.' + r;
13682 r*=1; // turn it into a number;
13684 if (String(r).length != n) {
13687 r = String(r).substring(1); // chop the end off.
13690 return ps[0] + '.' + r;
13695 * Format a number as US currency
13696 * @param {Number/String} value The numeric value to format
13697 * @return {String} The formatted currency string
13699 usMoney : function(v){
13700 return '$' + Roo.util.Format.number(v);
13705 * eventually this should probably emulate php's number_format
13706 * @param {Number/String} value The numeric value to format
13707 * @param {Number} decimals number of decimal places
13708 * @return {String} The formatted currency string
13710 number : function(v,decimals)
13712 // multiply and round.
13713 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13714 var mul = Math.pow(10, decimals);
13715 var zero = String(mul).substring(1);
13716 v = (Math.round((v-0)*mul))/mul;
13718 // if it's '0' number.. then
13720 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13722 var ps = v.split('.');
13726 var r = /(\d+)(\d{3})/;
13728 while (r.test(whole)) {
13729 whole = whole.replace(r, '$1' + ',' + '$2');
13735 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13736 // does not have decimals
13737 (decimals ? ('.' + zero) : '');
13740 return whole + sub ;
13744 * Parse a value into a formatted date using the specified format pattern.
13745 * @param {Mixed} value The value to format
13746 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13747 * @return {String} The formatted date string
13749 date : function(v, format){
13753 if(!(v instanceof Date)){
13754 v = new Date(Date.parse(v));
13756 return v.dateFormat(format || Roo.util.Format.defaults.date);
13760 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13761 * @param {String} format Any valid date format string
13762 * @return {Function} The date formatting function
13764 dateRenderer : function(format){
13765 return function(v){
13766 return Roo.util.Format.date(v, format);
13771 stripTagsRE : /<\/?[^>]+>/gi,
13774 * Strips all HTML tags
13775 * @param {Mixed} value The text from which to strip tags
13776 * @return {String} The stripped text
13778 stripTags : function(v){
13779 return !v ? v : String(v).replace(this.stripTagsRE, "");
13783 Roo.util.Format.defaults = {
13787 * Ext JS Library 1.1.1
13788 * Copyright(c) 2006-2007, Ext JS, LLC.
13790 * Originally Released Under LGPL - original licence link has changed is not relivant.
13793 * <script type="text/javascript">
13800 * @class Roo.MasterTemplate
13801 * @extends Roo.Template
13802 * Provides a template that can have child templates. The syntax is:
13804 var t = new Roo.MasterTemplate(
13805 '<select name="{name}">',
13806 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13809 t.add('options', {value: 'foo', text: 'bar'});
13810 // or you can add multiple child elements in one shot
13811 t.addAll('options', [
13812 {value: 'foo', text: 'bar'},
13813 {value: 'foo2', text: 'bar2'},
13814 {value: 'foo3', text: 'bar3'}
13816 // then append, applying the master template values
13817 t.append('my-form', {name: 'my-select'});
13819 * A name attribute for the child template is not required if you have only one child
13820 * template or you want to refer to them by index.
13822 Roo.MasterTemplate = function(){
13823 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13824 this.originalHtml = this.html;
13826 var m, re = this.subTemplateRe;
13829 while(m = re.exec(this.html)){
13830 var name = m[1], content = m[2];
13835 tpl : new Roo.Template(content)
13838 st[name] = st[subIndex];
13840 st[subIndex].tpl.compile();
13841 st[subIndex].tpl.call = this.call.createDelegate(this);
13844 this.subCount = subIndex;
13847 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13849 * The regular expression used to match sub templates
13853 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13856 * Applies the passed values to a child template.
13857 * @param {String/Number} name (optional) The name or index of the child template
13858 * @param {Array/Object} values The values to be applied to the template
13859 * @return {MasterTemplate} this
13861 add : function(name, values){
13862 if(arguments.length == 1){
13863 values = arguments[0];
13866 var s = this.subs[name];
13867 s.buffer[s.buffer.length] = s.tpl.apply(values);
13872 * Applies all the passed values to a child template.
13873 * @param {String/Number} name (optional) The name or index of the child template
13874 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13875 * @param {Boolean} reset (optional) True to reset the template first
13876 * @return {MasterTemplate} this
13878 fill : function(name, values, reset){
13880 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13888 for(var i = 0, len = values.length; i < len; i++){
13889 this.add(name, values[i]);
13895 * Resets the template for reuse
13896 * @return {MasterTemplate} this
13898 reset : function(){
13900 for(var i = 0; i < this.subCount; i++){
13906 applyTemplate : function(values){
13908 var replaceIndex = -1;
13909 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13910 return s[++replaceIndex].buffer.join("");
13912 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13915 apply : function(){
13916 return this.applyTemplate.apply(this, arguments);
13919 compile : function(){return this;}
13923 * Alias for fill().
13926 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13928 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13929 * var tpl = Roo.MasterTemplate.from('element-id');
13930 * @param {String/HTMLElement} el
13931 * @param {Object} config
13934 Roo.MasterTemplate.from = function(el, config){
13935 el = Roo.getDom(el);
13936 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13939 * Ext JS Library 1.1.1
13940 * Copyright(c) 2006-2007, Ext JS, LLC.
13942 * Originally Released Under LGPL - original licence link has changed is not relivant.
13945 * <script type="text/javascript">
13950 * @class Roo.util.CSS
13951 * Utility class for manipulating CSS rules
13954 Roo.util.CSS = function(){
13956 var doc = document;
13958 var camelRe = /(-[a-z])/gi;
13959 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13963 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13964 * tag and appended to the HEAD of the document.
13965 * @param {String|Object} cssText The text containing the css rules
13966 * @param {String} id An id to add to the stylesheet for later removal
13967 * @return {StyleSheet}
13969 createStyleSheet : function(cssText, id){
13971 var head = doc.getElementsByTagName("head")[0];
13972 var nrules = doc.createElement("style");
13973 nrules.setAttribute("type", "text/css");
13975 nrules.setAttribute("id", id);
13977 if (typeof(cssText) != 'string') {
13978 // support object maps..
13979 // not sure if this a good idea..
13980 // perhaps it should be merged with the general css handling
13981 // and handle js style props.
13982 var cssTextNew = [];
13983 for(var n in cssText) {
13985 for(var k in cssText[n]) {
13986 citems.push( k + ' : ' +cssText[n][k] + ';' );
13988 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13991 cssText = cssTextNew.join("\n");
13997 head.appendChild(nrules);
13998 ss = nrules.styleSheet;
13999 ss.cssText = cssText;
14002 nrules.appendChild(doc.createTextNode(cssText));
14004 nrules.cssText = cssText;
14006 head.appendChild(nrules);
14007 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14009 this.cacheStyleSheet(ss);
14014 * Removes a style or link tag by id
14015 * @param {String} id The id of the tag
14017 removeStyleSheet : function(id){
14018 var existing = doc.getElementById(id);
14020 existing.parentNode.removeChild(existing);
14025 * Dynamically swaps an existing stylesheet reference for a new one
14026 * @param {String} id The id of an existing link tag to remove
14027 * @param {String} url The href of the new stylesheet to include
14029 swapStyleSheet : function(id, url){
14030 this.removeStyleSheet(id);
14031 var ss = doc.createElement("link");
14032 ss.setAttribute("rel", "stylesheet");
14033 ss.setAttribute("type", "text/css");
14034 ss.setAttribute("id", id);
14035 ss.setAttribute("href", url);
14036 doc.getElementsByTagName("head")[0].appendChild(ss);
14040 * Refresh the rule cache if you have dynamically added stylesheets
14041 * @return {Object} An object (hash) of rules indexed by selector
14043 refreshCache : function(){
14044 return this.getRules(true);
14048 cacheStyleSheet : function(stylesheet){
14052 try{// try catch for cross domain access issue
14053 var ssRules = stylesheet.cssRules || stylesheet.rules;
14054 for(var j = ssRules.length-1; j >= 0; --j){
14055 rules[ssRules[j].selectorText] = ssRules[j];
14061 * Gets all css rules for the document
14062 * @param {Boolean} refreshCache true to refresh the internal cache
14063 * @return {Object} An object (hash) of rules indexed by selector
14065 getRules : function(refreshCache){
14066 if(rules == null || refreshCache){
14068 var ds = doc.styleSheets;
14069 for(var i =0, len = ds.length; i < len; i++){
14071 this.cacheStyleSheet(ds[i]);
14079 * Gets an an individual CSS rule by selector(s)
14080 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14081 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14082 * @return {CSSRule} The CSS rule or null if one is not found
14084 getRule : function(selector, refreshCache){
14085 var rs = this.getRules(refreshCache);
14086 if(!(selector instanceof Array)){
14087 return rs[selector];
14089 for(var i = 0; i < selector.length; i++){
14090 if(rs[selector[i]]){
14091 return rs[selector[i]];
14099 * Updates a rule property
14100 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14101 * @param {String} property The css property
14102 * @param {String} value The new value for the property
14103 * @return {Boolean} true If a rule was found and updated
14105 updateRule : function(selector, property, value){
14106 if(!(selector instanceof Array)){
14107 var rule = this.getRule(selector);
14109 rule.style[property.replace(camelRe, camelFn)] = value;
14113 for(var i = 0; i < selector.length; i++){
14114 if(this.updateRule(selector[i], property, value)){
14124 * Ext JS Library 1.1.1
14125 * Copyright(c) 2006-2007, Ext JS, LLC.
14127 * Originally Released Under LGPL - original licence link has changed is not relivant.
14130 * <script type="text/javascript">
14136 * @class Roo.util.ClickRepeater
14137 * @extends Roo.util.Observable
14139 * A wrapper class which can be applied to any element. Fires a "click" event while the
14140 * mouse is pressed. The interval between firings may be specified in the config but
14141 * defaults to 10 milliseconds.
14143 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14145 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14146 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14147 * Similar to an autorepeat key delay.
14148 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14149 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14150 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14151 * "interval" and "delay" are ignored. "immediate" is honored.
14152 * @cfg {Boolean} preventDefault True to prevent the default click event
14153 * @cfg {Boolean} stopDefault True to stop the default click event
14156 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14157 * 2007-02-02 jvs Renamed to ClickRepeater
14158 * 2007-02-03 jvs Modifications for FF Mac and Safari
14161 * @param {String/HTMLElement/Element} el The element to listen on
14162 * @param {Object} config
14164 Roo.util.ClickRepeater = function(el, config)
14166 this.el = Roo.get(el);
14167 this.el.unselectable();
14169 Roo.apply(this, config);
14174 * Fires when the mouse button is depressed.
14175 * @param {Roo.util.ClickRepeater} this
14177 "mousedown" : true,
14180 * Fires on a specified interval during the time the element is pressed.
14181 * @param {Roo.util.ClickRepeater} this
14186 * Fires when the mouse key is released.
14187 * @param {Roo.util.ClickRepeater} this
14192 this.el.on("mousedown", this.handleMouseDown, this);
14193 if(this.preventDefault || this.stopDefault){
14194 this.el.on("click", function(e){
14195 if(this.preventDefault){
14196 e.preventDefault();
14198 if(this.stopDefault){
14204 // allow inline handler
14206 this.on("click", this.handler, this.scope || this);
14209 Roo.util.ClickRepeater.superclass.constructor.call(this);
14212 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14215 preventDefault : true,
14216 stopDefault : false,
14220 handleMouseDown : function(){
14221 clearTimeout(this.timer);
14223 if(this.pressClass){
14224 this.el.addClass(this.pressClass);
14226 this.mousedownTime = new Date();
14228 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14229 this.el.on("mouseout", this.handleMouseOut, this);
14231 this.fireEvent("mousedown", this);
14232 this.fireEvent("click", this);
14234 this.timer = this.click.defer(this.delay || this.interval, this);
14238 click : function(){
14239 this.fireEvent("click", this);
14240 this.timer = this.click.defer(this.getInterval(), this);
14244 getInterval: function(){
14245 if(!this.accelerate){
14246 return this.interval;
14248 var pressTime = this.mousedownTime.getElapsed();
14249 if(pressTime < 500){
14251 }else if(pressTime < 1700){
14253 }else if(pressTime < 2600){
14255 }else if(pressTime < 3500){
14257 }else if(pressTime < 4400){
14259 }else if(pressTime < 5300){
14261 }else if(pressTime < 6200){
14269 handleMouseOut : function(){
14270 clearTimeout(this.timer);
14271 if(this.pressClass){
14272 this.el.removeClass(this.pressClass);
14274 this.el.on("mouseover", this.handleMouseReturn, this);
14278 handleMouseReturn : function(){
14279 this.el.un("mouseover", this.handleMouseReturn);
14280 if(this.pressClass){
14281 this.el.addClass(this.pressClass);
14287 handleMouseUp : function(){
14288 clearTimeout(this.timer);
14289 this.el.un("mouseover", this.handleMouseReturn);
14290 this.el.un("mouseout", this.handleMouseOut);
14291 Roo.get(document).un("mouseup", this.handleMouseUp);
14292 this.el.removeClass(this.pressClass);
14293 this.fireEvent("mouseup", this);
14297 * Ext JS Library 1.1.1
14298 * Copyright(c) 2006-2007, Ext JS, LLC.
14300 * Originally Released Under LGPL - original licence link has changed is not relivant.
14303 * <script type="text/javascript">
14308 * @class Roo.KeyNav
14309 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14310 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14311 * way to implement custom navigation schemes for any UI component.</p>
14312 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14313 * pageUp, pageDown, del, home, end. Usage:</p>
14315 var nav = new Roo.KeyNav("my-element", {
14316 "left" : function(e){
14317 this.moveLeft(e.ctrlKey);
14319 "right" : function(e){
14320 this.moveRight(e.ctrlKey);
14322 "enter" : function(e){
14329 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14330 * @param {Object} config The config
14332 Roo.KeyNav = function(el, config){
14333 this.el = Roo.get(el);
14334 Roo.apply(this, config);
14335 if(!this.disabled){
14336 this.disabled = true;
14341 Roo.KeyNav.prototype = {
14343 * @cfg {Boolean} disabled
14344 * True to disable this KeyNav instance (defaults to false)
14348 * @cfg {String} defaultEventAction
14349 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14350 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14351 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14353 defaultEventAction: "stopEvent",
14355 * @cfg {Boolean} forceKeyDown
14356 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14357 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14358 * handle keydown instead of keypress.
14360 forceKeyDown : false,
14363 prepareEvent : function(e){
14364 var k = e.getKey();
14365 var h = this.keyToHandler[k];
14366 //if(h && this[h]){
14367 // e.stopPropagation();
14369 if(Roo.isSafari && h && k >= 37 && k <= 40){
14375 relay : function(e){
14376 var k = e.getKey();
14377 var h = this.keyToHandler[k];
14379 if(this.doRelay(e, this[h], h) !== true){
14380 e[this.defaultEventAction]();
14386 doRelay : function(e, h, hname){
14387 return h.call(this.scope || this, e);
14390 // possible handlers
14404 // quick lookup hash
14421 * Enable this KeyNav
14423 enable: function(){
14425 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14426 // the EventObject will normalize Safari automatically
14427 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14428 this.el.on("keydown", this.relay, this);
14430 this.el.on("keydown", this.prepareEvent, this);
14431 this.el.on("keypress", this.relay, this);
14433 this.disabled = false;
14438 * Disable this KeyNav
14440 disable: function(){
14441 if(!this.disabled){
14442 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14443 this.el.un("keydown", this.relay);
14445 this.el.un("keydown", this.prepareEvent);
14446 this.el.un("keypress", this.relay);
14448 this.disabled = true;
14453 * Ext JS Library 1.1.1
14454 * Copyright(c) 2006-2007, Ext JS, LLC.
14456 * Originally Released Under LGPL - original licence link has changed is not relivant.
14459 * <script type="text/javascript">
14464 * @class Roo.KeyMap
14465 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14466 * The constructor accepts the same config object as defined by {@link #addBinding}.
14467 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14468 * combination it will call the function with this signature (if the match is a multi-key
14469 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14470 * A KeyMap can also handle a string representation of keys.<br />
14473 // map one key by key code
14474 var map = new Roo.KeyMap("my-element", {
14475 key: 13, // or Roo.EventObject.ENTER
14480 // map multiple keys to one action by string
14481 var map = new Roo.KeyMap("my-element", {
14487 // map multiple keys to multiple actions by strings and array of codes
14488 var map = new Roo.KeyMap("my-element", [
14491 fn: function(){ alert("Return was pressed"); }
14494 fn: function(){ alert('a, b or c was pressed'); }
14499 fn: function(){ alert('Control + shift + tab was pressed.'); }
14503 * <b>Note: A KeyMap starts enabled</b>
14505 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14506 * @param {Object} config The config (see {@link #addBinding})
14507 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14509 Roo.KeyMap = function(el, config, eventName){
14510 this.el = Roo.get(el);
14511 this.eventName = eventName || "keydown";
14512 this.bindings = [];
14514 this.addBinding(config);
14519 Roo.KeyMap.prototype = {
14521 * True to stop the event from bubbling and prevent the default browser action if the
14522 * key was handled by the KeyMap (defaults to false)
14528 * Add a new binding to this KeyMap. The following config object properties are supported:
14530 Property Type Description
14531 ---------- --------------- ----------------------------------------------------------------------
14532 key String/Array A single keycode or an array of keycodes to handle
14533 shift Boolean True to handle key only when shift is pressed (defaults to false)
14534 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14535 alt Boolean True to handle key only when alt is pressed (defaults to false)
14536 fn Function The function to call when KeyMap finds the expected key combination
14537 scope Object The scope of the callback function
14543 var map = new Roo.KeyMap(document, {
14544 key: Roo.EventObject.ENTER,
14549 //Add a new binding to the existing KeyMap later
14557 * @param {Object/Array} config A single KeyMap config or an array of configs
14559 addBinding : function(config){
14560 if(config instanceof Array){
14561 for(var i = 0, len = config.length; i < len; i++){
14562 this.addBinding(config[i]);
14566 var keyCode = config.key,
14567 shift = config.shift,
14568 ctrl = config.ctrl,
14571 scope = config.scope;
14572 if(typeof keyCode == "string"){
14574 var keyString = keyCode.toUpperCase();
14575 for(var j = 0, len = keyString.length; j < len; j++){
14576 ks.push(keyString.charCodeAt(j));
14580 var keyArray = keyCode instanceof Array;
14581 var handler = function(e){
14582 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14583 var k = e.getKey();
14585 for(var i = 0, len = keyCode.length; i < len; i++){
14586 if(keyCode[i] == k){
14587 if(this.stopEvent){
14590 fn.call(scope || window, k, e);
14596 if(this.stopEvent){
14599 fn.call(scope || window, k, e);
14604 this.bindings.push(handler);
14608 * Shorthand for adding a single key listener
14609 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14610 * following options:
14611 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14612 * @param {Function} fn The function to call
14613 * @param {Object} scope (optional) The scope of the function
14615 on : function(key, fn, scope){
14616 var keyCode, shift, ctrl, alt;
14617 if(typeof key == "object" && !(key instanceof Array)){
14636 handleKeyDown : function(e){
14637 if(this.enabled){ //just in case
14638 var b = this.bindings;
14639 for(var i = 0, len = b.length; i < len; i++){
14640 b[i].call(this, e);
14646 * Returns true if this KeyMap is enabled
14647 * @return {Boolean}
14649 isEnabled : function(){
14650 return this.enabled;
14654 * Enables this KeyMap
14656 enable: function(){
14658 this.el.on(this.eventName, this.handleKeyDown, this);
14659 this.enabled = true;
14664 * Disable this KeyMap
14666 disable: function(){
14668 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14669 this.enabled = false;
14674 * Ext JS Library 1.1.1
14675 * Copyright(c) 2006-2007, Ext JS, LLC.
14677 * Originally Released Under LGPL - original licence link has changed is not relivant.
14680 * <script type="text/javascript">
14685 * @class Roo.util.TextMetrics
14686 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14687 * wide, in pixels, a given block of text will be.
14690 Roo.util.TextMetrics = function(){
14694 * Measures the size of the specified text
14695 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14696 * that can affect the size of the rendered text
14697 * @param {String} text The text to measure
14698 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14699 * in order to accurately measure the text height
14700 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14702 measure : function(el, text, fixedWidth){
14704 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14707 shared.setFixedWidth(fixedWidth || 'auto');
14708 return shared.getSize(text);
14712 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14713 * the overhead of multiple calls to initialize the style properties on each measurement.
14714 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14715 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14716 * in order to accurately measure the text height
14717 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14719 createInstance : function(el, fixedWidth){
14720 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14727 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14728 var ml = new Roo.Element(document.createElement('div'));
14729 document.body.appendChild(ml.dom);
14730 ml.position('absolute');
14731 ml.setLeftTop(-1000, -1000);
14735 ml.setWidth(fixedWidth);
14740 * Returns the size of the specified text based on the internal element's style and width properties
14741 * @memberOf Roo.util.TextMetrics.Instance#
14742 * @param {String} text The text to measure
14743 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14745 getSize : function(text){
14747 var s = ml.getSize();
14753 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14754 * that can affect the size of the rendered text
14755 * @memberOf Roo.util.TextMetrics.Instance#
14756 * @param {String/HTMLElement} el The element, dom node or id
14758 bind : function(el){
14760 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14765 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14766 * to set a fixed width in order to accurately measure the text height.
14767 * @memberOf Roo.util.TextMetrics.Instance#
14768 * @param {Number} width The width to set on the element
14770 setFixedWidth : function(width){
14771 ml.setWidth(width);
14775 * Returns the measured width of the specified text
14776 * @memberOf Roo.util.TextMetrics.Instance#
14777 * @param {String} text The text to measure
14778 * @return {Number} width The width in pixels
14780 getWidth : function(text){
14781 ml.dom.style.width = 'auto';
14782 return this.getSize(text).width;
14786 * Returns the measured height of the specified text. For multiline text, be sure to call
14787 * {@link #setFixedWidth} if necessary.
14788 * @memberOf Roo.util.TextMetrics.Instance#
14789 * @param {String} text The text to measure
14790 * @return {Number} height The height in pixels
14792 getHeight : function(text){
14793 return this.getSize(text).height;
14797 instance.bind(bindTo);
14802 // backwards compat
14803 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14805 * Ext JS Library 1.1.1
14806 * Copyright(c) 2006-2007, Ext JS, LLC.
14808 * Originally Released Under LGPL - original licence link has changed is not relivant.
14811 * <script type="text/javascript">
14815 * @class Roo.state.Provider
14816 * Abstract base class for state provider implementations. This class provides methods
14817 * for encoding and decoding <b>typed</b> variables including dates and defines the
14818 * Provider interface.
14820 Roo.state.Provider = function(){
14822 * @event statechange
14823 * Fires when a state change occurs.
14824 * @param {Provider} this This state provider
14825 * @param {String} key The state key which was changed
14826 * @param {String} value The encoded value for the state
14829 "statechange": true
14832 Roo.state.Provider.superclass.constructor.call(this);
14834 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14836 * Returns the current value for a key
14837 * @param {String} name The key name
14838 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14839 * @return {Mixed} The state data
14841 get : function(name, defaultValue){
14842 return typeof this.state[name] == "undefined" ?
14843 defaultValue : this.state[name];
14847 * Clears a value from the state
14848 * @param {String} name The key name
14850 clear : function(name){
14851 delete this.state[name];
14852 this.fireEvent("statechange", this, name, null);
14856 * Sets the value for a key
14857 * @param {String} name The key name
14858 * @param {Mixed} value The value to set
14860 set : function(name, value){
14861 this.state[name] = value;
14862 this.fireEvent("statechange", this, name, value);
14866 * Decodes a string previously encoded with {@link #encodeValue}.
14867 * @param {String} value The value to decode
14868 * @return {Mixed} The decoded value
14870 decodeValue : function(cookie){
14871 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14872 var matches = re.exec(unescape(cookie));
14873 if(!matches || !matches[1]) {
14874 return; // non state cookie
14876 var type = matches[1];
14877 var v = matches[2];
14880 return parseFloat(v);
14882 return new Date(Date.parse(v));
14887 var values = v.split("^");
14888 for(var i = 0, len = values.length; i < len; i++){
14889 all.push(this.decodeValue(values[i]));
14894 var values = v.split("^");
14895 for(var i = 0, len = values.length; i < len; i++){
14896 var kv = values[i].split("=");
14897 all[kv[0]] = this.decodeValue(kv[1]);
14906 * Encodes a value including type information. Decode with {@link #decodeValue}.
14907 * @param {Mixed} value The value to encode
14908 * @return {String} The encoded value
14910 encodeValue : function(v){
14912 if(typeof v == "number"){
14914 }else if(typeof v == "boolean"){
14915 enc = "b:" + (v ? "1" : "0");
14916 }else if(v instanceof Date){
14917 enc = "d:" + v.toGMTString();
14918 }else if(v instanceof Array){
14920 for(var i = 0, len = v.length; i < len; i++){
14921 flat += this.encodeValue(v[i]);
14927 }else if(typeof v == "object"){
14930 if(typeof v[key] != "function"){
14931 flat += key + "=" + this.encodeValue(v[key]) + "^";
14934 enc = "o:" + flat.substring(0, flat.length-1);
14938 return escape(enc);
14944 * Ext JS Library 1.1.1
14945 * Copyright(c) 2006-2007, Ext JS, LLC.
14947 * Originally Released Under LGPL - original licence link has changed is not relivant.
14950 * <script type="text/javascript">
14953 * @class Roo.state.Manager
14954 * This is the global state manager. By default all components that are "state aware" check this class
14955 * for state information if you don't pass them a custom state provider. In order for this class
14956 * to be useful, it must be initialized with a provider when your application initializes.
14958 // in your initialization function
14960 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14962 // supposed you have a {@link Roo.BorderLayout}
14963 var layout = new Roo.BorderLayout(...);
14964 layout.restoreState();
14965 // or a {Roo.BasicDialog}
14966 var dialog = new Roo.BasicDialog(...);
14967 dialog.restoreState();
14971 Roo.state.Manager = function(){
14972 var provider = new Roo.state.Provider();
14976 * Configures the default state provider for your application
14977 * @param {Provider} stateProvider The state provider to set
14979 setProvider : function(stateProvider){
14980 provider = stateProvider;
14984 * Returns the current value for a key
14985 * @param {String} name The key name
14986 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14987 * @return {Mixed} The state data
14989 get : function(key, defaultValue){
14990 return provider.get(key, defaultValue);
14994 * Sets the value for a key
14995 * @param {String} name The key name
14996 * @param {Mixed} value The state data
14998 set : function(key, value){
14999 provider.set(key, value);
15003 * Clears a value from the state
15004 * @param {String} name The key name
15006 clear : function(key){
15007 provider.clear(key);
15011 * Gets the currently configured state provider
15012 * @return {Provider} The state provider
15014 getProvider : function(){
15021 * Ext JS Library 1.1.1
15022 * Copyright(c) 2006-2007, Ext JS, LLC.
15024 * Originally Released Under LGPL - original licence link has changed is not relivant.
15027 * <script type="text/javascript">
15030 * @class Roo.state.CookieProvider
15031 * @extends Roo.state.Provider
15032 * The default Provider implementation which saves state via cookies.
15035 var cp = new Roo.state.CookieProvider({
15037 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15038 domain: "roojs.com"
15040 Roo.state.Manager.setProvider(cp);
15042 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15043 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15044 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15045 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15046 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15047 * domain the page is running on including the 'www' like 'www.roojs.com')
15048 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15050 * Create a new CookieProvider
15051 * @param {Object} config The configuration object
15053 Roo.state.CookieProvider = function(config){
15054 Roo.state.CookieProvider.superclass.constructor.call(this);
15056 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15057 this.domain = null;
15058 this.secure = false;
15059 Roo.apply(this, config);
15060 this.state = this.readCookies();
15063 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15065 set : function(name, value){
15066 if(typeof value == "undefined" || value === null){
15070 this.setCookie(name, value);
15071 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15075 clear : function(name){
15076 this.clearCookie(name);
15077 Roo.state.CookieProvider.superclass.clear.call(this, name);
15081 readCookies : function(){
15083 var c = document.cookie + ";";
15084 var re = /\s?(.*?)=(.*?);/g;
15086 while((matches = re.exec(c)) != null){
15087 var name = matches[1];
15088 var value = matches[2];
15089 if(name && name.substring(0,3) == "ys-"){
15090 cookies[name.substr(3)] = this.decodeValue(value);
15097 setCookie : function(name, value){
15098 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15099 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15100 ((this.path == null) ? "" : ("; path=" + this.path)) +
15101 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15102 ((this.secure == true) ? "; secure" : "");
15106 clearCookie : function(name){
15107 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15108 ((this.path == null) ? "" : ("; path=" + this.path)) +
15109 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15110 ((this.secure == true) ? "; secure" : "");
15114 * Ext JS Library 1.1.1
15115 * Copyright(c) 2006-2007, Ext JS, LLC.
15117 * Originally Released Under LGPL - original licence link has changed is not relivant.
15120 * <script type="text/javascript">
15125 * @class Roo.ComponentMgr
15126 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15129 Roo.ComponentMgr = function(){
15130 var all = new Roo.util.MixedCollection();
15134 * Registers a component.
15135 * @param {Roo.Component} c The component
15137 register : function(c){
15142 * Unregisters a component.
15143 * @param {Roo.Component} c The component
15145 unregister : function(c){
15150 * Returns a component by id
15151 * @param {String} id The component id
15153 get : function(id){
15154 return all.get(id);
15158 * Registers a function that will be called when a specified component is added to ComponentMgr
15159 * @param {String} id The component id
15160 * @param {Funtction} fn The callback function
15161 * @param {Object} scope The scope of the callback
15163 onAvailable : function(id, fn, scope){
15164 all.on("add", function(index, o){
15166 fn.call(scope || o, o);
15167 all.un("add", fn, scope);
15174 * Ext JS Library 1.1.1
15175 * Copyright(c) 2006-2007, Ext JS, LLC.
15177 * Originally Released Under LGPL - original licence link has changed is not relivant.
15180 * <script type="text/javascript">
15184 * @class Roo.Component
15185 * @extends Roo.util.Observable
15186 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15187 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15188 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15189 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15190 * All visual components (widgets) that require rendering into a layout should subclass Component.
15192 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15193 * 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
15194 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15196 Roo.Component = function(config){
15197 config = config || {};
15198 if(config.tagName || config.dom || typeof config == "string"){ // element object
15199 config = {el: config, id: config.id || config};
15201 this.initialConfig = config;
15203 Roo.apply(this, config);
15207 * Fires after the component is disabled.
15208 * @param {Roo.Component} this
15213 * Fires after the component is enabled.
15214 * @param {Roo.Component} this
15218 * @event beforeshow
15219 * Fires before the component is shown. Return false to stop the show.
15220 * @param {Roo.Component} this
15225 * Fires after the component is shown.
15226 * @param {Roo.Component} this
15230 * @event beforehide
15231 * Fires before the component is hidden. Return false to stop the hide.
15232 * @param {Roo.Component} this
15237 * Fires after the component is hidden.
15238 * @param {Roo.Component} this
15242 * @event beforerender
15243 * Fires before the component is rendered. Return false to stop the render.
15244 * @param {Roo.Component} this
15246 beforerender : true,
15249 * Fires after the component is rendered.
15250 * @param {Roo.Component} this
15254 * @event beforedestroy
15255 * Fires before the component is destroyed. Return false to stop the destroy.
15256 * @param {Roo.Component} this
15258 beforedestroy : true,
15261 * Fires after the component is destroyed.
15262 * @param {Roo.Component} this
15267 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15269 Roo.ComponentMgr.register(this);
15270 Roo.Component.superclass.constructor.call(this);
15271 this.initComponent();
15272 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15273 this.render(this.renderTo);
15274 delete this.renderTo;
15279 Roo.Component.AUTO_ID = 1000;
15281 Roo.extend(Roo.Component, Roo.util.Observable, {
15283 * @scope Roo.Component.prototype
15285 * true if this component is hidden. Read-only.
15290 * true if this component is disabled. Read-only.
15295 * true if this component has been rendered. Read-only.
15299 /** @cfg {String} disableClass
15300 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15302 disabledClass : "x-item-disabled",
15303 /** @cfg {Boolean} allowDomMove
15304 * Whether the component can move the Dom node when rendering (defaults to true).
15306 allowDomMove : true,
15307 /** @cfg {String} hideMode (display|visibility)
15308 * How this component should hidden. Supported values are
15309 * "visibility" (css visibility), "offsets" (negative offset position) and
15310 * "display" (css display) - defaults to "display".
15312 hideMode: 'display',
15315 ctype : "Roo.Component",
15318 * @cfg {String} actionMode
15319 * which property holds the element that used for hide() / show() / disable() / enable()
15325 getActionEl : function(){
15326 return this[this.actionMode];
15329 initComponent : Roo.emptyFn,
15331 * If this is a lazy rendering component, render it to its container element.
15332 * @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.
15334 render : function(container, position){
15335 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15336 if(!container && this.el){
15337 this.el = Roo.get(this.el);
15338 container = this.el.dom.parentNode;
15339 this.allowDomMove = false;
15341 this.container = Roo.get(container);
15342 this.rendered = true;
15343 if(position !== undefined){
15344 if(typeof position == 'number'){
15345 position = this.container.dom.childNodes[position];
15347 position = Roo.getDom(position);
15350 this.onRender(this.container, position || null);
15352 this.el.addClass(this.cls);
15356 this.el.applyStyles(this.style);
15359 this.fireEvent("render", this);
15360 this.afterRender(this.container);
15372 // default function is not really useful
15373 onRender : function(ct, position){
15375 this.el = Roo.get(this.el);
15376 if(this.allowDomMove !== false){
15377 ct.dom.insertBefore(this.el.dom, position);
15383 getAutoCreate : function(){
15384 var cfg = typeof this.autoCreate == "object" ?
15385 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15386 if(this.id && !cfg.id){
15393 afterRender : Roo.emptyFn,
15396 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15397 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15399 destroy : function(){
15400 if(this.fireEvent("beforedestroy", this) !== false){
15401 this.purgeListeners();
15402 this.beforeDestroy();
15404 this.el.removeAllListeners();
15406 if(this.actionMode == "container"){
15407 this.container.remove();
15411 Roo.ComponentMgr.unregister(this);
15412 this.fireEvent("destroy", this);
15417 beforeDestroy : function(){
15422 onDestroy : function(){
15427 * Returns the underlying {@link Roo.Element}.
15428 * @return {Roo.Element} The element
15430 getEl : function(){
15435 * Returns the id of this component.
15438 getId : function(){
15443 * Try to focus this component.
15444 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15445 * @return {Roo.Component} this
15447 focus : function(selectText){
15450 if(selectText === true){
15451 this.el.dom.select();
15466 * Disable this component.
15467 * @return {Roo.Component} this
15469 disable : function(){
15473 this.disabled = true;
15474 this.fireEvent("disable", this);
15479 onDisable : function(){
15480 this.getActionEl().addClass(this.disabledClass);
15481 this.el.dom.disabled = true;
15485 * Enable this component.
15486 * @return {Roo.Component} this
15488 enable : function(){
15492 this.disabled = false;
15493 this.fireEvent("enable", this);
15498 onEnable : function(){
15499 this.getActionEl().removeClass(this.disabledClass);
15500 this.el.dom.disabled = false;
15504 * Convenience function for setting disabled/enabled by boolean.
15505 * @param {Boolean} disabled
15507 setDisabled : function(disabled){
15508 this[disabled ? "disable" : "enable"]();
15512 * Show this component.
15513 * @return {Roo.Component} this
15516 if(this.fireEvent("beforeshow", this) !== false){
15517 this.hidden = false;
15521 this.fireEvent("show", this);
15527 onShow : function(){
15528 var ae = this.getActionEl();
15529 if(this.hideMode == 'visibility'){
15530 ae.dom.style.visibility = "visible";
15531 }else if(this.hideMode == 'offsets'){
15532 ae.removeClass('x-hidden');
15534 ae.dom.style.display = "";
15539 * Hide this component.
15540 * @return {Roo.Component} this
15543 if(this.fireEvent("beforehide", this) !== false){
15544 this.hidden = true;
15548 this.fireEvent("hide", this);
15554 onHide : function(){
15555 var ae = this.getActionEl();
15556 if(this.hideMode == 'visibility'){
15557 ae.dom.style.visibility = "hidden";
15558 }else if(this.hideMode == 'offsets'){
15559 ae.addClass('x-hidden');
15561 ae.dom.style.display = "none";
15566 * Convenience function to hide or show this component by boolean.
15567 * @param {Boolean} visible True to show, false to hide
15568 * @return {Roo.Component} this
15570 setVisible: function(visible){
15580 * Returns true if this component is visible.
15582 isVisible : function(){
15583 return this.getActionEl().isVisible();
15586 cloneConfig : function(overrides){
15587 overrides = overrides || {};
15588 var id = overrides.id || Roo.id();
15589 var cfg = Roo.applyIf(overrides, this.initialConfig);
15590 cfg.id = id; // prevent dup id
15591 return new this.constructor(cfg);
15595 * Ext JS Library 1.1.1
15596 * Copyright(c) 2006-2007, Ext JS, LLC.
15598 * Originally Released Under LGPL - original licence link has changed is not relivant.
15601 * <script type="text/javascript">
15605 * @class Roo.BoxComponent
15606 * @extends Roo.Component
15607 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15608 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15609 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15610 * layout containers.
15612 * @param {Roo.Element/String/Object} config The configuration options.
15614 Roo.BoxComponent = function(config){
15615 Roo.Component.call(this, config);
15619 * Fires after the component is resized.
15620 * @param {Roo.Component} this
15621 * @param {Number} adjWidth The box-adjusted width that was set
15622 * @param {Number} adjHeight The box-adjusted height that was set
15623 * @param {Number} rawWidth The width that was originally specified
15624 * @param {Number} rawHeight The height that was originally specified
15629 * Fires after the component is moved.
15630 * @param {Roo.Component} this
15631 * @param {Number} x The new x position
15632 * @param {Number} y The new y position
15638 Roo.extend(Roo.BoxComponent, Roo.Component, {
15639 // private, set in afterRender to signify that the component has been rendered
15641 // private, used to defer height settings to subclasses
15642 deferHeight: false,
15643 /** @cfg {Number} width
15644 * width (optional) size of component
15646 /** @cfg {Number} height
15647 * height (optional) size of component
15651 * Sets the width and height of the component. This method fires the resize event. This method can accept
15652 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15653 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15654 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15655 * @return {Roo.BoxComponent} this
15657 setSize : function(w, h){
15658 // support for standard size objects
15659 if(typeof w == 'object'){
15664 if(!this.boxReady){
15670 // prevent recalcs when not needed
15671 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15674 this.lastSize = {width: w, height: h};
15676 var adj = this.adjustSize(w, h);
15677 var aw = adj.width, ah = adj.height;
15678 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15679 var rz = this.getResizeEl();
15680 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15681 rz.setSize(aw, ah);
15682 }else if(!this.deferHeight && ah !== undefined){
15684 }else if(aw !== undefined){
15687 this.onResize(aw, ah, w, h);
15688 this.fireEvent('resize', this, aw, ah, w, h);
15694 * Gets the current size of the component's underlying element.
15695 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15697 getSize : function(){
15698 return this.el.getSize();
15702 * Gets the current XY position of the component's underlying element.
15703 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15704 * @return {Array} The XY position of the element (e.g., [100, 200])
15706 getPosition : function(local){
15707 if(local === true){
15708 return [this.el.getLeft(true), this.el.getTop(true)];
15710 return this.xy || this.el.getXY();
15714 * Gets the current box measurements of the component's underlying element.
15715 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15716 * @returns {Object} box An object in the format {x, y, width, height}
15718 getBox : function(local){
15719 var s = this.el.getSize();
15721 s.x = this.el.getLeft(true);
15722 s.y = this.el.getTop(true);
15724 var xy = this.xy || this.el.getXY();
15732 * Sets the current box measurements of the component's underlying element.
15733 * @param {Object} box An object in the format {x, y, width, height}
15734 * @returns {Roo.BoxComponent} this
15736 updateBox : function(box){
15737 this.setSize(box.width, box.height);
15738 this.setPagePosition(box.x, box.y);
15743 getResizeEl : function(){
15744 return this.resizeEl || this.el;
15748 getPositionEl : function(){
15749 return this.positionEl || this.el;
15753 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15754 * This method fires the move event.
15755 * @param {Number} left The new left
15756 * @param {Number} top The new top
15757 * @returns {Roo.BoxComponent} this
15759 setPosition : function(x, y){
15762 if(!this.boxReady){
15765 var adj = this.adjustPosition(x, y);
15766 var ax = adj.x, ay = adj.y;
15768 var el = this.getPositionEl();
15769 if(ax !== undefined || ay !== undefined){
15770 if(ax !== undefined && ay !== undefined){
15771 el.setLeftTop(ax, ay);
15772 }else if(ax !== undefined){
15774 }else if(ay !== undefined){
15777 this.onPosition(ax, ay);
15778 this.fireEvent('move', this, ax, ay);
15784 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15785 * This method fires the move event.
15786 * @param {Number} x The new x position
15787 * @param {Number} y The new y position
15788 * @returns {Roo.BoxComponent} this
15790 setPagePosition : function(x, y){
15793 if(!this.boxReady){
15796 if(x === undefined || y === undefined){ // cannot translate undefined points
15799 var p = this.el.translatePoints(x, y);
15800 this.setPosition(p.left, p.top);
15805 onRender : function(ct, position){
15806 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15808 this.resizeEl = Roo.get(this.resizeEl);
15810 if(this.positionEl){
15811 this.positionEl = Roo.get(this.positionEl);
15816 afterRender : function(){
15817 Roo.BoxComponent.superclass.afterRender.call(this);
15818 this.boxReady = true;
15819 this.setSize(this.width, this.height);
15820 if(this.x || this.y){
15821 this.setPosition(this.x, this.y);
15823 if(this.pageX || this.pageY){
15824 this.setPagePosition(this.pageX, this.pageY);
15829 * Force the component's size to recalculate based on the underlying element's current height and width.
15830 * @returns {Roo.BoxComponent} this
15832 syncSize : function(){
15833 delete this.lastSize;
15834 this.setSize(this.el.getWidth(), this.el.getHeight());
15839 * Called after the component is resized, this method is empty by default but can be implemented by any
15840 * subclass that needs to perform custom logic after a resize occurs.
15841 * @param {Number} adjWidth The box-adjusted width that was set
15842 * @param {Number} adjHeight The box-adjusted height that was set
15843 * @param {Number} rawWidth The width that was originally specified
15844 * @param {Number} rawHeight The height that was originally specified
15846 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15851 * Called after the component is moved, this method is empty by default but can be implemented by any
15852 * subclass that needs to perform custom logic after a move occurs.
15853 * @param {Number} x The new x position
15854 * @param {Number} y The new y position
15856 onPosition : function(x, y){
15861 adjustSize : function(w, h){
15862 if(this.autoWidth){
15865 if(this.autoHeight){
15868 return {width : w, height: h};
15872 adjustPosition : function(x, y){
15873 return {x : x, y: y};
15876 * Original code for Roojs - LGPL
15877 * <script type="text/javascript">
15881 * @class Roo.XComponent
15882 * A delayed Element creator...
15883 * Or a way to group chunks of interface together.
15884 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15885 * used in conjunction with XComponent.build() it will create an instance of each element,
15886 * then call addxtype() to build the User interface.
15888 * Mypart.xyx = new Roo.XComponent({
15890 parent : 'Mypart.xyz', // empty == document.element.!!
15894 disabled : function() {}
15896 tree : function() { // return an tree of xtype declared components
15900 xtype : 'NestedLayoutPanel',
15907 * It can be used to build a big heiracy, with parent etc.
15908 * or you can just use this to render a single compoent to a dom element
15909 * MYPART.render(Roo.Element | String(id) | dom_element )
15916 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15917 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15919 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15921 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15922 * - if mulitple topModules exist, the last one is defined as the top module.
15926 * When the top level or multiple modules are to embedded into a existing HTML page,
15927 * the parent element can container '#id' of the element where the module will be drawn.
15931 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15932 * it relies more on a include mechanism, where sub modules are included into an outer page.
15933 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15935 * Bootstrap Roo Included elements
15937 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15938 * hence confusing the component builder as it thinks there are multiple top level elements.
15942 * @extends Roo.util.Observable
15944 * @param cfg {Object} configuration of component
15947 Roo.XComponent = function(cfg) {
15948 Roo.apply(this, cfg);
15952 * Fires when this the componnt is built
15953 * @param {Roo.XComponent} c the component
15958 this.region = this.region || 'center'; // default..
15959 Roo.XComponent.register(this);
15960 this.modules = false;
15961 this.el = false; // where the layout goes..
15965 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15968 * The created element (with Roo.factory())
15969 * @type {Roo.Layout}
15975 * for BC - use el in new code
15976 * @type {Roo.Layout}
15982 * for BC - use el in new code
15983 * @type {Roo.Layout}
15988 * @cfg {Function|boolean} disabled
15989 * If this module is disabled by some rule, return true from the funtion
15994 * @cfg {String} parent
15995 * Name of parent element which it get xtype added to..
16000 * @cfg {String} order
16001 * Used to set the order in which elements are created (usefull for multiple tabs)
16006 * @cfg {String} name
16007 * String to display while loading.
16011 * @cfg {String} region
16012 * Region to render component to (defaults to center)
16017 * @cfg {Array} items
16018 * A single item array - the first element is the root of the tree..
16019 * It's done this way to stay compatible with the Xtype system...
16025 * The method that retuns the tree of parts that make up this compoennt
16032 * render element to dom or tree
16033 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16036 render : function(el)
16040 var hp = this.parent ? 1 : 0;
16041 Roo.debug && Roo.log(this);
16043 var tree = this._tree ? this._tree() : this.tree();
16046 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16047 // if parent is a '#.....' string, then let's use that..
16048 var ename = this.parent.substr(1);
16049 this.parent = false;
16050 Roo.debug && Roo.log(ename);
16052 case 'bootstrap-body':
16053 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16054 // this is the BorderLayout standard?
16055 this.parent = { el : true };
16058 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16059 // need to insert stuff...
16061 el : new Roo.bootstrap.layout.Border({
16062 el : document.body,
16068 tabPosition: 'top',
16069 //resizeTabs: true,
16070 alwaysShowTabs: true,
16080 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16081 this.parent = { el : new Roo.bootstrap.Body() };
16082 Roo.debug && Roo.log("setting el to doc body");
16085 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16089 this.parent = { el : true};
16092 el = Roo.get(ename);
16093 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16094 this.parent = { el : true};
16101 if (!el && !this.parent) {
16102 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16107 Roo.debug && Roo.log("EL:");
16108 Roo.debug && Roo.log(el);
16109 Roo.debug && Roo.log("this.parent.el:");
16110 Roo.debug && Roo.log(this.parent.el);
16113 // altertive root elements ??? - we need a better way to indicate these.
16114 var is_alt = Roo.XComponent.is_alt ||
16115 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16116 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16117 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16121 if (!this.parent && is_alt) {
16122 //el = Roo.get(document.body);
16123 this.parent = { el : true };
16128 if (!this.parent) {
16130 Roo.debug && Roo.log("no parent - creating one");
16132 el = el ? Roo.get(el) : false;
16134 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16137 el : new Roo.bootstrap.layout.Border({
16138 el: el || document.body,
16144 tabPosition: 'top',
16145 //resizeTabs: true,
16146 alwaysShowTabs: false,
16149 overflow: 'visible'
16155 // it's a top level one..
16157 el : new Roo.BorderLayout(el || document.body, {
16162 tabPosition: 'top',
16163 //resizeTabs: true,
16164 alwaysShowTabs: el && hp? false : true,
16165 hideTabs: el || !hp ? true : false,
16173 if (!this.parent.el) {
16174 // probably an old style ctor, which has been disabled.
16178 // The 'tree' method is '_tree now'
16180 tree.region = tree.region || this.region;
16181 var is_body = false;
16182 if (this.parent.el === true) {
16183 // bootstrap... - body..
16187 this.parent.el = Roo.factory(tree);
16191 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16192 this.fireEvent('built', this);
16194 this.panel = this.el;
16195 this.layout = this.panel.layout;
16196 this.parentLayout = this.parent.layout || false;
16202 Roo.apply(Roo.XComponent, {
16204 * @property hideProgress
16205 * true to disable the building progress bar.. usefull on single page renders.
16208 hideProgress : false,
16210 * @property buildCompleted
16211 * True when the builder has completed building the interface.
16214 buildCompleted : false,
16217 * @property topModule
16218 * the upper most module - uses document.element as it's constructor.
16225 * @property modules
16226 * array of modules to be created by registration system.
16227 * @type {Array} of Roo.XComponent
16232 * @property elmodules
16233 * array of modules to be created by which use #ID
16234 * @type {Array} of Roo.XComponent
16241 * Is an alternative Root - normally used by bootstrap or other systems,
16242 * where the top element in the tree can wrap 'body'
16243 * @type {boolean} (default false)
16248 * @property build_from_html
16249 * Build elements from html - used by bootstrap HTML stuff
16250 * - this is cleared after build is completed
16251 * @type {boolean} (default false)
16254 build_from_html : false,
16256 * Register components to be built later.
16258 * This solves the following issues
16259 * - Building is not done on page load, but after an authentication process has occured.
16260 * - Interface elements are registered on page load
16261 * - Parent Interface elements may not be loaded before child, so this handles that..
16268 module : 'Pman.Tab.projectMgr',
16270 parent : 'Pman.layout',
16271 disabled : false, // or use a function..
16274 * * @param {Object} details about module
16276 register : function(obj) {
16278 Roo.XComponent.event.fireEvent('register', obj);
16279 switch(typeof(obj.disabled) ) {
16285 if ( obj.disabled() ) {
16291 if (obj.disabled) {
16297 this.modules.push(obj);
16301 * convert a string to an object..
16302 * eg. 'AAA.BBB' -> finds AAA.BBB
16306 toObject : function(str)
16308 if (!str || typeof(str) == 'object') {
16311 if (str.substring(0,1) == '#') {
16315 var ar = str.split('.');
16320 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16322 throw "Module not found : " + str;
16326 throw "Module not found : " + str;
16328 Roo.each(ar, function(e) {
16329 if (typeof(o[e]) == 'undefined') {
16330 throw "Module not found : " + str;
16341 * move modules into their correct place in the tree..
16344 preBuild : function ()
16347 Roo.each(this.modules , function (obj)
16349 Roo.XComponent.event.fireEvent('beforebuild', obj);
16351 var opar = obj.parent;
16353 obj.parent = this.toObject(opar);
16355 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16360 Roo.debug && Roo.log("GOT top level module");
16361 Roo.debug && Roo.log(obj);
16362 obj.modules = new Roo.util.MixedCollection(false,
16363 function(o) { return o.order + '' }
16365 this.topModule = obj;
16368 // parent is a string (usually a dom element name..)
16369 if (typeof(obj.parent) == 'string') {
16370 this.elmodules.push(obj);
16373 if (obj.parent.constructor != Roo.XComponent) {
16374 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16376 if (!obj.parent.modules) {
16377 obj.parent.modules = new Roo.util.MixedCollection(false,
16378 function(o) { return o.order + '' }
16381 if (obj.parent.disabled) {
16382 obj.disabled = true;
16384 obj.parent.modules.add(obj);
16389 * make a list of modules to build.
16390 * @return {Array} list of modules.
16393 buildOrder : function()
16396 var cmp = function(a,b) {
16397 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16399 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16400 throw "No top level modules to build";
16403 // make a flat list in order of modules to build.
16404 var mods = this.topModule ? [ this.topModule ] : [];
16407 // elmodules (is a list of DOM based modules )
16408 Roo.each(this.elmodules, function(e) {
16410 if (!this.topModule &&
16411 typeof(e.parent) == 'string' &&
16412 e.parent.substring(0,1) == '#' &&
16413 Roo.get(e.parent.substr(1))
16416 _this.topModule = e;
16422 // add modules to their parents..
16423 var addMod = function(m) {
16424 Roo.debug && Roo.log("build Order: add: " + m.name);
16427 if (m.modules && !m.disabled) {
16428 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16429 m.modules.keySort('ASC', cmp );
16430 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16432 m.modules.each(addMod);
16434 Roo.debug && Roo.log("build Order: no child modules");
16436 // not sure if this is used any more..
16438 m.finalize.name = m.name + " (clean up) ";
16439 mods.push(m.finalize);
16443 if (this.topModule && this.topModule.modules) {
16444 this.topModule.modules.keySort('ASC', cmp );
16445 this.topModule.modules.each(addMod);
16451 * Build the registered modules.
16452 * @param {Object} parent element.
16453 * @param {Function} optional method to call after module has been added.
16457 build : function(opts)
16460 if (typeof(opts) != 'undefined') {
16461 Roo.apply(this,opts);
16465 var mods = this.buildOrder();
16467 //this.allmods = mods;
16468 //Roo.debug && Roo.log(mods);
16470 if (!mods.length) { // should not happen
16471 throw "NO modules!!!";
16475 var msg = "Building Interface...";
16476 // flash it up as modal - so we store the mask!?
16477 if (!this.hideProgress && Roo.MessageBox) {
16478 Roo.MessageBox.show({ title: 'loading' });
16479 Roo.MessageBox.show({
16480 title: "Please wait...",
16489 var total = mods.length;
16492 var progressRun = function() {
16493 if (!mods.length) {
16494 Roo.debug && Roo.log('hide?');
16495 if (!this.hideProgress && Roo.MessageBox) {
16496 Roo.MessageBox.hide();
16498 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16500 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16506 var m = mods.shift();
16509 Roo.debug && Roo.log(m);
16510 // not sure if this is supported any more.. - modules that are are just function
16511 if (typeof(m) == 'function') {
16513 return progressRun.defer(10, _this);
16517 msg = "Building Interface " + (total - mods.length) +
16519 (m.name ? (' - ' + m.name) : '');
16520 Roo.debug && Roo.log(msg);
16521 if (!this.hideProgress && Roo.MessageBox) {
16522 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16526 // is the module disabled?
16527 var disabled = (typeof(m.disabled) == 'function') ?
16528 m.disabled.call(m.module.disabled) : m.disabled;
16532 return progressRun(); // we do not update the display!
16540 // it's 10 on top level, and 1 on others??? why...
16541 return progressRun.defer(10, _this);
16544 progressRun.defer(1, _this);
16558 * wrapper for event.on - aliased later..
16559 * Typically use to register a event handler for register:
16561 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16570 Roo.XComponent.event = new Roo.util.Observable({
16574 * Fires when an Component is registered,
16575 * set the disable property on the Component to stop registration.
16576 * @param {Roo.XComponent} c the component being registerd.
16581 * @event beforebuild
16582 * Fires before each Component is built
16583 * can be used to apply permissions.
16584 * @param {Roo.XComponent} c the component being registerd.
16587 'beforebuild' : true,
16589 * @event buildcomplete
16590 * Fires on the top level element when all elements have been built
16591 * @param {Roo.XComponent} the top level component.
16593 'buildcomplete' : true
16598 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16601 * marked - a markdown parser
16602 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16603 * https://github.com/chjj/marked
16609 * Roo.Markdown - is a very crude wrapper around marked..
16613 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16615 * Note: move the sample code to the bottom of this
16616 * file before uncommenting it.
16621 Roo.Markdown.toHtml = function(text) {
16623 var c = new Roo.Markdown.marked.setOptions({
16624 renderer: new Roo.Markdown.marked.Renderer(),
16635 text = text.replace(/\\\n/g,' ');
16636 return Roo.Markdown.marked(text);
16641 // Wraps all "globals" so that the only thing
16642 // exposed is makeHtml().
16647 * Block-Level Grammar
16652 code: /^( {4}[^\n]+\n*)+/,
16654 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16655 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16657 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16658 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16659 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16660 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16661 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16663 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16667 block.bullet = /(?:[*+-]|\d+\.)/;
16668 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16669 block.item = replace(block.item, 'gm')
16670 (/bull/g, block.bullet)
16673 block.list = replace(block.list)
16674 (/bull/g, block.bullet)
16675 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16676 ('def', '\\n+(?=' + block.def.source + ')')
16679 block.blockquote = replace(block.blockquote)
16683 block._tag = '(?!(?:'
16684 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16685 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16686 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16688 block.html = replace(block.html)
16689 ('comment', /<!--[\s\S]*?-->/)
16690 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16691 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16692 (/tag/g, block._tag)
16695 block.paragraph = replace(block.paragraph)
16697 ('heading', block.heading)
16698 ('lheading', block.lheading)
16699 ('blockquote', block.blockquote)
16700 ('tag', '<' + block._tag)
16705 * Normal Block Grammar
16708 block.normal = merge({}, block);
16711 * GFM Block Grammar
16714 block.gfm = merge({}, block.normal, {
16715 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16717 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16720 block.gfm.paragraph = replace(block.paragraph)
16722 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16723 + block.list.source.replace('\\1', '\\3') + '|')
16727 * GFM + Tables Block Grammar
16730 block.tables = merge({}, block.gfm, {
16731 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16732 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16739 function Lexer(options) {
16741 this.tokens.links = {};
16742 this.options = options || marked.defaults;
16743 this.rules = block.normal;
16745 if (this.options.gfm) {
16746 if (this.options.tables) {
16747 this.rules = block.tables;
16749 this.rules = block.gfm;
16755 * Expose Block Rules
16758 Lexer.rules = block;
16761 * Static Lex Method
16764 Lexer.lex = function(src, options) {
16765 var lexer = new Lexer(options);
16766 return lexer.lex(src);
16773 Lexer.prototype.lex = function(src) {
16775 .replace(/\r\n|\r/g, '\n')
16776 .replace(/\t/g, ' ')
16777 .replace(/\u00a0/g, ' ')
16778 .replace(/\u2424/g, '\n');
16780 return this.token(src, true);
16787 Lexer.prototype.token = function(src, top, bq) {
16788 var src = src.replace(/^ +$/gm, '')
16801 if (cap = this.rules.newline.exec(src)) {
16802 src = src.substring(cap[0].length);
16803 if (cap[0].length > 1) {
16811 if (cap = this.rules.code.exec(src)) {
16812 src = src.substring(cap[0].length);
16813 cap = cap[0].replace(/^ {4}/gm, '');
16816 text: !this.options.pedantic
16817 ? cap.replace(/\n+$/, '')
16824 if (cap = this.rules.fences.exec(src)) {
16825 src = src.substring(cap[0].length);
16835 if (cap = this.rules.heading.exec(src)) {
16836 src = src.substring(cap[0].length);
16839 depth: cap[1].length,
16845 // table no leading pipe (gfm)
16846 if (top && (cap = this.rules.nptable.exec(src))) {
16847 src = src.substring(cap[0].length);
16851 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16852 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16853 cells: cap[3].replace(/\n$/, '').split('\n')
16856 for (i = 0; i < item.align.length; i++) {
16857 if (/^ *-+: *$/.test(item.align[i])) {
16858 item.align[i] = 'right';
16859 } else if (/^ *:-+: *$/.test(item.align[i])) {
16860 item.align[i] = 'center';
16861 } else if (/^ *:-+ *$/.test(item.align[i])) {
16862 item.align[i] = 'left';
16864 item.align[i] = null;
16868 for (i = 0; i < item.cells.length; i++) {
16869 item.cells[i] = item.cells[i].split(/ *\| */);
16872 this.tokens.push(item);
16878 if (cap = this.rules.lheading.exec(src)) {
16879 src = src.substring(cap[0].length);
16882 depth: cap[2] === '=' ? 1 : 2,
16889 if (cap = this.rules.hr.exec(src)) {
16890 src = src.substring(cap[0].length);
16898 if (cap = this.rules.blockquote.exec(src)) {
16899 src = src.substring(cap[0].length);
16902 type: 'blockquote_start'
16905 cap = cap[0].replace(/^ *> ?/gm, '');
16907 // Pass `top` to keep the current
16908 // "toplevel" state. This is exactly
16909 // how markdown.pl works.
16910 this.token(cap, top, true);
16913 type: 'blockquote_end'
16920 if (cap = this.rules.list.exec(src)) {
16921 src = src.substring(cap[0].length);
16925 type: 'list_start',
16926 ordered: bull.length > 1
16929 // Get each top-level item.
16930 cap = cap[0].match(this.rules.item);
16936 for (; i < l; i++) {
16939 // Remove the list item's bullet
16940 // so it is seen as the next token.
16941 space = item.length;
16942 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16944 // Outdent whatever the
16945 // list item contains. Hacky.
16946 if (~item.indexOf('\n ')) {
16947 space -= item.length;
16948 item = !this.options.pedantic
16949 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16950 : item.replace(/^ {1,4}/gm, '');
16953 // Determine whether the next list item belongs here.
16954 // Backpedal if it does not belong in this list.
16955 if (this.options.smartLists && i !== l - 1) {
16956 b = block.bullet.exec(cap[i + 1])[0];
16957 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16958 src = cap.slice(i + 1).join('\n') + src;
16963 // Determine whether item is loose or not.
16964 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16965 // for discount behavior.
16966 loose = next || /\n\n(?!\s*$)/.test(item);
16968 next = item.charAt(item.length - 1) === '\n';
16969 if (!loose) { loose = next; }
16974 ? 'loose_item_start'
16975 : 'list_item_start'
16979 this.token(item, false, bq);
16982 type: 'list_item_end'
16994 if (cap = this.rules.html.exec(src)) {
16995 src = src.substring(cap[0].length);
16997 type: this.options.sanitize
17000 pre: !this.options.sanitizer
17001 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17008 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17009 src = src.substring(cap[0].length);
17010 this.tokens.links[cap[1].toLowerCase()] = {
17018 if (top && (cap = this.rules.table.exec(src))) {
17019 src = src.substring(cap[0].length);
17023 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17024 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17025 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17028 for (i = 0; i < item.align.length; i++) {
17029 if (/^ *-+: *$/.test(item.align[i])) {
17030 item.align[i] = 'right';
17031 } else if (/^ *:-+: *$/.test(item.align[i])) {
17032 item.align[i] = 'center';
17033 } else if (/^ *:-+ *$/.test(item.align[i])) {
17034 item.align[i] = 'left';
17036 item.align[i] = null;
17040 for (i = 0; i < item.cells.length; i++) {
17041 item.cells[i] = item.cells[i]
17042 .replace(/^ *\| *| *\| *$/g, '')
17046 this.tokens.push(item);
17051 // top-level paragraph
17052 if (top && (cap = this.rules.paragraph.exec(src))) {
17053 src = src.substring(cap[0].length);
17056 text: cap[1].charAt(cap[1].length - 1) === '\n'
17057 ? cap[1].slice(0, -1)
17064 if (cap = this.rules.text.exec(src)) {
17065 // Top-level should never reach here.
17066 src = src.substring(cap[0].length);
17076 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17080 return this.tokens;
17084 * Inline-Level Grammar
17088 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17089 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17091 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17092 link: /^!?\[(inside)\]\(href\)/,
17093 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17094 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17095 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17096 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17097 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17098 br: /^ {2,}\n(?!\s*$)/,
17100 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17103 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17104 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17106 inline.link = replace(inline.link)
17107 ('inside', inline._inside)
17108 ('href', inline._href)
17111 inline.reflink = replace(inline.reflink)
17112 ('inside', inline._inside)
17116 * Normal Inline Grammar
17119 inline.normal = merge({}, inline);
17122 * Pedantic Inline Grammar
17125 inline.pedantic = merge({}, inline.normal, {
17126 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17127 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17131 * GFM Inline Grammar
17134 inline.gfm = merge({}, inline.normal, {
17135 escape: replace(inline.escape)('])', '~|])')(),
17136 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17137 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17138 text: replace(inline.text)
17140 ('|', '|https?://|')
17145 * GFM + Line Breaks Inline Grammar
17148 inline.breaks = merge({}, inline.gfm, {
17149 br: replace(inline.br)('{2,}', '*')(),
17150 text: replace(inline.gfm.text)('{2,}', '*')()
17154 * Inline Lexer & Compiler
17157 function InlineLexer(links, options) {
17158 this.options = options || marked.defaults;
17159 this.links = links;
17160 this.rules = inline.normal;
17161 this.renderer = this.options.renderer || new Renderer;
17162 this.renderer.options = this.options;
17166 Error('Tokens array requires a `links` property.');
17169 if (this.options.gfm) {
17170 if (this.options.breaks) {
17171 this.rules = inline.breaks;
17173 this.rules = inline.gfm;
17175 } else if (this.options.pedantic) {
17176 this.rules = inline.pedantic;
17181 * Expose Inline Rules
17184 InlineLexer.rules = inline;
17187 * Static Lexing/Compiling Method
17190 InlineLexer.output = function(src, links, options) {
17191 var inline = new InlineLexer(links, options);
17192 return inline.output(src);
17199 InlineLexer.prototype.output = function(src) {
17208 if (cap = this.rules.escape.exec(src)) {
17209 src = src.substring(cap[0].length);
17215 if (cap = this.rules.autolink.exec(src)) {
17216 src = src.substring(cap[0].length);
17217 if (cap[2] === '@') {
17218 text = cap[1].charAt(6) === ':'
17219 ? this.mangle(cap[1].substring(7))
17220 : this.mangle(cap[1]);
17221 href = this.mangle('mailto:') + text;
17223 text = escape(cap[1]);
17226 out += this.renderer.link(href, null, text);
17231 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17232 src = src.substring(cap[0].length);
17233 text = escape(cap[1]);
17235 out += this.renderer.link(href, null, text);
17240 if (cap = this.rules.tag.exec(src)) {
17241 if (!this.inLink && /^<a /i.test(cap[0])) {
17242 this.inLink = true;
17243 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17244 this.inLink = false;
17246 src = src.substring(cap[0].length);
17247 out += this.options.sanitize
17248 ? this.options.sanitizer
17249 ? this.options.sanitizer(cap[0])
17256 if (cap = this.rules.link.exec(src)) {
17257 src = src.substring(cap[0].length);
17258 this.inLink = true;
17259 out += this.outputLink(cap, {
17263 this.inLink = false;
17268 if ((cap = this.rules.reflink.exec(src))
17269 || (cap = this.rules.nolink.exec(src))) {
17270 src = src.substring(cap[0].length);
17271 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17272 link = this.links[link.toLowerCase()];
17273 if (!link || !link.href) {
17274 out += cap[0].charAt(0);
17275 src = cap[0].substring(1) + src;
17278 this.inLink = true;
17279 out += this.outputLink(cap, link);
17280 this.inLink = false;
17285 if (cap = this.rules.strong.exec(src)) {
17286 src = src.substring(cap[0].length);
17287 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17292 if (cap = this.rules.em.exec(src)) {
17293 src = src.substring(cap[0].length);
17294 out += this.renderer.em(this.output(cap[2] || cap[1]));
17299 if (cap = this.rules.code.exec(src)) {
17300 src = src.substring(cap[0].length);
17301 out += this.renderer.codespan(escape(cap[2], true));
17306 if (cap = this.rules.br.exec(src)) {
17307 src = src.substring(cap[0].length);
17308 out += this.renderer.br();
17313 if (cap = this.rules.del.exec(src)) {
17314 src = src.substring(cap[0].length);
17315 out += this.renderer.del(this.output(cap[1]));
17320 if (cap = this.rules.text.exec(src)) {
17321 src = src.substring(cap[0].length);
17322 out += this.renderer.text(escape(this.smartypants(cap[0])));
17328 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17339 InlineLexer.prototype.outputLink = function(cap, link) {
17340 var href = escape(link.href)
17341 , title = link.title ? escape(link.title) : null;
17343 return cap[0].charAt(0) !== '!'
17344 ? this.renderer.link(href, title, this.output(cap[1]))
17345 : this.renderer.image(href, title, escape(cap[1]));
17349 * Smartypants Transformations
17352 InlineLexer.prototype.smartypants = function(text) {
17353 if (!this.options.smartypants) { return text; }
17356 .replace(/---/g, '\u2014')
17358 .replace(/--/g, '\u2013')
17360 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17361 // closing singles & apostrophes
17362 .replace(/'/g, '\u2019')
17364 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17366 .replace(/"/g, '\u201d')
17368 .replace(/\.{3}/g, '\u2026');
17375 InlineLexer.prototype.mangle = function(text) {
17376 if (!this.options.mangle) { return text; }
17382 for (; i < l; i++) {
17383 ch = text.charCodeAt(i);
17384 if (Math.random() > 0.5) {
17385 ch = 'x' + ch.toString(16);
17387 out += '&#' + ch + ';';
17397 function Renderer(options) {
17398 this.options = options || {};
17401 Renderer.prototype.code = function(code, lang, escaped) {
17402 if (this.options.highlight) {
17403 var out = this.options.highlight(code, lang);
17404 if (out != null && out !== code) {
17409 // hack!!! - it's already escapeD?
17414 return '<pre><code>'
17415 + (escaped ? code : escape(code, true))
17416 + '\n</code></pre>';
17419 return '<pre><code class="'
17420 + this.options.langPrefix
17421 + escape(lang, true)
17423 + (escaped ? code : escape(code, true))
17424 + '\n</code></pre>\n';
17427 Renderer.prototype.blockquote = function(quote) {
17428 return '<blockquote>\n' + quote + '</blockquote>\n';
17431 Renderer.prototype.html = function(html) {
17435 Renderer.prototype.heading = function(text, level, raw) {
17439 + this.options.headerPrefix
17440 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17448 Renderer.prototype.hr = function() {
17449 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17452 Renderer.prototype.list = function(body, ordered) {
17453 var type = ordered ? 'ol' : 'ul';
17454 return '<' + type + '>\n' + body + '</' + type + '>\n';
17457 Renderer.prototype.listitem = function(text) {
17458 return '<li>' + text + '</li>\n';
17461 Renderer.prototype.paragraph = function(text) {
17462 return '<p>' + text + '</p>\n';
17465 Renderer.prototype.table = function(header, body) {
17466 return '<table class="table table-striped">\n'
17476 Renderer.prototype.tablerow = function(content) {
17477 return '<tr>\n' + content + '</tr>\n';
17480 Renderer.prototype.tablecell = function(content, flags) {
17481 var type = flags.header ? 'th' : 'td';
17482 var tag = flags.align
17483 ? '<' + type + ' style="text-align:' + flags.align + '">'
17484 : '<' + type + '>';
17485 return tag + content + '</' + type + '>\n';
17488 // span level renderer
17489 Renderer.prototype.strong = function(text) {
17490 return '<strong>' + text + '</strong>';
17493 Renderer.prototype.em = function(text) {
17494 return '<em>' + text + '</em>';
17497 Renderer.prototype.codespan = function(text) {
17498 return '<code>' + text + '</code>';
17501 Renderer.prototype.br = function() {
17502 return this.options.xhtml ? '<br/>' : '<br>';
17505 Renderer.prototype.del = function(text) {
17506 return '<del>' + text + '</del>';
17509 Renderer.prototype.link = function(href, title, text) {
17510 if (this.options.sanitize) {
17512 var prot = decodeURIComponent(unescape(href))
17513 .replace(/[^\w:]/g, '')
17518 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17522 var out = '<a href="' + href + '"';
17524 out += ' title="' + title + '"';
17526 out += '>' + text + '</a>';
17530 Renderer.prototype.image = function(href, title, text) {
17531 var out = '<img src="' + href + '" alt="' + text + '"';
17533 out += ' title="' + title + '"';
17535 out += this.options.xhtml ? '/>' : '>';
17539 Renderer.prototype.text = function(text) {
17544 * Parsing & Compiling
17547 function Parser(options) {
17550 this.options = options || marked.defaults;
17551 this.options.renderer = this.options.renderer || new Renderer;
17552 this.renderer = this.options.renderer;
17553 this.renderer.options = this.options;
17557 * Static Parse Method
17560 Parser.parse = function(src, options, renderer) {
17561 var parser = new Parser(options, renderer);
17562 return parser.parse(src);
17569 Parser.prototype.parse = function(src) {
17570 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17571 this.tokens = src.reverse();
17574 while (this.next()) {
17585 Parser.prototype.next = function() {
17586 return this.token = this.tokens.pop();
17590 * Preview Next Token
17593 Parser.prototype.peek = function() {
17594 return this.tokens[this.tokens.length - 1] || 0;
17598 * Parse Text Tokens
17601 Parser.prototype.parseText = function() {
17602 var body = this.token.text;
17604 while (this.peek().type === 'text') {
17605 body += '\n' + this.next().text;
17608 return this.inline.output(body);
17612 * Parse Current Token
17615 Parser.prototype.tok = function() {
17616 switch (this.token.type) {
17621 return this.renderer.hr();
17624 return this.renderer.heading(
17625 this.inline.output(this.token.text),
17630 return this.renderer.code(this.token.text,
17632 this.token.escaped);
17645 for (i = 0; i < this.token.header.length; i++) {
17646 flags = { header: true, align: this.token.align[i] };
17647 cell += this.renderer.tablecell(
17648 this.inline.output(this.token.header[i]),
17649 { header: true, align: this.token.align[i] }
17652 header += this.renderer.tablerow(cell);
17654 for (i = 0; i < this.token.cells.length; i++) {
17655 row = this.token.cells[i];
17658 for (j = 0; j < row.length; j++) {
17659 cell += this.renderer.tablecell(
17660 this.inline.output(row[j]),
17661 { header: false, align: this.token.align[j] }
17665 body += this.renderer.tablerow(cell);
17667 return this.renderer.table(header, body);
17669 case 'blockquote_start': {
17672 while (this.next().type !== 'blockquote_end') {
17673 body += this.tok();
17676 return this.renderer.blockquote(body);
17678 case 'list_start': {
17680 , ordered = this.token.ordered;
17682 while (this.next().type !== 'list_end') {
17683 body += this.tok();
17686 return this.renderer.list(body, ordered);
17688 case 'list_item_start': {
17691 while (this.next().type !== 'list_item_end') {
17692 body += this.token.type === 'text'
17697 return this.renderer.listitem(body);
17699 case 'loose_item_start': {
17702 while (this.next().type !== 'list_item_end') {
17703 body += this.tok();
17706 return this.renderer.listitem(body);
17709 var html = !this.token.pre && !this.options.pedantic
17710 ? this.inline.output(this.token.text)
17712 return this.renderer.html(html);
17714 case 'paragraph': {
17715 return this.renderer.paragraph(this.inline.output(this.token.text));
17718 return this.renderer.paragraph(this.parseText());
17727 function escape(html, encode) {
17729 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17730 .replace(/</g, '<')
17731 .replace(/>/g, '>')
17732 .replace(/"/g, '"')
17733 .replace(/'/g, ''');
17736 function unescape(html) {
17737 // explicitly match decimal, hex, and named HTML entities
17738 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17739 n = n.toLowerCase();
17740 if (n === 'colon') { return ':'; }
17741 if (n.charAt(0) === '#') {
17742 return n.charAt(1) === 'x'
17743 ? String.fromCharCode(parseInt(n.substring(2), 16))
17744 : String.fromCharCode(+n.substring(1));
17750 function replace(regex, opt) {
17751 regex = regex.source;
17753 return function self(name, val) {
17754 if (!name) { return new RegExp(regex, opt); }
17755 val = val.source || val;
17756 val = val.replace(/(^|[^\[])\^/g, '$1');
17757 regex = regex.replace(name, val);
17765 function merge(obj) {
17770 for (; i < arguments.length; i++) {
17771 target = arguments[i];
17772 for (key in target) {
17773 if (Object.prototype.hasOwnProperty.call(target, key)) {
17774 obj[key] = target[key];
17787 function marked(src, opt, callback) {
17788 if (callback || typeof opt === 'function') {
17794 opt = merge({}, marked.defaults, opt || {});
17796 var highlight = opt.highlight
17802 tokens = Lexer.lex(src, opt)
17804 return callback(e);
17807 pending = tokens.length;
17809 var done = function(err) {
17811 opt.highlight = highlight;
17812 return callback(err);
17818 out = Parser.parse(tokens, opt);
17823 opt.highlight = highlight;
17827 : callback(null, out);
17830 if (!highlight || highlight.length < 3) {
17834 delete opt.highlight;
17836 if (!pending) { return done(); }
17838 for (; i < tokens.length; i++) {
17840 if (token.type !== 'code') {
17841 return --pending || done();
17843 return highlight(token.text, token.lang, function(err, code) {
17844 if (err) { return done(err); }
17845 if (code == null || code === token.text) {
17846 return --pending || done();
17849 token.escaped = true;
17850 --pending || done();
17858 if (opt) { opt = merge({}, marked.defaults, opt); }
17859 return Parser.parse(Lexer.lex(src, opt), opt);
17861 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17862 if ((opt || marked.defaults).silent) {
17863 return '<p>An error occured:</p><pre>'
17864 + escape(e.message + '', true)
17876 marked.setOptions = function(opt) {
17877 merge(marked.defaults, opt);
17881 marked.defaults = {
17892 langPrefix: 'lang-',
17893 smartypants: false,
17895 renderer: new Renderer,
17903 marked.Parser = Parser;
17904 marked.parser = Parser.parse;
17906 marked.Renderer = Renderer;
17908 marked.Lexer = Lexer;
17909 marked.lexer = Lexer.lex;
17911 marked.InlineLexer = InlineLexer;
17912 marked.inlineLexer = InlineLexer.output;
17914 marked.parse = marked;
17916 Roo.Markdown.marked = marked;
17920 * Ext JS Library 1.1.1
17921 * Copyright(c) 2006-2007, Ext JS, LLC.
17923 * Originally Released Under LGPL - original licence link has changed is not relivant.
17926 * <script type="text/javascript">
17932 * These classes are derivatives of the similarly named classes in the YUI Library.
17933 * The original license:
17934 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17935 * Code licensed under the BSD License:
17936 * http://developer.yahoo.net/yui/license.txt
17941 var Event=Roo.EventManager;
17942 var Dom=Roo.lib.Dom;
17945 * @class Roo.dd.DragDrop
17946 * @extends Roo.util.Observable
17947 * Defines the interface and base operation of items that that can be
17948 * dragged or can be drop targets. It was designed to be extended, overriding
17949 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17950 * Up to three html elements can be associated with a DragDrop instance:
17952 * <li>linked element: the element that is passed into the constructor.
17953 * This is the element which defines the boundaries for interaction with
17954 * other DragDrop objects.</li>
17955 * <li>handle element(s): The drag operation only occurs if the element that
17956 * was clicked matches a handle element. By default this is the linked
17957 * element, but there are times that you will want only a portion of the
17958 * linked element to initiate the drag operation, and the setHandleElId()
17959 * method provides a way to define this.</li>
17960 * <li>drag element: this represents the element that would be moved along
17961 * with the cursor during a drag operation. By default, this is the linked
17962 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
17963 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17966 * This class should not be instantiated until the onload event to ensure that
17967 * the associated elements are available.
17968 * The following would define a DragDrop obj that would interact with any
17969 * other DragDrop obj in the "group1" group:
17971 * dd = new Roo.dd.DragDrop("div1", "group1");
17973 * Since none of the event handlers have been implemented, nothing would
17974 * actually happen if you were to run the code above. Normally you would
17975 * override this class or one of the default implementations, but you can
17976 * also override the methods you want on an instance of the class...
17978 * dd.onDragDrop = function(e, id) {
17979 * alert("dd was dropped on " + id);
17983 * @param {String} id of the element that is linked to this instance
17984 * @param {String} sGroup the group of related DragDrop objects
17985 * @param {object} config an object containing configurable attributes
17986 * Valid properties for DragDrop:
17987 * padding, isTarget, maintainOffset, primaryButtonOnly
17989 Roo.dd.DragDrop = function(id, sGroup, config) {
17991 this.init(id, sGroup, config);
17996 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
17999 * The id of the element associated with this object. This is what we
18000 * refer to as the "linked element" because the size and position of
18001 * this element is used to determine when the drag and drop objects have
18009 * Configuration attributes passed into the constructor
18016 * The id of the element that will be dragged. By default this is same
18017 * as the linked element , but could be changed to another element. Ex:
18019 * @property dragElId
18026 * the id of the element that initiates the drag operation. By default
18027 * this is the linked element, but could be changed to be a child of this
18028 * element. This lets us do things like only starting the drag when the
18029 * header element within the linked html element is clicked.
18030 * @property handleElId
18037 * An associative array of HTML tags that will be ignored if clicked.
18038 * @property invalidHandleTypes
18039 * @type {string: string}
18041 invalidHandleTypes: null,
18044 * An associative array of ids for elements that will be ignored if clicked
18045 * @property invalidHandleIds
18046 * @type {string: string}
18048 invalidHandleIds: null,
18051 * An indexted array of css class names for elements that will be ignored
18053 * @property invalidHandleClasses
18056 invalidHandleClasses: null,
18059 * The linked element's absolute X position at the time the drag was
18061 * @property startPageX
18068 * The linked element's absolute X position at the time the drag was
18070 * @property startPageY
18077 * The group defines a logical collection of DragDrop objects that are
18078 * related. Instances only get events when interacting with other
18079 * DragDrop object in the same group. This lets us define multiple
18080 * groups using a single DragDrop subclass if we want.
18082 * @type {string: string}
18087 * Individual drag/drop instances can be locked. This will prevent
18088 * onmousedown start drag.
18096 * Lock this instance
18099 lock: function() { this.locked = true; },
18102 * Unlock this instace
18105 unlock: function() { this.locked = false; },
18108 * By default, all insances can be a drop target. This can be disabled by
18109 * setting isTarget to false.
18116 * The padding configured for this drag and drop object for calculating
18117 * the drop zone intersection with this object.
18124 * Cached reference to the linked element
18125 * @property _domRef
18131 * Internal typeof flag
18132 * @property __ygDragDrop
18135 __ygDragDrop: true,
18138 * Set to true when horizontal contraints are applied
18139 * @property constrainX
18146 * Set to true when vertical contraints are applied
18147 * @property constrainY
18154 * The left constraint
18162 * The right constraint
18170 * The up constraint
18179 * The down constraint
18187 * Maintain offsets when we resetconstraints. Set to true when you want
18188 * the position of the element relative to its parent to stay the same
18189 * when the page changes
18191 * @property maintainOffset
18194 maintainOffset: false,
18197 * Array of pixel locations the element will snap to if we specified a
18198 * horizontal graduation/interval. This array is generated automatically
18199 * when you define a tick interval.
18206 * Array of pixel locations the element will snap to if we specified a
18207 * vertical graduation/interval. This array is generated automatically
18208 * when you define a tick interval.
18215 * By default the drag and drop instance will only respond to the primary
18216 * button click (left button for a right-handed mouse). Set to true to
18217 * allow drag and drop to start with any mouse click that is propogated
18219 * @property primaryButtonOnly
18222 primaryButtonOnly: true,
18225 * The availabe property is false until the linked dom element is accessible.
18226 * @property available
18232 * By default, drags can only be initiated if the mousedown occurs in the
18233 * region the linked element is. This is done in part to work around a
18234 * bug in some browsers that mis-report the mousedown if the previous
18235 * mouseup happened outside of the window. This property is set to true
18236 * if outer handles are defined.
18238 * @property hasOuterHandles
18242 hasOuterHandles: false,
18245 * Code that executes immediately before the startDrag event
18246 * @method b4StartDrag
18249 b4StartDrag: function(x, y) { },
18252 * Abstract method called after a drag/drop object is clicked
18253 * and the drag or mousedown time thresholds have beeen met.
18254 * @method startDrag
18255 * @param {int} X click location
18256 * @param {int} Y click location
18258 startDrag: function(x, y) { /* override this */ },
18261 * Code that executes immediately before the onDrag event
18265 b4Drag: function(e) { },
18268 * Abstract method called during the onMouseMove event while dragging an
18271 * @param {Event} e the mousemove event
18273 onDrag: function(e) { /* override this */ },
18276 * Abstract method called when this element fist begins hovering over
18277 * another DragDrop obj
18278 * @method onDragEnter
18279 * @param {Event} e the mousemove event
18280 * @param {String|DragDrop[]} id In POINT mode, the element
18281 * id this is hovering over. In INTERSECT mode, an array of one or more
18282 * dragdrop items being hovered over.
18284 onDragEnter: function(e, id) { /* override this */ },
18287 * Code that executes immediately before the onDragOver event
18288 * @method b4DragOver
18291 b4DragOver: function(e) { },
18294 * Abstract method called when this element is hovering over another
18296 * @method onDragOver
18297 * @param {Event} e the mousemove event
18298 * @param {String|DragDrop[]} id In POINT mode, the element
18299 * id this is hovering over. In INTERSECT mode, an array of dd items
18300 * being hovered over.
18302 onDragOver: function(e, id) { /* override this */ },
18305 * Code that executes immediately before the onDragOut event
18306 * @method b4DragOut
18309 b4DragOut: function(e) { },
18312 * Abstract method called when we are no longer hovering over an element
18313 * @method onDragOut
18314 * @param {Event} e the mousemove event
18315 * @param {String|DragDrop[]} id In POINT mode, the element
18316 * id this was hovering over. In INTERSECT mode, an array of dd items
18317 * that the mouse is no longer over.
18319 onDragOut: function(e, id) { /* override this */ },
18322 * Code that executes immediately before the onDragDrop event
18323 * @method b4DragDrop
18326 b4DragDrop: function(e) { },
18329 * Abstract method called when this item is dropped on another DragDrop
18331 * @method onDragDrop
18332 * @param {Event} e the mouseup event
18333 * @param {String|DragDrop[]} id In POINT mode, the element
18334 * id this was dropped on. In INTERSECT mode, an array of dd items this
18337 onDragDrop: function(e, id) { /* override this */ },
18340 * Abstract method called when this item is dropped on an area with no
18342 * @method onInvalidDrop
18343 * @param {Event} e the mouseup event
18345 onInvalidDrop: function(e) { /* override this */ },
18348 * Code that executes immediately before the endDrag event
18349 * @method b4EndDrag
18352 b4EndDrag: function(e) { },
18355 * Fired when we are done dragging the object
18357 * @param {Event} e the mouseup event
18359 endDrag: function(e) { /* override this */ },
18362 * Code executed immediately before the onMouseDown event
18363 * @method b4MouseDown
18364 * @param {Event} e the mousedown event
18367 b4MouseDown: function(e) { },
18370 * Event handler that fires when a drag/drop obj gets a mousedown
18371 * @method onMouseDown
18372 * @param {Event} e the mousedown event
18374 onMouseDown: function(e) { /* override this */ },
18377 * Event handler that fires when a drag/drop obj gets a mouseup
18378 * @method onMouseUp
18379 * @param {Event} e the mouseup event
18381 onMouseUp: function(e) { /* override this */ },
18384 * Override the onAvailable method to do what is needed after the initial
18385 * position was determined.
18386 * @method onAvailable
18388 onAvailable: function () {
18392 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18395 defaultPadding : {left:0, right:0, top:0, bottom:0},
18398 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18402 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18403 { dragElId: "existingProxyDiv" });
18404 dd.startDrag = function(){
18405 this.constrainTo("parent-id");
18408 * Or you can initalize it using the {@link Roo.Element} object:
18410 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18411 startDrag : function(){
18412 this.constrainTo("parent-id");
18416 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18417 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18418 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18419 * an object containing the sides to pad. For example: {right:10, bottom:10}
18420 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18422 constrainTo : function(constrainTo, pad, inContent){
18423 if(typeof pad == "number"){
18424 pad = {left: pad, right:pad, top:pad, bottom:pad};
18426 pad = pad || this.defaultPadding;
18427 var b = Roo.get(this.getEl()).getBox();
18428 var ce = Roo.get(constrainTo);
18429 var s = ce.getScroll();
18430 var c, cd = ce.dom;
18431 if(cd == document.body){
18432 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18435 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18439 var topSpace = b.y - c.y;
18440 var leftSpace = b.x - c.x;
18442 this.resetConstraints();
18443 this.setXConstraint(leftSpace - (pad.left||0), // left
18444 c.width - leftSpace - b.width - (pad.right||0) //right
18446 this.setYConstraint(topSpace - (pad.top||0), //top
18447 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18452 * Returns a reference to the linked element
18454 * @return {HTMLElement} the html element
18456 getEl: function() {
18457 if (!this._domRef) {
18458 this._domRef = Roo.getDom(this.id);
18461 return this._domRef;
18465 * Returns a reference to the actual element to drag. By default this is
18466 * the same as the html element, but it can be assigned to another
18467 * element. An example of this can be found in Roo.dd.DDProxy
18468 * @method getDragEl
18469 * @return {HTMLElement} the html element
18471 getDragEl: function() {
18472 return Roo.getDom(this.dragElId);
18476 * Sets up the DragDrop object. Must be called in the constructor of any
18477 * Roo.dd.DragDrop subclass
18479 * @param id the id of the linked element
18480 * @param {String} sGroup the group of related items
18481 * @param {object} config configuration attributes
18483 init: function(id, sGroup, config) {
18484 this.initTarget(id, sGroup, config);
18485 if (!Roo.isTouch) {
18486 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18488 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18489 // Event.on(this.id, "selectstart", Event.preventDefault);
18493 * Initializes Targeting functionality only... the object does not
18494 * get a mousedown handler.
18495 * @method initTarget
18496 * @param id the id of the linked element
18497 * @param {String} sGroup the group of related items
18498 * @param {object} config configuration attributes
18500 initTarget: function(id, sGroup, config) {
18502 // configuration attributes
18503 this.config = config || {};
18505 // create a local reference to the drag and drop manager
18506 this.DDM = Roo.dd.DDM;
18507 // initialize the groups array
18510 // assume that we have an element reference instead of an id if the
18511 // parameter is not a string
18512 if (typeof id !== "string") {
18519 // add to an interaction group
18520 this.addToGroup((sGroup) ? sGroup : "default");
18522 // We don't want to register this as the handle with the manager
18523 // so we just set the id rather than calling the setter.
18524 this.handleElId = id;
18526 // the linked element is the element that gets dragged by default
18527 this.setDragElId(id);
18529 // by default, clicked anchors will not start drag operations.
18530 this.invalidHandleTypes = { A: "A" };
18531 this.invalidHandleIds = {};
18532 this.invalidHandleClasses = [];
18534 this.applyConfig();
18536 this.handleOnAvailable();
18540 * Applies the configuration parameters that were passed into the constructor.
18541 * This is supposed to happen at each level through the inheritance chain. So
18542 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18543 * DragDrop in order to get all of the parameters that are available in
18545 * @method applyConfig
18547 applyConfig: function() {
18549 // configurable properties:
18550 // padding, isTarget, maintainOffset, primaryButtonOnly
18551 this.padding = this.config.padding || [0, 0, 0, 0];
18552 this.isTarget = (this.config.isTarget !== false);
18553 this.maintainOffset = (this.config.maintainOffset);
18554 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18559 * Executed when the linked element is available
18560 * @method handleOnAvailable
18563 handleOnAvailable: function() {
18564 this.available = true;
18565 this.resetConstraints();
18566 this.onAvailable();
18570 * Configures the padding for the target zone in px. Effectively expands
18571 * (or reduces) the virtual object size for targeting calculations.
18572 * Supports css-style shorthand; if only one parameter is passed, all sides
18573 * will have that padding, and if only two are passed, the top and bottom
18574 * will have the first param, the left and right the second.
18575 * @method setPadding
18576 * @param {int} iTop Top pad
18577 * @param {int} iRight Right pad
18578 * @param {int} iBot Bot pad
18579 * @param {int} iLeft Left pad
18581 setPadding: function(iTop, iRight, iBot, iLeft) {
18582 // this.padding = [iLeft, iRight, iTop, iBot];
18583 if (!iRight && 0 !== iRight) {
18584 this.padding = [iTop, iTop, iTop, iTop];
18585 } else if (!iBot && 0 !== iBot) {
18586 this.padding = [iTop, iRight, iTop, iRight];
18588 this.padding = [iTop, iRight, iBot, iLeft];
18593 * Stores the initial placement of the linked element.
18594 * @method setInitialPosition
18595 * @param {int} diffX the X offset, default 0
18596 * @param {int} diffY the Y offset, default 0
18598 setInitPosition: function(diffX, diffY) {
18599 var el = this.getEl();
18601 if (!this.DDM.verifyEl(el)) {
18605 var dx = diffX || 0;
18606 var dy = diffY || 0;
18608 var p = Dom.getXY( el );
18610 this.initPageX = p[0] - dx;
18611 this.initPageY = p[1] - dy;
18613 this.lastPageX = p[0];
18614 this.lastPageY = p[1];
18617 this.setStartPosition(p);
18621 * Sets the start position of the element. This is set when the obj
18622 * is initialized, the reset when a drag is started.
18623 * @method setStartPosition
18624 * @param pos current position (from previous lookup)
18627 setStartPosition: function(pos) {
18628 var p = pos || Dom.getXY( this.getEl() );
18629 this.deltaSetXY = null;
18631 this.startPageX = p[0];
18632 this.startPageY = p[1];
18636 * Add this instance to a group of related drag/drop objects. All
18637 * instances belong to at least one group, and can belong to as many
18638 * groups as needed.
18639 * @method addToGroup
18640 * @param sGroup {string} the name of the group
18642 addToGroup: function(sGroup) {
18643 this.groups[sGroup] = true;
18644 this.DDM.regDragDrop(this, sGroup);
18648 * Remove's this instance from the supplied interaction group
18649 * @method removeFromGroup
18650 * @param {string} sGroup The group to drop
18652 removeFromGroup: function(sGroup) {
18653 if (this.groups[sGroup]) {
18654 delete this.groups[sGroup];
18657 this.DDM.removeDDFromGroup(this, sGroup);
18661 * Allows you to specify that an element other than the linked element
18662 * will be moved with the cursor during a drag
18663 * @method setDragElId
18664 * @param id {string} the id of the element that will be used to initiate the drag
18666 setDragElId: function(id) {
18667 this.dragElId = id;
18671 * Allows you to specify a child of the linked element that should be
18672 * used to initiate the drag operation. An example of this would be if
18673 * you have a content div with text and links. Clicking anywhere in the
18674 * content area would normally start the drag operation. Use this method
18675 * to specify that an element inside of the content div is the element
18676 * that starts the drag operation.
18677 * @method setHandleElId
18678 * @param id {string} the id of the element that will be used to
18679 * initiate the drag.
18681 setHandleElId: function(id) {
18682 if (typeof id !== "string") {
18685 this.handleElId = id;
18686 this.DDM.regHandle(this.id, id);
18690 * Allows you to set an element outside of the linked element as a drag
18692 * @method setOuterHandleElId
18693 * @param id the id of the element that will be used to initiate the drag
18695 setOuterHandleElId: function(id) {
18696 if (typeof id !== "string") {
18699 Event.on(id, "mousedown",
18700 this.handleMouseDown, this);
18701 this.setHandleElId(id);
18703 this.hasOuterHandles = true;
18707 * Remove all drag and drop hooks for this element
18710 unreg: function() {
18711 Event.un(this.id, "mousedown",
18712 this.handleMouseDown);
18713 Event.un(this.id, "touchstart",
18714 this.handleMouseDown);
18715 this._domRef = null;
18716 this.DDM._remove(this);
18719 destroy : function(){
18724 * Returns true if this instance is locked, or the drag drop mgr is locked
18725 * (meaning that all drag/drop is disabled on the page.)
18727 * @return {boolean} true if this obj or all drag/drop is locked, else
18730 isLocked: function() {
18731 return (this.DDM.isLocked() || this.locked);
18735 * Fired when this object is clicked
18736 * @method handleMouseDown
18738 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18741 handleMouseDown: function(e, oDD){
18743 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18744 //Roo.log('not touch/ button !=0');
18747 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18748 return; // double touch..
18752 if (this.isLocked()) {
18753 //Roo.log('locked');
18757 this.DDM.refreshCache(this.groups);
18758 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18759 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18760 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18761 //Roo.log('no outer handes or not over target');
18764 // Roo.log('check validator');
18765 if (this.clickValidator(e)) {
18766 // Roo.log('validate success');
18767 // set the initial element position
18768 this.setStartPosition();
18771 this.b4MouseDown(e);
18772 this.onMouseDown(e);
18774 this.DDM.handleMouseDown(e, this);
18776 this.DDM.stopEvent(e);
18784 clickValidator: function(e) {
18785 var target = e.getTarget();
18786 return ( this.isValidHandleChild(target) &&
18787 (this.id == this.handleElId ||
18788 this.DDM.handleWasClicked(target, this.id)) );
18792 * Allows you to specify a tag name that should not start a drag operation
18793 * when clicked. This is designed to facilitate embedding links within a
18794 * drag handle that do something other than start the drag.
18795 * @method addInvalidHandleType
18796 * @param {string} tagName the type of element to exclude
18798 addInvalidHandleType: function(tagName) {
18799 var type = tagName.toUpperCase();
18800 this.invalidHandleTypes[type] = type;
18804 * Lets you to specify an element id for a child of a drag handle
18805 * that should not initiate a drag
18806 * @method addInvalidHandleId
18807 * @param {string} id the element id of the element you wish to ignore
18809 addInvalidHandleId: function(id) {
18810 if (typeof id !== "string") {
18813 this.invalidHandleIds[id] = id;
18817 * Lets you specify a css class of elements that will not initiate a drag
18818 * @method addInvalidHandleClass
18819 * @param {string} cssClass the class of the elements you wish to ignore
18821 addInvalidHandleClass: function(cssClass) {
18822 this.invalidHandleClasses.push(cssClass);
18826 * Unsets an excluded tag name set by addInvalidHandleType
18827 * @method removeInvalidHandleType
18828 * @param {string} tagName the type of element to unexclude
18830 removeInvalidHandleType: function(tagName) {
18831 var type = tagName.toUpperCase();
18832 // this.invalidHandleTypes[type] = null;
18833 delete this.invalidHandleTypes[type];
18837 * Unsets an invalid handle id
18838 * @method removeInvalidHandleId
18839 * @param {string} id the id of the element to re-enable
18841 removeInvalidHandleId: function(id) {
18842 if (typeof id !== "string") {
18845 delete this.invalidHandleIds[id];
18849 * Unsets an invalid css class
18850 * @method removeInvalidHandleClass
18851 * @param {string} cssClass the class of the element(s) you wish to
18854 removeInvalidHandleClass: function(cssClass) {
18855 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18856 if (this.invalidHandleClasses[i] == cssClass) {
18857 delete this.invalidHandleClasses[i];
18863 * Checks the tag exclusion list to see if this click should be ignored
18864 * @method isValidHandleChild
18865 * @param {HTMLElement} node the HTMLElement to evaluate
18866 * @return {boolean} true if this is a valid tag type, false if not
18868 isValidHandleChild: function(node) {
18871 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18874 nodeName = node.nodeName.toUpperCase();
18876 nodeName = node.nodeName;
18878 valid = valid && !this.invalidHandleTypes[nodeName];
18879 valid = valid && !this.invalidHandleIds[node.id];
18881 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18882 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18891 * Create the array of horizontal tick marks if an interval was specified
18892 * in setXConstraint().
18893 * @method setXTicks
18896 setXTicks: function(iStartX, iTickSize) {
18898 this.xTickSize = iTickSize;
18902 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18904 this.xTicks[this.xTicks.length] = i;
18909 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18911 this.xTicks[this.xTicks.length] = i;
18916 this.xTicks.sort(this.DDM.numericSort) ;
18920 * Create the array of vertical tick marks if an interval was specified in
18921 * setYConstraint().
18922 * @method setYTicks
18925 setYTicks: function(iStartY, iTickSize) {
18927 this.yTickSize = iTickSize;
18931 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18933 this.yTicks[this.yTicks.length] = i;
18938 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18940 this.yTicks[this.yTicks.length] = i;
18945 this.yTicks.sort(this.DDM.numericSort) ;
18949 * By default, the element can be dragged any place on the screen. Use
18950 * this method to limit the horizontal travel of the element. Pass in
18951 * 0,0 for the parameters if you want to lock the drag to the y axis.
18952 * @method setXConstraint
18953 * @param {int} iLeft the number of pixels the element can move to the left
18954 * @param {int} iRight the number of pixels the element can move to the
18956 * @param {int} iTickSize optional parameter for specifying that the
18958 * should move iTickSize pixels at a time.
18960 setXConstraint: function(iLeft, iRight, iTickSize) {
18961 this.leftConstraint = iLeft;
18962 this.rightConstraint = iRight;
18964 this.minX = this.initPageX - iLeft;
18965 this.maxX = this.initPageX + iRight;
18966 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18968 this.constrainX = true;
18972 * Clears any constraints applied to this instance. Also clears ticks
18973 * since they can't exist independent of a constraint at this time.
18974 * @method clearConstraints
18976 clearConstraints: function() {
18977 this.constrainX = false;
18978 this.constrainY = false;
18983 * Clears any tick interval defined for this instance
18984 * @method clearTicks
18986 clearTicks: function() {
18987 this.xTicks = null;
18988 this.yTicks = null;
18989 this.xTickSize = 0;
18990 this.yTickSize = 0;
18994 * By default, the element can be dragged any place on the screen. Set
18995 * this to limit the vertical travel of the element. Pass in 0,0 for the
18996 * parameters if you want to lock the drag to the x axis.
18997 * @method setYConstraint
18998 * @param {int} iUp the number of pixels the element can move up
18999 * @param {int} iDown the number of pixels the element can move down
19000 * @param {int} iTickSize optional parameter for specifying that the
19001 * element should move iTickSize pixels at a time.
19003 setYConstraint: function(iUp, iDown, iTickSize) {
19004 this.topConstraint = iUp;
19005 this.bottomConstraint = iDown;
19007 this.minY = this.initPageY - iUp;
19008 this.maxY = this.initPageY + iDown;
19009 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19011 this.constrainY = true;
19016 * resetConstraints must be called if you manually reposition a dd element.
19017 * @method resetConstraints
19018 * @param {boolean} maintainOffset
19020 resetConstraints: function() {
19023 // Maintain offsets if necessary
19024 if (this.initPageX || this.initPageX === 0) {
19025 // figure out how much this thing has moved
19026 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19027 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19029 this.setInitPosition(dx, dy);
19031 // This is the first time we have detected the element's position
19033 this.setInitPosition();
19036 if (this.constrainX) {
19037 this.setXConstraint( this.leftConstraint,
19038 this.rightConstraint,
19042 if (this.constrainY) {
19043 this.setYConstraint( this.topConstraint,
19044 this.bottomConstraint,
19050 * Normally the drag element is moved pixel by pixel, but we can specify
19051 * that it move a number of pixels at a time. This method resolves the
19052 * location when we have it set up like this.
19054 * @param {int} val where we want to place the object
19055 * @param {int[]} tickArray sorted array of valid points
19056 * @return {int} the closest tick
19059 getTick: function(val, tickArray) {
19062 // If tick interval is not defined, it is effectively 1 pixel,
19063 // so we return the value passed to us.
19065 } else if (tickArray[0] >= val) {
19066 // The value is lower than the first tick, so we return the first
19068 return tickArray[0];
19070 for (var i=0, len=tickArray.length; i<len; ++i) {
19072 if (tickArray[next] && tickArray[next] >= val) {
19073 var diff1 = val - tickArray[i];
19074 var diff2 = tickArray[next] - val;
19075 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19079 // The value is larger than the last tick, so we return the last
19081 return tickArray[tickArray.length - 1];
19088 * @return {string} string representation of the dd obj
19090 toString: function() {
19091 return ("DragDrop " + this.id);
19099 * Ext JS Library 1.1.1
19100 * Copyright(c) 2006-2007, Ext JS, LLC.
19102 * Originally Released Under LGPL - original licence link has changed is not relivant.
19105 * <script type="text/javascript">
19110 * The drag and drop utility provides a framework for building drag and drop
19111 * applications. In addition to enabling drag and drop for specific elements,
19112 * the drag and drop elements are tracked by the manager class, and the
19113 * interactions between the various elements are tracked during the drag and
19114 * the implementing code is notified about these important moments.
19117 // Only load the library once. Rewriting the manager class would orphan
19118 // existing drag and drop instances.
19119 if (!Roo.dd.DragDropMgr) {
19122 * @class Roo.dd.DragDropMgr
19123 * DragDropMgr is a singleton that tracks the element interaction for
19124 * all DragDrop items in the window. Generally, you will not call
19125 * this class directly, but it does have helper methods that could
19126 * be useful in your DragDrop implementations.
19129 Roo.dd.DragDropMgr = function() {
19131 var Event = Roo.EventManager;
19136 * Two dimensional Array of registered DragDrop objects. The first
19137 * dimension is the DragDrop item group, the second the DragDrop
19140 * @type {string: string}
19147 * Array of element ids defined as drag handles. Used to determine
19148 * if the element that generated the mousedown event is actually the
19149 * handle and not the html element itself.
19150 * @property handleIds
19151 * @type {string: string}
19158 * the DragDrop object that is currently being dragged
19159 * @property dragCurrent
19167 * the DragDrop object(s) that are being hovered over
19168 * @property dragOvers
19176 * the X distance between the cursor and the object being dragged
19185 * the Y distance between the cursor and the object being dragged
19194 * Flag to determine if we should prevent the default behavior of the
19195 * events we define. By default this is true, but this can be set to
19196 * false if you need the default behavior (not recommended)
19197 * @property preventDefault
19201 preventDefault: true,
19204 * Flag to determine if we should stop the propagation of the events
19205 * we generate. This is true by default but you may want to set it to
19206 * false if the html element contains other features that require the
19208 * @property stopPropagation
19212 stopPropagation: true,
19215 * Internal flag that is set to true when drag and drop has been
19217 * @property initialized
19224 * All drag and drop can be disabled.
19232 * Called the first time an element is registered.
19238 this.initialized = true;
19242 * In point mode, drag and drop interaction is defined by the
19243 * location of the cursor during the drag/drop
19251 * In intersect mode, drag and drop interactio nis defined by the
19252 * overlap of two or more drag and drop objects.
19253 * @property INTERSECT
19260 * The current drag and drop mode. Default: POINT
19268 * Runs method on all drag and drop objects
19269 * @method _execOnAll
19273 _execOnAll: function(sMethod, args) {
19274 for (var i in this.ids) {
19275 for (var j in this.ids[i]) {
19276 var oDD = this.ids[i][j];
19277 if (! this.isTypeOfDD(oDD)) {
19280 oDD[sMethod].apply(oDD, args);
19286 * Drag and drop initialization. Sets up the global event handlers
19291 _onLoad: function() {
19295 if (!Roo.isTouch) {
19296 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19297 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19299 Event.on(document, "touchend", this.handleMouseUp, this, true);
19300 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19302 Event.on(window, "unload", this._onUnload, this, true);
19303 Event.on(window, "resize", this._onResize, this, true);
19304 // Event.on(window, "mouseout", this._test);
19309 * Reset constraints on all drag and drop objs
19310 * @method _onResize
19314 _onResize: function(e) {
19315 this._execOnAll("resetConstraints", []);
19319 * Lock all drag and drop functionality
19323 lock: function() { this.locked = true; },
19326 * Unlock all drag and drop functionality
19330 unlock: function() { this.locked = false; },
19333 * Is drag and drop locked?
19335 * @return {boolean} True if drag and drop is locked, false otherwise.
19338 isLocked: function() { return this.locked; },
19341 * Location cache that is set for all drag drop objects when a drag is
19342 * initiated, cleared when the drag is finished.
19343 * @property locationCache
19350 * Set useCache to false if you want to force object the lookup of each
19351 * drag and drop linked element constantly during a drag.
19352 * @property useCache
19359 * The number of pixels that the mouse needs to move after the
19360 * mousedown before the drag is initiated. Default=3;
19361 * @property clickPixelThresh
19365 clickPixelThresh: 3,
19368 * The number of milliseconds after the mousedown event to initiate the
19369 * drag if we don't get a mouseup event. Default=1000
19370 * @property clickTimeThresh
19374 clickTimeThresh: 350,
19377 * Flag that indicates that either the drag pixel threshold or the
19378 * mousdown time threshold has been met
19379 * @property dragThreshMet
19384 dragThreshMet: false,
19387 * Timeout used for the click time threshold
19388 * @property clickTimeout
19393 clickTimeout: null,
19396 * The X position of the mousedown event stored for later use when a
19397 * drag threshold is met.
19406 * The Y position of the mousedown event stored for later use when a
19407 * drag threshold is met.
19416 * Each DragDrop instance must be registered with the DragDropMgr.
19417 * This is executed in DragDrop.init()
19418 * @method regDragDrop
19419 * @param {DragDrop} oDD the DragDrop object to register
19420 * @param {String} sGroup the name of the group this element belongs to
19423 regDragDrop: function(oDD, sGroup) {
19424 if (!this.initialized) { this.init(); }
19426 if (!this.ids[sGroup]) {
19427 this.ids[sGroup] = {};
19429 this.ids[sGroup][oDD.id] = oDD;
19433 * Removes the supplied dd instance from the supplied group. Executed
19434 * by DragDrop.removeFromGroup, so don't call this function directly.
19435 * @method removeDDFromGroup
19439 removeDDFromGroup: function(oDD, sGroup) {
19440 if (!this.ids[sGroup]) {
19441 this.ids[sGroup] = {};
19444 var obj = this.ids[sGroup];
19445 if (obj && obj[oDD.id]) {
19446 delete obj[oDD.id];
19451 * Unregisters a drag and drop item. This is executed in
19452 * DragDrop.unreg, use that method instead of calling this directly.
19457 _remove: function(oDD) {
19458 for (var g in oDD.groups) {
19459 if (g && this.ids[g][oDD.id]) {
19460 delete this.ids[g][oDD.id];
19463 delete this.handleIds[oDD.id];
19467 * Each DragDrop handle element must be registered. This is done
19468 * automatically when executing DragDrop.setHandleElId()
19469 * @method regHandle
19470 * @param {String} sDDId the DragDrop id this element is a handle for
19471 * @param {String} sHandleId the id of the element that is the drag
19475 regHandle: function(sDDId, sHandleId) {
19476 if (!this.handleIds[sDDId]) {
19477 this.handleIds[sDDId] = {};
19479 this.handleIds[sDDId][sHandleId] = sHandleId;
19483 * Utility function to determine if a given element has been
19484 * registered as a drag drop item.
19485 * @method isDragDrop
19486 * @param {String} id the element id to check
19487 * @return {boolean} true if this element is a DragDrop item,
19491 isDragDrop: function(id) {
19492 return ( this.getDDById(id) ) ? true : false;
19496 * Returns the drag and drop instances that are in all groups the
19497 * passed in instance belongs to.
19498 * @method getRelated
19499 * @param {DragDrop} p_oDD the obj to get related data for
19500 * @param {boolean} bTargetsOnly if true, only return targetable objs
19501 * @return {DragDrop[]} the related instances
19504 getRelated: function(p_oDD, bTargetsOnly) {
19506 for (var i in p_oDD.groups) {
19507 for (j in this.ids[i]) {
19508 var dd = this.ids[i][j];
19509 if (! this.isTypeOfDD(dd)) {
19512 if (!bTargetsOnly || dd.isTarget) {
19513 oDDs[oDDs.length] = dd;
19522 * Returns true if the specified dd target is a legal target for
19523 * the specifice drag obj
19524 * @method isLegalTarget
19525 * @param {DragDrop} the drag obj
19526 * @param {DragDrop} the target
19527 * @return {boolean} true if the target is a legal target for the
19531 isLegalTarget: function (oDD, oTargetDD) {
19532 var targets = this.getRelated(oDD, true);
19533 for (var i=0, len=targets.length;i<len;++i) {
19534 if (targets[i].id == oTargetDD.id) {
19543 * My goal is to be able to transparently determine if an object is
19544 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19545 * returns "object", oDD.constructor.toString() always returns
19546 * "DragDrop" and not the name of the subclass. So for now it just
19547 * evaluates a well-known variable in DragDrop.
19548 * @method isTypeOfDD
19549 * @param {Object} the object to evaluate
19550 * @return {boolean} true if typeof oDD = DragDrop
19553 isTypeOfDD: function (oDD) {
19554 return (oDD && oDD.__ygDragDrop);
19558 * Utility function to determine if a given element has been
19559 * registered as a drag drop handle for the given Drag Drop object.
19561 * @param {String} id the element id to check
19562 * @return {boolean} true if this element is a DragDrop handle, false
19566 isHandle: function(sDDId, sHandleId) {
19567 return ( this.handleIds[sDDId] &&
19568 this.handleIds[sDDId][sHandleId] );
19572 * Returns the DragDrop instance for a given id
19573 * @method getDDById
19574 * @param {String} id the id of the DragDrop object
19575 * @return {DragDrop} the drag drop object, null if it is not found
19578 getDDById: function(id) {
19579 for (var i in this.ids) {
19580 if (this.ids[i][id]) {
19581 return this.ids[i][id];
19588 * Fired after a registered DragDrop object gets the mousedown event.
19589 * Sets up the events required to track the object being dragged
19590 * @method handleMouseDown
19591 * @param {Event} e the event
19592 * @param oDD the DragDrop object being dragged
19596 handleMouseDown: function(e, oDD) {
19598 Roo.QuickTips.disable();
19600 this.currentTarget = e.getTarget();
19602 this.dragCurrent = oDD;
19604 var el = oDD.getEl();
19606 // track start position
19607 this.startX = e.getPageX();
19608 this.startY = e.getPageY();
19610 this.deltaX = this.startX - el.offsetLeft;
19611 this.deltaY = this.startY - el.offsetTop;
19613 this.dragThreshMet = false;
19615 this.clickTimeout = setTimeout(
19617 var DDM = Roo.dd.DDM;
19618 DDM.startDrag(DDM.startX, DDM.startY);
19620 this.clickTimeThresh );
19624 * Fired when either the drag pixel threshol or the mousedown hold
19625 * time threshold has been met.
19626 * @method startDrag
19627 * @param x {int} the X position of the original mousedown
19628 * @param y {int} the Y position of the original mousedown
19631 startDrag: function(x, y) {
19632 clearTimeout(this.clickTimeout);
19633 if (this.dragCurrent) {
19634 this.dragCurrent.b4StartDrag(x, y);
19635 this.dragCurrent.startDrag(x, y);
19637 this.dragThreshMet = true;
19641 * Internal function to handle the mouseup event. Will be invoked
19642 * from the context of the document.
19643 * @method handleMouseUp
19644 * @param {Event} e the event
19648 handleMouseUp: function(e) {
19651 Roo.QuickTips.enable();
19653 if (! this.dragCurrent) {
19657 clearTimeout(this.clickTimeout);
19659 if (this.dragThreshMet) {
19660 this.fireEvents(e, true);
19670 * Utility to stop event propagation and event default, if these
19671 * features are turned on.
19672 * @method stopEvent
19673 * @param {Event} e the event as returned by this.getEvent()
19676 stopEvent: function(e){
19677 if(this.stopPropagation) {
19678 e.stopPropagation();
19681 if (this.preventDefault) {
19682 e.preventDefault();
19687 * Internal function to clean up event handlers after the drag
19688 * operation is complete
19690 * @param {Event} e the event
19694 stopDrag: function(e) {
19695 // Fire the drag end event for the item that was dragged
19696 if (this.dragCurrent) {
19697 if (this.dragThreshMet) {
19698 this.dragCurrent.b4EndDrag(e);
19699 this.dragCurrent.endDrag(e);
19702 this.dragCurrent.onMouseUp(e);
19705 this.dragCurrent = null;
19706 this.dragOvers = {};
19710 * Internal function to handle the mousemove event. Will be invoked
19711 * from the context of the html element.
19713 * @TODO figure out what we can do about mouse events lost when the
19714 * user drags objects beyond the window boundary. Currently we can
19715 * detect this in internet explorer by verifying that the mouse is
19716 * down during the mousemove event. Firefox doesn't give us the
19717 * button state on the mousemove event.
19718 * @method handleMouseMove
19719 * @param {Event} e the event
19723 handleMouseMove: function(e) {
19724 if (! this.dragCurrent) {
19728 // var button = e.which || e.button;
19730 // check for IE mouseup outside of page boundary
19731 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19733 return this.handleMouseUp(e);
19736 if (!this.dragThreshMet) {
19737 var diffX = Math.abs(this.startX - e.getPageX());
19738 var diffY = Math.abs(this.startY - e.getPageY());
19739 if (diffX > this.clickPixelThresh ||
19740 diffY > this.clickPixelThresh) {
19741 this.startDrag(this.startX, this.startY);
19745 if (this.dragThreshMet) {
19746 this.dragCurrent.b4Drag(e);
19747 this.dragCurrent.onDrag(e);
19748 if(!this.dragCurrent.moveOnly){
19749 this.fireEvents(e, false);
19759 * Iterates over all of the DragDrop elements to find ones we are
19760 * hovering over or dropping on
19761 * @method fireEvents
19762 * @param {Event} e the event
19763 * @param {boolean} isDrop is this a drop op or a mouseover op?
19767 fireEvents: function(e, isDrop) {
19768 var dc = this.dragCurrent;
19770 // If the user did the mouse up outside of the window, we could
19771 // get here even though we have ended the drag.
19772 if (!dc || dc.isLocked()) {
19776 var pt = e.getPoint();
19778 // cache the previous dragOver array
19784 var enterEvts = [];
19786 // Check to see if the object(s) we were hovering over is no longer
19787 // being hovered over so we can fire the onDragOut event
19788 for (var i in this.dragOvers) {
19790 var ddo = this.dragOvers[i];
19792 if (! this.isTypeOfDD(ddo)) {
19796 if (! this.isOverTarget(pt, ddo, this.mode)) {
19797 outEvts.push( ddo );
19800 oldOvers[i] = true;
19801 delete this.dragOvers[i];
19804 for (var sGroup in dc.groups) {
19806 if ("string" != typeof sGroup) {
19810 for (i in this.ids[sGroup]) {
19811 var oDD = this.ids[sGroup][i];
19812 if (! this.isTypeOfDD(oDD)) {
19816 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19817 if (this.isOverTarget(pt, oDD, this.mode)) {
19818 // look for drop interactions
19820 dropEvts.push( oDD );
19821 // look for drag enter and drag over interactions
19824 // initial drag over: dragEnter fires
19825 if (!oldOvers[oDD.id]) {
19826 enterEvts.push( oDD );
19827 // subsequent drag overs: dragOver fires
19829 overEvts.push( oDD );
19832 this.dragOvers[oDD.id] = oDD;
19840 if (outEvts.length) {
19841 dc.b4DragOut(e, outEvts);
19842 dc.onDragOut(e, outEvts);
19845 if (enterEvts.length) {
19846 dc.onDragEnter(e, enterEvts);
19849 if (overEvts.length) {
19850 dc.b4DragOver(e, overEvts);
19851 dc.onDragOver(e, overEvts);
19854 if (dropEvts.length) {
19855 dc.b4DragDrop(e, dropEvts);
19856 dc.onDragDrop(e, dropEvts);
19860 // fire dragout events
19862 for (i=0, len=outEvts.length; i<len; ++i) {
19863 dc.b4DragOut(e, outEvts[i].id);
19864 dc.onDragOut(e, outEvts[i].id);
19867 // fire enter events
19868 for (i=0,len=enterEvts.length; i<len; ++i) {
19869 // dc.b4DragEnter(e, oDD.id);
19870 dc.onDragEnter(e, enterEvts[i].id);
19873 // fire over events
19874 for (i=0,len=overEvts.length; i<len; ++i) {
19875 dc.b4DragOver(e, overEvts[i].id);
19876 dc.onDragOver(e, overEvts[i].id);
19879 // fire drop events
19880 for (i=0, len=dropEvts.length; i<len; ++i) {
19881 dc.b4DragDrop(e, dropEvts[i].id);
19882 dc.onDragDrop(e, dropEvts[i].id);
19887 // notify about a drop that did not find a target
19888 if (isDrop && !dropEvts.length) {
19889 dc.onInvalidDrop(e);
19895 * Helper function for getting the best match from the list of drag
19896 * and drop objects returned by the drag and drop events when we are
19897 * in INTERSECT mode. It returns either the first object that the
19898 * cursor is over, or the object that has the greatest overlap with
19899 * the dragged element.
19900 * @method getBestMatch
19901 * @param {DragDrop[]} dds The array of drag and drop objects
19903 * @return {DragDrop} The best single match
19906 getBestMatch: function(dds) {
19908 // Return null if the input is not what we expect
19909 //if (!dds || !dds.length || dds.length == 0) {
19911 // If there is only one item, it wins
19912 //} else if (dds.length == 1) {
19914 var len = dds.length;
19919 // Loop through the targeted items
19920 for (var i=0; i<len; ++i) {
19922 // If the cursor is over the object, it wins. If the
19923 // cursor is over multiple matches, the first one we come
19925 if (dd.cursorIsOver) {
19928 // Otherwise the object with the most overlap wins
19931 winner.overlap.getArea() < dd.overlap.getArea()) {
19942 * Refreshes the cache of the top-left and bottom-right points of the
19943 * drag and drop objects in the specified group(s). This is in the
19944 * format that is stored in the drag and drop instance, so typical
19947 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19951 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19953 * @TODO this really should be an indexed array. Alternatively this
19954 * method could accept both.
19955 * @method refreshCache
19956 * @param {Object} groups an associative array of groups to refresh
19959 refreshCache: function(groups) {
19960 for (var sGroup in groups) {
19961 if ("string" != typeof sGroup) {
19964 for (var i in this.ids[sGroup]) {
19965 var oDD = this.ids[sGroup][i];
19967 if (this.isTypeOfDD(oDD)) {
19968 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19969 var loc = this.getLocation(oDD);
19971 this.locationCache[oDD.id] = loc;
19973 delete this.locationCache[oDD.id];
19974 // this will unregister the drag and drop object if
19975 // the element is not in a usable state
19984 * This checks to make sure an element exists and is in the DOM. The
19985 * main purpose is to handle cases where innerHTML is used to remove
19986 * drag and drop objects from the DOM. IE provides an 'unspecified
19987 * error' when trying to access the offsetParent of such an element
19989 * @param {HTMLElement} el the element to check
19990 * @return {boolean} true if the element looks usable
19993 verifyEl: function(el) {
19998 parent = el.offsetParent;
20001 parent = el.offsetParent;
20012 * Returns a Region object containing the drag and drop element's position
20013 * and size, including the padding configured for it
20014 * @method getLocation
20015 * @param {DragDrop} oDD the drag and drop object to get the
20017 * @return {Roo.lib.Region} a Region object representing the total area
20018 * the element occupies, including any padding
20019 * the instance is configured for.
20022 getLocation: function(oDD) {
20023 if (! this.isTypeOfDD(oDD)) {
20027 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20030 pos= Roo.lib.Dom.getXY(el);
20038 x2 = x1 + el.offsetWidth;
20040 y2 = y1 + el.offsetHeight;
20042 t = y1 - oDD.padding[0];
20043 r = x2 + oDD.padding[1];
20044 b = y2 + oDD.padding[2];
20045 l = x1 - oDD.padding[3];
20047 return new Roo.lib.Region( t, r, b, l );
20051 * Checks the cursor location to see if it over the target
20052 * @method isOverTarget
20053 * @param {Roo.lib.Point} pt The point to evaluate
20054 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20055 * @return {boolean} true if the mouse is over the target
20059 isOverTarget: function(pt, oTarget, intersect) {
20060 // use cache if available
20061 var loc = this.locationCache[oTarget.id];
20062 if (!loc || !this.useCache) {
20063 loc = this.getLocation(oTarget);
20064 this.locationCache[oTarget.id] = loc;
20072 oTarget.cursorIsOver = loc.contains( pt );
20074 // DragDrop is using this as a sanity check for the initial mousedown
20075 // in this case we are done. In POINT mode, if the drag obj has no
20076 // contraints, we are also done. Otherwise we need to evaluate the
20077 // location of the target as related to the actual location of the
20078 // dragged element.
20079 var dc = this.dragCurrent;
20080 if (!dc || !dc.getTargetCoord ||
20081 (!intersect && !dc.constrainX && !dc.constrainY)) {
20082 return oTarget.cursorIsOver;
20085 oTarget.overlap = null;
20087 // Get the current location of the drag element, this is the
20088 // location of the mouse event less the delta that represents
20089 // where the original mousedown happened on the element. We
20090 // need to consider constraints and ticks as well.
20091 var pos = dc.getTargetCoord(pt.x, pt.y);
20093 var el = dc.getDragEl();
20094 var curRegion = new Roo.lib.Region( pos.y,
20095 pos.x + el.offsetWidth,
20096 pos.y + el.offsetHeight,
20099 var overlap = curRegion.intersect(loc);
20102 oTarget.overlap = overlap;
20103 return (intersect) ? true : oTarget.cursorIsOver;
20110 * unload event handler
20111 * @method _onUnload
20115 _onUnload: function(e, me) {
20116 Roo.dd.DragDropMgr.unregAll();
20120 * Cleans up the drag and drop events and objects.
20125 unregAll: function() {
20127 if (this.dragCurrent) {
20129 this.dragCurrent = null;
20132 this._execOnAll("unreg", []);
20134 for (i in this.elementCache) {
20135 delete this.elementCache[i];
20138 this.elementCache = {};
20143 * A cache of DOM elements
20144 * @property elementCache
20151 * Get the wrapper for the DOM element specified
20152 * @method getElWrapper
20153 * @param {String} id the id of the element to get
20154 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20156 * @deprecated This wrapper isn't that useful
20159 getElWrapper: function(id) {
20160 var oWrapper = this.elementCache[id];
20161 if (!oWrapper || !oWrapper.el) {
20162 oWrapper = this.elementCache[id] =
20163 new this.ElementWrapper(Roo.getDom(id));
20169 * Returns the actual DOM element
20170 * @method getElement
20171 * @param {String} id the id of the elment to get
20172 * @return {Object} The element
20173 * @deprecated use Roo.getDom instead
20176 getElement: function(id) {
20177 return Roo.getDom(id);
20181 * Returns the style property for the DOM element (i.e.,
20182 * document.getElById(id).style)
20184 * @param {String} id the id of the elment to get
20185 * @return {Object} The style property of the element
20186 * @deprecated use Roo.getDom instead
20189 getCss: function(id) {
20190 var el = Roo.getDom(id);
20191 return (el) ? el.style : null;
20195 * Inner class for cached elements
20196 * @class DragDropMgr.ElementWrapper
20201 ElementWrapper: function(el) {
20206 this.el = el || null;
20211 this.id = this.el && el.id;
20213 * A reference to the style property
20216 this.css = this.el && el.style;
20220 * Returns the X position of an html element
20222 * @param el the element for which to get the position
20223 * @return {int} the X coordinate
20225 * @deprecated use Roo.lib.Dom.getX instead
20228 getPosX: function(el) {
20229 return Roo.lib.Dom.getX(el);
20233 * Returns the Y position of an html element
20235 * @param el the element for which to get the position
20236 * @return {int} the Y coordinate
20237 * @deprecated use Roo.lib.Dom.getY instead
20240 getPosY: function(el) {
20241 return Roo.lib.Dom.getY(el);
20245 * Swap two nodes. In IE, we use the native method, for others we
20246 * emulate the IE behavior
20248 * @param n1 the first node to swap
20249 * @param n2 the other node to swap
20252 swapNode: function(n1, n2) {
20256 var p = n2.parentNode;
20257 var s = n2.nextSibling;
20260 p.insertBefore(n1, n2);
20261 } else if (n2 == n1.nextSibling) {
20262 p.insertBefore(n2, n1);
20264 n1.parentNode.replaceChild(n2, n1);
20265 p.insertBefore(n1, s);
20271 * Returns the current scroll position
20272 * @method getScroll
20276 getScroll: function () {
20277 var t, l, dde=document.documentElement, db=document.body;
20278 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20280 l = dde.scrollLeft;
20287 return { top: t, left: l };
20291 * Returns the specified element style property
20293 * @param {HTMLElement} el the element
20294 * @param {string} styleProp the style property
20295 * @return {string} The value of the style property
20296 * @deprecated use Roo.lib.Dom.getStyle
20299 getStyle: function(el, styleProp) {
20300 return Roo.fly(el).getStyle(styleProp);
20304 * Gets the scrollTop
20305 * @method getScrollTop
20306 * @return {int} the document's scrollTop
20309 getScrollTop: function () { return this.getScroll().top; },
20312 * Gets the scrollLeft
20313 * @method getScrollLeft
20314 * @return {int} the document's scrollTop
20317 getScrollLeft: function () { return this.getScroll().left; },
20320 * Sets the x/y position of an element to the location of the
20323 * @param {HTMLElement} moveEl The element to move
20324 * @param {HTMLElement} targetEl The position reference element
20327 moveToEl: function (moveEl, targetEl) {
20328 var aCoord = Roo.lib.Dom.getXY(targetEl);
20329 Roo.lib.Dom.setXY(moveEl, aCoord);
20333 * Numeric array sort function
20334 * @method numericSort
20337 numericSort: function(a, b) { return (a - b); },
20341 * @property _timeoutCount
20348 * Trying to make the load order less important. Without this we get
20349 * an error if this file is loaded before the Event Utility.
20350 * @method _addListeners
20354 _addListeners: function() {
20355 var DDM = Roo.dd.DDM;
20356 if ( Roo.lib.Event && document ) {
20359 if (DDM._timeoutCount > 2000) {
20361 setTimeout(DDM._addListeners, 10);
20362 if (document && document.body) {
20363 DDM._timeoutCount += 1;
20370 * Recursively searches the immediate parent and all child nodes for
20371 * the handle element in order to determine wheter or not it was
20373 * @method handleWasClicked
20374 * @param node the html element to inspect
20377 handleWasClicked: function(node, id) {
20378 if (this.isHandle(id, node.id)) {
20381 // check to see if this is a text node child of the one we want
20382 var p = node.parentNode;
20385 if (this.isHandle(id, p.id)) {
20400 // shorter alias, save a few bytes
20401 Roo.dd.DDM = Roo.dd.DragDropMgr;
20402 Roo.dd.DDM._addListeners();
20406 * Ext JS Library 1.1.1
20407 * Copyright(c) 2006-2007, Ext JS, LLC.
20409 * Originally Released Under LGPL - original licence link has changed is not relivant.
20412 * <script type="text/javascript">
20417 * A DragDrop implementation where the linked element follows the
20418 * mouse cursor during a drag.
20419 * @extends Roo.dd.DragDrop
20421 * @param {String} id the id of the linked element
20422 * @param {String} sGroup the group of related DragDrop items
20423 * @param {object} config an object containing configurable attributes
20424 * Valid properties for DD:
20427 Roo.dd.DD = function(id, sGroup, config) {
20429 this.init(id, sGroup, config);
20433 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20436 * When set to true, the utility automatically tries to scroll the browser
20437 * window wehn a drag and drop element is dragged near the viewport boundary.
20438 * Defaults to true.
20445 * Sets the pointer offset to the distance between the linked element's top
20446 * left corner and the location the element was clicked
20447 * @method autoOffset
20448 * @param {int} iPageX the X coordinate of the click
20449 * @param {int} iPageY the Y coordinate of the click
20451 autoOffset: function(iPageX, iPageY) {
20452 var x = iPageX - this.startPageX;
20453 var y = iPageY - this.startPageY;
20454 this.setDelta(x, y);
20458 * Sets the pointer offset. You can call this directly to force the
20459 * offset to be in a particular location (e.g., pass in 0,0 to set it
20460 * to the center of the object)
20462 * @param {int} iDeltaX the distance from the left
20463 * @param {int} iDeltaY the distance from the top
20465 setDelta: function(iDeltaX, iDeltaY) {
20466 this.deltaX = iDeltaX;
20467 this.deltaY = iDeltaY;
20471 * Sets the drag element to the location of the mousedown or click event,
20472 * maintaining the cursor location relative to the location on the element
20473 * that was clicked. Override this if you want to place the element in a
20474 * location other than where the cursor is.
20475 * @method setDragElPos
20476 * @param {int} iPageX the X coordinate of the mousedown or drag event
20477 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20479 setDragElPos: function(iPageX, iPageY) {
20480 // the first time we do this, we are going to check to make sure
20481 // the element has css positioning
20483 var el = this.getDragEl();
20484 this.alignElWithMouse(el, iPageX, iPageY);
20488 * Sets the element to the location of the mousedown or click event,
20489 * maintaining the cursor location relative to the location on the element
20490 * that was clicked. Override this if you want to place the element in a
20491 * location other than where the cursor is.
20492 * @method alignElWithMouse
20493 * @param {HTMLElement} el the element to move
20494 * @param {int} iPageX the X coordinate of the mousedown or drag event
20495 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20497 alignElWithMouse: function(el, iPageX, iPageY) {
20498 var oCoord = this.getTargetCoord(iPageX, iPageY);
20499 var fly = el.dom ? el : Roo.fly(el);
20500 if (!this.deltaSetXY) {
20501 var aCoord = [oCoord.x, oCoord.y];
20503 var newLeft = fly.getLeft(true);
20504 var newTop = fly.getTop(true);
20505 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20507 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20510 this.cachePosition(oCoord.x, oCoord.y);
20511 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20516 * Saves the most recent position so that we can reset the constraints and
20517 * tick marks on-demand. We need to know this so that we can calculate the
20518 * number of pixels the element is offset from its original position.
20519 * @method cachePosition
20520 * @param iPageX the current x position (optional, this just makes it so we
20521 * don't have to look it up again)
20522 * @param iPageY the current y position (optional, this just makes it so we
20523 * don't have to look it up again)
20525 cachePosition: function(iPageX, iPageY) {
20527 this.lastPageX = iPageX;
20528 this.lastPageY = iPageY;
20530 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20531 this.lastPageX = aCoord[0];
20532 this.lastPageY = aCoord[1];
20537 * Auto-scroll the window if the dragged object has been moved beyond the
20538 * visible window boundary.
20539 * @method autoScroll
20540 * @param {int} x the drag element's x position
20541 * @param {int} y the drag element's y position
20542 * @param {int} h the height of the drag element
20543 * @param {int} w the width of the drag element
20546 autoScroll: function(x, y, h, w) {
20549 // The client height
20550 var clientH = Roo.lib.Dom.getViewWidth();
20552 // The client width
20553 var clientW = Roo.lib.Dom.getViewHeight();
20555 // The amt scrolled down
20556 var st = this.DDM.getScrollTop();
20558 // The amt scrolled right
20559 var sl = this.DDM.getScrollLeft();
20561 // Location of the bottom of the element
20564 // Location of the right of the element
20567 // The distance from the cursor to the bottom of the visible area,
20568 // adjusted so that we don't scroll if the cursor is beyond the
20569 // element drag constraints
20570 var toBot = (clientH + st - y - this.deltaY);
20572 // The distance from the cursor to the right of the visible area
20573 var toRight = (clientW + sl - x - this.deltaX);
20576 // How close to the edge the cursor must be before we scroll
20577 // var thresh = (document.all) ? 100 : 40;
20580 // How many pixels to scroll per autoscroll op. This helps to reduce
20581 // clunky scrolling. IE is more sensitive about this ... it needs this
20582 // value to be higher.
20583 var scrAmt = (document.all) ? 80 : 30;
20585 // Scroll down if we are near the bottom of the visible page and the
20586 // obj extends below the crease
20587 if ( bot > clientH && toBot < thresh ) {
20588 window.scrollTo(sl, st + scrAmt);
20591 // Scroll up if the window is scrolled down and the top of the object
20592 // goes above the top border
20593 if ( y < st && st > 0 && y - st < thresh ) {
20594 window.scrollTo(sl, st - scrAmt);
20597 // Scroll right if the obj is beyond the right border and the cursor is
20598 // near the border.
20599 if ( right > clientW && toRight < thresh ) {
20600 window.scrollTo(sl + scrAmt, st);
20603 // Scroll left if the window has been scrolled to the right and the obj
20604 // extends past the left border
20605 if ( x < sl && sl > 0 && x - sl < thresh ) {
20606 window.scrollTo(sl - scrAmt, st);
20612 * Finds the location the element should be placed if we want to move
20613 * it to where the mouse location less the click offset would place us.
20614 * @method getTargetCoord
20615 * @param {int} iPageX the X coordinate of the click
20616 * @param {int} iPageY the Y coordinate of the click
20617 * @return an object that contains the coordinates (Object.x and Object.y)
20620 getTargetCoord: function(iPageX, iPageY) {
20623 var x = iPageX - this.deltaX;
20624 var y = iPageY - this.deltaY;
20626 if (this.constrainX) {
20627 if (x < this.minX) { x = this.minX; }
20628 if (x > this.maxX) { x = this.maxX; }
20631 if (this.constrainY) {
20632 if (y < this.minY) { y = this.minY; }
20633 if (y > this.maxY) { y = this.maxY; }
20636 x = this.getTick(x, this.xTicks);
20637 y = this.getTick(y, this.yTicks);
20644 * Sets up config options specific to this class. Overrides
20645 * Roo.dd.DragDrop, but all versions of this method through the
20646 * inheritance chain are called
20648 applyConfig: function() {
20649 Roo.dd.DD.superclass.applyConfig.call(this);
20650 this.scroll = (this.config.scroll !== false);
20654 * Event that fires prior to the onMouseDown event. Overrides
20657 b4MouseDown: function(e) {
20658 // this.resetConstraints();
20659 this.autoOffset(e.getPageX(),
20664 * Event that fires prior to the onDrag event. Overrides
20667 b4Drag: function(e) {
20668 this.setDragElPos(e.getPageX(),
20672 toString: function() {
20673 return ("DD " + this.id);
20676 //////////////////////////////////////////////////////////////////////////
20677 // Debugging ygDragDrop events that can be overridden
20678 //////////////////////////////////////////////////////////////////////////
20680 startDrag: function(x, y) {
20683 onDrag: function(e) {
20686 onDragEnter: function(e, id) {
20689 onDragOver: function(e, id) {
20692 onDragOut: function(e, id) {
20695 onDragDrop: function(e, id) {
20698 endDrag: function(e) {
20705 * Ext JS Library 1.1.1
20706 * Copyright(c) 2006-2007, Ext JS, LLC.
20708 * Originally Released Under LGPL - original licence link has changed is not relivant.
20711 * <script type="text/javascript">
20715 * @class Roo.dd.DDProxy
20716 * A DragDrop implementation that inserts an empty, bordered div into
20717 * the document that follows the cursor during drag operations. At the time of
20718 * the click, the frame div is resized to the dimensions of the linked html
20719 * element, and moved to the exact location of the linked element.
20721 * References to the "frame" element refer to the single proxy element that
20722 * was created to be dragged in place of all DDProxy elements on the
20725 * @extends Roo.dd.DD
20727 * @param {String} id the id of the linked html element
20728 * @param {String} sGroup the group of related DragDrop objects
20729 * @param {object} config an object containing configurable attributes
20730 * Valid properties for DDProxy in addition to those in DragDrop:
20731 * resizeFrame, centerFrame, dragElId
20733 Roo.dd.DDProxy = function(id, sGroup, config) {
20735 this.init(id, sGroup, config);
20741 * The default drag frame div id
20742 * @property Roo.dd.DDProxy.dragElId
20746 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20748 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20751 * By default we resize the drag frame to be the same size as the element
20752 * we want to drag (this is to get the frame effect). We can turn it off
20753 * if we want a different behavior.
20754 * @property resizeFrame
20760 * By default the frame is positioned exactly where the drag element is, so
20761 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20762 * you do not have constraints on the obj is to have the drag frame centered
20763 * around the cursor. Set centerFrame to true for this effect.
20764 * @property centerFrame
20767 centerFrame: false,
20770 * Creates the proxy element if it does not yet exist
20771 * @method createFrame
20773 createFrame: function() {
20775 var body = document.body;
20777 if (!body || !body.firstChild) {
20778 setTimeout( function() { self.createFrame(); }, 50 );
20782 var div = this.getDragEl();
20785 div = document.createElement("div");
20786 div.id = this.dragElId;
20789 s.position = "absolute";
20790 s.visibility = "hidden";
20792 s.border = "2px solid #aaa";
20795 // appendChild can blow up IE if invoked prior to the window load event
20796 // while rendering a table. It is possible there are other scenarios
20797 // that would cause this to happen as well.
20798 body.insertBefore(div, body.firstChild);
20803 * Initialization for the drag frame element. Must be called in the
20804 * constructor of all subclasses
20805 * @method initFrame
20807 initFrame: function() {
20808 this.createFrame();
20811 applyConfig: function() {
20812 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20814 this.resizeFrame = (this.config.resizeFrame !== false);
20815 this.centerFrame = (this.config.centerFrame);
20816 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20820 * Resizes the drag frame to the dimensions of the clicked object, positions
20821 * it over the object, and finally displays it
20822 * @method showFrame
20823 * @param {int} iPageX X click position
20824 * @param {int} iPageY Y click position
20827 showFrame: function(iPageX, iPageY) {
20828 var el = this.getEl();
20829 var dragEl = this.getDragEl();
20830 var s = dragEl.style;
20832 this._resizeProxy();
20834 if (this.centerFrame) {
20835 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20836 Math.round(parseInt(s.height, 10)/2) );
20839 this.setDragElPos(iPageX, iPageY);
20841 Roo.fly(dragEl).show();
20845 * The proxy is automatically resized to the dimensions of the linked
20846 * element when a drag is initiated, unless resizeFrame is set to false
20847 * @method _resizeProxy
20850 _resizeProxy: function() {
20851 if (this.resizeFrame) {
20852 var el = this.getEl();
20853 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20857 // overrides Roo.dd.DragDrop
20858 b4MouseDown: function(e) {
20859 var x = e.getPageX();
20860 var y = e.getPageY();
20861 this.autoOffset(x, y);
20862 this.setDragElPos(x, y);
20865 // overrides Roo.dd.DragDrop
20866 b4StartDrag: function(x, y) {
20867 // show the drag frame
20868 this.showFrame(x, y);
20871 // overrides Roo.dd.DragDrop
20872 b4EndDrag: function(e) {
20873 Roo.fly(this.getDragEl()).hide();
20876 // overrides Roo.dd.DragDrop
20877 // By default we try to move the element to the last location of the frame.
20878 // This is so that the default behavior mirrors that of Roo.dd.DD.
20879 endDrag: function(e) {
20881 var lel = this.getEl();
20882 var del = this.getDragEl();
20884 // Show the drag frame briefly so we can get its position
20885 del.style.visibility = "";
20888 // Hide the linked element before the move to get around a Safari
20890 lel.style.visibility = "hidden";
20891 Roo.dd.DDM.moveToEl(lel, del);
20892 del.style.visibility = "hidden";
20893 lel.style.visibility = "";
20898 beforeMove : function(){
20902 afterDrag : function(){
20906 toString: function() {
20907 return ("DDProxy " + this.id);
20913 * Ext JS Library 1.1.1
20914 * Copyright(c) 2006-2007, Ext JS, LLC.
20916 * Originally Released Under LGPL - original licence link has changed is not relivant.
20919 * <script type="text/javascript">
20923 * @class Roo.dd.DDTarget
20924 * A DragDrop implementation that does not move, but can be a drop
20925 * target. You would get the same result by simply omitting implementation
20926 * for the event callbacks, but this way we reduce the processing cost of the
20927 * event listener and the callbacks.
20928 * @extends Roo.dd.DragDrop
20930 * @param {String} id the id of the element that is a drop target
20931 * @param {String} sGroup the group of related DragDrop objects
20932 * @param {object} config an object containing configurable attributes
20933 * Valid properties for DDTarget in addition to those in
20937 Roo.dd.DDTarget = function(id, sGroup, config) {
20939 this.initTarget(id, sGroup, config);
20941 if (config.listeners || config.events) {
20942 Roo.dd.DragDrop.superclass.constructor.call(this, {
20943 listeners : config.listeners || {},
20944 events : config.events || {}
20949 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20950 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20951 toString: function() {
20952 return ("DDTarget " + this.id);
20957 * Ext JS Library 1.1.1
20958 * Copyright(c) 2006-2007, Ext JS, LLC.
20960 * Originally Released Under LGPL - original licence link has changed is not relivant.
20963 * <script type="text/javascript">
20968 * @class Roo.dd.ScrollManager
20969 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20970 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
20973 Roo.dd.ScrollManager = function(){
20974 var ddm = Roo.dd.DragDropMgr;
20981 var onStop = function(e){
20986 var triggerRefresh = function(){
20987 if(ddm.dragCurrent){
20988 ddm.refreshCache(ddm.dragCurrent.groups);
20992 var doScroll = function(){
20993 if(ddm.dragCurrent){
20994 var dds = Roo.dd.ScrollManager;
20996 if(proc.el.scroll(proc.dir, dds.increment)){
21000 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21005 var clearProc = function(){
21007 clearInterval(proc.id);
21014 var startProc = function(el, dir){
21015 Roo.log('scroll startproc');
21019 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21022 var onFire = function(e, isDrop){
21024 if(isDrop || !ddm.dragCurrent){ return; }
21025 var dds = Roo.dd.ScrollManager;
21026 if(!dragEl || dragEl != ddm.dragCurrent){
21027 dragEl = ddm.dragCurrent;
21028 // refresh regions on drag start
21029 dds.refreshCache();
21032 var xy = Roo.lib.Event.getXY(e);
21033 var pt = new Roo.lib.Point(xy[0], xy[1]);
21034 for(var id in els){
21035 var el = els[id], r = el._region;
21036 if(r && r.contains(pt) && el.isScrollable()){
21037 if(r.bottom - pt.y <= dds.thresh){
21039 startProc(el, "down");
21042 }else if(r.right - pt.x <= dds.thresh){
21044 startProc(el, "left");
21047 }else if(pt.y - r.top <= dds.thresh){
21049 startProc(el, "up");
21052 }else if(pt.x - r.left <= dds.thresh){
21054 startProc(el, "right");
21063 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21064 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21068 * Registers new overflow element(s) to auto scroll
21069 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21071 register : function(el){
21072 if(el instanceof Array){
21073 for(var i = 0, len = el.length; i < len; i++) {
21074 this.register(el[i]);
21080 Roo.dd.ScrollManager.els = els;
21084 * Unregisters overflow element(s) so they are no longer scrolled
21085 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21087 unregister : function(el){
21088 if(el instanceof Array){
21089 for(var i = 0, len = el.length; i < len; i++) {
21090 this.unregister(el[i]);
21099 * The number of pixels from the edge of a container the pointer needs to be to
21100 * trigger scrolling (defaults to 25)
21106 * The number of pixels to scroll in each scroll increment (defaults to 50)
21112 * The frequency of scrolls in milliseconds (defaults to 500)
21118 * True to animate the scroll (defaults to true)
21124 * The animation duration in seconds -
21125 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21131 * Manually trigger a cache refresh.
21133 refreshCache : function(){
21134 for(var id in els){
21135 if(typeof els[id] == 'object'){ // for people extending the object prototype
21136 els[id]._region = els[id].getRegion();
21143 * Ext JS Library 1.1.1
21144 * Copyright(c) 2006-2007, Ext JS, LLC.
21146 * Originally Released Under LGPL - original licence link has changed is not relivant.
21149 * <script type="text/javascript">
21154 * @class Roo.dd.Registry
21155 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21156 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21159 Roo.dd.Registry = function(){
21162 var autoIdSeed = 0;
21164 var getId = function(el, autogen){
21165 if(typeof el == "string"){
21169 if(!id && autogen !== false){
21170 id = "roodd-" + (++autoIdSeed);
21178 * Register a drag drop element
21179 * @param {String|HTMLElement} element The id or DOM node to register
21180 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21181 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21182 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21183 * populated in the data object (if applicable):
21185 Value Description<br />
21186 --------- ------------------------------------------<br />
21187 handles Array of DOM nodes that trigger dragging<br />
21188 for the element being registered<br />
21189 isHandle True if the element passed in triggers<br />
21190 dragging itself, else false
21193 register : function(el, data){
21195 if(typeof el == "string"){
21196 el = document.getElementById(el);
21199 elements[getId(el)] = data;
21200 if(data.isHandle !== false){
21201 handles[data.ddel.id] = data;
21204 var hs = data.handles;
21205 for(var i = 0, len = hs.length; i < len; i++){
21206 handles[getId(hs[i])] = data;
21212 * Unregister a drag drop element
21213 * @param {String|HTMLElement} element The id or DOM node to unregister
21215 unregister : function(el){
21216 var id = getId(el, false);
21217 var data = elements[id];
21219 delete elements[id];
21221 var hs = data.handles;
21222 for(var i = 0, len = hs.length; i < len; i++){
21223 delete handles[getId(hs[i], false)];
21230 * Returns the handle registered for a DOM Node by id
21231 * @param {String|HTMLElement} id The DOM node or id to look up
21232 * @return {Object} handle The custom handle data
21234 getHandle : function(id){
21235 if(typeof id != "string"){ // must be element?
21238 return handles[id];
21242 * Returns the handle that is registered for the DOM node that is the target of the event
21243 * @param {Event} e The event
21244 * @return {Object} handle The custom handle data
21246 getHandleFromEvent : function(e){
21247 var t = Roo.lib.Event.getTarget(e);
21248 return t ? handles[t.id] : null;
21252 * Returns a custom data object that is registered for a DOM node by id
21253 * @param {String|HTMLElement} id The DOM node or id to look up
21254 * @return {Object} data The custom data
21256 getTarget : function(id){
21257 if(typeof id != "string"){ // must be element?
21260 return elements[id];
21264 * Returns a custom data object that is registered for the DOM node that is the target of the event
21265 * @param {Event} e The event
21266 * @return {Object} data The custom data
21268 getTargetFromEvent : function(e){
21269 var t = Roo.lib.Event.getTarget(e);
21270 return t ? elements[t.id] || handles[t.id] : null;
21275 * Ext JS Library 1.1.1
21276 * Copyright(c) 2006-2007, Ext JS, LLC.
21278 * Originally Released Under LGPL - original licence link has changed is not relivant.
21281 * <script type="text/javascript">
21286 * @class Roo.dd.StatusProxy
21287 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21288 * default drag proxy used by all Roo.dd components.
21290 * @param {Object} config
21292 Roo.dd.StatusProxy = function(config){
21293 Roo.apply(this, config);
21294 this.id = this.id || Roo.id();
21295 this.el = new Roo.Layer({
21297 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21298 {tag: "div", cls: "x-dd-drop-icon"},
21299 {tag: "div", cls: "x-dd-drag-ghost"}
21302 shadow: !config || config.shadow !== false
21304 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21305 this.dropStatus = this.dropNotAllowed;
21308 Roo.dd.StatusProxy.prototype = {
21310 * @cfg {String} dropAllowed
21311 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21313 dropAllowed : "x-dd-drop-ok",
21315 * @cfg {String} dropNotAllowed
21316 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21318 dropNotAllowed : "x-dd-drop-nodrop",
21321 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21322 * over the current target element.
21323 * @param {String} cssClass The css class for the new drop status indicator image
21325 setStatus : function(cssClass){
21326 cssClass = cssClass || this.dropNotAllowed;
21327 if(this.dropStatus != cssClass){
21328 this.el.replaceClass(this.dropStatus, cssClass);
21329 this.dropStatus = cssClass;
21334 * Resets the status indicator to the default dropNotAllowed value
21335 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21337 reset : function(clearGhost){
21338 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21339 this.dropStatus = this.dropNotAllowed;
21341 this.ghost.update("");
21346 * Updates the contents of the ghost element
21347 * @param {String} html The html that will replace the current innerHTML of the ghost element
21349 update : function(html){
21350 if(typeof html == "string"){
21351 this.ghost.update(html);
21353 this.ghost.update("");
21354 html.style.margin = "0";
21355 this.ghost.dom.appendChild(html);
21357 // ensure float = none set?? cant remember why though.
21358 var el = this.ghost.dom.firstChild;
21360 Roo.fly(el).setStyle('float', 'none');
21365 * Returns the underlying proxy {@link Roo.Layer}
21366 * @return {Roo.Layer} el
21368 getEl : function(){
21373 * Returns the ghost element
21374 * @return {Roo.Element} el
21376 getGhost : function(){
21382 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21384 hide : function(clear){
21392 * Stops the repair animation if it's currently running
21395 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21401 * Displays this proxy
21408 * Force the Layer to sync its shadow and shim positions to the element
21415 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21416 * invalid drop operation by the item being dragged.
21417 * @param {Array} xy The XY position of the element ([x, y])
21418 * @param {Function} callback The function to call after the repair is complete
21419 * @param {Object} scope The scope in which to execute the callback
21421 repair : function(xy, callback, scope){
21422 this.callback = callback;
21423 this.scope = scope;
21424 if(xy && this.animRepair !== false){
21425 this.el.addClass("x-dd-drag-repair");
21426 this.el.hideUnders(true);
21427 this.anim = this.el.shift({
21428 duration: this.repairDuration || .5,
21432 callback: this.afterRepair,
21436 this.afterRepair();
21441 afterRepair : function(){
21443 if(typeof this.callback == "function"){
21444 this.callback.call(this.scope || this);
21446 this.callback = null;
21451 * Ext JS Library 1.1.1
21452 * Copyright(c) 2006-2007, Ext JS, LLC.
21454 * Originally Released Under LGPL - original licence link has changed is not relivant.
21457 * <script type="text/javascript">
21461 * @class Roo.dd.DragSource
21462 * @extends Roo.dd.DDProxy
21463 * A simple class that provides the basic implementation needed to make any element draggable.
21465 * @param {String/HTMLElement/Element} el The container element
21466 * @param {Object} config
21468 Roo.dd.DragSource = function(el, config){
21469 this.el = Roo.get(el);
21470 this.dragData = {};
21472 Roo.apply(this, config);
21475 this.proxy = new Roo.dd.StatusProxy();
21478 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21479 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21481 this.dragging = false;
21484 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21486 * @cfg {String} dropAllowed
21487 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21489 dropAllowed : "x-dd-drop-ok",
21491 * @cfg {String} dropNotAllowed
21492 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21494 dropNotAllowed : "x-dd-drop-nodrop",
21497 * Returns the data object associated with this drag source
21498 * @return {Object} data An object containing arbitrary data
21500 getDragData : function(e){
21501 return this.dragData;
21505 onDragEnter : function(e, id){
21506 var target = Roo.dd.DragDropMgr.getDDById(id);
21507 this.cachedTarget = target;
21508 if(this.beforeDragEnter(target, e, id) !== false){
21509 if(target.isNotifyTarget){
21510 var status = target.notifyEnter(this, e, this.dragData);
21511 this.proxy.setStatus(status);
21513 this.proxy.setStatus(this.dropAllowed);
21516 if(this.afterDragEnter){
21518 * An empty function by default, but provided so that you can perform a custom action
21519 * when the dragged item enters the drop target by providing an implementation.
21520 * @param {Roo.dd.DragDrop} target The drop target
21521 * @param {Event} e The event object
21522 * @param {String} id The id of the dragged element
21523 * @method afterDragEnter
21525 this.afterDragEnter(target, e, id);
21531 * An empty function by default, but provided so that you can perform a custom action
21532 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21533 * @param {Roo.dd.DragDrop} target The drop target
21534 * @param {Event} e The event object
21535 * @param {String} id The id of the dragged element
21536 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21538 beforeDragEnter : function(target, e, id){
21543 alignElWithMouse: function() {
21544 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21549 onDragOver : function(e, id){
21550 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21551 if(this.beforeDragOver(target, e, id) !== false){
21552 if(target.isNotifyTarget){
21553 var status = target.notifyOver(this, e, this.dragData);
21554 this.proxy.setStatus(status);
21557 if(this.afterDragOver){
21559 * An empty function by default, but provided so that you can perform a custom action
21560 * while the dragged item is over the drop target by providing an implementation.
21561 * @param {Roo.dd.DragDrop} target The drop target
21562 * @param {Event} e The event object
21563 * @param {String} id The id of the dragged element
21564 * @method afterDragOver
21566 this.afterDragOver(target, e, id);
21572 * An empty function by default, but provided so that you can perform a custom action
21573 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21574 * @param {Roo.dd.DragDrop} target The drop target
21575 * @param {Event} e The event object
21576 * @param {String} id The id of the dragged element
21577 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21579 beforeDragOver : function(target, e, id){
21584 onDragOut : function(e, id){
21585 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21586 if(this.beforeDragOut(target, e, id) !== false){
21587 if(target.isNotifyTarget){
21588 target.notifyOut(this, e, this.dragData);
21590 this.proxy.reset();
21591 if(this.afterDragOut){
21593 * An empty function by default, but provided so that you can perform a custom action
21594 * after the dragged item is dragged out of the target without dropping.
21595 * @param {Roo.dd.DragDrop} target The drop target
21596 * @param {Event} e The event object
21597 * @param {String} id The id of the dragged element
21598 * @method afterDragOut
21600 this.afterDragOut(target, e, id);
21603 this.cachedTarget = null;
21607 * An empty function by default, but provided so that you can perform a custom action before the dragged
21608 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21609 * @param {Roo.dd.DragDrop} target The drop target
21610 * @param {Event} e The event object
21611 * @param {String} id The id of the dragged element
21612 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21614 beforeDragOut : function(target, e, id){
21619 onDragDrop : function(e, id){
21620 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21621 if(this.beforeDragDrop(target, e, id) !== false){
21622 if(target.isNotifyTarget){
21623 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21624 this.onValidDrop(target, e, id);
21626 this.onInvalidDrop(target, e, id);
21629 this.onValidDrop(target, e, id);
21632 if(this.afterDragDrop){
21634 * An empty function by default, but provided so that you can perform a custom action
21635 * after a valid drag drop has occurred by providing an implementation.
21636 * @param {Roo.dd.DragDrop} target The drop target
21637 * @param {Event} e The event object
21638 * @param {String} id The id of the dropped element
21639 * @method afterDragDrop
21641 this.afterDragDrop(target, e, id);
21644 delete this.cachedTarget;
21648 * An empty function by default, but provided so that you can perform a custom action before the dragged
21649 * item is dropped onto the target and optionally cancel the onDragDrop.
21650 * @param {Roo.dd.DragDrop} target The drop target
21651 * @param {Event} e The event object
21652 * @param {String} id The id of the dragged element
21653 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21655 beforeDragDrop : function(target, e, id){
21660 onValidDrop : function(target, e, id){
21662 if(this.afterValidDrop){
21664 * An empty function by default, but provided so that you can perform a custom action
21665 * after a valid drop has occurred by providing an implementation.
21666 * @param {Object} target The target DD
21667 * @param {Event} e The event object
21668 * @param {String} id The id of the dropped element
21669 * @method afterInvalidDrop
21671 this.afterValidDrop(target, e, id);
21676 getRepairXY : function(e, data){
21677 return this.el.getXY();
21681 onInvalidDrop : function(target, e, id){
21682 this.beforeInvalidDrop(target, e, id);
21683 if(this.cachedTarget){
21684 if(this.cachedTarget.isNotifyTarget){
21685 this.cachedTarget.notifyOut(this, e, this.dragData);
21687 this.cacheTarget = null;
21689 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21691 if(this.afterInvalidDrop){
21693 * An empty function by default, but provided so that you can perform a custom action
21694 * after an invalid drop has occurred by providing an implementation.
21695 * @param {Event} e The event object
21696 * @param {String} id The id of the dropped element
21697 * @method afterInvalidDrop
21699 this.afterInvalidDrop(e, id);
21704 afterRepair : function(){
21706 this.el.highlight(this.hlColor || "c3daf9");
21708 this.dragging = false;
21712 * An empty function by default, but provided so that you can perform a custom action after an invalid
21713 * drop has occurred.
21714 * @param {Roo.dd.DragDrop} target The drop target
21715 * @param {Event} e The event object
21716 * @param {String} id The id of the dragged element
21717 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21719 beforeInvalidDrop : function(target, e, id){
21724 handleMouseDown : function(e){
21725 if(this.dragging) {
21728 var data = this.getDragData(e);
21729 if(data && this.onBeforeDrag(data, e) !== false){
21730 this.dragData = data;
21732 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21737 * An empty function by default, but provided so that you can perform a custom action before the initial
21738 * drag event begins and optionally cancel it.
21739 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21740 * @param {Event} e The event object
21741 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21743 onBeforeDrag : function(data, e){
21748 * An empty function by default, but provided so that you can perform a custom action once the initial
21749 * drag event has begun. The drag cannot be canceled from this function.
21750 * @param {Number} x The x position of the click on the dragged object
21751 * @param {Number} y The y position of the click on the dragged object
21753 onStartDrag : Roo.emptyFn,
21755 // private - YUI override
21756 startDrag : function(x, y){
21757 this.proxy.reset();
21758 this.dragging = true;
21759 this.proxy.update("");
21760 this.onInitDrag(x, y);
21765 onInitDrag : function(x, y){
21766 var clone = this.el.dom.cloneNode(true);
21767 clone.id = Roo.id(); // prevent duplicate ids
21768 this.proxy.update(clone);
21769 this.onStartDrag(x, y);
21774 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21775 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21777 getProxy : function(){
21782 * Hides the drag source's {@link Roo.dd.StatusProxy}
21784 hideProxy : function(){
21786 this.proxy.reset(true);
21787 this.dragging = false;
21791 triggerCacheRefresh : function(){
21792 Roo.dd.DDM.refreshCache(this.groups);
21795 // private - override to prevent hiding
21796 b4EndDrag: function(e) {
21799 // private - override to prevent moving
21800 endDrag : function(e){
21801 this.onEndDrag(this.dragData, e);
21805 onEndDrag : function(data, e){
21808 // private - pin to cursor
21809 autoOffset : function(x, y) {
21810 this.setDelta(-12, -20);
21814 * Ext JS Library 1.1.1
21815 * Copyright(c) 2006-2007, Ext JS, LLC.
21817 * Originally Released Under LGPL - original licence link has changed is not relivant.
21820 * <script type="text/javascript">
21825 * @class Roo.dd.DropTarget
21826 * @extends Roo.dd.DDTarget
21827 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21828 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21830 * @param {String/HTMLElement/Element} el The container element
21831 * @param {Object} config
21833 Roo.dd.DropTarget = function(el, config){
21834 this.el = Roo.get(el);
21836 var listeners = false; ;
21837 if (config && config.listeners) {
21838 listeners= config.listeners;
21839 delete config.listeners;
21841 Roo.apply(this, config);
21843 if(this.containerScroll){
21844 Roo.dd.ScrollManager.register(this.el);
21848 * @scope Roo.dd.DropTarget
21853 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21854 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21855 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21857 * IMPORTANT : it should set this.overClass and this.dropAllowed
21859 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21860 * @param {Event} e The event
21861 * @param {Object} data An object containing arbitrary data supplied by the drag source
21867 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21868 * This method will be called on every mouse movement while the drag source is over the drop target.
21869 * This default implementation simply returns the dropAllowed config value.
21871 * IMPORTANT : it should set this.dropAllowed
21873 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21874 * @param {Event} e The event
21875 * @param {Object} data An object containing arbitrary data supplied by the drag source
21881 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21882 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21883 * overClass (if any) from the drop element.
21885 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21886 * @param {Event} e The event
21887 * @param {Object} data An object containing arbitrary data supplied by the drag source
21893 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21894 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21895 * implementation that does something to process the drop event and returns true so that the drag source's
21896 * repair action does not run.
21898 * IMPORTANT : it should set this.success
21900 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21901 * @param {Event} e The event
21902 * @param {Object} data An object containing arbitrary data supplied by the drag source
21908 Roo.dd.DropTarget.superclass.constructor.call( this,
21910 this.ddGroup || this.group,
21913 listeners : listeners || {}
21921 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21923 * @cfg {String} overClass
21924 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21927 * @cfg {String} ddGroup
21928 * The drag drop group to handle drop events for
21932 * @cfg {String} dropAllowed
21933 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21935 dropAllowed : "x-dd-drop-ok",
21937 * @cfg {String} dropNotAllowed
21938 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21940 dropNotAllowed : "x-dd-drop-nodrop",
21942 * @cfg {boolean} success
21943 * set this after drop listener..
21947 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21948 * if the drop point is valid for over/enter..
21955 isNotifyTarget : true,
21960 notifyEnter : function(dd, e, data)
21963 this.fireEvent('enter', dd, e, data);
21964 if(this.overClass){
21965 this.el.addClass(this.overClass);
21967 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21968 this.valid ? this.dropAllowed : this.dropNotAllowed
21975 notifyOver : function(dd, e, data)
21978 this.fireEvent('over', dd, e, data);
21979 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21980 this.valid ? this.dropAllowed : this.dropNotAllowed
21987 notifyOut : function(dd, e, data)
21989 this.fireEvent('out', dd, e, data);
21990 if(this.overClass){
21991 this.el.removeClass(this.overClass);
21998 notifyDrop : function(dd, e, data)
22000 this.success = false;
22001 this.fireEvent('drop', dd, e, data);
22002 return this.success;
22006 * Ext JS Library 1.1.1
22007 * Copyright(c) 2006-2007, Ext JS, LLC.
22009 * Originally Released Under LGPL - original licence link has changed is not relivant.
22012 * <script type="text/javascript">
22017 * @class Roo.dd.DragZone
22018 * @extends Roo.dd.DragSource
22019 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22020 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22022 * @param {String/HTMLElement/Element} el The container element
22023 * @param {Object} config
22025 Roo.dd.DragZone = function(el, config){
22026 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22027 if(this.containerScroll){
22028 Roo.dd.ScrollManager.register(this.el);
22032 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22034 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22035 * for auto scrolling during drag operations.
22038 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22039 * method after a failed drop (defaults to "c3daf9" - light blue)
22043 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22044 * for a valid target to drag based on the mouse down. Override this method
22045 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22046 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22047 * @param {EventObject} e The mouse down event
22048 * @return {Object} The dragData
22050 getDragData : function(e){
22051 return Roo.dd.Registry.getHandleFromEvent(e);
22055 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22056 * this.dragData.ddel
22057 * @param {Number} x The x position of the click on the dragged object
22058 * @param {Number} y The y position of the click on the dragged object
22059 * @return {Boolean} true to continue the drag, false to cancel
22061 onInitDrag : function(x, y){
22062 this.proxy.update(this.dragData.ddel.cloneNode(true));
22063 this.onStartDrag(x, y);
22068 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22070 afterRepair : function(){
22072 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22074 this.dragging = false;
22078 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22079 * the XY of this.dragData.ddel
22080 * @param {EventObject} e The mouse up event
22081 * @return {Array} The xy location (e.g. [100, 200])
22083 getRepairXY : function(e){
22084 return Roo.Element.fly(this.dragData.ddel).getXY();
22088 * Ext JS Library 1.1.1
22089 * Copyright(c) 2006-2007, Ext JS, LLC.
22091 * Originally Released Under LGPL - original licence link has changed is not relivant.
22094 * <script type="text/javascript">
22097 * @class Roo.dd.DropZone
22098 * @extends Roo.dd.DropTarget
22099 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22100 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22102 * @param {String/HTMLElement/Element} el The container element
22103 * @param {Object} config
22105 Roo.dd.DropZone = function(el, config){
22106 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22109 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22111 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22112 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22113 * provide your own custom lookup.
22114 * @param {Event} e The event
22115 * @return {Object} data The custom data
22117 getTargetFromEvent : function(e){
22118 return Roo.dd.Registry.getTargetFromEvent(e);
22122 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22123 * that it has registered. This method has no default implementation and should be overridden to provide
22124 * node-specific processing if necessary.
22125 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22126 * {@link #getTargetFromEvent} for this node)
22127 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22128 * @param {Event} e The event
22129 * @param {Object} data An object containing arbitrary data supplied by the drag source
22131 onNodeEnter : function(n, dd, e, data){
22136 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22137 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22138 * overridden to provide the proper feedback.
22139 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22140 * {@link #getTargetFromEvent} for this node)
22141 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22142 * @param {Event} e The event
22143 * @param {Object} data An object containing arbitrary data supplied by the drag source
22144 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22145 * underlying {@link Roo.dd.StatusProxy} can be updated
22147 onNodeOver : function(n, dd, e, data){
22148 return this.dropAllowed;
22152 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22153 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22154 * node-specific processing if necessary.
22155 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22156 * {@link #getTargetFromEvent} for this node)
22157 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22158 * @param {Event} e The event
22159 * @param {Object} data An object containing arbitrary data supplied by the drag source
22161 onNodeOut : function(n, dd, e, data){
22166 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22167 * the drop node. The default implementation returns false, so it should be overridden to provide the
22168 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22169 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22170 * {@link #getTargetFromEvent} for this node)
22171 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22172 * @param {Event} e The event
22173 * @param {Object} data An object containing arbitrary data supplied by the drag source
22174 * @return {Boolean} True if the drop was valid, else false
22176 onNodeDrop : function(n, dd, e, data){
22181 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22182 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22183 * it should be overridden to provide the proper feedback if necessary.
22184 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22185 * @param {Event} e The event
22186 * @param {Object} data An object containing arbitrary data supplied by the drag source
22187 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22188 * underlying {@link Roo.dd.StatusProxy} can be updated
22190 onContainerOver : function(dd, e, data){
22191 return this.dropNotAllowed;
22195 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22196 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22197 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22198 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22199 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22200 * @param {Event} e The event
22201 * @param {Object} data An object containing arbitrary data supplied by the drag source
22202 * @return {Boolean} True if the drop was valid, else false
22204 onContainerDrop : function(dd, e, data){
22209 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22210 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22211 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22212 * you should override this method and provide a custom implementation.
22213 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22214 * @param {Event} e The event
22215 * @param {Object} data An object containing arbitrary data supplied by the drag source
22216 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22217 * underlying {@link Roo.dd.StatusProxy} can be updated
22219 notifyEnter : function(dd, e, data){
22220 return this.dropNotAllowed;
22224 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22225 * This method will be called on every mouse movement while the drag source is over the drop zone.
22226 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22227 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22228 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22229 * registered node, it will call {@link #onContainerOver}.
22230 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22231 * @param {Event} e The event
22232 * @param {Object} data An object containing arbitrary data supplied by the drag source
22233 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22234 * underlying {@link Roo.dd.StatusProxy} can be updated
22236 notifyOver : function(dd, e, data){
22237 var n = this.getTargetFromEvent(e);
22238 if(!n){ // not over valid drop target
22239 if(this.lastOverNode){
22240 this.onNodeOut(this.lastOverNode, dd, e, data);
22241 this.lastOverNode = null;
22243 return this.onContainerOver(dd, e, data);
22245 if(this.lastOverNode != n){
22246 if(this.lastOverNode){
22247 this.onNodeOut(this.lastOverNode, dd, e, data);
22249 this.onNodeEnter(n, dd, e, data);
22250 this.lastOverNode = n;
22252 return this.onNodeOver(n, dd, e, data);
22256 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22257 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22258 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22259 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22260 * @param {Event} e The event
22261 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22263 notifyOut : function(dd, e, data){
22264 if(this.lastOverNode){
22265 this.onNodeOut(this.lastOverNode, dd, e, data);
22266 this.lastOverNode = null;
22271 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22272 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22273 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22274 * otherwise it will call {@link #onContainerDrop}.
22275 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22276 * @param {Event} e The event
22277 * @param {Object} data An object containing arbitrary data supplied by the drag source
22278 * @return {Boolean} True if the drop was valid, else false
22280 notifyDrop : function(dd, e, data){
22281 if(this.lastOverNode){
22282 this.onNodeOut(this.lastOverNode, dd, e, data);
22283 this.lastOverNode = null;
22285 var n = this.getTargetFromEvent(e);
22287 this.onNodeDrop(n, dd, e, data) :
22288 this.onContainerDrop(dd, e, data);
22292 triggerCacheRefresh : function(){
22293 Roo.dd.DDM.refreshCache(this.groups);
22297 * Ext JS Library 1.1.1
22298 * Copyright(c) 2006-2007, Ext JS, LLC.
22300 * Originally Released Under LGPL - original licence link has changed is not relivant.
22303 * <script type="text/javascript">
22308 * @class Roo.data.SortTypes
22310 * Defines the default sorting (casting?) comparison functions used when sorting data.
22312 Roo.data.SortTypes = {
22314 * Default sort that does nothing
22315 * @param {Mixed} s The value being converted
22316 * @return {Mixed} The comparison value
22318 none : function(s){
22323 * The regular expression used to strip tags
22327 stripTagsRE : /<\/?[^>]+>/gi,
22330 * Strips all HTML tags to sort on text only
22331 * @param {Mixed} s The value being converted
22332 * @return {String} The comparison value
22334 asText : function(s){
22335 return String(s).replace(this.stripTagsRE, "");
22339 * Strips all HTML tags to sort on text only - Case insensitive
22340 * @param {Mixed} s The value being converted
22341 * @return {String} The comparison value
22343 asUCText : function(s){
22344 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22348 * Case insensitive string
22349 * @param {Mixed} s The value being converted
22350 * @return {String} The comparison value
22352 asUCString : function(s) {
22353 return String(s).toUpperCase();
22358 * @param {Mixed} s The value being converted
22359 * @return {Number} The comparison value
22361 asDate : function(s) {
22365 if(s instanceof Date){
22366 return s.getTime();
22368 return Date.parse(String(s));
22373 * @param {Mixed} s The value being converted
22374 * @return {Float} The comparison value
22376 asFloat : function(s) {
22377 var val = parseFloat(String(s).replace(/,/g, ""));
22386 * @param {Mixed} s The value being converted
22387 * @return {Number} The comparison value
22389 asInt : function(s) {
22390 var val = parseInt(String(s).replace(/,/g, ""));
22398 * Ext JS Library 1.1.1
22399 * Copyright(c) 2006-2007, Ext JS, LLC.
22401 * Originally Released Under LGPL - original licence link has changed is not relivant.
22404 * <script type="text/javascript">
22408 * @class Roo.data.Record
22409 * Instances of this class encapsulate both record <em>definition</em> information, and record
22410 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22411 * to access Records cached in an {@link Roo.data.Store} object.<br>
22413 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22414 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22417 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22419 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22420 * {@link #create}. The parameters are the same.
22421 * @param {Array} data An associative Array of data values keyed by the field name.
22422 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22423 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22424 * not specified an integer id is generated.
22426 Roo.data.Record = function(data, id){
22427 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22432 * Generate a constructor for a specific record layout.
22433 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22434 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22435 * Each field definition object may contain the following properties: <ul>
22436 * <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,
22437 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22438 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22439 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22440 * is being used, then this is a string containing the javascript expression to reference the data relative to
22441 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22442 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22443 * this may be omitted.</p></li>
22444 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22445 * <ul><li>auto (Default, implies no conversion)</li>
22450 * <li>date</li></ul></p></li>
22451 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22452 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22453 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22454 * by the Reader into an object that will be stored in the Record. It is passed the
22455 * following parameters:<ul>
22456 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22458 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22460 * <br>usage:<br><pre><code>
22461 var TopicRecord = Roo.data.Record.create(
22462 {name: 'title', mapping: 'topic_title'},
22463 {name: 'author', mapping: 'username'},
22464 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22465 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22466 {name: 'lastPoster', mapping: 'user2'},
22467 {name: 'excerpt', mapping: 'post_text'}
22470 var myNewRecord = new TopicRecord({
22471 title: 'Do my job please',
22474 lastPost: new Date(),
22475 lastPoster: 'Animal',
22476 excerpt: 'No way dude!'
22478 myStore.add(myNewRecord);
22483 Roo.data.Record.create = function(o){
22484 var f = function(){
22485 f.superclass.constructor.apply(this, arguments);
22487 Roo.extend(f, Roo.data.Record);
22488 var p = f.prototype;
22489 p.fields = new Roo.util.MixedCollection(false, function(field){
22492 for(var i = 0, len = o.length; i < len; i++){
22493 p.fields.add(new Roo.data.Field(o[i]));
22495 f.getField = function(name){
22496 return p.fields.get(name);
22501 Roo.data.Record.AUTO_ID = 1000;
22502 Roo.data.Record.EDIT = 'edit';
22503 Roo.data.Record.REJECT = 'reject';
22504 Roo.data.Record.COMMIT = 'commit';
22506 Roo.data.Record.prototype = {
22508 * Readonly flag - true if this record has been modified.
22517 join : function(store){
22518 this.store = store;
22522 * Set the named field to the specified value.
22523 * @param {String} name The name of the field to set.
22524 * @param {Object} value The value to set the field to.
22526 set : function(name, value){
22527 if(this.data[name] == value){
22531 if(!this.modified){
22532 this.modified = {};
22534 if(typeof this.modified[name] == 'undefined'){
22535 this.modified[name] = this.data[name];
22537 this.data[name] = value;
22538 if(!this.editing && this.store){
22539 this.store.afterEdit(this);
22544 * Get the value of the named field.
22545 * @param {String} name The name of the field to get the value of.
22546 * @return {Object} The value of the field.
22548 get : function(name){
22549 return this.data[name];
22553 beginEdit : function(){
22554 this.editing = true;
22555 this.modified = {};
22559 cancelEdit : function(){
22560 this.editing = false;
22561 delete this.modified;
22565 endEdit : function(){
22566 this.editing = false;
22567 if(this.dirty && this.store){
22568 this.store.afterEdit(this);
22573 * Usually called by the {@link Roo.data.Store} which owns the Record.
22574 * Rejects all changes made to the Record since either creation, or the last commit operation.
22575 * Modified fields are reverted to their original values.
22577 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22578 * of reject operations.
22580 reject : function(){
22581 var m = this.modified;
22583 if(typeof m[n] != "function"){
22584 this.data[n] = m[n];
22587 this.dirty = false;
22588 delete this.modified;
22589 this.editing = false;
22591 this.store.afterReject(this);
22596 * Usually called by the {@link Roo.data.Store} which owns the Record.
22597 * Commits all changes made to the Record since either creation, or the last commit operation.
22599 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22600 * of commit operations.
22602 commit : function(){
22603 this.dirty = false;
22604 delete this.modified;
22605 this.editing = false;
22607 this.store.afterCommit(this);
22612 hasError : function(){
22613 return this.error != null;
22617 clearError : function(){
22622 * Creates a copy of this record.
22623 * @param {String} id (optional) A new record id if you don't want to use this record's id
22626 copy : function(newId) {
22627 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22631 * Ext JS Library 1.1.1
22632 * Copyright(c) 2006-2007, Ext JS, LLC.
22634 * Originally Released Under LGPL - original licence link has changed is not relivant.
22637 * <script type="text/javascript">
22643 * @class Roo.data.Store
22644 * @extends Roo.util.Observable
22645 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22646 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22648 * 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
22649 * has no knowledge of the format of the data returned by the Proxy.<br>
22651 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22652 * instances from the data object. These records are cached and made available through accessor functions.
22654 * Creates a new Store.
22655 * @param {Object} config A config object containing the objects needed for the Store to access data,
22656 * and read the data into Records.
22658 Roo.data.Store = function(config){
22659 this.data = new Roo.util.MixedCollection(false);
22660 this.data.getKey = function(o){
22663 this.baseParams = {};
22665 this.paramNames = {
22670 "multisort" : "_multisort"
22673 if(config && config.data){
22674 this.inlineData = config.data;
22675 delete config.data;
22678 Roo.apply(this, config);
22680 if(this.reader){ // reader passed
22681 this.reader = Roo.factory(this.reader, Roo.data);
22682 this.reader.xmodule = this.xmodule || false;
22683 if(!this.recordType){
22684 this.recordType = this.reader.recordType;
22686 if(this.reader.onMetaChange){
22687 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22691 if(this.recordType){
22692 this.fields = this.recordType.prototype.fields;
22694 this.modified = [];
22698 * @event datachanged
22699 * Fires when the data cache has changed, and a widget which is using this Store
22700 * as a Record cache should refresh its view.
22701 * @param {Store} this
22703 datachanged : true,
22705 * @event metachange
22706 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22707 * @param {Store} this
22708 * @param {Object} meta The JSON metadata
22713 * Fires when Records have been added to the Store
22714 * @param {Store} this
22715 * @param {Roo.data.Record[]} records The array of Records added
22716 * @param {Number} index The index at which the record(s) were added
22721 * Fires when a Record has been removed from the Store
22722 * @param {Store} this
22723 * @param {Roo.data.Record} record The Record that was removed
22724 * @param {Number} index The index at which the record was removed
22729 * Fires when a Record has been updated
22730 * @param {Store} this
22731 * @param {Roo.data.Record} record The Record that was updated
22732 * @param {String} operation The update operation being performed. Value may be one of:
22734 Roo.data.Record.EDIT
22735 Roo.data.Record.REJECT
22736 Roo.data.Record.COMMIT
22742 * Fires when the data cache has been cleared.
22743 * @param {Store} this
22747 * @event beforeload
22748 * Fires before a request is made for a new data object. If the beforeload handler returns false
22749 * the load action will be canceled.
22750 * @param {Store} this
22751 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22755 * @event beforeloadadd
22756 * Fires after a new set of Records has been loaded.
22757 * @param {Store} this
22758 * @param {Roo.data.Record[]} records The Records that were loaded
22759 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22761 beforeloadadd : true,
22764 * Fires after a new set of Records has been loaded, before they are added to the store.
22765 * @param {Store} this
22766 * @param {Roo.data.Record[]} records The Records that were loaded
22767 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22768 * @params {Object} return from reader
22772 * @event loadexception
22773 * Fires if an exception occurs in the Proxy during loading.
22774 * Called with the signature of the Proxy's "loadexception" event.
22775 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22778 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22779 * @param {Object} load options
22780 * @param {Object} jsonData from your request (normally this contains the Exception)
22782 loadexception : true
22786 this.proxy = Roo.factory(this.proxy, Roo.data);
22787 this.proxy.xmodule = this.xmodule || false;
22788 this.relayEvents(this.proxy, ["loadexception"]);
22790 this.sortToggle = {};
22791 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22793 Roo.data.Store.superclass.constructor.call(this);
22795 if(this.inlineData){
22796 this.loadData(this.inlineData);
22797 delete this.inlineData;
22801 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22803 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22804 * without a remote query - used by combo/forms at present.
22808 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22811 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22814 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22815 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22818 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22819 * on any HTTP request
22822 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22825 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22829 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22830 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22832 remoteSort : false,
22835 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22836 * loaded or when a record is removed. (defaults to false).
22838 pruneModifiedRecords : false,
22841 lastOptions : null,
22844 * Add Records to the Store and fires the add event.
22845 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22847 add : function(records){
22848 records = [].concat(records);
22849 for(var i = 0, len = records.length; i < len; i++){
22850 records[i].join(this);
22852 var index = this.data.length;
22853 this.data.addAll(records);
22854 this.fireEvent("add", this, records, index);
22858 * Remove a Record from the Store and fires the remove event.
22859 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
22861 remove : function(record){
22862 var index = this.data.indexOf(record);
22863 this.data.removeAt(index);
22864 if(this.pruneModifiedRecords){
22865 this.modified.remove(record);
22867 this.fireEvent("remove", this, record, index);
22871 * Remove all Records from the Store and fires the clear event.
22873 removeAll : function(){
22875 if(this.pruneModifiedRecords){
22876 this.modified = [];
22878 this.fireEvent("clear", this);
22882 * Inserts Records to the Store at the given index and fires the add event.
22883 * @param {Number} index The start index at which to insert the passed Records.
22884 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22886 insert : function(index, records){
22887 records = [].concat(records);
22888 for(var i = 0, len = records.length; i < len; i++){
22889 this.data.insert(index, records[i]);
22890 records[i].join(this);
22892 this.fireEvent("add", this, records, index);
22896 * Get the index within the cache of the passed Record.
22897 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
22898 * @return {Number} The index of the passed Record. Returns -1 if not found.
22900 indexOf : function(record){
22901 return this.data.indexOf(record);
22905 * Get the index within the cache of the Record with the passed id.
22906 * @param {String} id The id of the Record to find.
22907 * @return {Number} The index of the Record. Returns -1 if not found.
22909 indexOfId : function(id){
22910 return this.data.indexOfKey(id);
22914 * Get the Record with the specified id.
22915 * @param {String} id The id of the Record to find.
22916 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
22918 getById : function(id){
22919 return this.data.key(id);
22923 * Get the Record at the specified index.
22924 * @param {Number} index The index of the Record to find.
22925 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
22927 getAt : function(index){
22928 return this.data.itemAt(index);
22932 * Returns a range of Records between specified indices.
22933 * @param {Number} startIndex (optional) The starting index (defaults to 0)
22934 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
22935 * @return {Roo.data.Record[]} An array of Records
22937 getRange : function(start, end){
22938 return this.data.getRange(start, end);
22942 storeOptions : function(o){
22943 o = Roo.apply({}, o);
22946 this.lastOptions = o;
22950 * Loads the Record cache from the configured Proxy using the configured Reader.
22952 * If using remote paging, then the first load call must specify the <em>start</em>
22953 * and <em>limit</em> properties in the options.params property to establish the initial
22954 * position within the dataset, and the number of Records to cache on each read from the Proxy.
22956 * <strong>It is important to note that for remote data sources, loading is asynchronous,
22957 * and this call will return before the new data has been loaded. Perform any post-processing
22958 * in a callback function, or in a "load" event handler.</strong>
22960 * @param {Object} options An object containing properties which control loading options:<ul>
22961 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
22962 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
22963 * passed the following arguments:<ul>
22964 * <li>r : Roo.data.Record[]</li>
22965 * <li>options: Options object from the load call</li>
22966 * <li>success: Boolean success indicator</li></ul></li>
22967 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
22968 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
22971 load : function(options){
22972 options = options || {};
22973 if(this.fireEvent("beforeload", this, options) !== false){
22974 this.storeOptions(options);
22975 var p = Roo.apply(options.params || {}, this.baseParams);
22976 // if meta was not loaded from remote source.. try requesting it.
22977 if (!this.reader.metaFromRemote) {
22978 p._requestMeta = 1;
22980 if(this.sortInfo && this.remoteSort){
22981 var pn = this.paramNames;
22982 p[pn["sort"]] = this.sortInfo.field;
22983 p[pn["dir"]] = this.sortInfo.direction;
22985 if (this.multiSort) {
22986 var pn = this.paramNames;
22987 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
22990 this.proxy.load(p, this.reader, this.loadRecords, this, options);
22995 * Reloads the Record cache from the configured Proxy using the configured Reader and
22996 * the options from the last load operation performed.
22997 * @param {Object} options (optional) An object containing properties which may override the options
22998 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
22999 * the most recently used options are reused).
23001 reload : function(options){
23002 this.load(Roo.applyIf(options||{}, this.lastOptions));
23006 // Called as a callback by the Reader during a load operation.
23007 loadRecords : function(o, options, success){
23008 if(!o || success === false){
23009 if(success !== false){
23010 this.fireEvent("load", this, [], options, o);
23012 if(options.callback){
23013 options.callback.call(options.scope || this, [], options, false);
23017 // if data returned failure - throw an exception.
23018 if (o.success === false) {
23019 // show a message if no listener is registered.
23020 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23021 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23023 // loadmask wil be hooked into this..
23024 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23027 var r = o.records, t = o.totalRecords || r.length;
23029 this.fireEvent("beforeloadadd", this, r, options, o);
23031 if(!options || options.add !== true){
23032 if(this.pruneModifiedRecords){
23033 this.modified = [];
23035 for(var i = 0, len = r.length; i < len; i++){
23039 this.data = this.snapshot;
23040 delete this.snapshot;
23043 this.data.addAll(r);
23044 this.totalLength = t;
23046 this.fireEvent("datachanged", this);
23048 this.totalLength = Math.max(t, this.data.length+r.length);
23051 this.fireEvent("load", this, r, options, o);
23052 if(options.callback){
23053 options.callback.call(options.scope || this, r, options, true);
23059 * Loads data from a passed data block. A Reader which understands the format of the data
23060 * must have been configured in the constructor.
23061 * @param {Object} data The data block from which to read the Records. The format of the data expected
23062 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23063 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23065 loadData : function(o, append){
23066 var r = this.reader.readRecords(o);
23067 this.loadRecords(r, {add: append}, true);
23071 * Gets the number of cached records.
23073 * <em>If using paging, this may not be the total size of the dataset. If the data object
23074 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23075 * the data set size</em>
23077 getCount : function(){
23078 return this.data.length || 0;
23082 * Gets the total number of records in the dataset as returned by the server.
23084 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23085 * the dataset size</em>
23087 getTotalCount : function(){
23088 return this.totalLength || 0;
23092 * Returns the sort state of the Store as an object with two properties:
23094 field {String} The name of the field by which the Records are sorted
23095 direction {String} The sort order, "ASC" or "DESC"
23098 getSortState : function(){
23099 return this.sortInfo;
23103 applySort : function(){
23104 if(this.sortInfo && !this.remoteSort){
23105 var s = this.sortInfo, f = s.field;
23106 var st = this.fields.get(f).sortType;
23107 var fn = function(r1, r2){
23108 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23109 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23111 this.data.sort(s.direction, fn);
23112 if(this.snapshot && this.snapshot != this.data){
23113 this.snapshot.sort(s.direction, fn);
23119 * Sets the default sort column and order to be used by the next load operation.
23120 * @param {String} fieldName The name of the field to sort by.
23121 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23123 setDefaultSort : function(field, dir){
23124 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23128 * Sort the Records.
23129 * If remote sorting is used, the sort is performed on the server, and the cache is
23130 * reloaded. If local sorting is used, the cache is sorted internally.
23131 * @param {String} fieldName The name of the field to sort by.
23132 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23134 sort : function(fieldName, dir){
23135 var f = this.fields.get(fieldName);
23137 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23139 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23140 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23145 this.sortToggle[f.name] = dir;
23146 this.sortInfo = {field: f.name, direction: dir};
23147 if(!this.remoteSort){
23149 this.fireEvent("datachanged", this);
23151 this.load(this.lastOptions);
23156 * Calls the specified function for each of the Records in the cache.
23157 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23158 * Returning <em>false</em> aborts and exits the iteration.
23159 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23161 each : function(fn, scope){
23162 this.data.each(fn, scope);
23166 * Gets all records modified since the last commit. Modified records are persisted across load operations
23167 * (e.g., during paging).
23168 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23170 getModifiedRecords : function(){
23171 return this.modified;
23175 createFilterFn : function(property, value, anyMatch){
23176 if(!value.exec){ // not a regex
23177 value = String(value);
23178 if(value.length == 0){
23181 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23183 return function(r){
23184 return value.test(r.data[property]);
23189 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23190 * @param {String} property A field on your records
23191 * @param {Number} start The record index to start at (defaults to 0)
23192 * @param {Number} end The last record index to include (defaults to length - 1)
23193 * @return {Number} The sum
23195 sum : function(property, start, end){
23196 var rs = this.data.items, v = 0;
23197 start = start || 0;
23198 end = (end || end === 0) ? end : rs.length-1;
23200 for(var i = start; i <= end; i++){
23201 v += (rs[i].data[property] || 0);
23207 * Filter the records by a specified property.
23208 * @param {String} field A field on your records
23209 * @param {String/RegExp} value Either a string that the field
23210 * should start with or a RegExp to test against the field
23211 * @param {Boolean} anyMatch True to match any part not just the beginning
23213 filter : function(property, value, anyMatch){
23214 var fn = this.createFilterFn(property, value, anyMatch);
23215 return fn ? this.filterBy(fn) : this.clearFilter();
23219 * Filter by a function. The specified function will be called with each
23220 * record in this data source. If the function returns true the record is included,
23221 * otherwise it is filtered.
23222 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23223 * @param {Object} scope (optional) The scope of the function (defaults to this)
23225 filterBy : function(fn, scope){
23226 this.snapshot = this.snapshot || this.data;
23227 this.data = this.queryBy(fn, scope||this);
23228 this.fireEvent("datachanged", this);
23232 * Query the records by a specified property.
23233 * @param {String} field A field on your records
23234 * @param {String/RegExp} value Either a string that the field
23235 * should start with or a RegExp to test against the field
23236 * @param {Boolean} anyMatch True to match any part not just the beginning
23237 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23239 query : function(property, value, anyMatch){
23240 var fn = this.createFilterFn(property, value, anyMatch);
23241 return fn ? this.queryBy(fn) : this.data.clone();
23245 * Query by a function. The specified function will be called with each
23246 * record in this data source. If the function returns true the record is included
23248 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23249 * @param {Object} scope (optional) The scope of the function (defaults to this)
23250 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23252 queryBy : function(fn, scope){
23253 var data = this.snapshot || this.data;
23254 return data.filterBy(fn, scope||this);
23258 * Collects unique values for a particular dataIndex from this store.
23259 * @param {String} dataIndex The property to collect
23260 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23261 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23262 * @return {Array} An array of the unique values
23264 collect : function(dataIndex, allowNull, bypassFilter){
23265 var d = (bypassFilter === true && this.snapshot) ?
23266 this.snapshot.items : this.data.items;
23267 var v, sv, r = [], l = {};
23268 for(var i = 0, len = d.length; i < len; i++){
23269 v = d[i].data[dataIndex];
23271 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23280 * Revert to a view of the Record cache with no filtering applied.
23281 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23283 clearFilter : function(suppressEvent){
23284 if(this.snapshot && this.snapshot != this.data){
23285 this.data = this.snapshot;
23286 delete this.snapshot;
23287 if(suppressEvent !== true){
23288 this.fireEvent("datachanged", this);
23294 afterEdit : function(record){
23295 if(this.modified.indexOf(record) == -1){
23296 this.modified.push(record);
23298 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23302 afterReject : function(record){
23303 this.modified.remove(record);
23304 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23308 afterCommit : function(record){
23309 this.modified.remove(record);
23310 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23314 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23315 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23317 commitChanges : function(){
23318 var m = this.modified.slice(0);
23319 this.modified = [];
23320 for(var i = 0, len = m.length; i < len; i++){
23326 * Cancel outstanding changes on all changed records.
23328 rejectChanges : function(){
23329 var m = this.modified.slice(0);
23330 this.modified = [];
23331 for(var i = 0, len = m.length; i < len; i++){
23336 onMetaChange : function(meta, rtype, o){
23337 this.recordType = rtype;
23338 this.fields = rtype.prototype.fields;
23339 delete this.snapshot;
23340 this.sortInfo = meta.sortInfo || this.sortInfo;
23341 this.modified = [];
23342 this.fireEvent('metachange', this, this.reader.meta);
23345 moveIndex : function(data, type)
23347 var index = this.indexOf(data);
23349 var newIndex = index + type;
23353 this.insert(newIndex, data);
23358 * Ext JS Library 1.1.1
23359 * Copyright(c) 2006-2007, Ext JS, LLC.
23361 * Originally Released Under LGPL - original licence link has changed is not relivant.
23364 * <script type="text/javascript">
23368 * @class Roo.data.SimpleStore
23369 * @extends Roo.data.Store
23370 * Small helper class to make creating Stores from Array data easier.
23371 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23372 * @cfg {Array} fields An array of field definition objects, or field name strings.
23373 * @cfg {Array} data The multi-dimensional array of data
23375 * @param {Object} config
23377 Roo.data.SimpleStore = function(config){
23378 Roo.data.SimpleStore.superclass.constructor.call(this, {
23380 reader: new Roo.data.ArrayReader({
23383 Roo.data.Record.create(config.fields)
23385 proxy : new Roo.data.MemoryProxy(config.data)
23389 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23391 * Ext JS Library 1.1.1
23392 * Copyright(c) 2006-2007, Ext JS, LLC.
23394 * Originally Released Under LGPL - original licence link has changed is not relivant.
23397 * <script type="text/javascript">
23402 * @extends Roo.data.Store
23403 * @class Roo.data.JsonStore
23404 * Small helper class to make creating Stores for JSON data easier. <br/>
23406 var store = new Roo.data.JsonStore({
23407 url: 'get-images.php',
23409 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23412 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23413 * JsonReader and HttpProxy (unless inline data is provided).</b>
23414 * @cfg {Array} fields An array of field definition objects, or field name strings.
23416 * @param {Object} config
23418 Roo.data.JsonStore = function(c){
23419 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23420 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23421 reader: new Roo.data.JsonReader(c, c.fields)
23424 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23426 * Ext JS Library 1.1.1
23427 * Copyright(c) 2006-2007, Ext JS, LLC.
23429 * Originally Released Under LGPL - original licence link has changed is not relivant.
23432 * <script type="text/javascript">
23436 Roo.data.Field = function(config){
23437 if(typeof config == "string"){
23438 config = {name: config};
23440 Roo.apply(this, config);
23443 this.type = "auto";
23446 var st = Roo.data.SortTypes;
23447 // named sortTypes are supported, here we look them up
23448 if(typeof this.sortType == "string"){
23449 this.sortType = st[this.sortType];
23452 // set default sortType for strings and dates
23453 if(!this.sortType){
23456 this.sortType = st.asUCString;
23459 this.sortType = st.asDate;
23462 this.sortType = st.none;
23467 var stripRe = /[\$,%]/g;
23469 // prebuilt conversion function for this field, instead of
23470 // switching every time we're reading a value
23472 var cv, dateFormat = this.dateFormat;
23477 cv = function(v){ return v; };
23480 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23484 return v !== undefined && v !== null && v !== '' ?
23485 parseInt(String(v).replace(stripRe, ""), 10) : '';
23490 return v !== undefined && v !== null && v !== '' ?
23491 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23496 cv = function(v){ return v === true || v === "true" || v == 1; };
23503 if(v instanceof Date){
23507 if(dateFormat == "timestamp"){
23508 return new Date(v*1000);
23510 return Date.parseDate(v, dateFormat);
23512 var parsed = Date.parse(v);
23513 return parsed ? new Date(parsed) : null;
23522 Roo.data.Field.prototype = {
23530 * Ext JS Library 1.1.1
23531 * Copyright(c) 2006-2007, Ext JS, LLC.
23533 * Originally Released Under LGPL - original licence link has changed is not relivant.
23536 * <script type="text/javascript">
23539 // Base class for reading structured data from a data source. This class is intended to be
23540 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23543 * @class Roo.data.DataReader
23544 * Base class for reading structured data from a data source. This class is intended to be
23545 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23548 Roo.data.DataReader = function(meta, recordType){
23552 this.recordType = recordType instanceof Array ?
23553 Roo.data.Record.create(recordType) : recordType;
23556 Roo.data.DataReader.prototype = {
23558 * Create an empty record
23559 * @param {Object} data (optional) - overlay some values
23560 * @return {Roo.data.Record} record created.
23562 newRow : function(d) {
23564 this.recordType.prototype.fields.each(function(c) {
23566 case 'int' : da[c.name] = 0; break;
23567 case 'date' : da[c.name] = new Date(); break;
23568 case 'float' : da[c.name] = 0.0; break;
23569 case 'boolean' : da[c.name] = false; break;
23570 default : da[c.name] = ""; break;
23574 return new this.recordType(Roo.apply(da, d));
23579 * Ext JS Library 1.1.1
23580 * Copyright(c) 2006-2007, Ext JS, LLC.
23582 * Originally Released Under LGPL - original licence link has changed is not relivant.
23585 * <script type="text/javascript">
23589 * @class Roo.data.DataProxy
23590 * @extends Roo.data.Observable
23591 * This class is an abstract base class for implementations which provide retrieval of
23592 * unformatted data objects.<br>
23594 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23595 * (of the appropriate type which knows how to parse the data object) to provide a block of
23596 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23598 * Custom implementations must implement the load method as described in
23599 * {@link Roo.data.HttpProxy#load}.
23601 Roo.data.DataProxy = function(){
23604 * @event beforeload
23605 * Fires before a network request is made to retrieve a data object.
23606 * @param {Object} This DataProxy object.
23607 * @param {Object} params The params parameter to the load function.
23612 * Fires before the load method's callback is called.
23613 * @param {Object} This DataProxy object.
23614 * @param {Object} o The data object.
23615 * @param {Object} arg The callback argument object passed to the load function.
23619 * @event loadexception
23620 * Fires if an Exception occurs during data retrieval.
23621 * @param {Object} This DataProxy object.
23622 * @param {Object} o The data object.
23623 * @param {Object} arg The callback argument object passed to the load function.
23624 * @param {Object} e The Exception.
23626 loadexception : true
23628 Roo.data.DataProxy.superclass.constructor.call(this);
23631 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23634 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23638 * Ext JS Library 1.1.1
23639 * Copyright(c) 2006-2007, Ext JS, LLC.
23641 * Originally Released Under LGPL - original licence link has changed is not relivant.
23644 * <script type="text/javascript">
23647 * @class Roo.data.MemoryProxy
23648 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23649 * to the Reader when its load method is called.
23651 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23653 Roo.data.MemoryProxy = function(data){
23657 Roo.data.MemoryProxy.superclass.constructor.call(this);
23661 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23664 * Load data from the requested source (in this case an in-memory
23665 * data object passed to the constructor), read the data object into
23666 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23667 * process that block using the passed callback.
23668 * @param {Object} params This parameter is not used by the MemoryProxy class.
23669 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23670 * object into a block of Roo.data.Records.
23671 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23672 * The function must be passed <ul>
23673 * <li>The Record block object</li>
23674 * <li>The "arg" argument from the load function</li>
23675 * <li>A boolean success indicator</li>
23677 * @param {Object} scope The scope in which to call the callback
23678 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23680 load : function(params, reader, callback, scope, arg){
23681 params = params || {};
23684 result = reader.readRecords(this.data);
23686 this.fireEvent("loadexception", this, arg, null, e);
23687 callback.call(scope, null, arg, false);
23690 callback.call(scope, result, arg, true);
23694 update : function(params, records){
23699 * Ext JS Library 1.1.1
23700 * Copyright(c) 2006-2007, Ext JS, LLC.
23702 * Originally Released Under LGPL - original licence link has changed is not relivant.
23705 * <script type="text/javascript">
23708 * @class Roo.data.HttpProxy
23709 * @extends Roo.data.DataProxy
23710 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23711 * configured to reference a certain URL.<br><br>
23713 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23714 * from which the running page was served.<br><br>
23716 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23718 * Be aware that to enable the browser to parse an XML document, the server must set
23719 * the Content-Type header in the HTTP response to "text/xml".
23721 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23722 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23723 * will be used to make the request.
23725 Roo.data.HttpProxy = function(conn){
23726 Roo.data.HttpProxy.superclass.constructor.call(this);
23727 // is conn a conn config or a real conn?
23729 this.useAjax = !conn || !conn.events;
23733 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23734 // thse are take from connection...
23737 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23740 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23741 * extra parameters to each request made by this object. (defaults to undefined)
23744 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23745 * to each request made by this object. (defaults to undefined)
23748 * @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)
23751 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23754 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23760 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23764 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23765 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23766 * a finer-grained basis than the DataProxy events.
23768 getConnection : function(){
23769 return this.useAjax ? Roo.Ajax : this.conn;
23773 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23774 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23775 * process that block using the passed callback.
23776 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23777 * for the request to the remote server.
23778 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23779 * object into a block of Roo.data.Records.
23780 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23781 * The function must be passed <ul>
23782 * <li>The Record block object</li>
23783 * <li>The "arg" argument from the load function</li>
23784 * <li>A boolean success indicator</li>
23786 * @param {Object} scope The scope in which to call the callback
23787 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23789 load : function(params, reader, callback, scope, arg){
23790 if(this.fireEvent("beforeload", this, params) !== false){
23792 params : params || {},
23794 callback : callback,
23799 callback : this.loadResponse,
23803 Roo.applyIf(o, this.conn);
23804 if(this.activeRequest){
23805 Roo.Ajax.abort(this.activeRequest);
23807 this.activeRequest = Roo.Ajax.request(o);
23809 this.conn.request(o);
23812 callback.call(scope||this, null, arg, false);
23817 loadResponse : function(o, success, response){
23818 delete this.activeRequest;
23820 this.fireEvent("loadexception", this, o, response);
23821 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23826 result = o.reader.read(response);
23828 this.fireEvent("loadexception", this, o, response, e);
23829 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23833 this.fireEvent("load", this, o, o.request.arg);
23834 o.request.callback.call(o.request.scope, result, o.request.arg, true);
23838 update : function(dataSet){
23843 updateResponse : function(dataSet){
23848 * Ext JS Library 1.1.1
23849 * Copyright(c) 2006-2007, Ext JS, LLC.
23851 * Originally Released Under LGPL - original licence link has changed is not relivant.
23854 * <script type="text/javascript">
23858 * @class Roo.data.ScriptTagProxy
23859 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
23860 * other than the originating domain of the running page.<br><br>
23862 * <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
23863 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
23865 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
23866 * source code that is used as the source inside a <script> tag.<br><br>
23868 * In order for the browser to process the returned data, the server must wrap the data object
23869 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
23870 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
23871 * depending on whether the callback name was passed:
23874 boolean scriptTag = false;
23875 String cb = request.getParameter("callback");
23878 response.setContentType("text/javascript");
23880 response.setContentType("application/x-json");
23882 Writer out = response.getWriter();
23884 out.write(cb + "(");
23886 out.print(dataBlock.toJsonString());
23893 * @param {Object} config A configuration object.
23895 Roo.data.ScriptTagProxy = function(config){
23896 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
23897 Roo.apply(this, config);
23898 this.head = document.getElementsByTagName("head")[0];
23901 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
23903 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
23905 * @cfg {String} url The URL from which to request the data object.
23908 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
23912 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
23913 * the server the name of the callback function set up by the load call to process the returned data object.
23914 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
23915 * javascript output which calls this named function passing the data object as its only parameter.
23917 callbackParam : "callback",
23919 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
23920 * name to the request.
23925 * Load data from the configured URL, read the data object into
23926 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23927 * process that block using the passed callback.
23928 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23929 * for the request to the remote server.
23930 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23931 * object into a block of Roo.data.Records.
23932 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23933 * The function must be passed <ul>
23934 * <li>The Record block object</li>
23935 * <li>The "arg" argument from the load function</li>
23936 * <li>A boolean success indicator</li>
23938 * @param {Object} scope The scope in which to call the callback
23939 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23941 load : function(params, reader, callback, scope, arg){
23942 if(this.fireEvent("beforeload", this, params) !== false){
23944 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
23946 var url = this.url;
23947 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
23949 url += "&_dc=" + (new Date().getTime());
23951 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
23954 cb : "stcCallback"+transId,
23955 scriptId : "stcScript"+transId,
23959 callback : callback,
23965 window[trans.cb] = function(o){
23966 conn.handleResponse(o, trans);
23969 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
23971 if(this.autoAbort !== false){
23975 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
23977 var script = document.createElement("script");
23978 script.setAttribute("src", url);
23979 script.setAttribute("type", "text/javascript");
23980 script.setAttribute("id", trans.scriptId);
23981 this.head.appendChild(script);
23983 this.trans = trans;
23985 callback.call(scope||this, null, arg, false);
23990 isLoading : function(){
23991 return this.trans ? true : false;
23995 * Abort the current server request.
23997 abort : function(){
23998 if(this.isLoading()){
23999 this.destroyTrans(this.trans);
24004 destroyTrans : function(trans, isLoaded){
24005 this.head.removeChild(document.getElementById(trans.scriptId));
24006 clearTimeout(trans.timeoutId);
24008 window[trans.cb] = undefined;
24010 delete window[trans.cb];
24013 // if hasn't been loaded, wait for load to remove it to prevent script error
24014 window[trans.cb] = function(){
24015 window[trans.cb] = undefined;
24017 delete window[trans.cb];
24024 handleResponse : function(o, trans){
24025 this.trans = false;
24026 this.destroyTrans(trans, true);
24029 result = trans.reader.readRecords(o);
24031 this.fireEvent("loadexception", this, o, trans.arg, e);
24032 trans.callback.call(trans.scope||window, null, trans.arg, false);
24035 this.fireEvent("load", this, o, trans.arg);
24036 trans.callback.call(trans.scope||window, result, trans.arg, true);
24040 handleFailure : function(trans){
24041 this.trans = false;
24042 this.destroyTrans(trans, false);
24043 this.fireEvent("loadexception", this, null, trans.arg);
24044 trans.callback.call(trans.scope||window, null, trans.arg, false);
24048 * Ext JS Library 1.1.1
24049 * Copyright(c) 2006-2007, Ext JS, LLC.
24051 * Originally Released Under LGPL - original licence link has changed is not relivant.
24054 * <script type="text/javascript">
24058 * @class Roo.data.JsonReader
24059 * @extends Roo.data.DataReader
24060 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24061 * based on mappings in a provided Roo.data.Record constructor.
24063 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24064 * in the reply previously.
24069 var RecordDef = Roo.data.Record.create([
24070 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24071 {name: 'occupation'} // This field will use "occupation" as the mapping.
24073 var myReader = new Roo.data.JsonReader({
24074 totalProperty: "results", // The property which contains the total dataset size (optional)
24075 root: "rows", // The property which contains an Array of row objects
24076 id: "id" // The property within each row object that provides an ID for the record (optional)
24080 * This would consume a JSON file like this:
24082 { 'results': 2, 'rows': [
24083 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24084 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24087 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24088 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24089 * paged from the remote server.
24090 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24091 * @cfg {String} root name of the property which contains the Array of row objects.
24092 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24093 * @cfg {Array} fields Array of field definition objects
24095 * Create a new JsonReader
24096 * @param {Object} meta Metadata configuration options
24097 * @param {Object} recordType Either an Array of field definition objects,
24098 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24100 Roo.data.JsonReader = function(meta, recordType){
24103 // set some defaults:
24104 Roo.applyIf(meta, {
24105 totalProperty: 'total',
24106 successProperty : 'success',
24111 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24113 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24116 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24117 * Used by Store query builder to append _requestMeta to params.
24120 metaFromRemote : false,
24122 * This method is only used by a DataProxy which has retrieved data from a remote server.
24123 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24124 * @return {Object} data A data block which is used by an Roo.data.Store object as
24125 * a cache of Roo.data.Records.
24127 read : function(response){
24128 var json = response.responseText;
24130 var o = /* eval:var:o */ eval("("+json+")");
24132 throw {message: "JsonReader.read: Json object not found"};
24138 this.metaFromRemote = true;
24139 this.meta = o.metaData;
24140 this.recordType = Roo.data.Record.create(o.metaData.fields);
24141 this.onMetaChange(this.meta, this.recordType, o);
24143 return this.readRecords(o);
24146 // private function a store will implement
24147 onMetaChange : function(meta, recordType, o){
24154 simpleAccess: function(obj, subsc) {
24161 getJsonAccessor: function(){
24163 return function(expr) {
24165 return(re.test(expr))
24166 ? new Function("obj", "return obj." + expr)
24171 return Roo.emptyFn;
24176 * Create a data block containing Roo.data.Records from an XML document.
24177 * @param {Object} o An object which contains an Array of row objects in the property specified
24178 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24179 * which contains the total size of the dataset.
24180 * @return {Object} data A data block which is used by an Roo.data.Store object as
24181 * a cache of Roo.data.Records.
24183 readRecords : function(o){
24185 * After any data loads, the raw JSON data is available for further custom processing.
24189 var s = this.meta, Record = this.recordType,
24190 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24192 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24194 if(s.totalProperty) {
24195 this.getTotal = this.getJsonAccessor(s.totalProperty);
24197 if(s.successProperty) {
24198 this.getSuccess = this.getJsonAccessor(s.successProperty);
24200 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24202 var g = this.getJsonAccessor(s.id);
24203 this.getId = function(rec) {
24205 return (r === undefined || r === "") ? null : r;
24208 this.getId = function(){return null;};
24211 for(var jj = 0; jj < fl; jj++){
24213 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24214 this.ef[jj] = this.getJsonAccessor(map);
24218 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24219 if(s.totalProperty){
24220 var vt = parseInt(this.getTotal(o), 10);
24225 if(s.successProperty){
24226 var vs = this.getSuccess(o);
24227 if(vs === false || vs === 'false'){
24232 for(var i = 0; i < c; i++){
24235 var id = this.getId(n);
24236 for(var j = 0; j < fl; j++){
24238 var v = this.ef[j](n);
24240 Roo.log('missing convert for ' + f.name);
24244 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24246 var record = new Record(values, id);
24248 records[i] = record;
24254 totalRecords : totalRecords
24259 * Ext JS Library 1.1.1
24260 * Copyright(c) 2006-2007, Ext JS, LLC.
24262 * Originally Released Under LGPL - original licence link has changed is not relivant.
24265 * <script type="text/javascript">
24269 * @class Roo.data.XmlReader
24270 * @extends Roo.data.DataReader
24271 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24272 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24274 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24275 * header in the HTTP response must be set to "text/xml".</em>
24279 var RecordDef = Roo.data.Record.create([
24280 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24281 {name: 'occupation'} // This field will use "occupation" as the mapping.
24283 var myReader = new Roo.data.XmlReader({
24284 totalRecords: "results", // The element which contains the total dataset size (optional)
24285 record: "row", // The repeated element which contains row information
24286 id: "id" // The element within the row that provides an ID for the record (optional)
24290 * This would consume an XML file like this:
24294 <results>2</results>
24297 <name>Bill</name>
24298 <occupation>Gardener</occupation>
24302 <name>Ben</name>
24303 <occupation>Horticulturalist</occupation>
24307 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24308 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24309 * paged from the remote server.
24310 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24311 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24312 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24313 * a record identifier value.
24315 * Create a new XmlReader
24316 * @param {Object} meta Metadata configuration options
24317 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24318 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24319 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24321 Roo.data.XmlReader = function(meta, recordType){
24323 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24325 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24327 * This method is only used by a DataProxy which has retrieved data from a remote server.
24328 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24329 * to contain a method called 'responseXML' that returns an XML document object.
24330 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24331 * a cache of Roo.data.Records.
24333 read : function(response){
24334 var doc = response.responseXML;
24336 throw {message: "XmlReader.read: XML Document not available"};
24338 return this.readRecords(doc);
24342 * Create a data block containing Roo.data.Records from an XML document.
24343 * @param {Object} doc A parsed XML document.
24344 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24345 * a cache of Roo.data.Records.
24347 readRecords : function(doc){
24349 * After any data loads/reads, the raw XML Document is available for further custom processing.
24350 * @type XMLDocument
24352 this.xmlData = doc;
24353 var root = doc.documentElement || doc;
24354 var q = Roo.DomQuery;
24355 var recordType = this.recordType, fields = recordType.prototype.fields;
24356 var sid = this.meta.id;
24357 var totalRecords = 0, success = true;
24358 if(this.meta.totalRecords){
24359 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24362 if(this.meta.success){
24363 var sv = q.selectValue(this.meta.success, root, true);
24364 success = sv !== false && sv !== 'false';
24367 var ns = q.select(this.meta.record, root);
24368 for(var i = 0, len = ns.length; i < len; i++) {
24371 var id = sid ? q.selectValue(sid, n) : undefined;
24372 for(var j = 0, jlen = fields.length; j < jlen; j++){
24373 var f = fields.items[j];
24374 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24376 values[f.name] = v;
24378 var record = new recordType(values, id);
24380 records[records.length] = record;
24386 totalRecords : totalRecords || records.length
24391 * Ext JS Library 1.1.1
24392 * Copyright(c) 2006-2007, Ext JS, LLC.
24394 * Originally Released Under LGPL - original licence link has changed is not relivant.
24397 * <script type="text/javascript">
24401 * @class Roo.data.ArrayReader
24402 * @extends Roo.data.DataReader
24403 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24404 * Each element of that Array represents a row of data fields. The
24405 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24406 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24410 var RecordDef = Roo.data.Record.create([
24411 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24412 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24414 var myReader = new Roo.data.ArrayReader({
24415 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24419 * This would consume an Array like this:
24421 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24423 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24425 * Create a new JsonReader
24426 * @param {Object} meta Metadata configuration options.
24427 * @param {Object} recordType Either an Array of field definition objects
24428 * as specified to {@link Roo.data.Record#create},
24429 * or an {@link Roo.data.Record} object
24430 * created using {@link Roo.data.Record#create}.
24432 Roo.data.ArrayReader = function(meta, recordType){
24433 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24436 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24438 * Create a data block containing Roo.data.Records from an XML document.
24439 * @param {Object} o An Array of row objects which represents the dataset.
24440 * @return {Object} data A data block which is used by an Roo.data.Store object as
24441 * a cache of Roo.data.Records.
24443 readRecords : function(o){
24444 var sid = this.meta ? this.meta.id : null;
24445 var recordType = this.recordType, fields = recordType.prototype.fields;
24448 for(var i = 0; i < root.length; i++){
24451 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24452 for(var j = 0, jlen = fields.length; j < jlen; j++){
24453 var f = fields.items[j];
24454 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24455 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24457 values[f.name] = v;
24459 var record = new recordType(values, id);
24461 records[records.length] = record;
24465 totalRecords : records.length
24470 * Ext JS Library 1.1.1
24471 * Copyright(c) 2006-2007, Ext JS, LLC.
24473 * Originally Released Under LGPL - original licence link has changed is not relivant.
24476 * <script type="text/javascript">
24481 * @class Roo.data.Tree
24482 * @extends Roo.util.Observable
24483 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24484 * in the tree have most standard DOM functionality.
24486 * @param {Node} root (optional) The root node
24488 Roo.data.Tree = function(root){
24489 this.nodeHash = {};
24491 * The root node for this tree
24496 this.setRootNode(root);
24501 * Fires when a new child node is appended to a node in this tree.
24502 * @param {Tree} tree The owner tree
24503 * @param {Node} parent The parent node
24504 * @param {Node} node The newly appended node
24505 * @param {Number} index The index of the newly appended node
24510 * Fires when a child node is removed from a node in this tree.
24511 * @param {Tree} tree The owner tree
24512 * @param {Node} parent The parent node
24513 * @param {Node} node The child node removed
24518 * Fires when a node is moved to a new location in the tree
24519 * @param {Tree} tree The owner tree
24520 * @param {Node} node The node moved
24521 * @param {Node} oldParent The old parent of this node
24522 * @param {Node} newParent The new parent of this node
24523 * @param {Number} index The index it was moved to
24528 * Fires when a new child node is inserted in a node in this tree.
24529 * @param {Tree} tree The owner tree
24530 * @param {Node} parent The parent node
24531 * @param {Node} node The child node inserted
24532 * @param {Node} refNode The child node the node was inserted before
24536 * @event beforeappend
24537 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24538 * @param {Tree} tree The owner tree
24539 * @param {Node} parent The parent node
24540 * @param {Node} node The child node to be appended
24542 "beforeappend" : true,
24544 * @event beforeremove
24545 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24546 * @param {Tree} tree The owner tree
24547 * @param {Node} parent The parent node
24548 * @param {Node} node The child node to be removed
24550 "beforeremove" : true,
24552 * @event beforemove
24553 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24554 * @param {Tree} tree The owner tree
24555 * @param {Node} node The node being moved
24556 * @param {Node} oldParent The parent of the node
24557 * @param {Node} newParent The new parent the node is moving to
24558 * @param {Number} index The index it is being moved to
24560 "beforemove" : true,
24562 * @event beforeinsert
24563 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24564 * @param {Tree} tree The owner tree
24565 * @param {Node} parent The parent node
24566 * @param {Node} node The child node to be inserted
24567 * @param {Node} refNode The child node the node is being inserted before
24569 "beforeinsert" : true
24572 Roo.data.Tree.superclass.constructor.call(this);
24575 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24576 pathSeparator: "/",
24578 proxyNodeEvent : function(){
24579 return this.fireEvent.apply(this, arguments);
24583 * Returns the root node for this tree.
24586 getRootNode : function(){
24591 * Sets the root node for this tree.
24592 * @param {Node} node
24595 setRootNode : function(node){
24597 node.ownerTree = this;
24598 node.isRoot = true;
24599 this.registerNode(node);
24604 * Gets a node in this tree by its id.
24605 * @param {String} id
24608 getNodeById : function(id){
24609 return this.nodeHash[id];
24612 registerNode : function(node){
24613 this.nodeHash[node.id] = node;
24616 unregisterNode : function(node){
24617 delete this.nodeHash[node.id];
24620 toString : function(){
24621 return "[Tree"+(this.id?" "+this.id:"")+"]";
24626 * @class Roo.data.Node
24627 * @extends Roo.util.Observable
24628 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24629 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24631 * @param {Object} attributes The attributes/config for the node
24633 Roo.data.Node = function(attributes){
24635 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24638 this.attributes = attributes || {};
24639 this.leaf = this.attributes.leaf;
24641 * The node id. @type String
24643 this.id = this.attributes.id;
24645 this.id = Roo.id(null, "ynode-");
24646 this.attributes.id = this.id;
24651 * All child nodes of this node. @type Array
24653 this.childNodes = [];
24654 if(!this.childNodes.indexOf){ // indexOf is a must
24655 this.childNodes.indexOf = function(o){
24656 for(var i = 0, len = this.length; i < len; i++){
24665 * The parent node for this node. @type Node
24667 this.parentNode = null;
24669 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24671 this.firstChild = null;
24673 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24675 this.lastChild = null;
24677 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24679 this.previousSibling = null;
24681 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24683 this.nextSibling = null;
24688 * Fires when a new child node is appended
24689 * @param {Tree} tree The owner tree
24690 * @param {Node} this This node
24691 * @param {Node} node The newly appended node
24692 * @param {Number} index The index of the newly appended node
24697 * Fires when a child node is removed
24698 * @param {Tree} tree The owner tree
24699 * @param {Node} this This node
24700 * @param {Node} node The removed node
24705 * Fires when this node is moved to a new location in the tree
24706 * @param {Tree} tree The owner tree
24707 * @param {Node} this This node
24708 * @param {Node} oldParent The old parent of this node
24709 * @param {Node} newParent The new parent of this node
24710 * @param {Number} index The index it was moved to
24715 * Fires when a new child node is inserted.
24716 * @param {Tree} tree The owner tree
24717 * @param {Node} this This node
24718 * @param {Node} node The child node inserted
24719 * @param {Node} refNode The child node the node was inserted before
24723 * @event beforeappend
24724 * Fires before a new child is appended, return false to cancel the append.
24725 * @param {Tree} tree The owner tree
24726 * @param {Node} this This node
24727 * @param {Node} node The child node to be appended
24729 "beforeappend" : true,
24731 * @event beforeremove
24732 * Fires before a child is removed, return false to cancel the remove.
24733 * @param {Tree} tree The owner tree
24734 * @param {Node} this This node
24735 * @param {Node} node The child node to be removed
24737 "beforeremove" : true,
24739 * @event beforemove
24740 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24741 * @param {Tree} tree The owner tree
24742 * @param {Node} this This node
24743 * @param {Node} oldParent The parent of this node
24744 * @param {Node} newParent The new parent this node is moving to
24745 * @param {Number} index The index it is being moved to
24747 "beforemove" : true,
24749 * @event beforeinsert
24750 * Fires before a new child is inserted, return false to cancel the insert.
24751 * @param {Tree} tree The owner tree
24752 * @param {Node} this This node
24753 * @param {Node} node The child node to be inserted
24754 * @param {Node} refNode The child node the node is being inserted before
24756 "beforeinsert" : true
24758 this.listeners = this.attributes.listeners;
24759 Roo.data.Node.superclass.constructor.call(this);
24762 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24763 fireEvent : function(evtName){
24764 // first do standard event for this node
24765 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24768 // then bubble it up to the tree if the event wasn't cancelled
24769 var ot = this.getOwnerTree();
24771 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24779 * Returns true if this node is a leaf
24780 * @return {Boolean}
24782 isLeaf : function(){
24783 return this.leaf === true;
24787 setFirstChild : function(node){
24788 this.firstChild = node;
24792 setLastChild : function(node){
24793 this.lastChild = node;
24798 * Returns true if this node is the last child of its parent
24799 * @return {Boolean}
24801 isLast : function(){
24802 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24806 * Returns true if this node is the first child of its parent
24807 * @return {Boolean}
24809 isFirst : function(){
24810 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24813 hasChildNodes : function(){
24814 return !this.isLeaf() && this.childNodes.length > 0;
24818 * Insert node(s) as the last child node of this node.
24819 * @param {Node/Array} node The node or Array of nodes to append
24820 * @return {Node} The appended node if single append, or null if an array was passed
24822 appendChild : function(node){
24824 if(node instanceof Array){
24826 }else if(arguments.length > 1){
24829 // if passed an array or multiple args do them one by one
24831 for(var i = 0, len = multi.length; i < len; i++) {
24832 this.appendChild(multi[i]);
24835 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
24838 var index = this.childNodes.length;
24839 var oldParent = node.parentNode;
24840 // it's a move, make sure we move it cleanly
24842 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
24845 oldParent.removeChild(node);
24847 index = this.childNodes.length;
24849 this.setFirstChild(node);
24851 this.childNodes.push(node);
24852 node.parentNode = this;
24853 var ps = this.childNodes[index-1];
24855 node.previousSibling = ps;
24856 ps.nextSibling = node;
24858 node.previousSibling = null;
24860 node.nextSibling = null;
24861 this.setLastChild(node);
24862 node.setOwnerTree(this.getOwnerTree());
24863 this.fireEvent("append", this.ownerTree, this, node, index);
24865 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
24872 * Removes a child node from this node.
24873 * @param {Node} node The node to remove
24874 * @return {Node} The removed node
24876 removeChild : function(node){
24877 var index = this.childNodes.indexOf(node);
24881 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
24885 // remove it from childNodes collection
24886 this.childNodes.splice(index, 1);
24889 if(node.previousSibling){
24890 node.previousSibling.nextSibling = node.nextSibling;
24892 if(node.nextSibling){
24893 node.nextSibling.previousSibling = node.previousSibling;
24896 // update child refs
24897 if(this.firstChild == node){
24898 this.setFirstChild(node.nextSibling);
24900 if(this.lastChild == node){
24901 this.setLastChild(node.previousSibling);
24904 node.setOwnerTree(null);
24905 // clear any references from the node
24906 node.parentNode = null;
24907 node.previousSibling = null;
24908 node.nextSibling = null;
24909 this.fireEvent("remove", this.ownerTree, this, node);
24914 * Inserts the first node before the second node in this nodes childNodes collection.
24915 * @param {Node} node The node to insert
24916 * @param {Node} refNode The node to insert before (if null the node is appended)
24917 * @return {Node} The inserted node
24919 insertBefore : function(node, refNode){
24920 if(!refNode){ // like standard Dom, refNode can be null for append
24921 return this.appendChild(node);
24924 if(node == refNode){
24928 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
24931 var index = this.childNodes.indexOf(refNode);
24932 var oldParent = node.parentNode;
24933 var refIndex = index;
24935 // when moving internally, indexes will change after remove
24936 if(oldParent == this && this.childNodes.indexOf(node) < index){
24940 // it's a move, make sure we move it cleanly
24942 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
24945 oldParent.removeChild(node);
24948 this.setFirstChild(node);
24950 this.childNodes.splice(refIndex, 0, node);
24951 node.parentNode = this;
24952 var ps = this.childNodes[refIndex-1];
24954 node.previousSibling = ps;
24955 ps.nextSibling = node;
24957 node.previousSibling = null;
24959 node.nextSibling = refNode;
24960 refNode.previousSibling = node;
24961 node.setOwnerTree(this.getOwnerTree());
24962 this.fireEvent("insert", this.ownerTree, this, node, refNode);
24964 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
24970 * Returns the child node at the specified index.
24971 * @param {Number} index
24974 item : function(index){
24975 return this.childNodes[index];
24979 * Replaces one child node in this node with another.
24980 * @param {Node} newChild The replacement node
24981 * @param {Node} oldChild The node to replace
24982 * @return {Node} The replaced node
24984 replaceChild : function(newChild, oldChild){
24985 this.insertBefore(newChild, oldChild);
24986 this.removeChild(oldChild);
24991 * Returns the index of a child node
24992 * @param {Node} node
24993 * @return {Number} The index of the node or -1 if it was not found
24995 indexOf : function(child){
24996 return this.childNodes.indexOf(child);
25000 * Returns the tree this node is in.
25003 getOwnerTree : function(){
25004 // if it doesn't have one, look for one
25005 if(!this.ownerTree){
25009 this.ownerTree = p.ownerTree;
25015 return this.ownerTree;
25019 * Returns depth of this node (the root node has a depth of 0)
25022 getDepth : function(){
25025 while(p.parentNode){
25033 setOwnerTree : function(tree){
25034 // if it's move, we need to update everyone
25035 if(tree != this.ownerTree){
25036 if(this.ownerTree){
25037 this.ownerTree.unregisterNode(this);
25039 this.ownerTree = tree;
25040 var cs = this.childNodes;
25041 for(var i = 0, len = cs.length; i < len; i++) {
25042 cs[i].setOwnerTree(tree);
25045 tree.registerNode(this);
25051 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25052 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25053 * @return {String} The path
25055 getPath : function(attr){
25056 attr = attr || "id";
25057 var p = this.parentNode;
25058 var b = [this.attributes[attr]];
25060 b.unshift(p.attributes[attr]);
25063 var sep = this.getOwnerTree().pathSeparator;
25064 return sep + b.join(sep);
25068 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25069 * function call will be the scope provided or the current node. The arguments to the function
25070 * will be the args provided or the current node. If the function returns false at any point,
25071 * the bubble is stopped.
25072 * @param {Function} fn The function to call
25073 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25074 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25076 bubble : function(fn, scope, args){
25079 if(fn.call(scope || p, args || p) === false){
25087 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25088 * function call will be the scope provided or the current node. The arguments to the function
25089 * will be the args provided or the current node. If the function returns false at any point,
25090 * the cascade is stopped on that branch.
25091 * @param {Function} fn The function to call
25092 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25093 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25095 cascade : function(fn, scope, args){
25096 if(fn.call(scope || this, args || this) !== false){
25097 var cs = this.childNodes;
25098 for(var i = 0, len = cs.length; i < len; i++) {
25099 cs[i].cascade(fn, scope, args);
25105 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25106 * function call will be the scope provided or the current node. The arguments to the function
25107 * will be the args provided or the current node. If the function returns false at any point,
25108 * the iteration stops.
25109 * @param {Function} fn The function to call
25110 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25111 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25113 eachChild : function(fn, scope, args){
25114 var cs = this.childNodes;
25115 for(var i = 0, len = cs.length; i < len; i++) {
25116 if(fn.call(scope || this, args || cs[i]) === false){
25123 * Finds the first child that has the attribute with the specified value.
25124 * @param {String} attribute The attribute name
25125 * @param {Mixed} value The value to search for
25126 * @return {Node} The found child or null if none was found
25128 findChild : function(attribute, value){
25129 var cs = this.childNodes;
25130 for(var i = 0, len = cs.length; i < len; i++) {
25131 if(cs[i].attributes[attribute] == value){
25139 * Finds the first child by a custom function. The child matches if the function passed
25141 * @param {Function} fn
25142 * @param {Object} scope (optional)
25143 * @return {Node} The found child or null if none was found
25145 findChildBy : function(fn, scope){
25146 var cs = this.childNodes;
25147 for(var i = 0, len = cs.length; i < len; i++) {
25148 if(fn.call(scope||cs[i], cs[i]) === true){
25156 * Sorts this nodes children using the supplied sort function
25157 * @param {Function} fn
25158 * @param {Object} scope (optional)
25160 sort : function(fn, scope){
25161 var cs = this.childNodes;
25162 var len = cs.length;
25164 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25166 for(var i = 0; i < len; i++){
25168 n.previousSibling = cs[i-1];
25169 n.nextSibling = cs[i+1];
25171 this.setFirstChild(n);
25174 this.setLastChild(n);
25181 * Returns true if this node is an ancestor (at any point) of the passed node.
25182 * @param {Node} node
25183 * @return {Boolean}
25185 contains : function(node){
25186 return node.isAncestor(this);
25190 * Returns true if the passed node is an ancestor (at any point) of this node.
25191 * @param {Node} node
25192 * @return {Boolean}
25194 isAncestor : function(node){
25195 var p = this.parentNode;
25205 toString : function(){
25206 return "[Node"+(this.id?" "+this.id:"")+"]";
25210 * Ext JS Library 1.1.1
25211 * Copyright(c) 2006-2007, Ext JS, LLC.
25213 * Originally Released Under LGPL - original licence link has changed is not relivant.
25216 * <script type="text/javascript">
25221 * @extends Roo.Element
25222 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25223 * automatic maintaining of shadow/shim positions.
25224 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25225 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25226 * you can pass a string with a CSS class name. False turns off the shadow.
25227 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25228 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25229 * @cfg {String} cls CSS class to add to the element
25230 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25231 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25233 * @param {Object} config An object with config options.
25234 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25237 Roo.Layer = function(config, existingEl){
25238 config = config || {};
25239 var dh = Roo.DomHelper;
25240 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25242 this.dom = Roo.getDom(existingEl);
25245 var o = config.dh || {tag: "div", cls: "x-layer"};
25246 this.dom = dh.append(pel, o);
25249 this.addClass(config.cls);
25251 this.constrain = config.constrain !== false;
25252 this.visibilityMode = Roo.Element.VISIBILITY;
25254 this.id = this.dom.id = config.id;
25256 this.id = Roo.id(this.dom);
25258 this.zindex = config.zindex || this.getZIndex();
25259 this.position("absolute", this.zindex);
25261 this.shadowOffset = config.shadowOffset || 4;
25262 this.shadow = new Roo.Shadow({
25263 offset : this.shadowOffset,
25264 mode : config.shadow
25267 this.shadowOffset = 0;
25269 this.useShim = config.shim !== false && Roo.useShims;
25270 this.useDisplay = config.useDisplay;
25274 var supr = Roo.Element.prototype;
25276 // shims are shared among layer to keep from having 100 iframes
25279 Roo.extend(Roo.Layer, Roo.Element, {
25281 getZIndex : function(){
25282 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25285 getShim : function(){
25292 var shim = shims.shift();
25294 shim = this.createShim();
25295 shim.enableDisplayMode('block');
25296 shim.dom.style.display = 'none';
25297 shim.dom.style.visibility = 'visible';
25299 var pn = this.dom.parentNode;
25300 if(shim.dom.parentNode != pn){
25301 pn.insertBefore(shim.dom, this.dom);
25303 shim.setStyle('z-index', this.getZIndex()-2);
25308 hideShim : function(){
25310 this.shim.setDisplayed(false);
25311 shims.push(this.shim);
25316 disableShadow : function(){
25318 this.shadowDisabled = true;
25319 this.shadow.hide();
25320 this.lastShadowOffset = this.shadowOffset;
25321 this.shadowOffset = 0;
25325 enableShadow : function(show){
25327 this.shadowDisabled = false;
25328 this.shadowOffset = this.lastShadowOffset;
25329 delete this.lastShadowOffset;
25337 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25338 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25339 sync : function(doShow){
25340 var sw = this.shadow;
25341 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25342 var sh = this.getShim();
25344 var w = this.getWidth(),
25345 h = this.getHeight();
25347 var l = this.getLeft(true),
25348 t = this.getTop(true);
25350 if(sw && !this.shadowDisabled){
25351 if(doShow && !sw.isVisible()){
25354 sw.realign(l, t, w, h);
25360 // fit the shim behind the shadow, so it is shimmed too
25361 var a = sw.adjusts, s = sh.dom.style;
25362 s.left = (Math.min(l, l+a.l))+"px";
25363 s.top = (Math.min(t, t+a.t))+"px";
25364 s.width = (w+a.w)+"px";
25365 s.height = (h+a.h)+"px";
25372 sh.setLeftTop(l, t);
25379 destroy : function(){
25382 this.shadow.hide();
25384 this.removeAllListeners();
25385 var pn = this.dom.parentNode;
25387 pn.removeChild(this.dom);
25389 Roo.Element.uncache(this.id);
25392 remove : function(){
25397 beginUpdate : function(){
25398 this.updating = true;
25402 endUpdate : function(){
25403 this.updating = false;
25408 hideUnders : function(negOffset){
25410 this.shadow.hide();
25416 constrainXY : function(){
25417 if(this.constrain){
25418 var vw = Roo.lib.Dom.getViewWidth(),
25419 vh = Roo.lib.Dom.getViewHeight();
25420 var s = Roo.get(document).getScroll();
25422 var xy = this.getXY();
25423 var x = xy[0], y = xy[1];
25424 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25425 // only move it if it needs it
25427 // first validate right/bottom
25428 if((x + w) > vw+s.left){
25429 x = vw - w - this.shadowOffset;
25432 if((y + h) > vh+s.top){
25433 y = vh - h - this.shadowOffset;
25436 // then make sure top/left isn't negative
25447 var ay = this.avoidY;
25448 if(y <= ay && (y+h) >= ay){
25454 supr.setXY.call(this, xy);
25460 isVisible : function(){
25461 return this.visible;
25465 showAction : function(){
25466 this.visible = true; // track visibility to prevent getStyle calls
25467 if(this.useDisplay === true){
25468 this.setDisplayed("");
25469 }else if(this.lastXY){
25470 supr.setXY.call(this, this.lastXY);
25471 }else if(this.lastLT){
25472 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25477 hideAction : function(){
25478 this.visible = false;
25479 if(this.useDisplay === true){
25480 this.setDisplayed(false);
25482 this.setLeftTop(-10000,-10000);
25486 // overridden Element method
25487 setVisible : function(v, a, d, c, e){
25492 var cb = function(){
25497 }.createDelegate(this);
25498 supr.setVisible.call(this, true, true, d, cb, e);
25501 this.hideUnders(true);
25510 }.createDelegate(this);
25512 supr.setVisible.call(this, v, a, d, cb, e);
25521 storeXY : function(xy){
25522 delete this.lastLT;
25526 storeLeftTop : function(left, top){
25527 delete this.lastXY;
25528 this.lastLT = [left, top];
25532 beforeFx : function(){
25533 this.beforeAction();
25534 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25538 afterFx : function(){
25539 Roo.Layer.superclass.afterFx.apply(this, arguments);
25540 this.sync(this.isVisible());
25544 beforeAction : function(){
25545 if(!this.updating && this.shadow){
25546 this.shadow.hide();
25550 // overridden Element method
25551 setLeft : function(left){
25552 this.storeLeftTop(left, this.getTop(true));
25553 supr.setLeft.apply(this, arguments);
25557 setTop : function(top){
25558 this.storeLeftTop(this.getLeft(true), top);
25559 supr.setTop.apply(this, arguments);
25563 setLeftTop : function(left, top){
25564 this.storeLeftTop(left, top);
25565 supr.setLeftTop.apply(this, arguments);
25569 setXY : function(xy, a, d, c, e){
25571 this.beforeAction();
25573 var cb = this.createCB(c);
25574 supr.setXY.call(this, xy, a, d, cb, e);
25581 createCB : function(c){
25592 // overridden Element method
25593 setX : function(x, a, d, c, e){
25594 this.setXY([x, this.getY()], a, d, c, e);
25597 // overridden Element method
25598 setY : function(y, a, d, c, e){
25599 this.setXY([this.getX(), y], a, d, c, e);
25602 // overridden Element method
25603 setSize : function(w, h, a, d, c, e){
25604 this.beforeAction();
25605 var cb = this.createCB(c);
25606 supr.setSize.call(this, w, h, a, d, cb, e);
25612 // overridden Element method
25613 setWidth : function(w, a, d, c, e){
25614 this.beforeAction();
25615 var cb = this.createCB(c);
25616 supr.setWidth.call(this, w, a, d, cb, e);
25622 // overridden Element method
25623 setHeight : function(h, a, d, c, e){
25624 this.beforeAction();
25625 var cb = this.createCB(c);
25626 supr.setHeight.call(this, h, a, d, cb, e);
25632 // overridden Element method
25633 setBounds : function(x, y, w, h, a, d, c, e){
25634 this.beforeAction();
25635 var cb = this.createCB(c);
25637 this.storeXY([x, y]);
25638 supr.setXY.call(this, [x, y]);
25639 supr.setSize.call(this, w, h, a, d, cb, e);
25642 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25648 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25649 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25650 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25651 * @param {Number} zindex The new z-index to set
25652 * @return {this} The Layer
25654 setZIndex : function(zindex){
25655 this.zindex = zindex;
25656 this.setStyle("z-index", zindex + 2);
25658 this.shadow.setZIndex(zindex + 1);
25661 this.shim.setStyle("z-index", zindex);
25667 * Ext JS Library 1.1.1
25668 * Copyright(c) 2006-2007, Ext JS, LLC.
25670 * Originally Released Under LGPL - original licence link has changed is not relivant.
25673 * <script type="text/javascript">
25678 * @class Roo.Shadow
25679 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25680 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25681 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25683 * Create a new Shadow
25684 * @param {Object} config The config object
25686 Roo.Shadow = function(config){
25687 Roo.apply(this, config);
25688 if(typeof this.mode != "string"){
25689 this.mode = this.defaultMode;
25691 var o = this.offset, a = {h: 0};
25692 var rad = Math.floor(this.offset/2);
25693 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25699 a.l -= this.offset + rad;
25700 a.t -= this.offset + rad;
25711 a.l -= (this.offset - rad);
25712 a.t -= this.offset + rad;
25714 a.w -= (this.offset - rad)*2;
25725 a.l -= (this.offset - rad);
25726 a.t -= (this.offset - rad);
25728 a.w -= (this.offset + rad + 1);
25729 a.h -= (this.offset + rad);
25738 Roo.Shadow.prototype = {
25740 * @cfg {String} mode
25741 * The shadow display mode. Supports the following options:<br />
25742 * sides: Shadow displays on both sides and bottom only<br />
25743 * frame: Shadow displays equally on all four sides<br />
25744 * drop: Traditional bottom-right drop shadow (default)
25747 * @cfg {String} offset
25748 * The number of pixels to offset the shadow from the element (defaults to 4)
25753 defaultMode: "drop",
25756 * Displays the shadow under the target element
25757 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25759 show : function(target){
25760 target = Roo.get(target);
25762 this.el = Roo.Shadow.Pool.pull();
25763 if(this.el.dom.nextSibling != target.dom){
25764 this.el.insertBefore(target);
25767 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25769 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25772 target.getLeft(true),
25773 target.getTop(true),
25777 this.el.dom.style.display = "block";
25781 * Returns true if the shadow is visible, else false
25783 isVisible : function(){
25784 return this.el ? true : false;
25788 * Direct alignment when values are already available. Show must be called at least once before
25789 * calling this method to ensure it is initialized.
25790 * @param {Number} left The target element left position
25791 * @param {Number} top The target element top position
25792 * @param {Number} width The target element width
25793 * @param {Number} height The target element height
25795 realign : function(l, t, w, h){
25799 var a = this.adjusts, d = this.el.dom, s = d.style;
25801 s.left = (l+a.l)+"px";
25802 s.top = (t+a.t)+"px";
25803 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25805 if(s.width != sws || s.height != shs){
25809 var cn = d.childNodes;
25810 var sww = Math.max(0, (sw-12))+"px";
25811 cn[0].childNodes[1].style.width = sww;
25812 cn[1].childNodes[1].style.width = sww;
25813 cn[2].childNodes[1].style.width = sww;
25814 cn[1].style.height = Math.max(0, (sh-12))+"px";
25820 * Hides this shadow
25824 this.el.dom.style.display = "none";
25825 Roo.Shadow.Pool.push(this.el);
25831 * Adjust the z-index of this shadow
25832 * @param {Number} zindex The new z-index
25834 setZIndex : function(z){
25837 this.el.setStyle("z-index", z);
25842 // Private utility class that manages the internal Shadow cache
25843 Roo.Shadow.Pool = function(){
25845 var markup = Roo.isIE ?
25846 '<div class="x-ie-shadow"></div>' :
25847 '<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>';
25850 var sh = p.shift();
25852 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
25853 sh.autoBoxAdjust = false;
25858 push : function(sh){
25864 * Ext JS Library 1.1.1
25865 * Copyright(c) 2006-2007, Ext JS, LLC.
25867 * Originally Released Under LGPL - original licence link has changed is not relivant.
25870 * <script type="text/javascript">
25875 * @class Roo.SplitBar
25876 * @extends Roo.util.Observable
25877 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
25881 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
25882 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
25883 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
25884 split.minSize = 100;
25885 split.maxSize = 600;
25886 split.animate = true;
25887 split.on('moved', splitterMoved);
25890 * Create a new SplitBar
25891 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
25892 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
25893 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25894 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
25895 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
25896 position of the SplitBar).
25898 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
25901 this.el = Roo.get(dragElement, true);
25902 this.el.dom.unselectable = "on";
25904 this.resizingEl = Roo.get(resizingElement, true);
25908 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25909 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
25912 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
25915 * The minimum size of the resizing element. (Defaults to 0)
25921 * The maximum size of the resizing element. (Defaults to 2000)
25924 this.maxSize = 2000;
25927 * Whether to animate the transition to the new size
25930 this.animate = false;
25933 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
25936 this.useShim = false;
25941 if(!existingProxy){
25943 this.proxy = Roo.SplitBar.createProxy(this.orientation);
25945 this.proxy = Roo.get(existingProxy).dom;
25948 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
25951 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
25954 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
25957 this.dragSpecs = {};
25960 * @private The adapter to use to positon and resize elements
25962 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
25963 this.adapter.init(this);
25965 if(this.orientation == Roo.SplitBar.HORIZONTAL){
25967 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
25968 this.el.addClass("x-splitbar-h");
25971 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
25972 this.el.addClass("x-splitbar-v");
25978 * Fires when the splitter is moved (alias for {@link #event-moved})
25979 * @param {Roo.SplitBar} this
25980 * @param {Number} newSize the new width or height
25985 * Fires when the splitter is moved
25986 * @param {Roo.SplitBar} this
25987 * @param {Number} newSize the new width or height
25991 * @event beforeresize
25992 * Fires before the splitter is dragged
25993 * @param {Roo.SplitBar} this
25995 "beforeresize" : true,
25997 "beforeapply" : true
26000 Roo.util.Observable.call(this);
26003 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26004 onStartProxyDrag : function(x, y){
26005 this.fireEvent("beforeresize", this);
26007 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26009 o.enableDisplayMode("block");
26010 // all splitbars share the same overlay
26011 Roo.SplitBar.prototype.overlay = o;
26013 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26014 this.overlay.show();
26015 Roo.get(this.proxy).setDisplayed("block");
26016 var size = this.adapter.getElementSize(this);
26017 this.activeMinSize = this.getMinimumSize();;
26018 this.activeMaxSize = this.getMaximumSize();;
26019 var c1 = size - this.activeMinSize;
26020 var c2 = Math.max(this.activeMaxSize - size, 0);
26021 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26022 this.dd.resetConstraints();
26023 this.dd.setXConstraint(
26024 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26025 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26027 this.dd.setYConstraint(0, 0);
26029 this.dd.resetConstraints();
26030 this.dd.setXConstraint(0, 0);
26031 this.dd.setYConstraint(
26032 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26033 this.placement == Roo.SplitBar.TOP ? c2 : c1
26036 this.dragSpecs.startSize = size;
26037 this.dragSpecs.startPoint = [x, y];
26038 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26042 * @private Called after the drag operation by the DDProxy
26044 onEndProxyDrag : function(e){
26045 Roo.get(this.proxy).setDisplayed(false);
26046 var endPoint = Roo.lib.Event.getXY(e);
26048 this.overlay.hide();
26051 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26052 newSize = this.dragSpecs.startSize +
26053 (this.placement == Roo.SplitBar.LEFT ?
26054 endPoint[0] - this.dragSpecs.startPoint[0] :
26055 this.dragSpecs.startPoint[0] - endPoint[0]
26058 newSize = this.dragSpecs.startSize +
26059 (this.placement == Roo.SplitBar.TOP ?
26060 endPoint[1] - this.dragSpecs.startPoint[1] :
26061 this.dragSpecs.startPoint[1] - endPoint[1]
26064 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26065 if(newSize != this.dragSpecs.startSize){
26066 if(this.fireEvent('beforeapply', this, newSize) !== false){
26067 this.adapter.setElementSize(this, newSize);
26068 this.fireEvent("moved", this, newSize);
26069 this.fireEvent("resize", this, newSize);
26075 * Get the adapter this SplitBar uses
26076 * @return The adapter object
26078 getAdapter : function(){
26079 return this.adapter;
26083 * Set the adapter this SplitBar uses
26084 * @param {Object} adapter A SplitBar adapter object
26086 setAdapter : function(adapter){
26087 this.adapter = adapter;
26088 this.adapter.init(this);
26092 * Gets the minimum size for the resizing element
26093 * @return {Number} The minimum size
26095 getMinimumSize : function(){
26096 return this.minSize;
26100 * Sets the minimum size for the resizing element
26101 * @param {Number} minSize The minimum size
26103 setMinimumSize : function(minSize){
26104 this.minSize = minSize;
26108 * Gets the maximum size for the resizing element
26109 * @return {Number} The maximum size
26111 getMaximumSize : function(){
26112 return this.maxSize;
26116 * Sets the maximum size for the resizing element
26117 * @param {Number} maxSize The maximum size
26119 setMaximumSize : function(maxSize){
26120 this.maxSize = maxSize;
26124 * Sets the initialize size for the resizing element
26125 * @param {Number} size The initial size
26127 setCurrentSize : function(size){
26128 var oldAnimate = this.animate;
26129 this.animate = false;
26130 this.adapter.setElementSize(this, size);
26131 this.animate = oldAnimate;
26135 * Destroy this splitbar.
26136 * @param {Boolean} removeEl True to remove the element
26138 destroy : function(removeEl){
26140 this.shim.remove();
26143 this.proxy.parentNode.removeChild(this.proxy);
26151 * @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.
26153 Roo.SplitBar.createProxy = function(dir){
26154 var proxy = new Roo.Element(document.createElement("div"));
26155 proxy.unselectable();
26156 var cls = 'x-splitbar-proxy';
26157 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26158 document.body.appendChild(proxy.dom);
26163 * @class Roo.SplitBar.BasicLayoutAdapter
26164 * Default Adapter. It assumes the splitter and resizing element are not positioned
26165 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26167 Roo.SplitBar.BasicLayoutAdapter = function(){
26170 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26171 // do nothing for now
26172 init : function(s){
26176 * Called before drag operations to get the current size of the resizing element.
26177 * @param {Roo.SplitBar} s The SplitBar using this adapter
26179 getElementSize : function(s){
26180 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26181 return s.resizingEl.getWidth();
26183 return s.resizingEl.getHeight();
26188 * Called after drag operations to set the size of the resizing element.
26189 * @param {Roo.SplitBar} s The SplitBar using this adapter
26190 * @param {Number} newSize The new size to set
26191 * @param {Function} onComplete A function to be invoked when resizing is complete
26193 setElementSize : function(s, newSize, onComplete){
26194 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26196 s.resizingEl.setWidth(newSize);
26198 onComplete(s, newSize);
26201 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26206 s.resizingEl.setHeight(newSize);
26208 onComplete(s, newSize);
26211 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26218 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26219 * @extends Roo.SplitBar.BasicLayoutAdapter
26220 * Adapter that moves the splitter element to align with the resized sizing element.
26221 * Used with an absolute positioned SplitBar.
26222 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26223 * document.body, make sure you assign an id to the body element.
26225 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26226 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26227 this.container = Roo.get(container);
26230 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26231 init : function(s){
26232 this.basic.init(s);
26235 getElementSize : function(s){
26236 return this.basic.getElementSize(s);
26239 setElementSize : function(s, newSize, onComplete){
26240 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26243 moveSplitter : function(s){
26244 var yes = Roo.SplitBar;
26245 switch(s.placement){
26247 s.el.setX(s.resizingEl.getRight());
26250 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26253 s.el.setY(s.resizingEl.getBottom());
26256 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26263 * Orientation constant - Create a vertical SplitBar
26267 Roo.SplitBar.VERTICAL = 1;
26270 * Orientation constant - Create a horizontal SplitBar
26274 Roo.SplitBar.HORIZONTAL = 2;
26277 * Placement constant - The resizing element is to the left of the splitter element
26281 Roo.SplitBar.LEFT = 1;
26284 * Placement constant - The resizing element is to the right of the splitter element
26288 Roo.SplitBar.RIGHT = 2;
26291 * Placement constant - The resizing element is positioned above the splitter element
26295 Roo.SplitBar.TOP = 3;
26298 * Placement constant - The resizing element is positioned under splitter element
26302 Roo.SplitBar.BOTTOM = 4;
26305 * Ext JS Library 1.1.1
26306 * Copyright(c) 2006-2007, Ext JS, LLC.
26308 * Originally Released Under LGPL - original licence link has changed is not relivant.
26311 * <script type="text/javascript">
26316 * @extends Roo.util.Observable
26317 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26318 * This class also supports single and multi selection modes. <br>
26319 * Create a data model bound view:
26321 var store = new Roo.data.Store(...);
26323 var view = new Roo.View({
26325 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26327 singleSelect: true,
26328 selectedClass: "ydataview-selected",
26332 // listen for node click?
26333 view.on("click", function(vw, index, node, e){
26334 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26338 dataModel.load("foobar.xml");
26340 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26342 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26343 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26345 * Note: old style constructor is still suported (container, template, config)
26348 * Create a new View
26349 * @param {Object} config The config object
26352 Roo.View = function(config, depreciated_tpl, depreciated_config){
26354 this.parent = false;
26356 if (typeof(depreciated_tpl) == 'undefined') {
26357 // new way.. - universal constructor.
26358 Roo.apply(this, config);
26359 this.el = Roo.get(this.el);
26362 this.el = Roo.get(config);
26363 this.tpl = depreciated_tpl;
26364 Roo.apply(this, depreciated_config);
26366 this.wrapEl = this.el.wrap().wrap();
26367 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26370 if(typeof(this.tpl) == "string"){
26371 this.tpl = new Roo.Template(this.tpl);
26373 // support xtype ctors..
26374 this.tpl = new Roo.factory(this.tpl, Roo);
26378 this.tpl.compile();
26383 * @event beforeclick
26384 * Fires before a click is processed. Returns false to cancel the default action.
26385 * @param {Roo.View} this
26386 * @param {Number} index The index of the target node
26387 * @param {HTMLElement} node The target node
26388 * @param {Roo.EventObject} e The raw event object
26390 "beforeclick" : true,
26393 * Fires when a template node is clicked.
26394 * @param {Roo.View} this
26395 * @param {Number} index The index of the target node
26396 * @param {HTMLElement} node The target node
26397 * @param {Roo.EventObject} e The raw event object
26402 * Fires when a template node is double clicked.
26403 * @param {Roo.View} this
26404 * @param {Number} index The index of the target node
26405 * @param {HTMLElement} node The target node
26406 * @param {Roo.EventObject} e The raw event object
26410 * @event contextmenu
26411 * Fires when a template node is right clicked.
26412 * @param {Roo.View} this
26413 * @param {Number} index The index of the target node
26414 * @param {HTMLElement} node The target node
26415 * @param {Roo.EventObject} e The raw event object
26417 "contextmenu" : true,
26419 * @event selectionchange
26420 * Fires when the selected nodes change.
26421 * @param {Roo.View} this
26422 * @param {Array} selections Array of the selected nodes
26424 "selectionchange" : true,
26427 * @event beforeselect
26428 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26429 * @param {Roo.View} this
26430 * @param {HTMLElement} node The node to be selected
26431 * @param {Array} selections Array of currently selected nodes
26433 "beforeselect" : true,
26435 * @event preparedata
26436 * Fires on every row to render, to allow you to change the data.
26437 * @param {Roo.View} this
26438 * @param {Object} data to be rendered (change this)
26440 "preparedata" : true
26448 "click": this.onClick,
26449 "dblclick": this.onDblClick,
26450 "contextmenu": this.onContextMenu,
26454 this.selections = [];
26456 this.cmp = new Roo.CompositeElementLite([]);
26458 this.store = Roo.factory(this.store, Roo.data);
26459 this.setStore(this.store, true);
26462 if ( this.footer && this.footer.xtype) {
26464 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26466 this.footer.dataSource = this.store;
26467 this.footer.container = fctr;
26468 this.footer = Roo.factory(this.footer, Roo);
26469 fctr.insertFirst(this.el);
26471 // this is a bit insane - as the paging toolbar seems to detach the el..
26472 // dom.parentNode.parentNode.parentNode
26473 // they get detached?
26477 Roo.View.superclass.constructor.call(this);
26482 Roo.extend(Roo.View, Roo.util.Observable, {
26485 * @cfg {Roo.data.Store} store Data store to load data from.
26490 * @cfg {String|Roo.Element} el The container element.
26495 * @cfg {String|Roo.Template} tpl The template used by this View
26499 * @cfg {String} dataName the named area of the template to use as the data area
26500 * Works with domtemplates roo-name="name"
26504 * @cfg {String} selectedClass The css class to add to selected nodes
26506 selectedClass : "x-view-selected",
26508 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26513 * @cfg {String} text to display on mask (default Loading)
26517 * @cfg {Boolean} multiSelect Allow multiple selection
26519 multiSelect : false,
26521 * @cfg {Boolean} singleSelect Allow single selection
26523 singleSelect: false,
26526 * @cfg {Boolean} toggleSelect - selecting
26528 toggleSelect : false,
26531 * @cfg {Boolean} tickable - selecting
26536 * Returns the element this view is bound to.
26537 * @return {Roo.Element}
26539 getEl : function(){
26540 return this.wrapEl;
26546 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26548 refresh : function(){
26549 //Roo.log('refresh');
26552 // if we are using something like 'domtemplate', then
26553 // the what gets used is:
26554 // t.applySubtemplate(NAME, data, wrapping data..)
26555 // the outer template then get' applied with
26556 // the store 'extra data'
26557 // and the body get's added to the
26558 // roo-name="data" node?
26559 // <span class='roo-tpl-{name}'></span> ?????
26563 this.clearSelections();
26564 this.el.update("");
26566 var records = this.store.getRange();
26567 if(records.length < 1) {
26569 // is this valid?? = should it render a template??
26571 this.el.update(this.emptyText);
26575 if (this.dataName) {
26576 this.el.update(t.apply(this.store.meta)); //????
26577 el = this.el.child('.roo-tpl-' + this.dataName);
26580 for(var i = 0, len = records.length; i < len; i++){
26581 var data = this.prepareData(records[i].data, i, records[i]);
26582 this.fireEvent("preparedata", this, data, i, records[i]);
26584 var d = Roo.apply({}, data);
26587 Roo.apply(d, {'roo-id' : Roo.id()});
26591 Roo.each(this.parent.item, function(item){
26592 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26595 Roo.apply(d, {'roo-data-checked' : 'checked'});
26599 html[html.length] = Roo.util.Format.trim(
26601 t.applySubtemplate(this.dataName, d, this.store.meta) :
26608 el.update(html.join(""));
26609 this.nodes = el.dom.childNodes;
26610 this.updateIndexes(0);
26615 * Function to override to reformat the data that is sent to
26616 * the template for each node.
26617 * DEPRICATED - use the preparedata event handler.
26618 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26619 * a JSON object for an UpdateManager bound view).
26621 prepareData : function(data, index, record)
26623 this.fireEvent("preparedata", this, data, index, record);
26627 onUpdate : function(ds, record){
26628 // Roo.log('on update');
26629 this.clearSelections();
26630 var index = this.store.indexOf(record);
26631 var n = this.nodes[index];
26632 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26633 n.parentNode.removeChild(n);
26634 this.updateIndexes(index, index);
26640 onAdd : function(ds, records, index)
26642 //Roo.log(['on Add', ds, records, index] );
26643 this.clearSelections();
26644 if(this.nodes.length == 0){
26648 var n = this.nodes[index];
26649 for(var i = 0, len = records.length; i < len; i++){
26650 var d = this.prepareData(records[i].data, i, records[i]);
26652 this.tpl.insertBefore(n, d);
26655 this.tpl.append(this.el, d);
26658 this.updateIndexes(index);
26661 onRemove : function(ds, record, index){
26662 // Roo.log('onRemove');
26663 this.clearSelections();
26664 var el = this.dataName ?
26665 this.el.child('.roo-tpl-' + this.dataName) :
26668 el.dom.removeChild(this.nodes[index]);
26669 this.updateIndexes(index);
26673 * Refresh an individual node.
26674 * @param {Number} index
26676 refreshNode : function(index){
26677 this.onUpdate(this.store, this.store.getAt(index));
26680 updateIndexes : function(startIndex, endIndex){
26681 var ns = this.nodes;
26682 startIndex = startIndex || 0;
26683 endIndex = endIndex || ns.length - 1;
26684 for(var i = startIndex; i <= endIndex; i++){
26685 ns[i].nodeIndex = i;
26690 * Changes the data store this view uses and refresh the view.
26691 * @param {Store} store
26693 setStore : function(store, initial){
26694 if(!initial && this.store){
26695 this.store.un("datachanged", this.refresh);
26696 this.store.un("add", this.onAdd);
26697 this.store.un("remove", this.onRemove);
26698 this.store.un("update", this.onUpdate);
26699 this.store.un("clear", this.refresh);
26700 this.store.un("beforeload", this.onBeforeLoad);
26701 this.store.un("load", this.onLoad);
26702 this.store.un("loadexception", this.onLoad);
26706 store.on("datachanged", this.refresh, this);
26707 store.on("add", this.onAdd, this);
26708 store.on("remove", this.onRemove, this);
26709 store.on("update", this.onUpdate, this);
26710 store.on("clear", this.refresh, this);
26711 store.on("beforeload", this.onBeforeLoad, this);
26712 store.on("load", this.onLoad, this);
26713 store.on("loadexception", this.onLoad, this);
26721 * onbeforeLoad - masks the loading area.
26724 onBeforeLoad : function(store,opts)
26726 //Roo.log('onBeforeLoad');
26728 this.el.update("");
26730 this.el.mask(this.mask ? this.mask : "Loading" );
26732 onLoad : function ()
26739 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26740 * @param {HTMLElement} node
26741 * @return {HTMLElement} The template node
26743 findItemFromChild : function(node){
26744 var el = this.dataName ?
26745 this.el.child('.roo-tpl-' + this.dataName,true) :
26748 if(!node || node.parentNode == el){
26751 var p = node.parentNode;
26752 while(p && p != el){
26753 if(p.parentNode == el){
26762 onClick : function(e){
26763 var item = this.findItemFromChild(e.getTarget());
26765 var index = this.indexOf(item);
26766 if(this.onItemClick(item, index, e) !== false){
26767 this.fireEvent("click", this, index, item, e);
26770 this.clearSelections();
26775 onContextMenu : function(e){
26776 var item = this.findItemFromChild(e.getTarget());
26778 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26783 onDblClick : function(e){
26784 var item = this.findItemFromChild(e.getTarget());
26786 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26790 onItemClick : function(item, index, e)
26792 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26795 if (this.toggleSelect) {
26796 var m = this.isSelected(item) ? 'unselect' : 'select';
26799 _t[m](item, true, false);
26802 if(this.multiSelect || this.singleSelect){
26803 if(this.multiSelect && e.shiftKey && this.lastSelection){
26804 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26806 this.select(item, this.multiSelect && e.ctrlKey);
26807 this.lastSelection = item;
26810 if(!this.tickable){
26811 e.preventDefault();
26819 * Get the number of selected nodes.
26822 getSelectionCount : function(){
26823 return this.selections.length;
26827 * Get the currently selected nodes.
26828 * @return {Array} An array of HTMLElements
26830 getSelectedNodes : function(){
26831 return this.selections;
26835 * Get the indexes of the selected nodes.
26838 getSelectedIndexes : function(){
26839 var indexes = [], s = this.selections;
26840 for(var i = 0, len = s.length; i < len; i++){
26841 indexes.push(s[i].nodeIndex);
26847 * Clear all selections
26848 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
26850 clearSelections : function(suppressEvent){
26851 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
26852 this.cmp.elements = this.selections;
26853 this.cmp.removeClass(this.selectedClass);
26854 this.selections = [];
26855 if(!suppressEvent){
26856 this.fireEvent("selectionchange", this, this.selections);
26862 * Returns true if the passed node is selected
26863 * @param {HTMLElement/Number} node The node or node index
26864 * @return {Boolean}
26866 isSelected : function(node){
26867 var s = this.selections;
26871 node = this.getNode(node);
26872 return s.indexOf(node) !== -1;
26877 * @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
26878 * @param {Boolean} keepExisting (optional) true to keep existing selections
26879 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26881 select : function(nodeInfo, keepExisting, suppressEvent){
26882 if(nodeInfo instanceof Array){
26884 this.clearSelections(true);
26886 for(var i = 0, len = nodeInfo.length; i < len; i++){
26887 this.select(nodeInfo[i], true, true);
26891 var node = this.getNode(nodeInfo);
26892 if(!node || this.isSelected(node)){
26893 return; // already selected.
26896 this.clearSelections(true);
26899 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
26900 Roo.fly(node).addClass(this.selectedClass);
26901 this.selections.push(node);
26902 if(!suppressEvent){
26903 this.fireEvent("selectionchange", this, this.selections);
26911 * @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
26912 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
26913 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26915 unselect : function(nodeInfo, keepExisting, suppressEvent)
26917 if(nodeInfo instanceof Array){
26918 Roo.each(this.selections, function(s) {
26919 this.unselect(s, nodeInfo);
26923 var node = this.getNode(nodeInfo);
26924 if(!node || !this.isSelected(node)){
26925 //Roo.log("not selected");
26926 return; // not selected.
26930 Roo.each(this.selections, function(s) {
26932 Roo.fly(node).removeClass(this.selectedClass);
26939 this.selections= ns;
26940 this.fireEvent("selectionchange", this, this.selections);
26944 * Gets a template node.
26945 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26946 * @return {HTMLElement} The node or null if it wasn't found
26948 getNode : function(nodeInfo){
26949 if(typeof nodeInfo == "string"){
26950 return document.getElementById(nodeInfo);
26951 }else if(typeof nodeInfo == "number"){
26952 return this.nodes[nodeInfo];
26958 * Gets a range template nodes.
26959 * @param {Number} startIndex
26960 * @param {Number} endIndex
26961 * @return {Array} An array of nodes
26963 getNodes : function(start, end){
26964 var ns = this.nodes;
26965 start = start || 0;
26966 end = typeof end == "undefined" ? ns.length - 1 : end;
26969 for(var i = start; i <= end; i++){
26973 for(var i = start; i >= end; i--){
26981 * Finds the index of the passed node
26982 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26983 * @return {Number} The index of the node or -1
26985 indexOf : function(node){
26986 node = this.getNode(node);
26987 if(typeof node.nodeIndex == "number"){
26988 return node.nodeIndex;
26990 var ns = this.nodes;
26991 for(var i = 0, len = ns.length; i < len; i++){
27001 * Ext JS Library 1.1.1
27002 * Copyright(c) 2006-2007, Ext JS, LLC.
27004 * Originally Released Under LGPL - original licence link has changed is not relivant.
27007 * <script type="text/javascript">
27011 * @class Roo.JsonView
27012 * @extends Roo.View
27013 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27015 var view = new Roo.JsonView({
27016 container: "my-element",
27017 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27022 // listen for node click?
27023 view.on("click", function(vw, index, node, e){
27024 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27027 // direct load of JSON data
27028 view.load("foobar.php");
27030 // Example from my blog list
27031 var tpl = new Roo.Template(
27032 '<div class="entry">' +
27033 '<a class="entry-title" href="{link}">{title}</a>' +
27034 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27035 "</div><hr />"
27038 var moreView = new Roo.JsonView({
27039 container : "entry-list",
27043 moreView.on("beforerender", this.sortEntries, this);
27045 url: "/blog/get-posts.php",
27046 params: "allposts=true",
27047 text: "Loading Blog Entries..."
27051 * Note: old code is supported with arguments : (container, template, config)
27055 * Create a new JsonView
27057 * @param {Object} config The config object
27060 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27063 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27065 var um = this.el.getUpdateManager();
27066 um.setRenderer(this);
27067 um.on("update", this.onLoad, this);
27068 um.on("failure", this.onLoadException, this);
27071 * @event beforerender
27072 * Fires before rendering of the downloaded JSON data.
27073 * @param {Roo.JsonView} this
27074 * @param {Object} data The JSON data loaded
27078 * Fires when data is loaded.
27079 * @param {Roo.JsonView} this
27080 * @param {Object} data The JSON data loaded
27081 * @param {Object} response The raw Connect response object
27084 * @event loadexception
27085 * Fires when loading fails.
27086 * @param {Roo.JsonView} this
27087 * @param {Object} response The raw Connect response object
27090 'beforerender' : true,
27092 'loadexception' : true
27095 Roo.extend(Roo.JsonView, Roo.View, {
27097 * @type {String} The root property in the loaded JSON object that contains the data
27102 * Refreshes the view.
27104 refresh : function(){
27105 this.clearSelections();
27106 this.el.update("");
27108 var o = this.jsonData;
27109 if(o && o.length > 0){
27110 for(var i = 0, len = o.length; i < len; i++){
27111 var data = this.prepareData(o[i], i, o);
27112 html[html.length] = this.tpl.apply(data);
27115 html.push(this.emptyText);
27117 this.el.update(html.join(""));
27118 this.nodes = this.el.dom.childNodes;
27119 this.updateIndexes(0);
27123 * 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.
27124 * @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:
27127 url: "your-url.php",
27128 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27129 callback: yourFunction,
27130 scope: yourObject, //(optional scope)
27133 text: "Loading...",
27138 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27139 * 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.
27140 * @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}
27141 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27142 * @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.
27145 var um = this.el.getUpdateManager();
27146 um.update.apply(um, arguments);
27149 // note - render is a standard framework call...
27150 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27151 render : function(el, response){
27153 this.clearSelections();
27154 this.el.update("");
27157 if (response != '') {
27158 o = Roo.util.JSON.decode(response.responseText);
27161 o = o[this.jsonRoot];
27167 * The current JSON data or null
27170 this.beforeRender();
27175 * Get the number of records in the current JSON dataset
27178 getCount : function(){
27179 return this.jsonData ? this.jsonData.length : 0;
27183 * Returns the JSON object for the specified node(s)
27184 * @param {HTMLElement/Array} node The node or an array of nodes
27185 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27186 * you get the JSON object for the node
27188 getNodeData : function(node){
27189 if(node instanceof Array){
27191 for(var i = 0, len = node.length; i < len; i++){
27192 data.push(this.getNodeData(node[i]));
27196 return this.jsonData[this.indexOf(node)] || null;
27199 beforeRender : function(){
27200 this.snapshot = this.jsonData;
27202 this.sort.apply(this, this.sortInfo);
27204 this.fireEvent("beforerender", this, this.jsonData);
27207 onLoad : function(el, o){
27208 this.fireEvent("load", this, this.jsonData, o);
27211 onLoadException : function(el, o){
27212 this.fireEvent("loadexception", this, o);
27216 * Filter the data by a specific property.
27217 * @param {String} property A property on your JSON objects
27218 * @param {String/RegExp} value Either string that the property values
27219 * should start with, or a RegExp to test against the property
27221 filter : function(property, value){
27224 var ss = this.snapshot;
27225 if(typeof value == "string"){
27226 var vlen = value.length;
27228 this.clearFilter();
27231 value = value.toLowerCase();
27232 for(var i = 0, len = ss.length; i < len; i++){
27234 if(o[property].substr(0, vlen).toLowerCase() == value){
27238 } else if(value.exec){ // regex?
27239 for(var i = 0, len = ss.length; i < len; i++){
27241 if(value.test(o[property])){
27248 this.jsonData = data;
27254 * Filter by a function. The passed function will be called with each
27255 * object in the current dataset. If the function returns true the value is kept,
27256 * otherwise it is filtered.
27257 * @param {Function} fn
27258 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27260 filterBy : function(fn, scope){
27263 var ss = this.snapshot;
27264 for(var i = 0, len = ss.length; i < len; i++){
27266 if(fn.call(scope || this, o)){
27270 this.jsonData = data;
27276 * Clears the current filter.
27278 clearFilter : function(){
27279 if(this.snapshot && this.jsonData != this.snapshot){
27280 this.jsonData = this.snapshot;
27287 * Sorts the data for this view and refreshes it.
27288 * @param {String} property A property on your JSON objects to sort on
27289 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27290 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27292 sort : function(property, dir, sortType){
27293 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27296 var dsc = dir && dir.toLowerCase() == "desc";
27297 var f = function(o1, o2){
27298 var v1 = sortType ? sortType(o1[p]) : o1[p];
27299 var v2 = sortType ? sortType(o2[p]) : o2[p];
27302 return dsc ? +1 : -1;
27303 } else if(v1 > v2){
27304 return dsc ? -1 : +1;
27309 this.jsonData.sort(f);
27311 if(this.jsonData != this.snapshot){
27312 this.snapshot.sort(f);
27318 * Ext JS Library 1.1.1
27319 * Copyright(c) 2006-2007, Ext JS, LLC.
27321 * Originally Released Under LGPL - original licence link has changed is not relivant.
27324 * <script type="text/javascript">
27329 * @class Roo.ColorPalette
27330 * @extends Roo.Component
27331 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27332 * Here's an example of typical usage:
27334 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27335 cp.render('my-div');
27337 cp.on('select', function(palette, selColor){
27338 // do something with selColor
27342 * Create a new ColorPalette
27343 * @param {Object} config The config object
27345 Roo.ColorPalette = function(config){
27346 Roo.ColorPalette.superclass.constructor.call(this, config);
27350 * Fires when a color is selected
27351 * @param {ColorPalette} this
27352 * @param {String} color The 6-digit color hex code (without the # symbol)
27358 this.on("select", this.handler, this.scope, true);
27361 Roo.extend(Roo.ColorPalette, Roo.Component, {
27363 * @cfg {String} itemCls
27364 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27366 itemCls : "x-color-palette",
27368 * @cfg {String} value
27369 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27370 * the hex codes are case-sensitive.
27373 clickEvent:'click',
27375 ctype: "Roo.ColorPalette",
27378 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27380 allowReselect : false,
27383 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27384 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27385 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27386 * of colors with the width setting until the box is symmetrical.</p>
27387 * <p>You can override individual colors if needed:</p>
27389 var cp = new Roo.ColorPalette();
27390 cp.colors[0] = "FF0000"; // change the first box to red
27393 Or you can provide a custom array of your own for complete control:
27395 var cp = new Roo.ColorPalette();
27396 cp.colors = ["000000", "993300", "333300"];
27401 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27402 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27403 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27404 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27405 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27409 onRender : function(container, position){
27410 var t = new Roo.MasterTemplate(
27411 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27413 var c = this.colors;
27414 for(var i = 0, len = c.length; i < len; i++){
27417 var el = document.createElement("div");
27418 el.className = this.itemCls;
27420 container.dom.insertBefore(el, position);
27421 this.el = Roo.get(el);
27422 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27423 if(this.clickEvent != 'click'){
27424 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27429 afterRender : function(){
27430 Roo.ColorPalette.superclass.afterRender.call(this);
27432 var s = this.value;
27439 handleClick : function(e, t){
27440 e.preventDefault();
27441 if(!this.disabled){
27442 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27443 this.select(c.toUpperCase());
27448 * Selects the specified color in the palette (fires the select event)
27449 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27451 select : function(color){
27452 color = color.replace("#", "");
27453 if(color != this.value || this.allowReselect){
27456 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27458 el.child("a.color-"+color).addClass("x-color-palette-sel");
27459 this.value = color;
27460 this.fireEvent("select", this, color);
27465 * Ext JS Library 1.1.1
27466 * Copyright(c) 2006-2007, Ext JS, LLC.
27468 * Originally Released Under LGPL - original licence link has changed is not relivant.
27471 * <script type="text/javascript">
27475 * @class Roo.DatePicker
27476 * @extends Roo.Component
27477 * Simple date picker class.
27479 * Create a new DatePicker
27480 * @param {Object} config The config object
27482 Roo.DatePicker = function(config){
27483 Roo.DatePicker.superclass.constructor.call(this, config);
27485 this.value = config && config.value ?
27486 config.value.clearTime() : new Date().clearTime();
27491 * Fires when a date is selected
27492 * @param {DatePicker} this
27493 * @param {Date} date The selected date
27497 * @event monthchange
27498 * Fires when the displayed month changes
27499 * @param {DatePicker} this
27500 * @param {Date} date The selected month
27502 'monthchange': true
27506 this.on("select", this.handler, this.scope || this);
27508 // build the disabledDatesRE
27509 if(!this.disabledDatesRE && this.disabledDates){
27510 var dd = this.disabledDates;
27512 for(var i = 0; i < dd.length; i++){
27514 if(i != dd.length-1) {
27518 this.disabledDatesRE = new RegExp(re + ")");
27522 Roo.extend(Roo.DatePicker, Roo.Component, {
27524 * @cfg {String} todayText
27525 * The text to display on the button that selects the current date (defaults to "Today")
27527 todayText : "Today",
27529 * @cfg {String} okText
27530 * The text to display on the ok button
27532 okText : " OK ", //   to give the user extra clicking room
27534 * @cfg {String} cancelText
27535 * The text to display on the cancel button
27537 cancelText : "Cancel",
27539 * @cfg {String} todayTip
27540 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27542 todayTip : "{0} (Spacebar)",
27544 * @cfg {Date} minDate
27545 * Minimum allowable date (JavaScript date object, defaults to null)
27549 * @cfg {Date} maxDate
27550 * Maximum allowable date (JavaScript date object, defaults to null)
27554 * @cfg {String} minText
27555 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27557 minText : "This date is before the minimum date",
27559 * @cfg {String} maxText
27560 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27562 maxText : "This date is after the maximum date",
27564 * @cfg {String} format
27565 * The default date format string which can be overriden for localization support. The format must be
27566 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27570 * @cfg {Array} disabledDays
27571 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27573 disabledDays : null,
27575 * @cfg {String} disabledDaysText
27576 * The tooltip to display when the date falls on a disabled day (defaults to "")
27578 disabledDaysText : "",
27580 * @cfg {RegExp} disabledDatesRE
27581 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27583 disabledDatesRE : null,
27585 * @cfg {String} disabledDatesText
27586 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27588 disabledDatesText : "",
27590 * @cfg {Boolean} constrainToViewport
27591 * True to constrain the date picker to the viewport (defaults to true)
27593 constrainToViewport : true,
27595 * @cfg {Array} monthNames
27596 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27598 monthNames : Date.monthNames,
27600 * @cfg {Array} dayNames
27601 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27603 dayNames : Date.dayNames,
27605 * @cfg {String} nextText
27606 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27608 nextText: 'Next Month (Control+Right)',
27610 * @cfg {String} prevText
27611 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27613 prevText: 'Previous Month (Control+Left)',
27615 * @cfg {String} monthYearText
27616 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27618 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27620 * @cfg {Number} startDay
27621 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27625 * @cfg {Bool} showClear
27626 * Show a clear button (usefull for date form elements that can be blank.)
27632 * Sets the value of the date field
27633 * @param {Date} value The date to set
27635 setValue : function(value){
27636 var old = this.value;
27638 if (typeof(value) == 'string') {
27640 value = Date.parseDate(value, this.format);
27643 value = new Date();
27646 this.value = value.clearTime(true);
27648 this.update(this.value);
27653 * Gets the current selected value of the date field
27654 * @return {Date} The selected date
27656 getValue : function(){
27661 focus : function(){
27663 this.update(this.activeDate);
27668 onRender : function(container, position){
27671 '<table cellspacing="0">',
27672 '<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>',
27673 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27674 var dn = this.dayNames;
27675 for(var i = 0; i < 7; i++){
27676 var d = this.startDay+i;
27680 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27682 m[m.length] = "</tr></thead><tbody><tr>";
27683 for(var i = 0; i < 42; i++) {
27684 if(i % 7 == 0 && i != 0){
27685 m[m.length] = "</tr><tr>";
27687 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27689 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27690 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27692 var el = document.createElement("div");
27693 el.className = "x-date-picker";
27694 el.innerHTML = m.join("");
27696 container.dom.insertBefore(el, position);
27698 this.el = Roo.get(el);
27699 this.eventEl = Roo.get(el.firstChild);
27701 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27702 handler: this.showPrevMonth,
27704 preventDefault:true,
27708 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27709 handler: this.showNextMonth,
27711 preventDefault:true,
27715 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27717 this.monthPicker = this.el.down('div.x-date-mp');
27718 this.monthPicker.enableDisplayMode('block');
27720 var kn = new Roo.KeyNav(this.eventEl, {
27721 "left" : function(e){
27723 this.showPrevMonth() :
27724 this.update(this.activeDate.add("d", -1));
27727 "right" : function(e){
27729 this.showNextMonth() :
27730 this.update(this.activeDate.add("d", 1));
27733 "up" : function(e){
27735 this.showNextYear() :
27736 this.update(this.activeDate.add("d", -7));
27739 "down" : function(e){
27741 this.showPrevYear() :
27742 this.update(this.activeDate.add("d", 7));
27745 "pageUp" : function(e){
27746 this.showNextMonth();
27749 "pageDown" : function(e){
27750 this.showPrevMonth();
27753 "enter" : function(e){
27754 e.stopPropagation();
27761 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27763 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27765 this.el.unselectable();
27767 this.cells = this.el.select("table.x-date-inner tbody td");
27768 this.textNodes = this.el.query("table.x-date-inner tbody span");
27770 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27772 tooltip: this.monthYearText
27775 this.mbtn.on('click', this.showMonthPicker, this);
27776 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27779 var today = (new Date()).dateFormat(this.format);
27781 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27782 if (this.showClear) {
27783 baseTb.add( new Roo.Toolbar.Fill());
27786 text: String.format(this.todayText, today),
27787 tooltip: String.format(this.todayTip, today),
27788 handler: this.selectToday,
27792 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27795 if (this.showClear) {
27797 baseTb.add( new Roo.Toolbar.Fill());
27800 cls: 'x-btn-icon x-btn-clear',
27801 handler: function() {
27803 this.fireEvent("select", this, '');
27813 this.update(this.value);
27816 createMonthPicker : function(){
27817 if(!this.monthPicker.dom.firstChild){
27818 var buf = ['<table border="0" cellspacing="0">'];
27819 for(var i = 0; i < 6; i++){
27821 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27822 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27824 '<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>' :
27825 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27829 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27831 '</button><button type="button" class="x-date-mp-cancel">',
27833 '</button></td></tr>',
27836 this.monthPicker.update(buf.join(''));
27837 this.monthPicker.on('click', this.onMonthClick, this);
27838 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
27840 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
27841 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
27843 this.mpMonths.each(function(m, a, i){
27846 m.dom.xmonth = 5 + Math.round(i * .5);
27848 m.dom.xmonth = Math.round((i-1) * .5);
27854 showMonthPicker : function(){
27855 this.createMonthPicker();
27856 var size = this.el.getSize();
27857 this.monthPicker.setSize(size);
27858 this.monthPicker.child('table').setSize(size);
27860 this.mpSelMonth = (this.activeDate || this.value).getMonth();
27861 this.updateMPMonth(this.mpSelMonth);
27862 this.mpSelYear = (this.activeDate || this.value).getFullYear();
27863 this.updateMPYear(this.mpSelYear);
27865 this.monthPicker.slideIn('t', {duration:.2});
27868 updateMPYear : function(y){
27870 var ys = this.mpYears.elements;
27871 for(var i = 1; i <= 10; i++){
27872 var td = ys[i-1], y2;
27874 y2 = y + Math.round(i * .5);
27875 td.firstChild.innerHTML = y2;
27878 y2 = y - (5-Math.round(i * .5));
27879 td.firstChild.innerHTML = y2;
27882 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
27886 updateMPMonth : function(sm){
27887 this.mpMonths.each(function(m, a, i){
27888 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
27892 selectMPMonth: function(m){
27896 onMonthClick : function(e, t){
27898 var el = new Roo.Element(t), pn;
27899 if(el.is('button.x-date-mp-cancel')){
27900 this.hideMonthPicker();
27902 else if(el.is('button.x-date-mp-ok')){
27903 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27904 this.hideMonthPicker();
27906 else if(pn = el.up('td.x-date-mp-month', 2)){
27907 this.mpMonths.removeClass('x-date-mp-sel');
27908 pn.addClass('x-date-mp-sel');
27909 this.mpSelMonth = pn.dom.xmonth;
27911 else if(pn = el.up('td.x-date-mp-year', 2)){
27912 this.mpYears.removeClass('x-date-mp-sel');
27913 pn.addClass('x-date-mp-sel');
27914 this.mpSelYear = pn.dom.xyear;
27916 else if(el.is('a.x-date-mp-prev')){
27917 this.updateMPYear(this.mpyear-10);
27919 else if(el.is('a.x-date-mp-next')){
27920 this.updateMPYear(this.mpyear+10);
27924 onMonthDblClick : function(e, t){
27926 var el = new Roo.Element(t), pn;
27927 if(pn = el.up('td.x-date-mp-month', 2)){
27928 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
27929 this.hideMonthPicker();
27931 else if(pn = el.up('td.x-date-mp-year', 2)){
27932 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27933 this.hideMonthPicker();
27937 hideMonthPicker : function(disableAnim){
27938 if(this.monthPicker){
27939 if(disableAnim === true){
27940 this.monthPicker.hide();
27942 this.monthPicker.slideOut('t', {duration:.2});
27948 showPrevMonth : function(e){
27949 this.update(this.activeDate.add("mo", -1));
27953 showNextMonth : function(e){
27954 this.update(this.activeDate.add("mo", 1));
27958 showPrevYear : function(){
27959 this.update(this.activeDate.add("y", -1));
27963 showNextYear : function(){
27964 this.update(this.activeDate.add("y", 1));
27968 handleMouseWheel : function(e){
27969 var delta = e.getWheelDelta();
27971 this.showPrevMonth();
27973 } else if(delta < 0){
27974 this.showNextMonth();
27980 handleDateClick : function(e, t){
27982 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
27983 this.setValue(new Date(t.dateValue));
27984 this.fireEvent("select", this, this.value);
27989 selectToday : function(){
27990 this.setValue(new Date().clearTime());
27991 this.fireEvent("select", this, this.value);
27995 update : function(date)
27997 var vd = this.activeDate;
27998 this.activeDate = date;
28000 var t = date.getTime();
28001 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28002 this.cells.removeClass("x-date-selected");
28003 this.cells.each(function(c){
28004 if(c.dom.firstChild.dateValue == t){
28005 c.addClass("x-date-selected");
28006 setTimeout(function(){
28007 try{c.dom.firstChild.focus();}catch(e){}
28016 var days = date.getDaysInMonth();
28017 var firstOfMonth = date.getFirstDateOfMonth();
28018 var startingPos = firstOfMonth.getDay()-this.startDay;
28020 if(startingPos <= this.startDay){
28024 var pm = date.add("mo", -1);
28025 var prevStart = pm.getDaysInMonth()-startingPos;
28027 var cells = this.cells.elements;
28028 var textEls = this.textNodes;
28029 days += startingPos;
28031 // convert everything to numbers so it's fast
28032 var day = 86400000;
28033 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28034 var today = new Date().clearTime().getTime();
28035 var sel = date.clearTime().getTime();
28036 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28037 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28038 var ddMatch = this.disabledDatesRE;
28039 var ddText = this.disabledDatesText;
28040 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28041 var ddaysText = this.disabledDaysText;
28042 var format = this.format;
28044 var setCellClass = function(cal, cell){
28046 var t = d.getTime();
28047 cell.firstChild.dateValue = t;
28049 cell.className += " x-date-today";
28050 cell.title = cal.todayText;
28053 cell.className += " x-date-selected";
28054 setTimeout(function(){
28055 try{cell.firstChild.focus();}catch(e){}
28060 cell.className = " x-date-disabled";
28061 cell.title = cal.minText;
28065 cell.className = " x-date-disabled";
28066 cell.title = cal.maxText;
28070 if(ddays.indexOf(d.getDay()) != -1){
28071 cell.title = ddaysText;
28072 cell.className = " x-date-disabled";
28075 if(ddMatch && format){
28076 var fvalue = d.dateFormat(format);
28077 if(ddMatch.test(fvalue)){
28078 cell.title = ddText.replace("%0", fvalue);
28079 cell.className = " x-date-disabled";
28085 for(; i < startingPos; i++) {
28086 textEls[i].innerHTML = (++prevStart);
28087 d.setDate(d.getDate()+1);
28088 cells[i].className = "x-date-prevday";
28089 setCellClass(this, cells[i]);
28091 for(; i < days; i++){
28092 intDay = i - startingPos + 1;
28093 textEls[i].innerHTML = (intDay);
28094 d.setDate(d.getDate()+1);
28095 cells[i].className = "x-date-active";
28096 setCellClass(this, cells[i]);
28099 for(; i < 42; i++) {
28100 textEls[i].innerHTML = (++extraDays);
28101 d.setDate(d.getDate()+1);
28102 cells[i].className = "x-date-nextday";
28103 setCellClass(this, cells[i]);
28106 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28107 this.fireEvent('monthchange', this, date);
28109 if(!this.internalRender){
28110 var main = this.el.dom.firstChild;
28111 var w = main.offsetWidth;
28112 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28113 Roo.fly(main).setWidth(w);
28114 this.internalRender = true;
28115 // opera does not respect the auto grow header center column
28116 // then, after it gets a width opera refuses to recalculate
28117 // without a second pass
28118 if(Roo.isOpera && !this.secondPass){
28119 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28120 this.secondPass = true;
28121 this.update.defer(10, this, [date]);
28129 * Ext JS Library 1.1.1
28130 * Copyright(c) 2006-2007, Ext JS, LLC.
28132 * Originally Released Under LGPL - original licence link has changed is not relivant.
28135 * <script type="text/javascript">
28138 * @class Roo.TabPanel
28139 * @extends Roo.util.Observable
28140 * A lightweight tab container.
28144 // basic tabs 1, built from existing content
28145 var tabs = new Roo.TabPanel("tabs1");
28146 tabs.addTab("script", "View Script");
28147 tabs.addTab("markup", "View Markup");
28148 tabs.activate("script");
28150 // more advanced tabs, built from javascript
28151 var jtabs = new Roo.TabPanel("jtabs");
28152 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28154 // set up the UpdateManager
28155 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28156 var updater = tab2.getUpdateManager();
28157 updater.setDefaultUrl("ajax1.htm");
28158 tab2.on('activate', updater.refresh, updater, true);
28160 // Use setUrl for Ajax loading
28161 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28162 tab3.setUrl("ajax2.htm", null, true);
28165 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28168 jtabs.activate("jtabs-1");
28171 * Create a new TabPanel.
28172 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28173 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28175 Roo.TabPanel = function(container, config){
28177 * The container element for this TabPanel.
28178 * @type Roo.Element
28180 this.el = Roo.get(container, true);
28182 if(typeof config == "boolean"){
28183 this.tabPosition = config ? "bottom" : "top";
28185 Roo.apply(this, config);
28188 if(this.tabPosition == "bottom"){
28189 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28190 this.el.addClass("x-tabs-bottom");
28192 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28193 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28194 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28196 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28198 if(this.tabPosition != "bottom"){
28199 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28200 * @type Roo.Element
28202 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28203 this.el.addClass("x-tabs-top");
28207 this.bodyEl.setStyle("position", "relative");
28209 this.active = null;
28210 this.activateDelegate = this.activate.createDelegate(this);
28215 * Fires when the active tab changes
28216 * @param {Roo.TabPanel} this
28217 * @param {Roo.TabPanelItem} activePanel The new active tab
28221 * @event beforetabchange
28222 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28223 * @param {Roo.TabPanel} this
28224 * @param {Object} e Set cancel to true on this object to cancel the tab change
28225 * @param {Roo.TabPanelItem} tab The tab being changed to
28227 "beforetabchange" : true
28230 Roo.EventManager.onWindowResize(this.onResize, this);
28231 this.cpad = this.el.getPadding("lr");
28232 this.hiddenCount = 0;
28235 // toolbar on the tabbar support...
28236 if (this.toolbar) {
28237 var tcfg = this.toolbar;
28238 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28239 this.toolbar = new Roo.Toolbar(tcfg);
28240 if (Roo.isSafari) {
28241 var tbl = tcfg.container.child('table', true);
28242 tbl.setAttribute('width', '100%');
28249 Roo.TabPanel.superclass.constructor.call(this);
28252 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28254 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28256 tabPosition : "top",
28258 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28260 currentTabWidth : 0,
28262 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28266 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28270 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28272 preferredTabWidth : 175,
28274 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28276 resizeTabs : false,
28278 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28280 monitorResize : true,
28282 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28287 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28288 * @param {String} id The id of the div to use <b>or create</b>
28289 * @param {String} text The text for the tab
28290 * @param {String} content (optional) Content to put in the TabPanelItem body
28291 * @param {Boolean} closable (optional) True to create a close icon on the tab
28292 * @return {Roo.TabPanelItem} The created TabPanelItem
28294 addTab : function(id, text, content, closable){
28295 var item = new Roo.TabPanelItem(this, id, text, closable);
28296 this.addTabItem(item);
28298 item.setContent(content);
28304 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28305 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28306 * @return {Roo.TabPanelItem}
28308 getTab : function(id){
28309 return this.items[id];
28313 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28314 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28316 hideTab : function(id){
28317 var t = this.items[id];
28320 this.hiddenCount++;
28321 this.autoSizeTabs();
28326 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28327 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28329 unhideTab : function(id){
28330 var t = this.items[id];
28332 t.setHidden(false);
28333 this.hiddenCount--;
28334 this.autoSizeTabs();
28339 * Adds an existing {@link Roo.TabPanelItem}.
28340 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28342 addTabItem : function(item){
28343 this.items[item.id] = item;
28344 this.items.push(item);
28345 if(this.resizeTabs){
28346 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28347 this.autoSizeTabs();
28354 * Removes a {@link Roo.TabPanelItem}.
28355 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28357 removeTab : function(id){
28358 var items = this.items;
28359 var tab = items[id];
28360 if(!tab) { return; }
28361 var index = items.indexOf(tab);
28362 if(this.active == tab && items.length > 1){
28363 var newTab = this.getNextAvailable(index);
28368 this.stripEl.dom.removeChild(tab.pnode.dom);
28369 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28370 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28372 items.splice(index, 1);
28373 delete this.items[tab.id];
28374 tab.fireEvent("close", tab);
28375 tab.purgeListeners();
28376 this.autoSizeTabs();
28379 getNextAvailable : function(start){
28380 var items = this.items;
28382 // look for a next tab that will slide over to
28383 // replace the one being removed
28384 while(index < items.length){
28385 var item = items[++index];
28386 if(item && !item.isHidden()){
28390 // if one isn't found select the previous tab (on the left)
28393 var item = items[--index];
28394 if(item && !item.isHidden()){
28402 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28403 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28405 disableTab : function(id){
28406 var tab = this.items[id];
28407 if(tab && this.active != tab){
28413 * Enables a {@link Roo.TabPanelItem} that is disabled.
28414 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28416 enableTab : function(id){
28417 var tab = this.items[id];
28422 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28423 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28424 * @return {Roo.TabPanelItem} The TabPanelItem.
28426 activate : function(id){
28427 var tab = this.items[id];
28431 if(tab == this.active || tab.disabled){
28435 this.fireEvent("beforetabchange", this, e, tab);
28436 if(e.cancel !== true && !tab.disabled){
28438 this.active.hide();
28440 this.active = this.items[id];
28441 this.active.show();
28442 this.fireEvent("tabchange", this, this.active);
28448 * Gets the active {@link Roo.TabPanelItem}.
28449 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28451 getActiveTab : function(){
28452 return this.active;
28456 * Updates the tab body element to fit the height of the container element
28457 * for overflow scrolling
28458 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28460 syncHeight : function(targetHeight){
28461 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28462 var bm = this.bodyEl.getMargins();
28463 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28464 this.bodyEl.setHeight(newHeight);
28468 onResize : function(){
28469 if(this.monitorResize){
28470 this.autoSizeTabs();
28475 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28477 beginUpdate : function(){
28478 this.updating = true;
28482 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28484 endUpdate : function(){
28485 this.updating = false;
28486 this.autoSizeTabs();
28490 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28492 autoSizeTabs : function(){
28493 var count = this.items.length;
28494 var vcount = count - this.hiddenCount;
28495 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28498 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28499 var availWidth = Math.floor(w / vcount);
28500 var b = this.stripBody;
28501 if(b.getWidth() > w){
28502 var tabs = this.items;
28503 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28504 if(availWidth < this.minTabWidth){
28505 /*if(!this.sleft){ // incomplete scrolling code
28506 this.createScrollButtons();
28509 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28512 if(this.currentTabWidth < this.preferredTabWidth){
28513 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28519 * Returns the number of tabs in this TabPanel.
28522 getCount : function(){
28523 return this.items.length;
28527 * Resizes all the tabs to the passed width
28528 * @param {Number} The new width
28530 setTabWidth : function(width){
28531 this.currentTabWidth = width;
28532 for(var i = 0, len = this.items.length; i < len; i++) {
28533 if(!this.items[i].isHidden()) {
28534 this.items[i].setWidth(width);
28540 * Destroys this TabPanel
28541 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28543 destroy : function(removeEl){
28544 Roo.EventManager.removeResizeListener(this.onResize, this);
28545 for(var i = 0, len = this.items.length; i < len; i++){
28546 this.items[i].purgeListeners();
28548 if(removeEl === true){
28549 this.el.update("");
28556 * @class Roo.TabPanelItem
28557 * @extends Roo.util.Observable
28558 * Represents an individual item (tab plus body) in a TabPanel.
28559 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28560 * @param {String} id The id of this TabPanelItem
28561 * @param {String} text The text for the tab of this TabPanelItem
28562 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28564 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28566 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28567 * @type Roo.TabPanel
28569 this.tabPanel = tabPanel;
28571 * The id for this TabPanelItem
28576 this.disabled = false;
28580 this.loaded = false;
28581 this.closable = closable;
28584 * The body element for this TabPanelItem.
28585 * @type Roo.Element
28587 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28588 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28589 this.bodyEl.setStyle("display", "block");
28590 this.bodyEl.setStyle("zoom", "1");
28593 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28595 this.el = Roo.get(els.el, true);
28596 this.inner = Roo.get(els.inner, true);
28597 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28598 this.pnode = Roo.get(els.el.parentNode, true);
28599 this.el.on("mousedown", this.onTabMouseDown, this);
28600 this.el.on("click", this.onTabClick, this);
28603 var c = Roo.get(els.close, true);
28604 c.dom.title = this.closeText;
28605 c.addClassOnOver("close-over");
28606 c.on("click", this.closeClick, this);
28612 * Fires when this tab becomes the active tab.
28613 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28614 * @param {Roo.TabPanelItem} this
28618 * @event beforeclose
28619 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28620 * @param {Roo.TabPanelItem} this
28621 * @param {Object} e Set cancel to true on this object to cancel the close.
28623 "beforeclose": true,
28626 * Fires when this tab is closed.
28627 * @param {Roo.TabPanelItem} this
28631 * @event deactivate
28632 * Fires when this tab is no longer the active tab.
28633 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28634 * @param {Roo.TabPanelItem} this
28636 "deactivate" : true
28638 this.hidden = false;
28640 Roo.TabPanelItem.superclass.constructor.call(this);
28643 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28644 purgeListeners : function(){
28645 Roo.util.Observable.prototype.purgeListeners.call(this);
28646 this.el.removeAllListeners();
28649 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28652 this.pnode.addClass("on");
28655 this.tabPanel.stripWrap.repaint();
28657 this.fireEvent("activate", this.tabPanel, this);
28661 * Returns true if this tab is the active tab.
28662 * @return {Boolean}
28664 isActive : function(){
28665 return this.tabPanel.getActiveTab() == this;
28669 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28672 this.pnode.removeClass("on");
28674 this.fireEvent("deactivate", this.tabPanel, this);
28677 hideAction : function(){
28678 this.bodyEl.hide();
28679 this.bodyEl.setStyle("position", "absolute");
28680 this.bodyEl.setLeft("-20000px");
28681 this.bodyEl.setTop("-20000px");
28684 showAction : function(){
28685 this.bodyEl.setStyle("position", "relative");
28686 this.bodyEl.setTop("");
28687 this.bodyEl.setLeft("");
28688 this.bodyEl.show();
28692 * Set the tooltip for the tab.
28693 * @param {String} tooltip The tab's tooltip
28695 setTooltip : function(text){
28696 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28697 this.textEl.dom.qtip = text;
28698 this.textEl.dom.removeAttribute('title');
28700 this.textEl.dom.title = text;
28704 onTabClick : function(e){
28705 e.preventDefault();
28706 this.tabPanel.activate(this.id);
28709 onTabMouseDown : function(e){
28710 e.preventDefault();
28711 this.tabPanel.activate(this.id);
28714 getWidth : function(){
28715 return this.inner.getWidth();
28718 setWidth : function(width){
28719 var iwidth = width - this.pnode.getPadding("lr");
28720 this.inner.setWidth(iwidth);
28721 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28722 this.pnode.setWidth(width);
28726 * Show or hide the tab
28727 * @param {Boolean} hidden True to hide or false to show.
28729 setHidden : function(hidden){
28730 this.hidden = hidden;
28731 this.pnode.setStyle("display", hidden ? "none" : "");
28735 * Returns true if this tab is "hidden"
28736 * @return {Boolean}
28738 isHidden : function(){
28739 return this.hidden;
28743 * Returns the text for this tab
28746 getText : function(){
28750 autoSize : function(){
28751 //this.el.beginMeasure();
28752 this.textEl.setWidth(1);
28754 * #2804 [new] Tabs in Roojs
28755 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28757 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28758 //this.el.endMeasure();
28762 * Sets the text for the tab (Note: this also sets the tooltip text)
28763 * @param {String} text The tab's text and tooltip
28765 setText : function(text){
28767 this.textEl.update(text);
28768 this.setTooltip(text);
28769 if(!this.tabPanel.resizeTabs){
28774 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28776 activate : function(){
28777 this.tabPanel.activate(this.id);
28781 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28783 disable : function(){
28784 if(this.tabPanel.active != this){
28785 this.disabled = true;
28786 this.pnode.addClass("disabled");
28791 * Enables this TabPanelItem if it was previously disabled.
28793 enable : function(){
28794 this.disabled = false;
28795 this.pnode.removeClass("disabled");
28799 * Sets the content for this TabPanelItem.
28800 * @param {String} content The content
28801 * @param {Boolean} loadScripts true to look for and load scripts
28803 setContent : function(content, loadScripts){
28804 this.bodyEl.update(content, loadScripts);
28808 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28809 * @return {Roo.UpdateManager} The UpdateManager
28811 getUpdateManager : function(){
28812 return this.bodyEl.getUpdateManager();
28816 * Set a URL to be used to load the content for this TabPanelItem.
28817 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28818 * @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)
28819 * @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)
28820 * @return {Roo.UpdateManager} The UpdateManager
28822 setUrl : function(url, params, loadOnce){
28823 if(this.refreshDelegate){
28824 this.un('activate', this.refreshDelegate);
28826 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28827 this.on("activate", this.refreshDelegate);
28828 return this.bodyEl.getUpdateManager();
28832 _handleRefresh : function(url, params, loadOnce){
28833 if(!loadOnce || !this.loaded){
28834 var updater = this.bodyEl.getUpdateManager();
28835 updater.update(url, params, this._setLoaded.createDelegate(this));
28840 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
28841 * Will fail silently if the setUrl method has not been called.
28842 * This does not activate the panel, just updates its content.
28844 refresh : function(){
28845 if(this.refreshDelegate){
28846 this.loaded = false;
28847 this.refreshDelegate();
28852 _setLoaded : function(){
28853 this.loaded = true;
28857 closeClick : function(e){
28860 this.fireEvent("beforeclose", this, o);
28861 if(o.cancel !== true){
28862 this.tabPanel.removeTab(this.id);
28866 * The text displayed in the tooltip for the close icon.
28869 closeText : "Close this tab"
28873 Roo.TabPanel.prototype.createStrip = function(container){
28874 var strip = document.createElement("div");
28875 strip.className = "x-tabs-wrap";
28876 container.appendChild(strip);
28880 Roo.TabPanel.prototype.createStripList = function(strip){
28881 // div wrapper for retard IE
28882 // returns the "tr" element.
28883 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
28884 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
28885 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
28886 return strip.firstChild.firstChild.firstChild.firstChild;
28889 Roo.TabPanel.prototype.createBody = function(container){
28890 var body = document.createElement("div");
28891 Roo.id(body, "tab-body");
28892 Roo.fly(body).addClass("x-tabs-body");
28893 container.appendChild(body);
28897 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
28898 var body = Roo.getDom(id);
28900 body = document.createElement("div");
28903 Roo.fly(body).addClass("x-tabs-item-body");
28904 bodyEl.insertBefore(body, bodyEl.firstChild);
28908 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
28909 var td = document.createElement("td");
28910 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
28911 //stripEl.appendChild(td);
28913 td.className = "x-tabs-closable";
28914 if(!this.closeTpl){
28915 this.closeTpl = new Roo.Template(
28916 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28917 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
28918 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
28921 var el = this.closeTpl.overwrite(td, {"text": text});
28922 var close = el.getElementsByTagName("div")[0];
28923 var inner = el.getElementsByTagName("em")[0];
28924 return {"el": el, "close": close, "inner": inner};
28927 this.tabTpl = new Roo.Template(
28928 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28929 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
28932 var el = this.tabTpl.overwrite(td, {"text": text});
28933 var inner = el.getElementsByTagName("em")[0];
28934 return {"el": el, "inner": inner};
28938 * Ext JS Library 1.1.1
28939 * Copyright(c) 2006-2007, Ext JS, LLC.
28941 * Originally Released Under LGPL - original licence link has changed is not relivant.
28944 * <script type="text/javascript">
28948 * @class Roo.Button
28949 * @extends Roo.util.Observable
28950 * Simple Button class
28951 * @cfg {String} text The button text
28952 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
28953 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
28954 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
28955 * @cfg {Object} scope The scope of the handler
28956 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
28957 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
28958 * @cfg {Boolean} hidden True to start hidden (defaults to false)
28959 * @cfg {Boolean} disabled True to start disabled (defaults to false)
28960 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
28961 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
28962 applies if enableToggle = true)
28963 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
28964 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
28965 an {@link Roo.util.ClickRepeater} config object (defaults to false).
28967 * Create a new button
28968 * @param {Object} config The config object
28970 Roo.Button = function(renderTo, config)
28974 renderTo = config.renderTo || false;
28977 Roo.apply(this, config);
28981 * Fires when this button is clicked
28982 * @param {Button} this
28983 * @param {EventObject} e The click event
28988 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
28989 * @param {Button} this
28990 * @param {Boolean} pressed
28995 * Fires when the mouse hovers over the button
28996 * @param {Button} this
28997 * @param {Event} e The event object
28999 'mouseover' : true,
29002 * Fires when the mouse exits the button
29003 * @param {Button} this
29004 * @param {Event} e The event object
29009 * Fires when the button is rendered
29010 * @param {Button} this
29015 this.menu = Roo.menu.MenuMgr.get(this.menu);
29017 // register listeners first!! - so render can be captured..
29018 Roo.util.Observable.call(this);
29020 this.render(renderTo);
29026 Roo.extend(Roo.Button, Roo.util.Observable, {
29032 * Read-only. True if this button is hidden
29037 * Read-only. True if this button is disabled
29042 * Read-only. True if this button is pressed (only if enableToggle = true)
29048 * @cfg {Number} tabIndex
29049 * The DOM tabIndex for this button (defaults to undefined)
29051 tabIndex : undefined,
29054 * @cfg {Boolean} enableToggle
29055 * True to enable pressed/not pressed toggling (defaults to false)
29057 enableToggle: false,
29059 * @cfg {Mixed} menu
29060 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29064 * @cfg {String} menuAlign
29065 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29067 menuAlign : "tl-bl?",
29070 * @cfg {String} iconCls
29071 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29073 iconCls : undefined,
29075 * @cfg {String} type
29076 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29081 menuClassTarget: 'tr',
29084 * @cfg {String} clickEvent
29085 * The type of event to map to the button's event handler (defaults to 'click')
29087 clickEvent : 'click',
29090 * @cfg {Boolean} handleMouseEvents
29091 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29093 handleMouseEvents : true,
29096 * @cfg {String} tooltipType
29097 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29099 tooltipType : 'qtip',
29102 * @cfg {String} cls
29103 * A CSS class to apply to the button's main element.
29107 * @cfg {Roo.Template} template (Optional)
29108 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29109 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29110 * require code modifications if required elements (e.g. a button) aren't present.
29114 render : function(renderTo){
29116 if(this.hideParent){
29117 this.parentEl = Roo.get(renderTo);
29119 if(!this.dhconfig){
29120 if(!this.template){
29121 if(!Roo.Button.buttonTemplate){
29122 // hideous table template
29123 Roo.Button.buttonTemplate = new Roo.Template(
29124 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29125 '<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>',
29126 "</tr></tbody></table>");
29128 this.template = Roo.Button.buttonTemplate;
29130 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29131 var btnEl = btn.child("button:first");
29132 btnEl.on('focus', this.onFocus, this);
29133 btnEl.on('blur', this.onBlur, this);
29135 btn.addClass(this.cls);
29138 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29141 btnEl.addClass(this.iconCls);
29143 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29146 if(this.tabIndex !== undefined){
29147 btnEl.dom.tabIndex = this.tabIndex;
29150 if(typeof this.tooltip == 'object'){
29151 Roo.QuickTips.tips(Roo.apply({
29155 btnEl.dom[this.tooltipType] = this.tooltip;
29159 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29163 this.el.dom.id = this.el.id = this.id;
29166 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29167 this.menu.on("show", this.onMenuShow, this);
29168 this.menu.on("hide", this.onMenuHide, this);
29170 btn.addClass("x-btn");
29171 if(Roo.isIE && !Roo.isIE7){
29172 this.autoWidth.defer(1, this);
29176 if(this.handleMouseEvents){
29177 btn.on("mouseover", this.onMouseOver, this);
29178 btn.on("mouseout", this.onMouseOut, this);
29179 btn.on("mousedown", this.onMouseDown, this);
29181 btn.on(this.clickEvent, this.onClick, this);
29182 //btn.on("mouseup", this.onMouseUp, this);
29189 Roo.ButtonToggleMgr.register(this);
29191 this.el.addClass("x-btn-pressed");
29194 var repeater = new Roo.util.ClickRepeater(btn,
29195 typeof this.repeat == "object" ? this.repeat : {}
29197 repeater.on("click", this.onClick, this);
29200 this.fireEvent('render', this);
29204 * Returns the button's underlying element
29205 * @return {Roo.Element} The element
29207 getEl : function(){
29212 * Destroys this Button and removes any listeners.
29214 destroy : function(){
29215 Roo.ButtonToggleMgr.unregister(this);
29216 this.el.removeAllListeners();
29217 this.purgeListeners();
29222 autoWidth : function(){
29224 this.el.setWidth("auto");
29225 if(Roo.isIE7 && Roo.isStrict){
29226 var ib = this.el.child('button');
29227 if(ib && ib.getWidth() > 20){
29229 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29234 this.el.beginMeasure();
29236 if(this.el.getWidth() < this.minWidth){
29237 this.el.setWidth(this.minWidth);
29240 this.el.endMeasure();
29247 * Assigns this button's click handler
29248 * @param {Function} handler The function to call when the button is clicked
29249 * @param {Object} scope (optional) Scope for the function passed in
29251 setHandler : function(handler, scope){
29252 this.handler = handler;
29253 this.scope = scope;
29257 * Sets this button's text
29258 * @param {String} text The button text
29260 setText : function(text){
29263 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29269 * Gets the text for this button
29270 * @return {String} The button text
29272 getText : function(){
29280 this.hidden = false;
29282 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29290 this.hidden = true;
29292 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29297 * Convenience function for boolean show/hide
29298 * @param {Boolean} visible True to show, false to hide
29300 setVisible: function(visible){
29309 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29310 * @param {Boolean} state (optional) Force a particular state
29312 toggle : function(state){
29313 state = state === undefined ? !this.pressed : state;
29314 if(state != this.pressed){
29316 this.el.addClass("x-btn-pressed");
29317 this.pressed = true;
29318 this.fireEvent("toggle", this, true);
29320 this.el.removeClass("x-btn-pressed");
29321 this.pressed = false;
29322 this.fireEvent("toggle", this, false);
29324 if(this.toggleHandler){
29325 this.toggleHandler.call(this.scope || this, this, state);
29333 focus : function(){
29334 this.el.child('button:first').focus();
29338 * Disable this button
29340 disable : function(){
29342 this.el.addClass("x-btn-disabled");
29344 this.disabled = true;
29348 * Enable this button
29350 enable : function(){
29352 this.el.removeClass("x-btn-disabled");
29354 this.disabled = false;
29358 * Convenience function for boolean enable/disable
29359 * @param {Boolean} enabled True to enable, false to disable
29361 setDisabled : function(v){
29362 this[v !== true ? "enable" : "disable"]();
29366 onClick : function(e)
29369 e.preventDefault();
29374 if(!this.disabled){
29375 if(this.enableToggle){
29378 if(this.menu && !this.menu.isVisible()){
29379 this.menu.show(this.el, this.menuAlign);
29381 this.fireEvent("click", this, e);
29383 this.el.removeClass("x-btn-over");
29384 this.handler.call(this.scope || this, this, e);
29389 onMouseOver : function(e){
29390 if(!this.disabled){
29391 this.el.addClass("x-btn-over");
29392 this.fireEvent('mouseover', this, e);
29396 onMouseOut : function(e){
29397 if(!e.within(this.el, true)){
29398 this.el.removeClass("x-btn-over");
29399 this.fireEvent('mouseout', this, e);
29403 onFocus : function(e){
29404 if(!this.disabled){
29405 this.el.addClass("x-btn-focus");
29409 onBlur : function(e){
29410 this.el.removeClass("x-btn-focus");
29413 onMouseDown : function(e){
29414 if(!this.disabled && e.button == 0){
29415 this.el.addClass("x-btn-click");
29416 Roo.get(document).on('mouseup', this.onMouseUp, this);
29420 onMouseUp : function(e){
29422 this.el.removeClass("x-btn-click");
29423 Roo.get(document).un('mouseup', this.onMouseUp, this);
29427 onMenuShow : function(e){
29428 this.el.addClass("x-btn-menu-active");
29431 onMenuHide : function(e){
29432 this.el.removeClass("x-btn-menu-active");
29436 // Private utility class used by Button
29437 Roo.ButtonToggleMgr = function(){
29440 function toggleGroup(btn, state){
29442 var g = groups[btn.toggleGroup];
29443 for(var i = 0, l = g.length; i < l; i++){
29445 g[i].toggle(false);
29452 register : function(btn){
29453 if(!btn.toggleGroup){
29456 var g = groups[btn.toggleGroup];
29458 g = groups[btn.toggleGroup] = [];
29461 btn.on("toggle", toggleGroup);
29464 unregister : function(btn){
29465 if(!btn.toggleGroup){
29468 var g = groups[btn.toggleGroup];
29471 btn.un("toggle", toggleGroup);
29477 * Ext JS Library 1.1.1
29478 * Copyright(c) 2006-2007, Ext JS, LLC.
29480 * Originally Released Under LGPL - original licence link has changed is not relivant.
29483 * <script type="text/javascript">
29487 * @class Roo.SplitButton
29488 * @extends Roo.Button
29489 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29490 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29491 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29492 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29493 * @cfg {String} arrowTooltip The title attribute of the arrow
29495 * Create a new menu button
29496 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29497 * @param {Object} config The config object
29499 Roo.SplitButton = function(renderTo, config){
29500 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29502 * @event arrowclick
29503 * Fires when this button's arrow is clicked
29504 * @param {SplitButton} this
29505 * @param {EventObject} e The click event
29507 this.addEvents({"arrowclick":true});
29510 Roo.extend(Roo.SplitButton, Roo.Button, {
29511 render : function(renderTo){
29512 // this is one sweet looking template!
29513 var tpl = new Roo.Template(
29514 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29515 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29516 '<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>',
29517 "</tbody></table></td><td>",
29518 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29519 '<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>',
29520 "</tbody></table></td></tr></table>"
29522 var btn = tpl.append(renderTo, [this.text, this.type], true);
29523 var btnEl = btn.child("button");
29525 btn.addClass(this.cls);
29528 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29531 btnEl.addClass(this.iconCls);
29533 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29537 if(this.handleMouseEvents){
29538 btn.on("mouseover", this.onMouseOver, this);
29539 btn.on("mouseout", this.onMouseOut, this);
29540 btn.on("mousedown", this.onMouseDown, this);
29541 btn.on("mouseup", this.onMouseUp, this);
29543 btn.on(this.clickEvent, this.onClick, this);
29545 if(typeof this.tooltip == 'object'){
29546 Roo.QuickTips.tips(Roo.apply({
29550 btnEl.dom[this.tooltipType] = this.tooltip;
29553 if(this.arrowTooltip){
29554 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29563 this.el.addClass("x-btn-pressed");
29565 if(Roo.isIE && !Roo.isIE7){
29566 this.autoWidth.defer(1, this);
29571 this.menu.on("show", this.onMenuShow, this);
29572 this.menu.on("hide", this.onMenuHide, this);
29574 this.fireEvent('render', this);
29578 autoWidth : function(){
29580 var tbl = this.el.child("table:first");
29581 var tbl2 = this.el.child("table:last");
29582 this.el.setWidth("auto");
29583 tbl.setWidth("auto");
29584 if(Roo.isIE7 && Roo.isStrict){
29585 var ib = this.el.child('button:first');
29586 if(ib && ib.getWidth() > 20){
29588 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29593 this.el.beginMeasure();
29595 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29596 tbl.setWidth(this.minWidth-tbl2.getWidth());
29599 this.el.endMeasure();
29602 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29606 * Sets this button's click handler
29607 * @param {Function} handler The function to call when the button is clicked
29608 * @param {Object} scope (optional) Scope for the function passed above
29610 setHandler : function(handler, scope){
29611 this.handler = handler;
29612 this.scope = scope;
29616 * Sets this button's arrow click handler
29617 * @param {Function} handler The function to call when the arrow is clicked
29618 * @param {Object} scope (optional) Scope for the function passed above
29620 setArrowHandler : function(handler, scope){
29621 this.arrowHandler = handler;
29622 this.scope = scope;
29628 focus : function(){
29630 this.el.child("button:first").focus();
29635 onClick : function(e){
29636 e.preventDefault();
29637 if(!this.disabled){
29638 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29639 if(this.menu && !this.menu.isVisible()){
29640 this.menu.show(this.el, this.menuAlign);
29642 this.fireEvent("arrowclick", this, e);
29643 if(this.arrowHandler){
29644 this.arrowHandler.call(this.scope || this, this, e);
29647 this.fireEvent("click", this, e);
29649 this.handler.call(this.scope || this, this, e);
29655 onMouseDown : function(e){
29656 if(!this.disabled){
29657 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29661 onMouseUp : function(e){
29662 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29667 // backwards compat
29668 Roo.MenuButton = Roo.SplitButton;/*
29670 * Ext JS Library 1.1.1
29671 * Copyright(c) 2006-2007, Ext JS, LLC.
29673 * Originally Released Under LGPL - original licence link has changed is not relivant.
29676 * <script type="text/javascript">
29680 * @class Roo.Toolbar
29681 * Basic Toolbar class.
29683 * Creates a new Toolbar
29684 * @param {Object} container The config object
29686 Roo.Toolbar = function(container, buttons, config)
29688 /// old consturctor format still supported..
29689 if(container instanceof Array){ // omit the container for later rendering
29690 buttons = container;
29694 if (typeof(container) == 'object' && container.xtype) {
29695 config = container;
29696 container = config.container;
29697 buttons = config.buttons || []; // not really - use items!!
29700 if (config && config.items) {
29701 xitems = config.items;
29702 delete config.items;
29704 Roo.apply(this, config);
29705 this.buttons = buttons;
29708 this.render(container);
29710 this.xitems = xitems;
29711 Roo.each(xitems, function(b) {
29717 Roo.Toolbar.prototype = {
29719 * @cfg {Array} items
29720 * array of button configs or elements to add (will be converted to a MixedCollection)
29724 * @cfg {String/HTMLElement/Element} container
29725 * The id or element that will contain the toolbar
29728 render : function(ct){
29729 this.el = Roo.get(ct);
29731 this.el.addClass(this.cls);
29733 // using a table allows for vertical alignment
29734 // 100% width is needed by Safari...
29735 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29736 this.tr = this.el.child("tr", true);
29738 this.items = new Roo.util.MixedCollection(false, function(o){
29739 return o.id || ("item" + (++autoId));
29742 this.add.apply(this, this.buttons);
29743 delete this.buttons;
29748 * Adds element(s) to the toolbar -- this function takes a variable number of
29749 * arguments of mixed type and adds them to the toolbar.
29750 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29752 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29753 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29754 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29755 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29756 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29757 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29758 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29759 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29760 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29762 * @param {Mixed} arg2
29763 * @param {Mixed} etc.
29766 var a = arguments, l = a.length;
29767 for(var i = 0; i < l; i++){
29772 _add : function(el) {
29775 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29778 if (el.applyTo){ // some kind of form field
29779 return this.addField(el);
29781 if (el.render){ // some kind of Toolbar.Item
29782 return this.addItem(el);
29784 if (typeof el == "string"){ // string
29785 if(el == "separator" || el == "-"){
29786 return this.addSeparator();
29789 return this.addSpacer();
29792 return this.addFill();
29794 return this.addText(el);
29797 if(el.tagName){ // element
29798 return this.addElement(el);
29800 if(typeof el == "object"){ // must be button config?
29801 return this.addButton(el);
29803 // and now what?!?!
29809 * Add an Xtype element
29810 * @param {Object} xtype Xtype Object
29811 * @return {Object} created Object
29813 addxtype : function(e){
29814 return this.add(e);
29818 * Returns the Element for this toolbar.
29819 * @return {Roo.Element}
29821 getEl : function(){
29827 * @return {Roo.Toolbar.Item} The separator item
29829 addSeparator : function(){
29830 return this.addItem(new Roo.Toolbar.Separator());
29834 * Adds a spacer element
29835 * @return {Roo.Toolbar.Spacer} The spacer item
29837 addSpacer : function(){
29838 return this.addItem(new Roo.Toolbar.Spacer());
29842 * Adds a fill element that forces subsequent additions to the right side of the toolbar
29843 * @return {Roo.Toolbar.Fill} The fill item
29845 addFill : function(){
29846 return this.addItem(new Roo.Toolbar.Fill());
29850 * Adds any standard HTML element to the toolbar
29851 * @param {String/HTMLElement/Element} el The element or id of the element to add
29852 * @return {Roo.Toolbar.Item} The element's item
29854 addElement : function(el){
29855 return this.addItem(new Roo.Toolbar.Item(el));
29858 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
29859 * @type Roo.util.MixedCollection
29864 * Adds any Toolbar.Item or subclass
29865 * @param {Roo.Toolbar.Item} item
29866 * @return {Roo.Toolbar.Item} The item
29868 addItem : function(item){
29869 var td = this.nextBlock();
29871 this.items.add(item);
29876 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
29877 * @param {Object/Array} config A button config or array of configs
29878 * @return {Roo.Toolbar.Button/Array}
29880 addButton : function(config){
29881 if(config instanceof Array){
29883 for(var i = 0, len = config.length; i < len; i++) {
29884 buttons.push(this.addButton(config[i]));
29889 if(!(config instanceof Roo.Toolbar.Button)){
29891 new Roo.Toolbar.SplitButton(config) :
29892 new Roo.Toolbar.Button(config);
29894 var td = this.nextBlock();
29901 * Adds text to the toolbar
29902 * @param {String} text The text to add
29903 * @return {Roo.Toolbar.Item} The element's item
29905 addText : function(text){
29906 return this.addItem(new Roo.Toolbar.TextItem(text));
29910 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
29911 * @param {Number} index The index where the item is to be inserted
29912 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
29913 * @return {Roo.Toolbar.Button/Item}
29915 insertButton : function(index, item){
29916 if(item instanceof Array){
29918 for(var i = 0, len = item.length; i < len; i++) {
29919 buttons.push(this.insertButton(index + i, item[i]));
29923 if (!(item instanceof Roo.Toolbar.Button)){
29924 item = new Roo.Toolbar.Button(item);
29926 var td = document.createElement("td");
29927 this.tr.insertBefore(td, this.tr.childNodes[index]);
29929 this.items.insert(index, item);
29934 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
29935 * @param {Object} config
29936 * @return {Roo.Toolbar.Item} The element's item
29938 addDom : function(config, returnEl){
29939 var td = this.nextBlock();
29940 Roo.DomHelper.overwrite(td, config);
29941 var ti = new Roo.Toolbar.Item(td.firstChild);
29943 this.items.add(ti);
29948 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
29949 * @type Roo.util.MixedCollection
29954 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
29955 * Note: the field should not have been rendered yet. For a field that has already been
29956 * rendered, use {@link #addElement}.
29957 * @param {Roo.form.Field} field
29958 * @return {Roo.ToolbarItem}
29962 addField : function(field) {
29963 if (!this.fields) {
29965 this.fields = new Roo.util.MixedCollection(false, function(o){
29966 return o.id || ("item" + (++autoId));
29971 var td = this.nextBlock();
29973 var ti = new Roo.Toolbar.Item(td.firstChild);
29975 this.items.add(ti);
29976 this.fields.add(field);
29987 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
29988 this.el.child('div').hide();
29996 this.el.child('div').show();
30000 nextBlock : function(){
30001 var td = document.createElement("td");
30002 this.tr.appendChild(td);
30007 destroy : function(){
30008 if(this.items){ // rendered?
30009 Roo.destroy.apply(Roo, this.items.items);
30011 if(this.fields){ // rendered?
30012 Roo.destroy.apply(Roo, this.fields.items);
30014 Roo.Element.uncache(this.el, this.tr);
30019 * @class Roo.Toolbar.Item
30020 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30022 * Creates a new Item
30023 * @param {HTMLElement} el
30025 Roo.Toolbar.Item = function(el){
30027 if (typeof (el.xtype) != 'undefined') {
30032 this.el = Roo.getDom(el);
30033 this.id = Roo.id(this.el);
30034 this.hidden = false;
30039 * Fires when the button is rendered
30040 * @param {Button} this
30044 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30046 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30047 //Roo.Toolbar.Item.prototype = {
30050 * Get this item's HTML Element
30051 * @return {HTMLElement}
30053 getEl : function(){
30058 render : function(td){
30061 td.appendChild(this.el);
30063 this.fireEvent('render', this);
30067 * Removes and destroys this item.
30069 destroy : function(){
30070 this.td.parentNode.removeChild(this.td);
30077 this.hidden = false;
30078 this.td.style.display = "";
30085 this.hidden = true;
30086 this.td.style.display = "none";
30090 * Convenience function for boolean show/hide.
30091 * @param {Boolean} visible true to show/false to hide
30093 setVisible: function(visible){
30102 * Try to focus this item.
30104 focus : function(){
30105 Roo.fly(this.el).focus();
30109 * Disables this item.
30111 disable : function(){
30112 Roo.fly(this.td).addClass("x-item-disabled");
30113 this.disabled = true;
30114 this.el.disabled = true;
30118 * Enables this item.
30120 enable : function(){
30121 Roo.fly(this.td).removeClass("x-item-disabled");
30122 this.disabled = false;
30123 this.el.disabled = false;
30129 * @class Roo.Toolbar.Separator
30130 * @extends Roo.Toolbar.Item
30131 * A simple toolbar separator class
30133 * Creates a new Separator
30135 Roo.Toolbar.Separator = function(cfg){
30137 var s = document.createElement("span");
30138 s.className = "ytb-sep";
30143 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30145 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30146 enable:Roo.emptyFn,
30147 disable:Roo.emptyFn,
30152 * @class Roo.Toolbar.Spacer
30153 * @extends Roo.Toolbar.Item
30154 * A simple element that adds extra horizontal space to a toolbar.
30156 * Creates a new Spacer
30158 Roo.Toolbar.Spacer = function(cfg){
30159 var s = document.createElement("div");
30160 s.className = "ytb-spacer";
30164 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30166 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30167 enable:Roo.emptyFn,
30168 disable:Roo.emptyFn,
30173 * @class Roo.Toolbar.Fill
30174 * @extends Roo.Toolbar.Spacer
30175 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30177 * Creates a new Spacer
30179 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30181 render : function(td){
30182 td.style.width = '100%';
30183 Roo.Toolbar.Fill.superclass.render.call(this, td);
30188 * @class Roo.Toolbar.TextItem
30189 * @extends Roo.Toolbar.Item
30190 * A simple class that renders text directly into a toolbar.
30192 * Creates a new TextItem
30193 * @param {String} text
30195 Roo.Toolbar.TextItem = function(cfg){
30196 var text = cfg || "";
30197 if (typeof(cfg) == 'object') {
30198 text = cfg.text || "";
30202 var s = document.createElement("span");
30203 s.className = "ytb-text";
30204 s.innerHTML = text;
30209 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30211 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30214 enable:Roo.emptyFn,
30215 disable:Roo.emptyFn,
30220 * @class Roo.Toolbar.Button
30221 * @extends Roo.Button
30222 * A button that renders into a toolbar.
30224 * Creates a new Button
30225 * @param {Object} config A standard {@link Roo.Button} config object
30227 Roo.Toolbar.Button = function(config){
30228 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30230 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30231 render : function(td){
30233 Roo.Toolbar.Button.superclass.render.call(this, td);
30237 * Removes and destroys this button
30239 destroy : function(){
30240 Roo.Toolbar.Button.superclass.destroy.call(this);
30241 this.td.parentNode.removeChild(this.td);
30245 * Shows this button
30248 this.hidden = false;
30249 this.td.style.display = "";
30253 * Hides this button
30256 this.hidden = true;
30257 this.td.style.display = "none";
30261 * Disables this item
30263 disable : function(){
30264 Roo.fly(this.td).addClass("x-item-disabled");
30265 this.disabled = true;
30269 * Enables this item
30271 enable : function(){
30272 Roo.fly(this.td).removeClass("x-item-disabled");
30273 this.disabled = false;
30276 // backwards compat
30277 Roo.ToolbarButton = Roo.Toolbar.Button;
30280 * @class Roo.Toolbar.SplitButton
30281 * @extends Roo.SplitButton
30282 * A menu button that renders into a toolbar.
30284 * Creates a new SplitButton
30285 * @param {Object} config A standard {@link Roo.SplitButton} config object
30287 Roo.Toolbar.SplitButton = function(config){
30288 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30290 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30291 render : function(td){
30293 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30297 * Removes and destroys this button
30299 destroy : function(){
30300 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30301 this.td.parentNode.removeChild(this.td);
30305 * Shows this button
30308 this.hidden = false;
30309 this.td.style.display = "";
30313 * Hides this button
30316 this.hidden = true;
30317 this.td.style.display = "none";
30321 // backwards compat
30322 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30324 * Ext JS Library 1.1.1
30325 * Copyright(c) 2006-2007, Ext JS, LLC.
30327 * Originally Released Under LGPL - original licence link has changed is not relivant.
30330 * <script type="text/javascript">
30334 * @class Roo.PagingToolbar
30335 * @extends Roo.Toolbar
30336 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30338 * Create a new PagingToolbar
30339 * @param {Object} config The config object
30341 Roo.PagingToolbar = function(el, ds, config)
30343 // old args format still supported... - xtype is prefered..
30344 if (typeof(el) == 'object' && el.xtype) {
30345 // created from xtype...
30347 ds = el.dataSource;
30348 el = config.container;
30351 if (config.items) {
30352 items = config.items;
30356 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30359 this.renderButtons(this.el);
30362 // supprot items array.
30364 Roo.each(items, function(e) {
30365 this.add(Roo.factory(e));
30370 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30372 * @cfg {Roo.data.Store} dataSource
30373 * The underlying data store providing the paged data
30376 * @cfg {String/HTMLElement/Element} container
30377 * container The id or element that will contain the toolbar
30380 * @cfg {Boolean} displayInfo
30381 * True to display the displayMsg (defaults to false)
30384 * @cfg {Number} pageSize
30385 * The number of records to display per page (defaults to 20)
30389 * @cfg {String} displayMsg
30390 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30392 displayMsg : 'Displaying {0} - {1} of {2}',
30394 * @cfg {String} emptyMsg
30395 * The message to display when no records are found (defaults to "No data to display")
30397 emptyMsg : 'No data to display',
30399 * Customizable piece of the default paging text (defaults to "Page")
30402 beforePageText : "Page",
30404 * Customizable piece of the default paging text (defaults to "of %0")
30407 afterPageText : "of {0}",
30409 * Customizable piece of the default paging text (defaults to "First Page")
30412 firstText : "First Page",
30414 * Customizable piece of the default paging text (defaults to "Previous Page")
30417 prevText : "Previous Page",
30419 * Customizable piece of the default paging text (defaults to "Next Page")
30422 nextText : "Next Page",
30424 * Customizable piece of the default paging text (defaults to "Last Page")
30427 lastText : "Last Page",
30429 * Customizable piece of the default paging text (defaults to "Refresh")
30432 refreshText : "Refresh",
30435 renderButtons : function(el){
30436 Roo.PagingToolbar.superclass.render.call(this, el);
30437 this.first = this.addButton({
30438 tooltip: this.firstText,
30439 cls: "x-btn-icon x-grid-page-first",
30441 handler: this.onClick.createDelegate(this, ["first"])
30443 this.prev = this.addButton({
30444 tooltip: this.prevText,
30445 cls: "x-btn-icon x-grid-page-prev",
30447 handler: this.onClick.createDelegate(this, ["prev"])
30449 //this.addSeparator();
30450 this.add(this.beforePageText);
30451 this.field = Roo.get(this.addDom({
30456 cls: "x-grid-page-number"
30458 this.field.on("keydown", this.onPagingKeydown, this);
30459 this.field.on("focus", function(){this.dom.select();});
30460 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30461 this.field.setHeight(18);
30462 //this.addSeparator();
30463 this.next = this.addButton({
30464 tooltip: this.nextText,
30465 cls: "x-btn-icon x-grid-page-next",
30467 handler: this.onClick.createDelegate(this, ["next"])
30469 this.last = this.addButton({
30470 tooltip: this.lastText,
30471 cls: "x-btn-icon x-grid-page-last",
30473 handler: this.onClick.createDelegate(this, ["last"])
30475 //this.addSeparator();
30476 this.loading = this.addButton({
30477 tooltip: this.refreshText,
30478 cls: "x-btn-icon x-grid-loading",
30479 handler: this.onClick.createDelegate(this, ["refresh"])
30482 if(this.displayInfo){
30483 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30488 updateInfo : function(){
30489 if(this.displayEl){
30490 var count = this.ds.getCount();
30491 var msg = count == 0 ?
30495 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30497 this.displayEl.update(msg);
30502 onLoad : function(ds, r, o){
30503 this.cursor = o.params ? o.params.start : 0;
30504 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30506 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30507 this.field.dom.value = ap;
30508 this.first.setDisabled(ap == 1);
30509 this.prev.setDisabled(ap == 1);
30510 this.next.setDisabled(ap == ps);
30511 this.last.setDisabled(ap == ps);
30512 this.loading.enable();
30517 getPageData : function(){
30518 var total = this.ds.getTotalCount();
30521 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30522 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30527 onLoadError : function(){
30528 this.loading.enable();
30532 onPagingKeydown : function(e){
30533 var k = e.getKey();
30534 var d = this.getPageData();
30536 var v = this.field.dom.value, pageNum;
30537 if(!v || isNaN(pageNum = parseInt(v, 10))){
30538 this.field.dom.value = d.activePage;
30541 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30542 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30545 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))
30547 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30548 this.field.dom.value = pageNum;
30549 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30552 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30554 var v = this.field.dom.value, pageNum;
30555 var increment = (e.shiftKey) ? 10 : 1;
30556 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30559 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30560 this.field.dom.value = d.activePage;
30563 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30565 this.field.dom.value = parseInt(v, 10) + increment;
30566 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30567 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30574 beforeLoad : function(){
30576 this.loading.disable();
30581 onClick : function(which){
30585 ds.load({params:{start: 0, limit: this.pageSize}});
30588 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30591 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30594 var total = ds.getTotalCount();
30595 var extra = total % this.pageSize;
30596 var lastStart = extra ? (total - extra) : total-this.pageSize;
30597 ds.load({params:{start: lastStart, limit: this.pageSize}});
30600 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30606 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30607 * @param {Roo.data.Store} store The data store to unbind
30609 unbind : function(ds){
30610 ds.un("beforeload", this.beforeLoad, this);
30611 ds.un("load", this.onLoad, this);
30612 ds.un("loadexception", this.onLoadError, this);
30613 ds.un("remove", this.updateInfo, this);
30614 ds.un("add", this.updateInfo, this);
30615 this.ds = undefined;
30619 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30620 * @param {Roo.data.Store} store The data store to bind
30622 bind : function(ds){
30623 ds.on("beforeload", this.beforeLoad, this);
30624 ds.on("load", this.onLoad, this);
30625 ds.on("loadexception", this.onLoadError, this);
30626 ds.on("remove", this.updateInfo, this);
30627 ds.on("add", this.updateInfo, this);
30632 * Ext JS Library 1.1.1
30633 * Copyright(c) 2006-2007, Ext JS, LLC.
30635 * Originally Released Under LGPL - original licence link has changed is not relivant.
30638 * <script type="text/javascript">
30642 * @class Roo.Resizable
30643 * @extends Roo.util.Observable
30644 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30645 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30646 * 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
30647 * the element will be wrapped for you automatically.</p>
30648 * <p>Here is the list of valid resize handles:</p>
30651 ------ -------------------
30660 'hd' horizontal drag
30663 * <p>Here's an example showing the creation of a typical Resizable:</p>
30665 var resizer = new Roo.Resizable("element-id", {
30673 resizer.on("resize", myHandler);
30675 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30676 * resizer.east.setDisplayed(false);</p>
30677 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30678 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30679 * resize operation's new size (defaults to [0, 0])
30680 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30681 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30682 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30683 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30684 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30685 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30686 * @cfg {Number} width The width of the element in pixels (defaults to null)
30687 * @cfg {Number} height The height of the element in pixels (defaults to null)
30688 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30689 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30690 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30691 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30692 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30693 * in favor of the handles config option (defaults to false)
30694 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30695 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30696 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30697 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30698 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30699 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30700 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30701 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30702 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30703 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30704 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30706 * Create a new resizable component
30707 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30708 * @param {Object} config configuration options
30710 Roo.Resizable = function(el, config)
30712 this.el = Roo.get(el);
30714 if(config && config.wrap){
30715 config.resizeChild = this.el;
30716 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30717 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30718 this.el.setStyle("overflow", "hidden");
30719 this.el.setPositioning(config.resizeChild.getPositioning());
30720 config.resizeChild.clearPositioning();
30721 if(!config.width || !config.height){
30722 var csize = config.resizeChild.getSize();
30723 this.el.setSize(csize.width, csize.height);
30725 if(config.pinned && !config.adjustments){
30726 config.adjustments = "auto";
30730 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30731 this.proxy.unselectable();
30732 this.proxy.enableDisplayMode('block');
30734 Roo.apply(this, config);
30737 this.disableTrackOver = true;
30738 this.el.addClass("x-resizable-pinned");
30740 // if the element isn't positioned, make it relative
30741 var position = this.el.getStyle("position");
30742 if(position != "absolute" && position != "fixed"){
30743 this.el.setStyle("position", "relative");
30745 if(!this.handles){ // no handles passed, must be legacy style
30746 this.handles = 's,e,se';
30747 if(this.multiDirectional){
30748 this.handles += ',n,w';
30751 if(this.handles == "all"){
30752 this.handles = "n s e w ne nw se sw";
30754 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30755 var ps = Roo.Resizable.positions;
30756 for(var i = 0, len = hs.length; i < len; i++){
30757 if(hs[i] && ps[hs[i]]){
30758 var pos = ps[hs[i]];
30759 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30763 this.corner = this.southeast;
30765 // updateBox = the box can move..
30766 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30767 this.updateBox = true;
30770 this.activeHandle = null;
30772 if(this.resizeChild){
30773 if(typeof this.resizeChild == "boolean"){
30774 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30776 this.resizeChild = Roo.get(this.resizeChild, true);
30780 if(this.adjustments == "auto"){
30781 var rc = this.resizeChild;
30782 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30783 if(rc && (hw || hn)){
30784 rc.position("relative");
30785 rc.setLeft(hw ? hw.el.getWidth() : 0);
30786 rc.setTop(hn ? hn.el.getHeight() : 0);
30788 this.adjustments = [
30789 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30790 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30794 if(this.draggable){
30795 this.dd = this.dynamic ?
30796 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30797 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30803 * @event beforeresize
30804 * Fired before resize is allowed. Set enabled to false to cancel resize.
30805 * @param {Roo.Resizable} this
30806 * @param {Roo.EventObject} e The mousedown event
30808 "beforeresize" : true,
30811 * Fired a resizing.
30812 * @param {Roo.Resizable} this
30813 * @param {Number} x The new x position
30814 * @param {Number} y The new y position
30815 * @param {Number} w The new w width
30816 * @param {Number} h The new h hight
30817 * @param {Roo.EventObject} e The mouseup event
30822 * Fired after a resize.
30823 * @param {Roo.Resizable} this
30824 * @param {Number} width The new width
30825 * @param {Number} height The new height
30826 * @param {Roo.EventObject} e The mouseup event
30831 if(this.width !== null && this.height !== null){
30832 this.resizeTo(this.width, this.height);
30834 this.updateChildSize();
30837 this.el.dom.style.zoom = 1;
30839 Roo.Resizable.superclass.constructor.call(this);
30842 Roo.extend(Roo.Resizable, Roo.util.Observable, {
30843 resizeChild : false,
30844 adjustments : [0, 0],
30854 multiDirectional : false,
30855 disableTrackOver : false,
30856 easing : 'easeOutStrong',
30857 widthIncrement : 0,
30858 heightIncrement : 0,
30862 preserveRatio : false,
30863 transparent: false,
30869 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
30871 constrainTo: undefined,
30873 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
30875 resizeRegion: undefined,
30879 * Perform a manual resize
30880 * @param {Number} width
30881 * @param {Number} height
30883 resizeTo : function(width, height){
30884 this.el.setSize(width, height);
30885 this.updateChildSize();
30886 this.fireEvent("resize", this, width, height, null);
30890 startSizing : function(e, handle){
30891 this.fireEvent("beforeresize", this, e);
30892 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
30895 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
30896 this.overlay.unselectable();
30897 this.overlay.enableDisplayMode("block");
30898 this.overlay.on("mousemove", this.onMouseMove, this);
30899 this.overlay.on("mouseup", this.onMouseUp, this);
30901 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
30903 this.resizing = true;
30904 this.startBox = this.el.getBox();
30905 this.startPoint = e.getXY();
30906 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
30907 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
30909 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30910 this.overlay.show();
30912 if(this.constrainTo) {
30913 var ct = Roo.get(this.constrainTo);
30914 this.resizeRegion = ct.getRegion().adjust(
30915 ct.getFrameWidth('t'),
30916 ct.getFrameWidth('l'),
30917 -ct.getFrameWidth('b'),
30918 -ct.getFrameWidth('r')
30922 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
30924 this.proxy.setBox(this.startBox);
30926 this.proxy.setStyle('visibility', 'visible');
30932 onMouseDown : function(handle, e){
30935 this.activeHandle = handle;
30936 this.startSizing(e, handle);
30941 onMouseUp : function(e){
30942 var size = this.resizeElement();
30943 this.resizing = false;
30945 this.overlay.hide();
30947 this.fireEvent("resize", this, size.width, size.height, e);
30951 updateChildSize : function(){
30953 if(this.resizeChild){
30955 var child = this.resizeChild;
30956 var adj = this.adjustments;
30957 if(el.dom.offsetWidth){
30958 var b = el.getSize(true);
30959 child.setSize(b.width+adj[0], b.height+adj[1]);
30961 // Second call here for IE
30962 // The first call enables instant resizing and
30963 // the second call corrects scroll bars if they
30966 setTimeout(function(){
30967 if(el.dom.offsetWidth){
30968 var b = el.getSize(true);
30969 child.setSize(b.width+adj[0], b.height+adj[1]);
30977 snap : function(value, inc, min){
30978 if(!inc || !value) {
30981 var newValue = value;
30982 var m = value % inc;
30985 newValue = value + (inc-m);
30987 newValue = value - m;
30990 return Math.max(min, newValue);
30994 resizeElement : function(){
30995 var box = this.proxy.getBox();
30996 if(this.updateBox){
30997 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
30999 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31001 this.updateChildSize();
31009 constrain : function(v, diff, m, mx){
31012 }else if(v - diff > mx){
31019 onMouseMove : function(e){
31022 try{// try catch so if something goes wrong the user doesn't get hung
31024 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31028 //var curXY = this.startPoint;
31029 var curSize = this.curSize || this.startBox;
31030 var x = this.startBox.x, y = this.startBox.y;
31031 var ox = x, oy = y;
31032 var w = curSize.width, h = curSize.height;
31033 var ow = w, oh = h;
31034 var mw = this.minWidth, mh = this.minHeight;
31035 var mxw = this.maxWidth, mxh = this.maxHeight;
31036 var wi = this.widthIncrement;
31037 var hi = this.heightIncrement;
31039 var eventXY = e.getXY();
31040 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31041 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31043 var pos = this.activeHandle.position;
31048 w = Math.min(Math.max(mw, w), mxw);
31053 h = Math.min(Math.max(mh, h), mxh);
31058 w = Math.min(Math.max(mw, w), mxw);
31059 h = Math.min(Math.max(mh, h), mxh);
31062 diffY = this.constrain(h, diffY, mh, mxh);
31069 var adiffX = Math.abs(diffX);
31070 var sub = (adiffX % wi); // how much
31071 if (sub > (wi/2)) { // far enough to snap
31072 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31074 // remove difference..
31075 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31079 x = Math.max(this.minX, x);
31082 diffX = this.constrain(w, diffX, mw, mxw);
31088 w = Math.min(Math.max(mw, w), mxw);
31089 diffY = this.constrain(h, diffY, mh, mxh);
31094 diffX = this.constrain(w, diffX, mw, mxw);
31095 diffY = this.constrain(h, diffY, mh, mxh);
31102 diffX = this.constrain(w, diffX, mw, mxw);
31104 h = Math.min(Math.max(mh, h), mxh);
31110 var sw = this.snap(w, wi, mw);
31111 var sh = this.snap(h, hi, mh);
31112 if(sw != w || sh != h){
31135 if(this.preserveRatio){
31140 h = Math.min(Math.max(mh, h), mxh);
31145 w = Math.min(Math.max(mw, w), mxw);
31150 w = Math.min(Math.max(mw, w), mxw);
31156 w = Math.min(Math.max(mw, w), mxw);
31162 h = Math.min(Math.max(mh, h), mxh);
31170 h = Math.min(Math.max(mh, h), mxh);
31180 h = Math.min(Math.max(mh, h), mxh);
31188 if (pos == 'hdrag') {
31191 this.proxy.setBounds(x, y, w, h);
31193 this.resizeElement();
31197 this.fireEvent("resizing", this, x, y, w, h, e);
31201 handleOver : function(){
31203 this.el.addClass("x-resizable-over");
31208 handleOut : function(){
31209 if(!this.resizing){
31210 this.el.removeClass("x-resizable-over");
31215 * Returns the element this component is bound to.
31216 * @return {Roo.Element}
31218 getEl : function(){
31223 * Returns the resizeChild element (or null).
31224 * @return {Roo.Element}
31226 getResizeChild : function(){
31227 return this.resizeChild;
31229 groupHandler : function()
31234 * Destroys this resizable. If the element was wrapped and
31235 * removeEl is not true then the element remains.
31236 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31238 destroy : function(removeEl){
31239 this.proxy.remove();
31241 this.overlay.removeAllListeners();
31242 this.overlay.remove();
31244 var ps = Roo.Resizable.positions;
31246 if(typeof ps[k] != "function" && this[ps[k]]){
31247 var h = this[ps[k]];
31248 h.el.removeAllListeners();
31253 this.el.update("");
31260 // hash to map config positions to true positions
31261 Roo.Resizable.positions = {
31262 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31267 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31269 // only initialize the template if resizable is used
31270 var tpl = Roo.DomHelper.createTemplate(
31271 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31274 Roo.Resizable.Handle.prototype.tpl = tpl;
31276 this.position = pos;
31278 // show north drag fro topdra
31279 var handlepos = pos == 'hdrag' ? 'north' : pos;
31281 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31282 if (pos == 'hdrag') {
31283 this.el.setStyle('cursor', 'pointer');
31285 this.el.unselectable();
31287 this.el.setOpacity(0);
31289 this.el.on("mousedown", this.onMouseDown, this);
31290 if(!disableTrackOver){
31291 this.el.on("mouseover", this.onMouseOver, this);
31292 this.el.on("mouseout", this.onMouseOut, this);
31297 Roo.Resizable.Handle.prototype = {
31298 afterResize : function(rz){
31303 onMouseDown : function(e){
31304 this.rz.onMouseDown(this, e);
31307 onMouseOver : function(e){
31308 this.rz.handleOver(this, e);
31311 onMouseOut : function(e){
31312 this.rz.handleOut(this, e);
31316 * Ext JS Library 1.1.1
31317 * Copyright(c) 2006-2007, Ext JS, LLC.
31319 * Originally Released Under LGPL - original licence link has changed is not relivant.
31322 * <script type="text/javascript">
31326 * @class Roo.Editor
31327 * @extends Roo.Component
31328 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31330 * Create a new Editor
31331 * @param {Roo.form.Field} field The Field object (or descendant)
31332 * @param {Object} config The config object
31334 Roo.Editor = function(field, config){
31335 Roo.Editor.superclass.constructor.call(this, config);
31336 this.field = field;
31339 * @event beforestartedit
31340 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31341 * false from the handler of this event.
31342 * @param {Editor} this
31343 * @param {Roo.Element} boundEl The underlying element bound to this editor
31344 * @param {Mixed} value The field value being set
31346 "beforestartedit" : true,
31349 * Fires when this editor is displayed
31350 * @param {Roo.Element} boundEl The underlying element bound to this editor
31351 * @param {Mixed} value The starting field value
31353 "startedit" : true,
31355 * @event beforecomplete
31356 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31357 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31358 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31359 * event will not fire since no edit actually occurred.
31360 * @param {Editor} this
31361 * @param {Mixed} value The current field value
31362 * @param {Mixed} startValue The original field value
31364 "beforecomplete" : true,
31367 * Fires after editing is complete and any changed value has been written to the underlying field.
31368 * @param {Editor} this
31369 * @param {Mixed} value The current field value
31370 * @param {Mixed} startValue The original field value
31374 * @event specialkey
31375 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31376 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31377 * @param {Roo.form.Field} this
31378 * @param {Roo.EventObject} e The event object
31380 "specialkey" : true
31384 Roo.extend(Roo.Editor, Roo.Component, {
31386 * @cfg {Boolean/String} autosize
31387 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31388 * or "height" to adopt the height only (defaults to false)
31391 * @cfg {Boolean} revertInvalid
31392 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31393 * validation fails (defaults to true)
31396 * @cfg {Boolean} ignoreNoChange
31397 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31398 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31399 * will never be ignored.
31402 * @cfg {Boolean} hideEl
31403 * False to keep the bound element visible while the editor is displayed (defaults to true)
31406 * @cfg {Mixed} value
31407 * The data value of the underlying field (defaults to "")
31411 * @cfg {String} alignment
31412 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31416 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31417 * for bottom-right shadow (defaults to "frame")
31421 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31425 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31427 completeOnEnter : false,
31429 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31431 cancelOnEsc : false,
31433 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31438 onRender : function(ct, position){
31439 this.el = new Roo.Layer({
31440 shadow: this.shadow,
31446 constrain: this.constrain
31448 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31449 if(this.field.msgTarget != 'title'){
31450 this.field.msgTarget = 'qtip';
31452 this.field.render(this.el);
31454 this.field.el.dom.setAttribute('autocomplete', 'off');
31456 this.field.on("specialkey", this.onSpecialKey, this);
31457 if(this.swallowKeys){
31458 this.field.el.swallowEvent(['keydown','keypress']);
31461 this.field.on("blur", this.onBlur, this);
31462 if(this.field.grow){
31463 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31467 onSpecialKey : function(field, e)
31469 //Roo.log('editor onSpecialKey');
31470 if(this.completeOnEnter && e.getKey() == e.ENTER){
31472 this.completeEdit();
31475 // do not fire special key otherwise it might hide close the editor...
31476 if(e.getKey() == e.ENTER){
31479 if(this.cancelOnEsc && e.getKey() == e.ESC){
31483 this.fireEvent('specialkey', field, e);
31488 * Starts the editing process and shows the editor.
31489 * @param {String/HTMLElement/Element} el The element to edit
31490 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31491 * to the innerHTML of el.
31493 startEdit : function(el, value){
31495 this.completeEdit();
31497 this.boundEl = Roo.get(el);
31498 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31499 if(!this.rendered){
31500 this.render(this.parentEl || document.body);
31502 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31505 this.startValue = v;
31506 this.field.setValue(v);
31508 var sz = this.boundEl.getSize();
31509 switch(this.autoSize){
31511 this.setSize(sz.width, "");
31514 this.setSize("", sz.height);
31517 this.setSize(sz.width, sz.height);
31520 this.el.alignTo(this.boundEl, this.alignment);
31521 this.editing = true;
31523 Roo.QuickTips.disable();
31529 * Sets the height and width of this editor.
31530 * @param {Number} width The new width
31531 * @param {Number} height The new height
31533 setSize : function(w, h){
31534 this.field.setSize(w, h);
31541 * Realigns the editor to the bound field based on the current alignment config value.
31543 realign : function(){
31544 this.el.alignTo(this.boundEl, this.alignment);
31548 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31549 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31551 completeEdit : function(remainVisible){
31555 var v = this.getValue();
31556 if(this.revertInvalid !== false && !this.field.isValid()){
31557 v = this.startValue;
31558 this.cancelEdit(true);
31560 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31561 this.editing = false;
31565 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31566 this.editing = false;
31567 if(this.updateEl && this.boundEl){
31568 this.boundEl.update(v);
31570 if(remainVisible !== true){
31573 this.fireEvent("complete", this, v, this.startValue);
31578 onShow : function(){
31580 if(this.hideEl !== false){
31581 this.boundEl.hide();
31584 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31585 this.fixIEFocus = true;
31586 this.deferredFocus.defer(50, this);
31588 this.field.focus();
31590 this.fireEvent("startedit", this.boundEl, this.startValue);
31593 deferredFocus : function(){
31595 this.field.focus();
31600 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31601 * reverted to the original starting value.
31602 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31603 * cancel (defaults to false)
31605 cancelEdit : function(remainVisible){
31607 this.setValue(this.startValue);
31608 if(remainVisible !== true){
31615 onBlur : function(){
31616 if(this.allowBlur !== true && this.editing){
31617 this.completeEdit();
31622 onHide : function(){
31624 this.completeEdit();
31628 if(this.field.collapse){
31629 this.field.collapse();
31632 if(this.hideEl !== false){
31633 this.boundEl.show();
31636 Roo.QuickTips.enable();
31641 * Sets the data value of the editor
31642 * @param {Mixed} value Any valid value supported by the underlying field
31644 setValue : function(v){
31645 this.field.setValue(v);
31649 * Gets the data value of the editor
31650 * @return {Mixed} The data value
31652 getValue : function(){
31653 return this.field.getValue();
31657 * Ext JS Library 1.1.1
31658 * Copyright(c) 2006-2007, Ext JS, LLC.
31660 * Originally Released Under LGPL - original licence link has changed is not relivant.
31663 * <script type="text/javascript">
31667 * @class Roo.BasicDialog
31668 * @extends Roo.util.Observable
31669 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31671 var dlg = new Roo.BasicDialog("my-dlg", {
31680 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31681 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31682 dlg.addButton('Cancel', dlg.hide, dlg);
31685 <b>A Dialog should always be a direct child of the body element.</b>
31686 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31687 * @cfg {String} title Default text to display in the title bar (defaults to null)
31688 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31689 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31690 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31691 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31692 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31693 * (defaults to null with no animation)
31694 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31695 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31696 * property for valid values (defaults to 'all')
31697 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31698 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31699 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31700 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31701 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31702 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31703 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31704 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31705 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31706 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31707 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31708 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31709 * draggable = true (defaults to false)
31710 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31711 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31712 * shadow (defaults to false)
31713 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31714 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31715 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31716 * @cfg {Array} buttons Array of buttons
31717 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31719 * Create a new BasicDialog.
31720 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31721 * @param {Object} config Configuration options
31723 Roo.BasicDialog = function(el, config){
31724 this.el = Roo.get(el);
31725 var dh = Roo.DomHelper;
31726 if(!this.el && config && config.autoCreate){
31727 if(typeof config.autoCreate == "object"){
31728 if(!config.autoCreate.id){
31729 config.autoCreate.id = el;
31731 this.el = dh.append(document.body,
31732 config.autoCreate, true);
31734 this.el = dh.append(document.body,
31735 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31739 el.setDisplayed(true);
31740 el.hide = this.hideAction;
31742 el.addClass("x-dlg");
31744 Roo.apply(this, config);
31746 this.proxy = el.createProxy("x-dlg-proxy");
31747 this.proxy.hide = this.hideAction;
31748 this.proxy.setOpacity(.5);
31752 el.setWidth(config.width);
31755 el.setHeight(config.height);
31757 this.size = el.getSize();
31758 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31759 this.xy = [config.x,config.y];
31761 this.xy = el.getCenterXY(true);
31763 /** The header element @type Roo.Element */
31764 this.header = el.child("> .x-dlg-hd");
31765 /** The body element @type Roo.Element */
31766 this.body = el.child("> .x-dlg-bd");
31767 /** The footer element @type Roo.Element */
31768 this.footer = el.child("> .x-dlg-ft");
31771 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31774 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31777 this.header.unselectable();
31779 this.header.update(this.title);
31781 // this element allows the dialog to be focused for keyboard event
31782 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31783 this.focusEl.swallowEvent("click", true);
31785 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31787 // wrap the body and footer for special rendering
31788 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31790 this.bwrap.dom.appendChild(this.footer.dom);
31793 this.bg = this.el.createChild({
31794 tag: "div", cls:"x-dlg-bg",
31795 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31797 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31800 if(this.autoScroll !== false && !this.autoTabs){
31801 this.body.setStyle("overflow", "auto");
31804 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31806 if(this.closable !== false){
31807 this.el.addClass("x-dlg-closable");
31808 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31809 this.close.on("click", this.closeClick, this);
31810 this.close.addClassOnOver("x-dlg-close-over");
31812 if(this.collapsible !== false){
31813 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31814 this.collapseBtn.on("click", this.collapseClick, this);
31815 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31816 this.header.on("dblclick", this.collapseClick, this);
31818 if(this.resizable !== false){
31819 this.el.addClass("x-dlg-resizable");
31820 this.resizer = new Roo.Resizable(el, {
31821 minWidth: this.minWidth || 80,
31822 minHeight:this.minHeight || 80,
31823 handles: this.resizeHandles || "all",
31826 this.resizer.on("beforeresize", this.beforeResize, this);
31827 this.resizer.on("resize", this.onResize, this);
31829 if(this.draggable !== false){
31830 el.addClass("x-dlg-draggable");
31831 if (!this.proxyDrag) {
31832 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
31835 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
31837 dd.setHandleElId(this.header.id);
31838 dd.endDrag = this.endMove.createDelegate(this);
31839 dd.startDrag = this.startMove.createDelegate(this);
31840 dd.onDrag = this.onDrag.createDelegate(this);
31845 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
31846 this.mask.enableDisplayMode("block");
31848 this.el.addClass("x-dlg-modal");
31851 this.shadow = new Roo.Shadow({
31852 mode : typeof this.shadow == "string" ? this.shadow : "sides",
31853 offset : this.shadowOffset
31856 this.shadowOffset = 0;
31858 if(Roo.useShims && this.shim !== false){
31859 this.shim = this.el.createShim();
31860 this.shim.hide = this.hideAction;
31868 if (this.buttons) {
31869 var bts= this.buttons;
31871 Roo.each(bts, function(b) {
31880 * Fires when a key is pressed
31881 * @param {Roo.BasicDialog} this
31882 * @param {Roo.EventObject} e
31887 * Fires when this dialog is moved by the user.
31888 * @param {Roo.BasicDialog} this
31889 * @param {Number} x The new page X
31890 * @param {Number} y The new page Y
31895 * Fires when this dialog is resized by the user.
31896 * @param {Roo.BasicDialog} this
31897 * @param {Number} width The new width
31898 * @param {Number} height The new height
31902 * @event beforehide
31903 * Fires before this dialog is hidden.
31904 * @param {Roo.BasicDialog} this
31906 "beforehide" : true,
31909 * Fires when this dialog is hidden.
31910 * @param {Roo.BasicDialog} this
31914 * @event beforeshow
31915 * Fires before this dialog is shown.
31916 * @param {Roo.BasicDialog} this
31918 "beforeshow" : true,
31921 * Fires when this dialog is shown.
31922 * @param {Roo.BasicDialog} this
31926 el.on("keydown", this.onKeyDown, this);
31927 el.on("mousedown", this.toFront, this);
31928 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
31930 Roo.DialogManager.register(this);
31931 Roo.BasicDialog.superclass.constructor.call(this);
31934 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
31935 shadowOffset: Roo.isIE ? 6 : 5,
31938 minButtonWidth: 75,
31939 defaultButton: null,
31940 buttonAlign: "right",
31945 * Sets the dialog title text
31946 * @param {String} text The title text to display
31947 * @return {Roo.BasicDialog} this
31949 setTitle : function(text){
31950 this.header.update(text);
31955 closeClick : function(){
31960 collapseClick : function(){
31961 this[this.collapsed ? "expand" : "collapse"]();
31965 * Collapses the dialog to its minimized state (only the title bar is visible).
31966 * Equivalent to the user clicking the collapse dialog button.
31968 collapse : function(){
31969 if(!this.collapsed){
31970 this.collapsed = true;
31971 this.el.addClass("x-dlg-collapsed");
31972 this.restoreHeight = this.el.getHeight();
31973 this.resizeTo(this.el.getWidth(), this.header.getHeight());
31978 * Expands a collapsed dialog back to its normal state. Equivalent to the user
31979 * clicking the expand dialog button.
31981 expand : function(){
31982 if(this.collapsed){
31983 this.collapsed = false;
31984 this.el.removeClass("x-dlg-collapsed");
31985 this.resizeTo(this.el.getWidth(), this.restoreHeight);
31990 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
31991 * @return {Roo.TabPanel} The tabs component
31993 initTabs : function(){
31994 var tabs = this.getTabs();
31995 while(tabs.getTab(0)){
31998 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32000 tabs.addTab(Roo.id(dom), dom.title);
32008 beforeResize : function(){
32009 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32013 onResize : function(){
32014 this.refreshSize();
32015 this.syncBodyHeight();
32016 this.adjustAssets();
32018 this.fireEvent("resize", this, this.size.width, this.size.height);
32022 onKeyDown : function(e){
32023 if(this.isVisible()){
32024 this.fireEvent("keydown", this, e);
32029 * Resizes the dialog.
32030 * @param {Number} width
32031 * @param {Number} height
32032 * @return {Roo.BasicDialog} this
32034 resizeTo : function(width, height){
32035 this.el.setSize(width, height);
32036 this.size = {width: width, height: height};
32037 this.syncBodyHeight();
32038 if(this.fixedcenter){
32041 if(this.isVisible()){
32042 this.constrainXY();
32043 this.adjustAssets();
32045 this.fireEvent("resize", this, width, height);
32051 * Resizes the dialog to fit the specified content size.
32052 * @param {Number} width
32053 * @param {Number} height
32054 * @return {Roo.BasicDialog} this
32056 setContentSize : function(w, h){
32057 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32058 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32059 //if(!this.el.isBorderBox()){
32060 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32061 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32064 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32065 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32067 this.resizeTo(w, h);
32072 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32073 * executed in response to a particular key being pressed while the dialog is active.
32074 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32075 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32076 * @param {Function} fn The function to call
32077 * @param {Object} scope (optional) The scope of the function
32078 * @return {Roo.BasicDialog} this
32080 addKeyListener : function(key, fn, scope){
32081 var keyCode, shift, ctrl, alt;
32082 if(typeof key == "object" && !(key instanceof Array)){
32083 keyCode = key["key"];
32084 shift = key["shift"];
32085 ctrl = key["ctrl"];
32090 var handler = function(dlg, e){
32091 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32092 var k = e.getKey();
32093 if(keyCode instanceof Array){
32094 for(var i = 0, len = keyCode.length; i < len; i++){
32095 if(keyCode[i] == k){
32096 fn.call(scope || window, dlg, k, e);
32102 fn.call(scope || window, dlg, k, e);
32107 this.on("keydown", handler);
32112 * Returns the TabPanel component (creates it if it doesn't exist).
32113 * Note: If you wish to simply check for the existence of tabs without creating them,
32114 * check for a null 'tabs' property.
32115 * @return {Roo.TabPanel} The tabs component
32117 getTabs : function(){
32119 this.el.addClass("x-dlg-auto-tabs");
32120 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32121 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32127 * Adds a button to the footer section of the dialog.
32128 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32129 * object or a valid Roo.DomHelper element config
32130 * @param {Function} handler The function called when the button is clicked
32131 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32132 * @return {Roo.Button} The new button
32134 addButton : function(config, handler, scope){
32135 var dh = Roo.DomHelper;
32137 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32139 if(!this.btnContainer){
32140 var tb = this.footer.createChild({
32142 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32143 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32145 this.btnContainer = tb.firstChild.firstChild.firstChild;
32150 minWidth: this.minButtonWidth,
32153 if(typeof config == "string"){
32154 bconfig.text = config;
32157 bconfig.dhconfig = config;
32159 Roo.apply(bconfig, config);
32163 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32164 bconfig.position = Math.max(0, bconfig.position);
32165 fc = this.btnContainer.childNodes[bconfig.position];
32168 var btn = new Roo.Button(
32170 this.btnContainer.insertBefore(document.createElement("td"),fc)
32171 : this.btnContainer.appendChild(document.createElement("td")),
32172 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32175 this.syncBodyHeight();
32178 * Array of all the buttons that have been added to this dialog via addButton
32183 this.buttons.push(btn);
32188 * Sets the default button to be focused when the dialog is displayed.
32189 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32190 * @return {Roo.BasicDialog} this
32192 setDefaultButton : function(btn){
32193 this.defaultButton = btn;
32198 getHeaderFooterHeight : function(safe){
32201 height += this.header.getHeight();
32204 var fm = this.footer.getMargins();
32205 height += (this.footer.getHeight()+fm.top+fm.bottom);
32207 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32208 height += this.centerBg.getPadding("tb");
32213 syncBodyHeight : function()
32215 var bd = this.body, // the text
32216 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32218 var height = this.size.height - this.getHeaderFooterHeight(false);
32219 bd.setHeight(height-bd.getMargins("tb"));
32220 var hh = this.header.getHeight();
32221 var h = this.size.height-hh;
32224 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32225 bw.setHeight(h-cb.getPadding("tb"));
32227 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32228 bd.setWidth(bw.getWidth(true));
32230 this.tabs.syncHeight();
32232 this.tabs.el.repaint();
32238 * Restores the previous state of the dialog if Roo.state is configured.
32239 * @return {Roo.BasicDialog} this
32241 restoreState : function(){
32242 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32243 if(box && box.width){
32244 this.xy = [box.x, box.y];
32245 this.resizeTo(box.width, box.height);
32251 beforeShow : function(){
32253 if(this.fixedcenter){
32254 this.xy = this.el.getCenterXY(true);
32257 Roo.get(document.body).addClass("x-body-masked");
32258 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32261 this.constrainXY();
32265 animShow : function(){
32266 var b = Roo.get(this.animateTarget).getBox();
32267 this.proxy.setSize(b.width, b.height);
32268 this.proxy.setLocation(b.x, b.y);
32270 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32271 true, .35, this.showEl.createDelegate(this));
32275 * Shows the dialog.
32276 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32277 * @return {Roo.BasicDialog} this
32279 show : function(animateTarget){
32280 if (this.fireEvent("beforeshow", this) === false){
32283 if(this.syncHeightBeforeShow){
32284 this.syncBodyHeight();
32285 }else if(this.firstShow){
32286 this.firstShow = false;
32287 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32289 this.animateTarget = animateTarget || this.animateTarget;
32290 if(!this.el.isVisible()){
32292 if(this.animateTarget && Roo.get(this.animateTarget)){
32302 showEl : function(){
32304 this.el.setXY(this.xy);
32306 this.adjustAssets(true);
32309 // IE peekaboo bug - fix found by Dave Fenwick
32313 this.fireEvent("show", this);
32317 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32318 * dialog itself will receive focus.
32320 focus : function(){
32321 if(this.defaultButton){
32322 this.defaultButton.focus();
32324 this.focusEl.focus();
32329 constrainXY : function(){
32330 if(this.constraintoviewport !== false){
32331 if(!this.viewSize){
32332 if(this.container){
32333 var s = this.container.getSize();
32334 this.viewSize = [s.width, s.height];
32336 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32339 var s = Roo.get(this.container||document).getScroll();
32341 var x = this.xy[0], y = this.xy[1];
32342 var w = this.size.width, h = this.size.height;
32343 var vw = this.viewSize[0], vh = this.viewSize[1];
32344 // only move it if it needs it
32346 // first validate right/bottom
32347 if(x + w > vw+s.left){
32351 if(y + h > vh+s.top){
32355 // then make sure top/left isn't negative
32367 if(this.isVisible()){
32368 this.el.setLocation(x, y);
32369 this.adjustAssets();
32376 onDrag : function(){
32377 if(!this.proxyDrag){
32378 this.xy = this.el.getXY();
32379 this.adjustAssets();
32384 adjustAssets : function(doShow){
32385 var x = this.xy[0], y = this.xy[1];
32386 var w = this.size.width, h = this.size.height;
32387 if(doShow === true){
32389 this.shadow.show(this.el);
32395 if(this.shadow && this.shadow.isVisible()){
32396 this.shadow.show(this.el);
32398 if(this.shim && this.shim.isVisible()){
32399 this.shim.setBounds(x, y, w, h);
32404 adjustViewport : function(w, h){
32406 w = Roo.lib.Dom.getViewWidth();
32407 h = Roo.lib.Dom.getViewHeight();
32410 this.viewSize = [w, h];
32411 if(this.modal && this.mask.isVisible()){
32412 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32413 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32415 if(this.isVisible()){
32416 this.constrainXY();
32421 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32422 * shadow, proxy, mask, etc.) Also removes all event listeners.
32423 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32425 destroy : function(removeEl){
32426 if(this.isVisible()){
32427 this.animateTarget = null;
32430 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32432 this.tabs.destroy(removeEl);
32445 for(var i = 0, len = this.buttons.length; i < len; i++){
32446 this.buttons[i].destroy();
32449 this.el.removeAllListeners();
32450 if(removeEl === true){
32451 this.el.update("");
32454 Roo.DialogManager.unregister(this);
32458 startMove : function(){
32459 if(this.proxyDrag){
32462 if(this.constraintoviewport !== false){
32463 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32468 endMove : function(){
32469 if(!this.proxyDrag){
32470 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32472 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32475 this.refreshSize();
32476 this.adjustAssets();
32478 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32482 * Brings this dialog to the front of any other visible dialogs
32483 * @return {Roo.BasicDialog} this
32485 toFront : function(){
32486 Roo.DialogManager.bringToFront(this);
32491 * Sends this dialog to the back (under) of any other visible dialogs
32492 * @return {Roo.BasicDialog} this
32494 toBack : function(){
32495 Roo.DialogManager.sendToBack(this);
32500 * Centers this dialog in the viewport
32501 * @return {Roo.BasicDialog} this
32503 center : function(){
32504 var xy = this.el.getCenterXY(true);
32505 this.moveTo(xy[0], xy[1]);
32510 * Moves the dialog's top-left corner to the specified point
32511 * @param {Number} x
32512 * @param {Number} y
32513 * @return {Roo.BasicDialog} this
32515 moveTo : function(x, y){
32517 if(this.isVisible()){
32518 this.el.setXY(this.xy);
32519 this.adjustAssets();
32525 * Aligns the dialog to the specified element
32526 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32527 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32528 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32529 * @return {Roo.BasicDialog} this
32531 alignTo : function(element, position, offsets){
32532 this.xy = this.el.getAlignToXY(element, position, offsets);
32533 if(this.isVisible()){
32534 this.el.setXY(this.xy);
32535 this.adjustAssets();
32541 * Anchors an element to another element and realigns it when the window is resized.
32542 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32543 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32544 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32545 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32546 * is a number, it is used as the buffer delay (defaults to 50ms).
32547 * @return {Roo.BasicDialog} this
32549 anchorTo : function(el, alignment, offsets, monitorScroll){
32550 var action = function(){
32551 this.alignTo(el, alignment, offsets);
32553 Roo.EventManager.onWindowResize(action, this);
32554 var tm = typeof monitorScroll;
32555 if(tm != 'undefined'){
32556 Roo.EventManager.on(window, 'scroll', action, this,
32557 {buffer: tm == 'number' ? monitorScroll : 50});
32564 * Returns true if the dialog is visible
32565 * @return {Boolean}
32567 isVisible : function(){
32568 return this.el.isVisible();
32572 animHide : function(callback){
32573 var b = Roo.get(this.animateTarget).getBox();
32575 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32577 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32578 this.hideEl.createDelegate(this, [callback]));
32582 * Hides the dialog.
32583 * @param {Function} callback (optional) Function to call when the dialog is hidden
32584 * @return {Roo.BasicDialog} this
32586 hide : function(callback){
32587 if (this.fireEvent("beforehide", this) === false){
32591 this.shadow.hide();
32596 // sometimes animateTarget seems to get set.. causing problems...
32597 // this just double checks..
32598 if(this.animateTarget && Roo.get(this.animateTarget)) {
32599 this.animHide(callback);
32602 this.hideEl(callback);
32608 hideEl : function(callback){
32612 Roo.get(document.body).removeClass("x-body-masked");
32614 this.fireEvent("hide", this);
32615 if(typeof callback == "function"){
32621 hideAction : function(){
32622 this.setLeft("-10000px");
32623 this.setTop("-10000px");
32624 this.setStyle("visibility", "hidden");
32628 refreshSize : function(){
32629 this.size = this.el.getSize();
32630 this.xy = this.el.getXY();
32631 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32635 // z-index is managed by the DialogManager and may be overwritten at any time
32636 setZIndex : function(index){
32638 this.mask.setStyle("z-index", index);
32641 this.shim.setStyle("z-index", ++index);
32644 this.shadow.setZIndex(++index);
32646 this.el.setStyle("z-index", ++index);
32648 this.proxy.setStyle("z-index", ++index);
32651 this.resizer.proxy.setStyle("z-index", ++index);
32654 this.lastZIndex = index;
32658 * Returns the element for this dialog
32659 * @return {Roo.Element} The underlying dialog Element
32661 getEl : function(){
32667 * @class Roo.DialogManager
32668 * Provides global access to BasicDialogs that have been created and
32669 * support for z-indexing (layering) multiple open dialogs.
32671 Roo.DialogManager = function(){
32673 var accessList = [];
32677 var sortDialogs = function(d1, d2){
32678 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32682 var orderDialogs = function(){
32683 accessList.sort(sortDialogs);
32684 var seed = Roo.DialogManager.zseed;
32685 for(var i = 0, len = accessList.length; i < len; i++){
32686 var dlg = accessList[i];
32688 dlg.setZIndex(seed + (i*10));
32695 * The starting z-index for BasicDialogs (defaults to 9000)
32696 * @type Number The z-index value
32701 register : function(dlg){
32702 list[dlg.id] = dlg;
32703 accessList.push(dlg);
32707 unregister : function(dlg){
32708 delete list[dlg.id];
32711 if(!accessList.indexOf){
32712 for( i = 0, len = accessList.length; i < len; i++){
32713 if(accessList[i] == dlg){
32714 accessList.splice(i, 1);
32719 i = accessList.indexOf(dlg);
32721 accessList.splice(i, 1);
32727 * Gets a registered dialog by id
32728 * @param {String/Object} id The id of the dialog or a dialog
32729 * @return {Roo.BasicDialog} this
32731 get : function(id){
32732 return typeof id == "object" ? id : list[id];
32736 * Brings the specified dialog to the front
32737 * @param {String/Object} dlg The id of the dialog or a dialog
32738 * @return {Roo.BasicDialog} this
32740 bringToFront : function(dlg){
32741 dlg = this.get(dlg);
32744 dlg._lastAccess = new Date().getTime();
32751 * Sends the specified dialog to the back
32752 * @param {String/Object} dlg The id of the dialog or a dialog
32753 * @return {Roo.BasicDialog} this
32755 sendToBack : function(dlg){
32756 dlg = this.get(dlg);
32757 dlg._lastAccess = -(new Date().getTime());
32763 * Hides all dialogs
32765 hideAll : function(){
32766 for(var id in list){
32767 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32776 * @class Roo.LayoutDialog
32777 * @extends Roo.BasicDialog
32778 * Dialog which provides adjustments for working with a layout in a Dialog.
32779 * Add your necessary layout config options to the dialog's config.<br>
32780 * Example usage (including a nested layout):
32783 dialog = new Roo.LayoutDialog("download-dlg", {
32792 // layout config merges with the dialog config
32794 tabPosition: "top",
32795 alwaysShowTabs: true
32798 dialog.addKeyListener(27, dialog.hide, dialog);
32799 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32800 dialog.addButton("Build It!", this.getDownload, this);
32802 // we can even add nested layouts
32803 var innerLayout = new Roo.BorderLayout("dl-inner", {
32813 innerLayout.beginUpdate();
32814 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32815 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32816 innerLayout.endUpdate(true);
32818 var layout = dialog.getLayout();
32819 layout.beginUpdate();
32820 layout.add("center", new Roo.ContentPanel("standard-panel",
32821 {title: "Download the Source", fitToFrame:true}));
32822 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32823 {title: "Build your own roo.js"}));
32824 layout.getRegion("center").showPanel(sp);
32825 layout.endUpdate();
32829 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32830 * @param {Object} config configuration options
32832 Roo.LayoutDialog = function(el, cfg){
32835 if (typeof(cfg) == 'undefined') {
32836 config = Roo.apply({}, el);
32837 // not sure why we use documentElement here.. - it should always be body.
32838 // IE7 borks horribly if we use documentElement.
32839 // webkit also does not like documentElement - it creates a body element...
32840 el = Roo.get( document.body || document.documentElement ).createChild();
32841 //config.autoCreate = true;
32845 config.autoTabs = false;
32846 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
32847 this.body.setStyle({overflow:"hidden", position:"relative"});
32848 this.layout = new Roo.BorderLayout(this.body.dom, config);
32849 this.layout.monitorWindowResize = false;
32850 this.el.addClass("x-dlg-auto-layout");
32851 // fix case when center region overwrites center function
32852 this.center = Roo.BasicDialog.prototype.center;
32853 this.on("show", this.layout.layout, this.layout, true);
32854 if (config.items) {
32855 var xitems = config.items;
32856 delete config.items;
32857 Roo.each(xitems, this.addxtype, this);
32862 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
32864 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
32867 endUpdate : function(){
32868 this.layout.endUpdate();
32872 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
32875 beginUpdate : function(){
32876 this.layout.beginUpdate();
32880 * Get the BorderLayout for this dialog
32881 * @return {Roo.BorderLayout}
32883 getLayout : function(){
32884 return this.layout;
32887 showEl : function(){
32888 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
32890 this.layout.layout();
32895 // Use the syncHeightBeforeShow config option to control this automatically
32896 syncBodyHeight : function(){
32897 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
32898 if(this.layout){this.layout.layout();}
32902 * Add an xtype element (actually adds to the layout.)
32903 * @return {Object} xdata xtype object data.
32906 addxtype : function(c) {
32907 return this.layout.addxtype(c);
32911 * Ext JS Library 1.1.1
32912 * Copyright(c) 2006-2007, Ext JS, LLC.
32914 * Originally Released Under LGPL - original licence link has changed is not relivant.
32917 * <script type="text/javascript">
32921 * @class Roo.MessageBox
32922 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
32926 Roo.Msg.alert('Status', 'Changes saved successfully.');
32928 // Prompt for user data:
32929 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
32931 // process text value...
32935 // Show a dialog using config options:
32937 title:'Save Changes?',
32938 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
32939 buttons: Roo.Msg.YESNOCANCEL,
32946 Roo.MessageBox = function(){
32947 var dlg, opt, mask, waitTimer;
32948 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
32949 var buttons, activeTextEl, bwidth;
32952 var handleButton = function(button){
32954 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
32958 var handleHide = function(){
32959 if(opt && opt.cls){
32960 dlg.el.removeClass(opt.cls);
32963 Roo.TaskMgr.stop(waitTimer);
32969 var updateButtons = function(b){
32972 buttons["ok"].hide();
32973 buttons["cancel"].hide();
32974 buttons["yes"].hide();
32975 buttons["no"].hide();
32976 dlg.footer.dom.style.display = 'none';
32979 dlg.footer.dom.style.display = '';
32980 for(var k in buttons){
32981 if(typeof buttons[k] != "function"){
32984 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
32985 width += buttons[k].el.getWidth()+15;
32995 var handleEsc = function(d, k, e){
32996 if(opt && opt.closable !== false){
33006 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33007 * @return {Roo.BasicDialog} The BasicDialog element
33009 getDialog : function(){
33011 dlg = new Roo.BasicDialog("x-msg-box", {
33016 constraintoviewport:false,
33018 collapsible : false,
33021 width:400, height:100,
33022 buttonAlign:"center",
33023 closeClick : function(){
33024 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33025 handleButton("no");
33027 handleButton("cancel");
33031 dlg.on("hide", handleHide);
33033 dlg.addKeyListener(27, handleEsc);
33035 var bt = this.buttonText;
33036 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33037 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33038 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33039 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33040 bodyEl = dlg.body.createChild({
33042 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>'
33044 msgEl = bodyEl.dom.firstChild;
33045 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33046 textboxEl.enableDisplayMode();
33047 textboxEl.addKeyListener([10,13], function(){
33048 if(dlg.isVisible() && opt && opt.buttons){
33049 if(opt.buttons.ok){
33050 handleButton("ok");
33051 }else if(opt.buttons.yes){
33052 handleButton("yes");
33056 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33057 textareaEl.enableDisplayMode();
33058 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33059 progressEl.enableDisplayMode();
33060 var pf = progressEl.dom.firstChild;
33062 pp = Roo.get(pf.firstChild);
33063 pp.setHeight(pf.offsetHeight);
33071 * Updates the message box body text
33072 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33073 * the XHTML-compliant non-breaking space character '&#160;')
33074 * @return {Roo.MessageBox} This message box
33076 updateText : function(text){
33077 if(!dlg.isVisible() && !opt.width){
33078 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33080 msgEl.innerHTML = text || ' ';
33082 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33083 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33085 Math.min(opt.width || cw , this.maxWidth),
33086 Math.max(opt.minWidth || this.minWidth, bwidth)
33089 activeTextEl.setWidth(w);
33091 if(dlg.isVisible()){
33092 dlg.fixedcenter = false;
33094 // to big, make it scroll. = But as usual stupid IE does not support
33097 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33098 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33099 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33101 bodyEl.dom.style.height = '';
33102 bodyEl.dom.style.overflowY = '';
33105 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33107 bodyEl.dom.style.overflowX = '';
33110 dlg.setContentSize(w, bodyEl.getHeight());
33111 if(dlg.isVisible()){
33112 dlg.fixedcenter = true;
33118 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33119 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33120 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33121 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33122 * @return {Roo.MessageBox} This message box
33124 updateProgress : function(value, text){
33126 this.updateText(text);
33128 if (pp) { // weird bug on my firefox - for some reason this is not defined
33129 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33135 * Returns true if the message box is currently displayed
33136 * @return {Boolean} True if the message box is visible, else false
33138 isVisible : function(){
33139 return dlg && dlg.isVisible();
33143 * Hides the message box if it is displayed
33146 if(this.isVisible()){
33152 * Displays a new message box, or reinitializes an existing message box, based on the config options
33153 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33154 * The following config object properties are supported:
33156 Property Type Description
33157 ---------- --------------- ------------------------------------------------------------------------------------
33158 animEl String/Element An id or Element from which the message box should animate as it opens and
33159 closes (defaults to undefined)
33160 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33161 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33162 closable Boolean False to hide the top-right close button (defaults to true). Note that
33163 progress and wait dialogs will ignore this property and always hide the
33164 close button as they can only be closed programmatically.
33165 cls String A custom CSS class to apply to the message box element
33166 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33167 displayed (defaults to 75)
33168 fn Function A callback function to execute after closing the dialog. The arguments to the
33169 function will be btn (the name of the button that was clicked, if applicable,
33170 e.g. "ok"), and text (the value of the active text field, if applicable).
33171 Progress and wait dialogs will ignore this option since they do not respond to
33172 user actions and can only be closed programmatically, so any required function
33173 should be called by the same code after it closes the dialog.
33174 icon String A CSS class that provides a background image to be used as an icon for
33175 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33176 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33177 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33178 modal Boolean False to allow user interaction with the page while the message box is
33179 displayed (defaults to true)
33180 msg String A string that will replace the existing message box body text (defaults
33181 to the XHTML-compliant non-breaking space character ' ')
33182 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33183 progress Boolean True to display a progress bar (defaults to false)
33184 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33185 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33186 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33187 title String The title text
33188 value String The string value to set into the active textbox element if displayed
33189 wait Boolean True to display a progress bar (defaults to false)
33190 width Number The width of the dialog in pixels
33197 msg: 'Please enter your address:',
33199 buttons: Roo.MessageBox.OKCANCEL,
33202 animEl: 'addAddressBtn'
33205 * @param {Object} config Configuration options
33206 * @return {Roo.MessageBox} This message box
33208 show : function(options)
33211 // this causes nightmares if you show one dialog after another
33212 // especially on callbacks..
33214 if(this.isVisible()){
33217 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33218 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33219 Roo.log("New Dialog Message:" + options.msg )
33220 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33221 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33224 var d = this.getDialog();
33226 d.setTitle(opt.title || " ");
33227 d.close.setDisplayed(opt.closable !== false);
33228 activeTextEl = textboxEl;
33229 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33234 textareaEl.setHeight(typeof opt.multiline == "number" ?
33235 opt.multiline : this.defaultTextHeight);
33236 activeTextEl = textareaEl;
33245 progressEl.setDisplayed(opt.progress === true);
33246 this.updateProgress(0);
33247 activeTextEl.dom.value = opt.value || "";
33249 dlg.setDefaultButton(activeTextEl);
33251 var bs = opt.buttons;
33254 db = buttons["ok"];
33255 }else if(bs && bs.yes){
33256 db = buttons["yes"];
33258 dlg.setDefaultButton(db);
33260 bwidth = updateButtons(opt.buttons);
33261 this.updateText(opt.msg);
33263 d.el.addClass(opt.cls);
33265 d.proxyDrag = opt.proxyDrag === true;
33266 d.modal = opt.modal !== false;
33267 d.mask = opt.modal !== false ? mask : false;
33268 if(!d.isVisible()){
33269 // force it to the end of the z-index stack so it gets a cursor in FF
33270 document.body.appendChild(dlg.el.dom);
33271 d.animateTarget = null;
33272 d.show(options.animEl);
33278 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33279 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33280 * and closing the message box when the process is complete.
33281 * @param {String} title The title bar text
33282 * @param {String} msg The message box body text
33283 * @return {Roo.MessageBox} This message box
33285 progress : function(title, msg){
33292 minWidth: this.minProgressWidth,
33299 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33300 * If a callback function is passed it will be called after the user clicks the button, and the
33301 * id of the button that was clicked will be passed as the only parameter to the callback
33302 * (could also be the top-right close button).
33303 * @param {String} title The title bar text
33304 * @param {String} msg The message box body text
33305 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33306 * @param {Object} scope (optional) The scope of the callback function
33307 * @return {Roo.MessageBox} This message box
33309 alert : function(title, msg, fn, scope){
33322 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33323 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33324 * You are responsible for closing the message box when the process is complete.
33325 * @param {String} msg The message box body text
33326 * @param {String} title (optional) The title bar text
33327 * @return {Roo.MessageBox} This message box
33329 wait : function(msg, title){
33340 waitTimer = Roo.TaskMgr.start({
33342 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33350 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33351 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33352 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33353 * @param {String} title The title bar text
33354 * @param {String} msg The message box body text
33355 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33356 * @param {Object} scope (optional) The scope of the callback function
33357 * @return {Roo.MessageBox} This message box
33359 confirm : function(title, msg, fn, scope){
33363 buttons: this.YESNO,
33372 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33373 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33374 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33375 * (could also be the top-right close button) and the text that was entered will be passed as the two
33376 * parameters to the callback.
33377 * @param {String} title The title bar text
33378 * @param {String} msg The message box body text
33379 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33380 * @param {Object} scope (optional) The scope of the callback function
33381 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33382 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33383 * @return {Roo.MessageBox} This message box
33385 prompt : function(title, msg, fn, scope, multiline){
33389 buttons: this.OKCANCEL,
33394 multiline: multiline,
33401 * Button config that displays a single OK button
33406 * Button config that displays Yes and No buttons
33409 YESNO : {yes:true, no:true},
33411 * Button config that displays OK and Cancel buttons
33414 OKCANCEL : {ok:true, cancel:true},
33416 * Button config that displays Yes, No and Cancel buttons
33419 YESNOCANCEL : {yes:true, no:true, cancel:true},
33422 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33425 defaultTextHeight : 75,
33427 * The maximum width in pixels of the message box (defaults to 600)
33432 * The minimum width in pixels of the message box (defaults to 100)
33437 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33438 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33441 minProgressWidth : 250,
33443 * An object containing the default button text strings that can be overriden for localized language support.
33444 * Supported properties are: ok, cancel, yes and no.
33445 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33458 * Shorthand for {@link Roo.MessageBox}
33460 Roo.Msg = Roo.MessageBox;/*
33462 * Ext JS Library 1.1.1
33463 * Copyright(c) 2006-2007, Ext JS, LLC.
33465 * Originally Released Under LGPL - original licence link has changed is not relivant.
33468 * <script type="text/javascript">
33471 * @class Roo.QuickTips
33472 * Provides attractive and customizable tooltips for any element.
33475 Roo.QuickTips = function(){
33476 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33477 var ce, bd, xy, dd;
33478 var visible = false, disabled = true, inited = false;
33479 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33481 var onOver = function(e){
33485 var t = e.getTarget();
33486 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33489 if(ce && t == ce.el){
33490 clearTimeout(hideProc);
33493 if(t && tagEls[t.id]){
33494 tagEls[t.id].el = t;
33495 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33498 var ttp, et = Roo.fly(t);
33499 var ns = cfg.namespace;
33500 if(tm.interceptTitles && t.title){
33503 t.removeAttribute("title");
33504 e.preventDefault();
33506 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33509 showProc = show.defer(tm.showDelay, tm, [{
33512 width: et.getAttributeNS(ns, cfg.width),
33513 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33514 title: et.getAttributeNS(ns, cfg.title),
33515 cls: et.getAttributeNS(ns, cfg.cls)
33520 var onOut = function(e){
33521 clearTimeout(showProc);
33522 var t = e.getTarget();
33523 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33524 hideProc = setTimeout(hide, tm.hideDelay);
33528 var onMove = function(e){
33534 if(tm.trackMouse && ce){
33539 var onDown = function(e){
33540 clearTimeout(showProc);
33541 clearTimeout(hideProc);
33543 if(tm.hideOnClick){
33546 tm.enable.defer(100, tm);
33551 var getPad = function(){
33552 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33555 var show = function(o){
33559 clearTimeout(dismissProc);
33561 if(removeCls){ // in case manually hidden
33562 el.removeClass(removeCls);
33566 el.addClass(ce.cls);
33567 removeCls = ce.cls;
33570 tipTitle.update(ce.title);
33573 tipTitle.update('');
33576 el.dom.style.width = tm.maxWidth+'px';
33577 //tipBody.dom.style.width = '';
33578 tipBodyText.update(o.text);
33579 var p = getPad(), w = ce.width;
33581 var td = tipBodyText.dom;
33582 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33583 if(aw > tm.maxWidth){
33585 }else if(aw < tm.minWidth){
33591 //tipBody.setWidth(w);
33592 el.setWidth(parseInt(w, 10) + p);
33593 if(ce.autoHide === false){
33594 close.setDisplayed(true);
33599 close.setDisplayed(false);
33605 el.avoidY = xy[1]-18;
33610 el.setStyle("visibility", "visible");
33611 el.fadeIn({callback: afterShow});
33617 var afterShow = function(){
33621 if(tm.autoDismiss && ce.autoHide !== false){
33622 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33627 var hide = function(noanim){
33628 clearTimeout(dismissProc);
33629 clearTimeout(hideProc);
33631 if(el.isVisible()){
33633 if(noanim !== true && tm.animate){
33634 el.fadeOut({callback: afterHide});
33641 var afterHide = function(){
33644 el.removeClass(removeCls);
33651 * @cfg {Number} minWidth
33652 * The minimum width of the quick tip (defaults to 40)
33656 * @cfg {Number} maxWidth
33657 * The maximum width of the quick tip (defaults to 300)
33661 * @cfg {Boolean} interceptTitles
33662 * True to automatically use the element's DOM title value if available (defaults to false)
33664 interceptTitles : false,
33666 * @cfg {Boolean} trackMouse
33667 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33669 trackMouse : false,
33671 * @cfg {Boolean} hideOnClick
33672 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33674 hideOnClick : true,
33676 * @cfg {Number} showDelay
33677 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33681 * @cfg {Number} hideDelay
33682 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33686 * @cfg {Boolean} autoHide
33687 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33688 * Used in conjunction with hideDelay.
33693 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33694 * (defaults to true). Used in conjunction with autoDismissDelay.
33696 autoDismiss : true,
33699 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33701 autoDismissDelay : 5000,
33703 * @cfg {Boolean} animate
33704 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33709 * @cfg {String} title
33710 * Title text to display (defaults to ''). This can be any valid HTML markup.
33714 * @cfg {String} text
33715 * Body text to display (defaults to ''). This can be any valid HTML markup.
33719 * @cfg {String} cls
33720 * A CSS class to apply to the base quick tip element (defaults to '').
33724 * @cfg {Number} width
33725 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33726 * minWidth or maxWidth.
33731 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33732 * or display QuickTips in a page.
33735 tm = Roo.QuickTips;
33736 cfg = tm.tagConfig;
33738 if(!Roo.isReady){ // allow calling of init() before onReady
33739 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33742 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33743 el.fxDefaults = {stopFx: true};
33744 // maximum custom styling
33745 //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>');
33746 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>');
33747 tipTitle = el.child('h3');
33748 tipTitle.enableDisplayMode("block");
33749 tipBody = el.child('div.x-tip-bd');
33750 tipBodyText = el.child('div.x-tip-bd-inner');
33751 //bdLeft = el.child('div.x-tip-bd-left');
33752 //bdRight = el.child('div.x-tip-bd-right');
33753 close = el.child('div.x-tip-close');
33754 close.enableDisplayMode("block");
33755 close.on("click", hide);
33756 var d = Roo.get(document);
33757 d.on("mousedown", onDown);
33758 d.on("mouseover", onOver);
33759 d.on("mouseout", onOut);
33760 d.on("mousemove", onMove);
33761 esc = d.addKeyListener(27, hide);
33764 dd = el.initDD("default", null, {
33765 onDrag : function(){
33769 dd.setHandleElId(tipTitle.id);
33778 * Configures a new quick tip instance and assigns it to a target element. The following config options
33781 Property Type Description
33782 ---------- --------------------- ------------------------------------------------------------------------
33783 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33785 * @param {Object} config The config object
33787 register : function(config){
33788 var cs = config instanceof Array ? config : arguments;
33789 for(var i = 0, len = cs.length; i < len; i++) {
33791 var target = c.target;
33793 if(target instanceof Array){
33794 for(var j = 0, jlen = target.length; j < jlen; j++){
33795 tagEls[target[j]] = c;
33798 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33805 * Removes this quick tip from its element and destroys it.
33806 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33808 unregister : function(el){
33809 delete tagEls[Roo.id(el)];
33813 * Enable this quick tip.
33815 enable : function(){
33816 if(inited && disabled){
33818 if(locks.length < 1){
33825 * Disable this quick tip.
33827 disable : function(){
33829 clearTimeout(showProc);
33830 clearTimeout(hideProc);
33831 clearTimeout(dismissProc);
33839 * Returns true if the quick tip is enabled, else false.
33841 isEnabled : function(){
33847 namespace : "roo", // was ext?? this may break..
33848 alt_namespace : "ext",
33849 attribute : "qtip",
33859 // backwards compat
33860 Roo.QuickTips.tips = Roo.QuickTips.register;/*
33862 * Ext JS Library 1.1.1
33863 * Copyright(c) 2006-2007, Ext JS, LLC.
33865 * Originally Released Under LGPL - original licence link has changed is not relivant.
33868 * <script type="text/javascript">
33873 * @class Roo.tree.TreePanel
33874 * @extends Roo.data.Tree
33876 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
33877 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
33878 * @cfg {Boolean} enableDD true to enable drag and drop
33879 * @cfg {Boolean} enableDrag true to enable just drag
33880 * @cfg {Boolean} enableDrop true to enable just drop
33881 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
33882 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
33883 * @cfg {String} ddGroup The DD group this TreePanel belongs to
33884 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
33885 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
33886 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
33887 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
33888 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
33889 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
33890 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
33891 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
33892 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
33893 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
33894 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
33895 * @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>
33896 * @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>
33899 * @param {String/HTMLElement/Element} el The container element
33900 * @param {Object} config
33902 Roo.tree.TreePanel = function(el, config){
33904 var loader = false;
33906 root = config.root;
33907 delete config.root;
33909 if (config.loader) {
33910 loader = config.loader;
33911 delete config.loader;
33914 Roo.apply(this, config);
33915 Roo.tree.TreePanel.superclass.constructor.call(this);
33916 this.el = Roo.get(el);
33917 this.el.addClass('x-tree');
33918 //console.log(root);
33920 this.setRootNode( Roo.factory(root, Roo.tree));
33923 this.loader = Roo.factory(loader, Roo.tree);
33926 * Read-only. The id of the container element becomes this TreePanel's id.
33928 this.id = this.el.id;
33931 * @event beforeload
33932 * Fires before a node is loaded, return false to cancel
33933 * @param {Node} node The node being loaded
33935 "beforeload" : true,
33938 * Fires when a node is loaded
33939 * @param {Node} node The node that was loaded
33943 * @event textchange
33944 * Fires when the text for a node is changed
33945 * @param {Node} node The node
33946 * @param {String} text The new text
33947 * @param {String} oldText The old text
33949 "textchange" : true,
33951 * @event beforeexpand
33952 * Fires before a node is expanded, return false to cancel.
33953 * @param {Node} node The node
33954 * @param {Boolean} deep
33955 * @param {Boolean} anim
33957 "beforeexpand" : true,
33959 * @event beforecollapse
33960 * Fires before a node is collapsed, return false to cancel.
33961 * @param {Node} node The node
33962 * @param {Boolean} deep
33963 * @param {Boolean} anim
33965 "beforecollapse" : true,
33968 * Fires when a node is expanded
33969 * @param {Node} node The node
33973 * @event disabledchange
33974 * Fires when the disabled status of a node changes
33975 * @param {Node} node The node
33976 * @param {Boolean} disabled
33978 "disabledchange" : true,
33981 * Fires when a node is collapsed
33982 * @param {Node} node The node
33986 * @event beforeclick
33987 * Fires before click processing on a node. Return false to cancel the default action.
33988 * @param {Node} node The node
33989 * @param {Roo.EventObject} e The event object
33991 "beforeclick":true,
33993 * @event checkchange
33994 * Fires when a node with a checkbox's checked property changes
33995 * @param {Node} this This node
33996 * @param {Boolean} checked
33998 "checkchange":true,
34001 * Fires when a node is clicked
34002 * @param {Node} node The node
34003 * @param {Roo.EventObject} e The event object
34008 * Fires when a node is double clicked
34009 * @param {Node} node The node
34010 * @param {Roo.EventObject} e The event object
34014 * @event contextmenu
34015 * Fires when a node is right clicked
34016 * @param {Node} node The node
34017 * @param {Roo.EventObject} e The event object
34019 "contextmenu":true,
34021 * @event beforechildrenrendered
34022 * Fires right before the child nodes for a node are rendered
34023 * @param {Node} node The node
34025 "beforechildrenrendered":true,
34028 * Fires when a node starts being dragged
34029 * @param {Roo.tree.TreePanel} this
34030 * @param {Roo.tree.TreeNode} node
34031 * @param {event} e The raw browser event
34033 "startdrag" : true,
34036 * Fires when a drag operation is complete
34037 * @param {Roo.tree.TreePanel} this
34038 * @param {Roo.tree.TreeNode} node
34039 * @param {event} e The raw browser event
34044 * Fires when a dragged node is dropped on a valid DD target
34045 * @param {Roo.tree.TreePanel} this
34046 * @param {Roo.tree.TreeNode} node
34047 * @param {DD} dd The dd it was dropped on
34048 * @param {event} e The raw browser event
34052 * @event beforenodedrop
34053 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34054 * passed to handlers has the following properties:<br />
34055 * <ul style="padding:5px;padding-left:16px;">
34056 * <li>tree - The TreePanel</li>
34057 * <li>target - The node being targeted for the drop</li>
34058 * <li>data - The drag data from the drag source</li>
34059 * <li>point - The point of the drop - append, above or below</li>
34060 * <li>source - The drag source</li>
34061 * <li>rawEvent - Raw mouse event</li>
34062 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34063 * to be inserted by setting them on this object.</li>
34064 * <li>cancel - Set this to true to cancel the drop.</li>
34066 * @param {Object} dropEvent
34068 "beforenodedrop" : true,
34071 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34072 * passed to handlers has the following properties:<br />
34073 * <ul style="padding:5px;padding-left:16px;">
34074 * <li>tree - The TreePanel</li>
34075 * <li>target - The node being targeted for the drop</li>
34076 * <li>data - The drag data from the drag source</li>
34077 * <li>point - The point of the drop - append, above or below</li>
34078 * <li>source - The drag source</li>
34079 * <li>rawEvent - Raw mouse event</li>
34080 * <li>dropNode - Dropped node(s).</li>
34082 * @param {Object} dropEvent
34086 * @event nodedragover
34087 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34088 * passed to handlers has the following properties:<br />
34089 * <ul style="padding:5px;padding-left:16px;">
34090 * <li>tree - The TreePanel</li>
34091 * <li>target - The node being targeted for the drop</li>
34092 * <li>data - The drag data from the drag source</li>
34093 * <li>point - The point of the drop - append, above or below</li>
34094 * <li>source - The drag source</li>
34095 * <li>rawEvent - Raw mouse event</li>
34096 * <li>dropNode - Drop node(s) provided by the source.</li>
34097 * <li>cancel - Set this to true to signal drop not allowed.</li>
34099 * @param {Object} dragOverEvent
34101 "nodedragover" : true
34104 if(this.singleExpand){
34105 this.on("beforeexpand", this.restrictExpand, this);
34108 this.editor.tree = this;
34109 this.editor = Roo.factory(this.editor, Roo.tree);
34112 if (this.selModel) {
34113 this.selModel = Roo.factory(this.selModel, Roo.tree);
34117 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34118 rootVisible : true,
34119 animate: Roo.enableFx,
34122 hlDrop : Roo.enableFx,
34126 rendererTip: false,
34128 restrictExpand : function(node){
34129 var p = node.parentNode;
34131 if(p.expandedChild && p.expandedChild.parentNode == p){
34132 p.expandedChild.collapse();
34134 p.expandedChild = node;
34138 // private override
34139 setRootNode : function(node){
34140 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34141 if(!this.rootVisible){
34142 node.ui = new Roo.tree.RootTreeNodeUI(node);
34148 * Returns the container element for this TreePanel
34150 getEl : function(){
34155 * Returns the default TreeLoader for this TreePanel
34157 getLoader : function(){
34158 return this.loader;
34164 expandAll : function(){
34165 this.root.expand(true);
34169 * Collapse all nodes
34171 collapseAll : function(){
34172 this.root.collapse(true);
34176 * Returns the selection model used by this TreePanel
34178 getSelectionModel : function(){
34179 if(!this.selModel){
34180 this.selModel = new Roo.tree.DefaultSelectionModel();
34182 return this.selModel;
34186 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34187 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34188 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34191 getChecked : function(a, startNode){
34192 startNode = startNode || this.root;
34194 var f = function(){
34195 if(this.attributes.checked){
34196 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34199 startNode.cascade(f);
34204 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34205 * @param {String} path
34206 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34207 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34208 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34210 expandPath : function(path, attr, callback){
34211 attr = attr || "id";
34212 var keys = path.split(this.pathSeparator);
34213 var curNode = this.root;
34214 if(curNode.attributes[attr] != keys[1]){ // invalid root
34216 callback(false, null);
34221 var f = function(){
34222 if(++index == keys.length){
34224 callback(true, curNode);
34228 var c = curNode.findChild(attr, keys[index]);
34231 callback(false, curNode);
34236 c.expand(false, false, f);
34238 curNode.expand(false, false, f);
34242 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34243 * @param {String} path
34244 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34245 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34246 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34248 selectPath : function(path, attr, callback){
34249 attr = attr || "id";
34250 var keys = path.split(this.pathSeparator);
34251 var v = keys.pop();
34252 if(keys.length > 0){
34253 var f = function(success, node){
34254 if(success && node){
34255 var n = node.findChild(attr, v);
34261 }else if(callback){
34262 callback(false, n);
34266 callback(false, n);
34270 this.expandPath(keys.join(this.pathSeparator), attr, f);
34272 this.root.select();
34274 callback(true, this.root);
34279 getTreeEl : function(){
34284 * Trigger rendering of this TreePanel
34286 render : function(){
34287 if (this.innerCt) {
34288 return this; // stop it rendering more than once!!
34291 this.innerCt = this.el.createChild({tag:"ul",
34292 cls:"x-tree-root-ct " +
34293 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34295 if(this.containerScroll){
34296 Roo.dd.ScrollManager.register(this.el);
34298 if((this.enableDD || this.enableDrop) && !this.dropZone){
34300 * The dropZone used by this tree if drop is enabled
34301 * @type Roo.tree.TreeDropZone
34303 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34304 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34307 if((this.enableDD || this.enableDrag) && !this.dragZone){
34309 * The dragZone used by this tree if drag is enabled
34310 * @type Roo.tree.TreeDragZone
34312 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34313 ddGroup: this.ddGroup || "TreeDD",
34314 scroll: this.ddScroll
34317 this.getSelectionModel().init(this);
34319 Roo.log("ROOT not set in tree");
34322 this.root.render();
34323 if(!this.rootVisible){
34324 this.root.renderChildren();
34330 * Ext JS Library 1.1.1
34331 * Copyright(c) 2006-2007, Ext JS, LLC.
34333 * Originally Released Under LGPL - original licence link has changed is not relivant.
34336 * <script type="text/javascript">
34341 * @class Roo.tree.DefaultSelectionModel
34342 * @extends Roo.util.Observable
34343 * The default single selection for a TreePanel.
34344 * @param {Object} cfg Configuration
34346 Roo.tree.DefaultSelectionModel = function(cfg){
34347 this.selNode = null;
34353 * @event selectionchange
34354 * Fires when the selected node changes
34355 * @param {DefaultSelectionModel} this
34356 * @param {TreeNode} node the new selection
34358 "selectionchange" : true,
34361 * @event beforeselect
34362 * Fires before the selected node changes, return false to cancel the change
34363 * @param {DefaultSelectionModel} this
34364 * @param {TreeNode} node the new selection
34365 * @param {TreeNode} node the old selection
34367 "beforeselect" : true
34370 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34373 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34374 init : function(tree){
34376 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34377 tree.on("click", this.onNodeClick, this);
34380 onNodeClick : function(node, e){
34381 if (e.ctrlKey && this.selNode == node) {
34382 this.unselect(node);
34390 * @param {TreeNode} node The node to select
34391 * @return {TreeNode} The selected node
34393 select : function(node){
34394 var last = this.selNode;
34395 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34397 last.ui.onSelectedChange(false);
34399 this.selNode = node;
34400 node.ui.onSelectedChange(true);
34401 this.fireEvent("selectionchange", this, node, last);
34408 * @param {TreeNode} node The node to unselect
34410 unselect : function(node){
34411 if(this.selNode == node){
34412 this.clearSelections();
34417 * Clear all selections
34419 clearSelections : function(){
34420 var n = this.selNode;
34422 n.ui.onSelectedChange(false);
34423 this.selNode = null;
34424 this.fireEvent("selectionchange", this, null);
34430 * Get the selected node
34431 * @return {TreeNode} The selected node
34433 getSelectedNode : function(){
34434 return this.selNode;
34438 * Returns true if the node is selected
34439 * @param {TreeNode} node The node to check
34440 * @return {Boolean}
34442 isSelected : function(node){
34443 return this.selNode == node;
34447 * Selects the node above the selected node in the tree, intelligently walking the nodes
34448 * @return TreeNode The new selection
34450 selectPrevious : function(){
34451 var s = this.selNode || this.lastSelNode;
34455 var ps = s.previousSibling;
34457 if(!ps.isExpanded() || ps.childNodes.length < 1){
34458 return this.select(ps);
34460 var lc = ps.lastChild;
34461 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34464 return this.select(lc);
34466 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34467 return this.select(s.parentNode);
34473 * Selects the node above the selected node in the tree, intelligently walking the nodes
34474 * @return TreeNode The new selection
34476 selectNext : function(){
34477 var s = this.selNode || this.lastSelNode;
34481 if(s.firstChild && s.isExpanded()){
34482 return this.select(s.firstChild);
34483 }else if(s.nextSibling){
34484 return this.select(s.nextSibling);
34485 }else if(s.parentNode){
34487 s.parentNode.bubble(function(){
34488 if(this.nextSibling){
34489 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34498 onKeyDown : function(e){
34499 var s = this.selNode || this.lastSelNode;
34500 // undesirable, but required
34505 var k = e.getKey();
34513 this.selectPrevious();
34516 e.preventDefault();
34517 if(s.hasChildNodes()){
34518 if(!s.isExpanded()){
34520 }else if(s.firstChild){
34521 this.select(s.firstChild, e);
34526 e.preventDefault();
34527 if(s.hasChildNodes() && s.isExpanded()){
34529 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34530 this.select(s.parentNode, e);
34538 * @class Roo.tree.MultiSelectionModel
34539 * @extends Roo.util.Observable
34540 * Multi selection for a TreePanel.
34541 * @param {Object} cfg Configuration
34543 Roo.tree.MultiSelectionModel = function(){
34544 this.selNodes = [];
34548 * @event selectionchange
34549 * Fires when the selected nodes change
34550 * @param {MultiSelectionModel} this
34551 * @param {Array} nodes Array of the selected nodes
34553 "selectionchange" : true
34555 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34559 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34560 init : function(tree){
34562 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34563 tree.on("click", this.onNodeClick, this);
34566 onNodeClick : function(node, e){
34567 this.select(node, e, e.ctrlKey);
34572 * @param {TreeNode} node The node to select
34573 * @param {EventObject} e (optional) An event associated with the selection
34574 * @param {Boolean} keepExisting True to retain existing selections
34575 * @return {TreeNode} The selected node
34577 select : function(node, e, keepExisting){
34578 if(keepExisting !== true){
34579 this.clearSelections(true);
34581 if(this.isSelected(node)){
34582 this.lastSelNode = node;
34585 this.selNodes.push(node);
34586 this.selMap[node.id] = node;
34587 this.lastSelNode = node;
34588 node.ui.onSelectedChange(true);
34589 this.fireEvent("selectionchange", this, this.selNodes);
34595 * @param {TreeNode} node The node to unselect
34597 unselect : function(node){
34598 if(this.selMap[node.id]){
34599 node.ui.onSelectedChange(false);
34600 var sn = this.selNodes;
34603 index = sn.indexOf(node);
34605 for(var i = 0, len = sn.length; i < len; i++){
34613 this.selNodes.splice(index, 1);
34615 delete this.selMap[node.id];
34616 this.fireEvent("selectionchange", this, this.selNodes);
34621 * Clear all selections
34623 clearSelections : function(suppressEvent){
34624 var sn = this.selNodes;
34626 for(var i = 0, len = sn.length; i < len; i++){
34627 sn[i].ui.onSelectedChange(false);
34629 this.selNodes = [];
34631 if(suppressEvent !== true){
34632 this.fireEvent("selectionchange", this, this.selNodes);
34638 * Returns true if the node is selected
34639 * @param {TreeNode} node The node to check
34640 * @return {Boolean}
34642 isSelected : function(node){
34643 return this.selMap[node.id] ? true : false;
34647 * Returns an array of the selected nodes
34650 getSelectedNodes : function(){
34651 return this.selNodes;
34654 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34656 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34658 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34661 * Ext JS Library 1.1.1
34662 * Copyright(c) 2006-2007, Ext JS, LLC.
34664 * Originally Released Under LGPL - original licence link has changed is not relivant.
34667 * <script type="text/javascript">
34671 * @class Roo.tree.TreeNode
34672 * @extends Roo.data.Node
34673 * @cfg {String} text The text for this node
34674 * @cfg {Boolean} expanded true to start the node expanded
34675 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34676 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34677 * @cfg {Boolean} disabled true to start the node disabled
34678 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34679 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34680 * @cfg {String} cls A css class to be added to the node
34681 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34682 * @cfg {String} href URL of the link used for the node (defaults to #)
34683 * @cfg {String} hrefTarget target frame for the link
34684 * @cfg {String} qtip An Ext QuickTip for the node
34685 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34686 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34687 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34688 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34689 * (defaults to undefined with no checkbox rendered)
34691 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34693 Roo.tree.TreeNode = function(attributes){
34694 attributes = attributes || {};
34695 if(typeof attributes == "string"){
34696 attributes = {text: attributes};
34698 this.childrenRendered = false;
34699 this.rendered = false;
34700 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34701 this.expanded = attributes.expanded === true;
34702 this.isTarget = attributes.isTarget !== false;
34703 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34704 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34707 * Read-only. The text for this node. To change it use setText().
34710 this.text = attributes.text;
34712 * True if this node is disabled.
34715 this.disabled = attributes.disabled === true;
34719 * @event textchange
34720 * Fires when the text for this node is changed
34721 * @param {Node} this This node
34722 * @param {String} text The new text
34723 * @param {String} oldText The old text
34725 "textchange" : true,
34727 * @event beforeexpand
34728 * Fires before this node is expanded, return false to cancel.
34729 * @param {Node} this This node
34730 * @param {Boolean} deep
34731 * @param {Boolean} anim
34733 "beforeexpand" : true,
34735 * @event beforecollapse
34736 * Fires before this node is collapsed, return false to cancel.
34737 * @param {Node} this This node
34738 * @param {Boolean} deep
34739 * @param {Boolean} anim
34741 "beforecollapse" : true,
34744 * Fires when this node is expanded
34745 * @param {Node} this This node
34749 * @event disabledchange
34750 * Fires when the disabled status of this node changes
34751 * @param {Node} this This node
34752 * @param {Boolean} disabled
34754 "disabledchange" : true,
34757 * Fires when this node is collapsed
34758 * @param {Node} this This node
34762 * @event beforeclick
34763 * Fires before click processing. Return false to cancel the default action.
34764 * @param {Node} this This node
34765 * @param {Roo.EventObject} e The event object
34767 "beforeclick":true,
34769 * @event checkchange
34770 * Fires when a node with a checkbox's checked property changes
34771 * @param {Node} this This node
34772 * @param {Boolean} checked
34774 "checkchange":true,
34777 * Fires when this node is clicked
34778 * @param {Node} this This node
34779 * @param {Roo.EventObject} e The event object
34784 * Fires when this node is double clicked
34785 * @param {Node} this This node
34786 * @param {Roo.EventObject} e The event object
34790 * @event contextmenu
34791 * Fires when this node is right clicked
34792 * @param {Node} this This node
34793 * @param {Roo.EventObject} e The event object
34795 "contextmenu":true,
34797 * @event beforechildrenrendered
34798 * Fires right before the child nodes for this node are rendered
34799 * @param {Node} this This node
34801 "beforechildrenrendered":true
34804 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34807 * Read-only. The UI for this node
34810 this.ui = new uiClass(this);
34812 // finally support items[]
34813 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34818 Roo.each(this.attributes.items, function(c) {
34819 this.appendChild(Roo.factory(c,Roo.Tree));
34821 delete this.attributes.items;
34826 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34827 preventHScroll: true,
34829 * Returns true if this node is expanded
34830 * @return {Boolean}
34832 isExpanded : function(){
34833 return this.expanded;
34837 * Returns the UI object for this node
34838 * @return {TreeNodeUI}
34840 getUI : function(){
34844 // private override
34845 setFirstChild : function(node){
34846 var of = this.firstChild;
34847 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
34848 if(this.childrenRendered && of && node != of){
34849 of.renderIndent(true, true);
34852 this.renderIndent(true, true);
34856 // private override
34857 setLastChild : function(node){
34858 var ol = this.lastChild;
34859 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
34860 if(this.childrenRendered && ol && node != ol){
34861 ol.renderIndent(true, true);
34864 this.renderIndent(true, true);
34868 // these methods are overridden to provide lazy rendering support
34869 // private override
34870 appendChild : function()
34872 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
34873 if(node && this.childrenRendered){
34876 this.ui.updateExpandIcon();
34880 // private override
34881 removeChild : function(node){
34882 this.ownerTree.getSelectionModel().unselect(node);
34883 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
34884 // if it's been rendered remove dom node
34885 if(this.childrenRendered){
34888 if(this.childNodes.length < 1){
34889 this.collapse(false, false);
34891 this.ui.updateExpandIcon();
34893 if(!this.firstChild) {
34894 this.childrenRendered = false;
34899 // private override
34900 insertBefore : function(node, refNode){
34901 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
34902 if(newNode && refNode && this.childrenRendered){
34905 this.ui.updateExpandIcon();
34910 * Sets the text for this node
34911 * @param {String} text
34913 setText : function(text){
34914 var oldText = this.text;
34916 this.attributes.text = text;
34917 if(this.rendered){ // event without subscribing
34918 this.ui.onTextChange(this, text, oldText);
34920 this.fireEvent("textchange", this, text, oldText);
34924 * Triggers selection of this node
34926 select : function(){
34927 this.getOwnerTree().getSelectionModel().select(this);
34931 * Triggers deselection of this node
34933 unselect : function(){
34934 this.getOwnerTree().getSelectionModel().unselect(this);
34938 * Returns true if this node is selected
34939 * @return {Boolean}
34941 isSelected : function(){
34942 return this.getOwnerTree().getSelectionModel().isSelected(this);
34946 * Expand this node.
34947 * @param {Boolean} deep (optional) True to expand all children as well
34948 * @param {Boolean} anim (optional) false to cancel the default animation
34949 * @param {Function} callback (optional) A callback to be called when
34950 * expanding this node completes (does not wait for deep expand to complete).
34951 * Called with 1 parameter, this node.
34953 expand : function(deep, anim, callback){
34954 if(!this.expanded){
34955 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
34958 if(!this.childrenRendered){
34959 this.renderChildren();
34961 this.expanded = true;
34962 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
34963 this.ui.animExpand(function(){
34964 this.fireEvent("expand", this);
34965 if(typeof callback == "function"){
34969 this.expandChildNodes(true);
34971 }.createDelegate(this));
34975 this.fireEvent("expand", this);
34976 if(typeof callback == "function"){
34981 if(typeof callback == "function"){
34986 this.expandChildNodes(true);
34990 isHiddenRoot : function(){
34991 return this.isRoot && !this.getOwnerTree().rootVisible;
34995 * Collapse this node.
34996 * @param {Boolean} deep (optional) True to collapse all children as well
34997 * @param {Boolean} anim (optional) false to cancel the default animation
34999 collapse : function(deep, anim){
35000 if(this.expanded && !this.isHiddenRoot()){
35001 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35004 this.expanded = false;
35005 if((this.getOwnerTree().animate && anim !== false) || anim){
35006 this.ui.animCollapse(function(){
35007 this.fireEvent("collapse", this);
35009 this.collapseChildNodes(true);
35011 }.createDelegate(this));
35014 this.ui.collapse();
35015 this.fireEvent("collapse", this);
35019 var cs = this.childNodes;
35020 for(var i = 0, len = cs.length; i < len; i++) {
35021 cs[i].collapse(true, false);
35027 delayedExpand : function(delay){
35028 if(!this.expandProcId){
35029 this.expandProcId = this.expand.defer(delay, this);
35034 cancelExpand : function(){
35035 if(this.expandProcId){
35036 clearTimeout(this.expandProcId);
35038 this.expandProcId = false;
35042 * Toggles expanded/collapsed state of the node
35044 toggle : function(){
35053 * Ensures all parent nodes are expanded
35055 ensureVisible : function(callback){
35056 var tree = this.getOwnerTree();
35057 tree.expandPath(this.parentNode.getPath(), false, function(){
35058 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35059 Roo.callback(callback);
35060 }.createDelegate(this));
35064 * Expand all child nodes
35065 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35067 expandChildNodes : function(deep){
35068 var cs = this.childNodes;
35069 for(var i = 0, len = cs.length; i < len; i++) {
35070 cs[i].expand(deep);
35075 * Collapse all child nodes
35076 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35078 collapseChildNodes : function(deep){
35079 var cs = this.childNodes;
35080 for(var i = 0, len = cs.length; i < len; i++) {
35081 cs[i].collapse(deep);
35086 * Disables this node
35088 disable : function(){
35089 this.disabled = true;
35091 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35092 this.ui.onDisableChange(this, true);
35094 this.fireEvent("disabledchange", this, true);
35098 * Enables this node
35100 enable : function(){
35101 this.disabled = false;
35102 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35103 this.ui.onDisableChange(this, false);
35105 this.fireEvent("disabledchange", this, false);
35109 renderChildren : function(suppressEvent){
35110 if(suppressEvent !== false){
35111 this.fireEvent("beforechildrenrendered", this);
35113 var cs = this.childNodes;
35114 for(var i = 0, len = cs.length; i < len; i++){
35115 cs[i].render(true);
35117 this.childrenRendered = true;
35121 sort : function(fn, scope){
35122 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35123 if(this.childrenRendered){
35124 var cs = this.childNodes;
35125 for(var i = 0, len = cs.length; i < len; i++){
35126 cs[i].render(true);
35132 render : function(bulkRender){
35133 this.ui.render(bulkRender);
35134 if(!this.rendered){
35135 this.rendered = true;
35137 this.expanded = false;
35138 this.expand(false, false);
35144 renderIndent : function(deep, refresh){
35146 this.ui.childIndent = null;
35148 this.ui.renderIndent();
35149 if(deep === true && this.childrenRendered){
35150 var cs = this.childNodes;
35151 for(var i = 0, len = cs.length; i < len; i++){
35152 cs[i].renderIndent(true, refresh);
35158 * Ext JS Library 1.1.1
35159 * Copyright(c) 2006-2007, Ext JS, LLC.
35161 * Originally Released Under LGPL - original licence link has changed is not relivant.
35164 * <script type="text/javascript">
35168 * @class Roo.tree.AsyncTreeNode
35169 * @extends Roo.tree.TreeNode
35170 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35172 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35174 Roo.tree.AsyncTreeNode = function(config){
35175 this.loaded = false;
35176 this.loading = false;
35177 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35179 * @event beforeload
35180 * Fires before this node is loaded, return false to cancel
35181 * @param {Node} this This node
35183 this.addEvents({'beforeload':true, 'load': true});
35186 * Fires when this node is loaded
35187 * @param {Node} this This node
35190 * The loader used by this node (defaults to using the tree's defined loader)
35195 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35196 expand : function(deep, anim, callback){
35197 if(this.loading){ // if an async load is already running, waiting til it's done
35199 var f = function(){
35200 if(!this.loading){ // done loading
35201 clearInterval(timer);
35202 this.expand(deep, anim, callback);
35204 }.createDelegate(this);
35205 timer = setInterval(f, 200);
35209 if(this.fireEvent("beforeload", this) === false){
35212 this.loading = true;
35213 this.ui.beforeLoad(this);
35214 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35216 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35220 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35224 * Returns true if this node is currently loading
35225 * @return {Boolean}
35227 isLoading : function(){
35228 return this.loading;
35231 loadComplete : function(deep, anim, callback){
35232 this.loading = false;
35233 this.loaded = true;
35234 this.ui.afterLoad(this);
35235 this.fireEvent("load", this);
35236 this.expand(deep, anim, callback);
35240 * Returns true if this node has been loaded
35241 * @return {Boolean}
35243 isLoaded : function(){
35244 return this.loaded;
35247 hasChildNodes : function(){
35248 if(!this.isLeaf() && !this.loaded){
35251 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35256 * Trigger a reload for this node
35257 * @param {Function} callback
35259 reload : function(callback){
35260 this.collapse(false, false);
35261 while(this.firstChild){
35262 this.removeChild(this.firstChild);
35264 this.childrenRendered = false;
35265 this.loaded = false;
35266 if(this.isHiddenRoot()){
35267 this.expanded = false;
35269 this.expand(false, false, callback);
35273 * Ext JS Library 1.1.1
35274 * Copyright(c) 2006-2007, Ext JS, LLC.
35276 * Originally Released Under LGPL - original licence link has changed is not relivant.
35279 * <script type="text/javascript">
35283 * @class Roo.tree.TreeNodeUI
35285 * @param {Object} node The node to render
35286 * The TreeNode UI implementation is separate from the
35287 * tree implementation. Unless you are customizing the tree UI,
35288 * you should never have to use this directly.
35290 Roo.tree.TreeNodeUI = function(node){
35292 this.rendered = false;
35293 this.animating = false;
35294 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35297 Roo.tree.TreeNodeUI.prototype = {
35298 removeChild : function(node){
35300 this.ctNode.removeChild(node.ui.getEl());
35304 beforeLoad : function(){
35305 this.addClass("x-tree-node-loading");
35308 afterLoad : function(){
35309 this.removeClass("x-tree-node-loading");
35312 onTextChange : function(node, text, oldText){
35314 this.textNode.innerHTML = text;
35318 onDisableChange : function(node, state){
35319 this.disabled = state;
35321 this.addClass("x-tree-node-disabled");
35323 this.removeClass("x-tree-node-disabled");
35327 onSelectedChange : function(state){
35330 this.addClass("x-tree-selected");
35333 this.removeClass("x-tree-selected");
35337 onMove : function(tree, node, oldParent, newParent, index, refNode){
35338 this.childIndent = null;
35340 var targetNode = newParent.ui.getContainer();
35341 if(!targetNode){//target not rendered
35342 this.holder = document.createElement("div");
35343 this.holder.appendChild(this.wrap);
35346 var insertBefore = refNode ? refNode.ui.getEl() : null;
35348 targetNode.insertBefore(this.wrap, insertBefore);
35350 targetNode.appendChild(this.wrap);
35352 this.node.renderIndent(true);
35356 addClass : function(cls){
35358 Roo.fly(this.elNode).addClass(cls);
35362 removeClass : function(cls){
35364 Roo.fly(this.elNode).removeClass(cls);
35368 remove : function(){
35370 this.holder = document.createElement("div");
35371 this.holder.appendChild(this.wrap);
35375 fireEvent : function(){
35376 return this.node.fireEvent.apply(this.node, arguments);
35379 initEvents : function(){
35380 this.node.on("move", this.onMove, this);
35381 var E = Roo.EventManager;
35382 var a = this.anchor;
35384 var el = Roo.fly(a, '_treeui');
35386 if(Roo.isOpera){ // opera render bug ignores the CSS
35387 el.setStyle("text-decoration", "none");
35390 el.on("click", this.onClick, this);
35391 el.on("dblclick", this.onDblClick, this);
35394 Roo.EventManager.on(this.checkbox,
35395 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35398 el.on("contextmenu", this.onContextMenu, this);
35400 var icon = Roo.fly(this.iconNode);
35401 icon.on("click", this.onClick, this);
35402 icon.on("dblclick", this.onDblClick, this);
35403 icon.on("contextmenu", this.onContextMenu, this);
35404 E.on(this.ecNode, "click", this.ecClick, this, true);
35406 if(this.node.disabled){
35407 this.addClass("x-tree-node-disabled");
35409 if(this.node.hidden){
35410 this.addClass("x-tree-node-disabled");
35412 var ot = this.node.getOwnerTree();
35413 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35414 if(dd && (!this.node.isRoot || ot.rootVisible)){
35415 Roo.dd.Registry.register(this.elNode, {
35417 handles: this.getDDHandles(),
35423 getDDHandles : function(){
35424 return [this.iconNode, this.textNode];
35429 this.wrap.style.display = "none";
35435 this.wrap.style.display = "";
35439 onContextMenu : function(e){
35440 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35441 e.preventDefault();
35443 this.fireEvent("contextmenu", this.node, e);
35447 onClick : function(e){
35452 if(this.fireEvent("beforeclick", this.node, e) !== false){
35453 if(!this.disabled && this.node.attributes.href){
35454 this.fireEvent("click", this.node, e);
35457 e.preventDefault();
35462 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35463 this.node.toggle();
35466 this.fireEvent("click", this.node, e);
35472 onDblClick : function(e){
35473 e.preventDefault();
35478 this.toggleCheck();
35480 if(!this.animating && this.node.hasChildNodes()){
35481 this.node.toggle();
35483 this.fireEvent("dblclick", this.node, e);
35486 onCheckChange : function(){
35487 var checked = this.checkbox.checked;
35488 this.node.attributes.checked = checked;
35489 this.fireEvent('checkchange', this.node, checked);
35492 ecClick : function(e){
35493 if(!this.animating && this.node.hasChildNodes()){
35494 this.node.toggle();
35498 startDrop : function(){
35499 this.dropping = true;
35502 // delayed drop so the click event doesn't get fired on a drop
35503 endDrop : function(){
35504 setTimeout(function(){
35505 this.dropping = false;
35506 }.createDelegate(this), 50);
35509 expand : function(){
35510 this.updateExpandIcon();
35511 this.ctNode.style.display = "";
35514 focus : function(){
35515 if(!this.node.preventHScroll){
35516 try{this.anchor.focus();
35518 }else if(!Roo.isIE){
35520 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35521 var l = noscroll.scrollLeft;
35522 this.anchor.focus();
35523 noscroll.scrollLeft = l;
35528 toggleCheck : function(value){
35529 var cb = this.checkbox;
35531 cb.checked = (value === undefined ? !cb.checked : value);
35537 this.anchor.blur();
35541 animExpand : function(callback){
35542 var ct = Roo.get(this.ctNode);
35544 if(!this.node.hasChildNodes()){
35545 this.updateExpandIcon();
35546 this.ctNode.style.display = "";
35547 Roo.callback(callback);
35550 this.animating = true;
35551 this.updateExpandIcon();
35554 callback : function(){
35555 this.animating = false;
35556 Roo.callback(callback);
35559 duration: this.node.ownerTree.duration || .25
35563 highlight : function(){
35564 var tree = this.node.getOwnerTree();
35565 Roo.fly(this.wrap).highlight(
35566 tree.hlColor || "C3DAF9",
35567 {endColor: tree.hlBaseColor}
35571 collapse : function(){
35572 this.updateExpandIcon();
35573 this.ctNode.style.display = "none";
35576 animCollapse : function(callback){
35577 var ct = Roo.get(this.ctNode);
35578 ct.enableDisplayMode('block');
35581 this.animating = true;
35582 this.updateExpandIcon();
35585 callback : function(){
35586 this.animating = false;
35587 Roo.callback(callback);
35590 duration: this.node.ownerTree.duration || .25
35594 getContainer : function(){
35595 return this.ctNode;
35598 getEl : function(){
35602 appendDDGhost : function(ghostNode){
35603 ghostNode.appendChild(this.elNode.cloneNode(true));
35606 getDDRepairXY : function(){
35607 return Roo.lib.Dom.getXY(this.iconNode);
35610 onRender : function(){
35614 render : function(bulkRender){
35615 var n = this.node, a = n.attributes;
35616 var targetNode = n.parentNode ?
35617 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35619 if(!this.rendered){
35620 this.rendered = true;
35622 this.renderElements(n, a, targetNode, bulkRender);
35625 if(this.textNode.setAttributeNS){
35626 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35628 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35631 this.textNode.setAttribute("ext:qtip", a.qtip);
35633 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35636 }else if(a.qtipCfg){
35637 a.qtipCfg.target = Roo.id(this.textNode);
35638 Roo.QuickTips.register(a.qtipCfg);
35641 if(!this.node.expanded){
35642 this.updateExpandIcon();
35645 if(bulkRender === true) {
35646 targetNode.appendChild(this.wrap);
35651 renderElements : function(n, a, targetNode, bulkRender)
35653 // add some indent caching, this helps performance when rendering a large tree
35654 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35655 var t = n.getOwnerTree();
35656 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35657 if (typeof(n.attributes.html) != 'undefined') {
35658 txt = n.attributes.html;
35660 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35661 var cb = typeof a.checked == 'boolean';
35662 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35663 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35664 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35665 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35666 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35667 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35668 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35669 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35670 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35671 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35674 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35675 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35676 n.nextSibling.ui.getEl(), buf.join(""));
35678 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35681 this.elNode = this.wrap.childNodes[0];
35682 this.ctNode = this.wrap.childNodes[1];
35683 var cs = this.elNode.childNodes;
35684 this.indentNode = cs[0];
35685 this.ecNode = cs[1];
35686 this.iconNode = cs[2];
35689 this.checkbox = cs[3];
35692 this.anchor = cs[index];
35693 this.textNode = cs[index].firstChild;
35696 getAnchor : function(){
35697 return this.anchor;
35700 getTextEl : function(){
35701 return this.textNode;
35704 getIconEl : function(){
35705 return this.iconNode;
35708 isChecked : function(){
35709 return this.checkbox ? this.checkbox.checked : false;
35712 updateExpandIcon : function(){
35714 var n = this.node, c1, c2;
35715 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35716 var hasChild = n.hasChildNodes();
35720 c1 = "x-tree-node-collapsed";
35721 c2 = "x-tree-node-expanded";
35724 c1 = "x-tree-node-expanded";
35725 c2 = "x-tree-node-collapsed";
35728 this.removeClass("x-tree-node-leaf");
35729 this.wasLeaf = false;
35731 if(this.c1 != c1 || this.c2 != c2){
35732 Roo.fly(this.elNode).replaceClass(c1, c2);
35733 this.c1 = c1; this.c2 = c2;
35736 // this changes non-leafs into leafs if they have no children.
35737 // it's not very rational behaviour..
35739 if(!this.wasLeaf && this.node.leaf){
35740 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35743 this.wasLeaf = true;
35746 var ecc = "x-tree-ec-icon "+cls;
35747 if(this.ecc != ecc){
35748 this.ecNode.className = ecc;
35754 getChildIndent : function(){
35755 if(!this.childIndent){
35759 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35761 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35763 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35768 this.childIndent = buf.join("");
35770 return this.childIndent;
35773 renderIndent : function(){
35776 var p = this.node.parentNode;
35778 indent = p.ui.getChildIndent();
35780 if(this.indentMarkup != indent){ // don't rerender if not required
35781 this.indentNode.innerHTML = indent;
35782 this.indentMarkup = indent;
35784 this.updateExpandIcon();
35789 Roo.tree.RootTreeNodeUI = function(){
35790 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35792 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35793 render : function(){
35794 if(!this.rendered){
35795 var targetNode = this.node.ownerTree.innerCt.dom;
35796 this.node.expanded = true;
35797 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35798 this.wrap = this.ctNode = targetNode.firstChild;
35801 collapse : function(){
35803 expand : function(){
35807 * Ext JS Library 1.1.1
35808 * Copyright(c) 2006-2007, Ext JS, LLC.
35810 * Originally Released Under LGPL - original licence link has changed is not relivant.
35813 * <script type="text/javascript">
35816 * @class Roo.tree.TreeLoader
35817 * @extends Roo.util.Observable
35818 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35819 * nodes from a specified URL. The response must be a javascript Array definition
35820 * who's elements are node definition objects. eg:
35825 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35826 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
35833 * The old style respose with just an array is still supported, but not recommended.
35836 * A server request is sent, and child nodes are loaded only when a node is expanded.
35837 * The loading node's id is passed to the server under the parameter name "node" to
35838 * enable the server to produce the correct child nodes.
35840 * To pass extra parameters, an event handler may be attached to the "beforeload"
35841 * event, and the parameters specified in the TreeLoader's baseParams property:
35843 myTreeLoader.on("beforeload", function(treeLoader, node) {
35844 this.baseParams.category = node.attributes.category;
35847 * This would pass an HTTP parameter called "category" to the server containing
35848 * the value of the Node's "category" attribute.
35850 * Creates a new Treeloader.
35851 * @param {Object} config A config object containing config properties.
35853 Roo.tree.TreeLoader = function(config){
35854 this.baseParams = {};
35855 this.requestMethod = "POST";
35856 Roo.apply(this, config);
35861 * @event beforeload
35862 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
35863 * @param {Object} This TreeLoader object.
35864 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35865 * @param {Object} callback The callback function specified in the {@link #load} call.
35870 * Fires when the node has been successfuly loaded.
35871 * @param {Object} This TreeLoader object.
35872 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35873 * @param {Object} response The response object containing the data from the server.
35877 * @event loadexception
35878 * Fires if the network request failed.
35879 * @param {Object} This TreeLoader object.
35880 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35881 * @param {Object} response The response object containing the data from the server.
35883 loadexception : true,
35886 * Fires before a node is created, enabling you to return custom Node types
35887 * @param {Object} This TreeLoader object.
35888 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
35893 Roo.tree.TreeLoader.superclass.constructor.call(this);
35896 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
35898 * @cfg {String} dataUrl The URL from which to request a Json string which
35899 * specifies an array of node definition object representing the child nodes
35903 * @cfg {String} requestMethod either GET or POST
35904 * defaults to POST (due to BC)
35908 * @cfg {Object} baseParams (optional) An object containing properties which
35909 * specify HTTP parameters to be passed to each request for child nodes.
35912 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
35913 * created by this loader. If the attributes sent by the server have an attribute in this object,
35914 * they take priority.
35917 * @cfg {Object} uiProviders (optional) An object containing properties which
35919 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
35920 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
35921 * <i>uiProvider</i> attribute of a returned child node is a string rather
35922 * than a reference to a TreeNodeUI implementation, this that string value
35923 * is used as a property name in the uiProviders object. You can define the provider named
35924 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
35929 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
35930 * child nodes before loading.
35932 clearOnLoad : true,
35935 * @cfg {String} root (optional) Default to false. Use this to read data from an object
35936 * property on loading, rather than expecting an array. (eg. more compatible to a standard
35937 * Grid query { data : [ .....] }
35942 * @cfg {String} queryParam (optional)
35943 * Name of the query as it will be passed on the querystring (defaults to 'node')
35944 * eg. the request will be ?node=[id]
35951 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
35952 * This is called automatically when a node is expanded, but may be used to reload
35953 * a node (or append new children if the {@link #clearOnLoad} option is false.)
35954 * @param {Roo.tree.TreeNode} node
35955 * @param {Function} callback
35957 load : function(node, callback){
35958 if(this.clearOnLoad){
35959 while(node.firstChild){
35960 node.removeChild(node.firstChild);
35963 if(node.attributes.children){ // preloaded json children
35964 var cs = node.attributes.children;
35965 for(var i = 0, len = cs.length; i < len; i++){
35966 node.appendChild(this.createNode(cs[i]));
35968 if(typeof callback == "function"){
35971 }else if(this.dataUrl){
35972 this.requestData(node, callback);
35976 getParams: function(node){
35977 var buf = [], bp = this.baseParams;
35978 for(var key in bp){
35979 if(typeof bp[key] != "function"){
35980 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
35983 var n = this.queryParam === false ? 'node' : this.queryParam;
35984 buf.push(n + "=", encodeURIComponent(node.id));
35985 return buf.join("");
35988 requestData : function(node, callback){
35989 if(this.fireEvent("beforeload", this, node, callback) !== false){
35990 this.transId = Roo.Ajax.request({
35991 method:this.requestMethod,
35992 url: this.dataUrl||this.url,
35993 success: this.handleResponse,
35994 failure: this.handleFailure,
35996 argument: {callback: callback, node: node},
35997 params: this.getParams(node)
36000 // if the load is cancelled, make sure we notify
36001 // the node that we are done
36002 if(typeof callback == "function"){
36008 isLoading : function(){
36009 return this.transId ? true : false;
36012 abort : function(){
36013 if(this.isLoading()){
36014 Roo.Ajax.abort(this.transId);
36019 createNode : function(attr)
36021 // apply baseAttrs, nice idea Corey!
36022 if(this.baseAttrs){
36023 Roo.applyIf(attr, this.baseAttrs);
36025 if(this.applyLoader !== false){
36026 attr.loader = this;
36028 // uiProvider = depreciated..
36030 if(typeof(attr.uiProvider) == 'string'){
36031 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36032 /** eval:var:attr */ eval(attr.uiProvider);
36034 if(typeof(this.uiProviders['default']) != 'undefined') {
36035 attr.uiProvider = this.uiProviders['default'];
36038 this.fireEvent('create', this, attr);
36040 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36042 new Roo.tree.TreeNode(attr) :
36043 new Roo.tree.AsyncTreeNode(attr));
36046 processResponse : function(response, node, callback)
36048 var json = response.responseText;
36051 var o = Roo.decode(json);
36053 if (this.root === false && typeof(o.success) != undefined) {
36054 this.root = 'data'; // the default behaviour for list like data..
36057 if (this.root !== false && !o.success) {
36058 // it's a failure condition.
36059 var a = response.argument;
36060 this.fireEvent("loadexception", this, a.node, response);
36061 Roo.log("Load failed - should have a handler really");
36067 if (this.root !== false) {
36071 for(var i = 0, len = o.length; i < len; i++){
36072 var n = this.createNode(o[i]);
36074 node.appendChild(n);
36077 if(typeof callback == "function"){
36078 callback(this, node);
36081 this.handleFailure(response);
36085 handleResponse : function(response){
36086 this.transId = false;
36087 var a = response.argument;
36088 this.processResponse(response, a.node, a.callback);
36089 this.fireEvent("load", this, a.node, response);
36092 handleFailure : function(response)
36094 // should handle failure better..
36095 this.transId = false;
36096 var a = response.argument;
36097 this.fireEvent("loadexception", this, a.node, response);
36098 if(typeof a.callback == "function"){
36099 a.callback(this, a.node);
36104 * Ext JS Library 1.1.1
36105 * Copyright(c) 2006-2007, Ext JS, LLC.
36107 * Originally Released Under LGPL - original licence link has changed is not relivant.
36110 * <script type="text/javascript">
36114 * @class Roo.tree.TreeFilter
36115 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36116 * @param {TreePanel} tree
36117 * @param {Object} config (optional)
36119 Roo.tree.TreeFilter = function(tree, config){
36121 this.filtered = {};
36122 Roo.apply(this, config);
36125 Roo.tree.TreeFilter.prototype = {
36132 * Filter the data by a specific attribute.
36133 * @param {String/RegExp} value Either string that the attribute value
36134 * should start with or a RegExp to test against the attribute
36135 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36136 * @param {TreeNode} startNode (optional) The node to start the filter at.
36138 filter : function(value, attr, startNode){
36139 attr = attr || "text";
36141 if(typeof value == "string"){
36142 var vlen = value.length;
36143 // auto clear empty filter
36144 if(vlen == 0 && this.clearBlank){
36148 value = value.toLowerCase();
36150 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36152 }else if(value.exec){ // regex?
36154 return value.test(n.attributes[attr]);
36157 throw 'Illegal filter type, must be string or regex';
36159 this.filterBy(f, null, startNode);
36163 * Filter by a function. The passed function will be called with each
36164 * node in the tree (or from the startNode). If the function returns true, the node is kept
36165 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36166 * @param {Function} fn The filter function
36167 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36169 filterBy : function(fn, scope, startNode){
36170 startNode = startNode || this.tree.root;
36171 if(this.autoClear){
36174 var af = this.filtered, rv = this.reverse;
36175 var f = function(n){
36176 if(n == startNode){
36182 var m = fn.call(scope || n, n);
36190 startNode.cascade(f);
36193 if(typeof id != "function"){
36195 if(n && n.parentNode){
36196 n.parentNode.removeChild(n);
36204 * Clears the current filter. Note: with the "remove" option
36205 * set a filter cannot be cleared.
36207 clear : function(){
36209 var af = this.filtered;
36211 if(typeof id != "function"){
36218 this.filtered = {};
36223 * Ext JS Library 1.1.1
36224 * Copyright(c) 2006-2007, Ext JS, LLC.
36226 * Originally Released Under LGPL - original licence link has changed is not relivant.
36229 * <script type="text/javascript">
36234 * @class Roo.tree.TreeSorter
36235 * Provides sorting of nodes in a TreePanel
36237 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36238 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36239 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36240 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36241 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36242 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36244 * @param {TreePanel} tree
36245 * @param {Object} config
36247 Roo.tree.TreeSorter = function(tree, config){
36248 Roo.apply(this, config);
36249 tree.on("beforechildrenrendered", this.doSort, this);
36250 tree.on("append", this.updateSort, this);
36251 tree.on("insert", this.updateSort, this);
36253 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36254 var p = this.property || "text";
36255 var sortType = this.sortType;
36256 var fs = this.folderSort;
36257 var cs = this.caseSensitive === true;
36258 var leafAttr = this.leafAttr || 'leaf';
36260 this.sortFn = function(n1, n2){
36262 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36265 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36269 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36270 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36272 return dsc ? +1 : -1;
36274 return dsc ? -1 : +1;
36281 Roo.tree.TreeSorter.prototype = {
36282 doSort : function(node){
36283 node.sort(this.sortFn);
36286 compareNodes : function(n1, n2){
36287 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36290 updateSort : function(tree, node){
36291 if(node.childrenRendered){
36292 this.doSort.defer(1, this, [node]);
36297 * Ext JS Library 1.1.1
36298 * Copyright(c) 2006-2007, Ext JS, LLC.
36300 * Originally Released Under LGPL - original licence link has changed is not relivant.
36303 * <script type="text/javascript">
36306 if(Roo.dd.DropZone){
36308 Roo.tree.TreeDropZone = function(tree, config){
36309 this.allowParentInsert = false;
36310 this.allowContainerDrop = false;
36311 this.appendOnly = false;
36312 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36314 this.lastInsertClass = "x-tree-no-status";
36315 this.dragOverData = {};
36318 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36319 ddGroup : "TreeDD",
36322 expandDelay : 1000,
36324 expandNode : function(node){
36325 if(node.hasChildNodes() && !node.isExpanded()){
36326 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36330 queueExpand : function(node){
36331 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36334 cancelExpand : function(){
36335 if(this.expandProcId){
36336 clearTimeout(this.expandProcId);
36337 this.expandProcId = false;
36341 isValidDropPoint : function(n, pt, dd, e, data){
36342 if(!n || !data){ return false; }
36343 var targetNode = n.node;
36344 var dropNode = data.node;
36345 // default drop rules
36346 if(!(targetNode && targetNode.isTarget && pt)){
36349 if(pt == "append" && targetNode.allowChildren === false){
36352 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36355 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36358 // reuse the object
36359 var overEvent = this.dragOverData;
36360 overEvent.tree = this.tree;
36361 overEvent.target = targetNode;
36362 overEvent.data = data;
36363 overEvent.point = pt;
36364 overEvent.source = dd;
36365 overEvent.rawEvent = e;
36366 overEvent.dropNode = dropNode;
36367 overEvent.cancel = false;
36368 var result = this.tree.fireEvent("nodedragover", overEvent);
36369 return overEvent.cancel === false && result !== false;
36372 getDropPoint : function(e, n, dd)
36376 return tn.allowChildren !== false ? "append" : false; // always append for root
36378 var dragEl = n.ddel;
36379 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36380 var y = Roo.lib.Event.getPageY(e);
36381 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36383 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36384 var noAppend = tn.allowChildren === false;
36385 if(this.appendOnly || tn.parentNode.allowChildren === false){
36386 return noAppend ? false : "append";
36388 var noBelow = false;
36389 if(!this.allowParentInsert){
36390 noBelow = tn.hasChildNodes() && tn.isExpanded();
36392 var q = (b - t) / (noAppend ? 2 : 3);
36393 if(y >= t && y < (t + q)){
36395 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36402 onNodeEnter : function(n, dd, e, data)
36404 this.cancelExpand();
36407 onNodeOver : function(n, dd, e, data)
36410 var pt = this.getDropPoint(e, n, dd);
36413 // auto node expand check
36414 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36415 this.queueExpand(node);
36416 }else if(pt != "append"){
36417 this.cancelExpand();
36420 // set the insert point style on the target node
36421 var returnCls = this.dropNotAllowed;
36422 if(this.isValidDropPoint(n, pt, dd, e, data)){
36427 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36428 cls = "x-tree-drag-insert-above";
36429 }else if(pt == "below"){
36430 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36431 cls = "x-tree-drag-insert-below";
36433 returnCls = "x-tree-drop-ok-append";
36434 cls = "x-tree-drag-append";
36436 if(this.lastInsertClass != cls){
36437 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36438 this.lastInsertClass = cls;
36445 onNodeOut : function(n, dd, e, data){
36447 this.cancelExpand();
36448 this.removeDropIndicators(n);
36451 onNodeDrop : function(n, dd, e, data){
36452 var point = this.getDropPoint(e, n, dd);
36453 var targetNode = n.node;
36454 targetNode.ui.startDrop();
36455 if(!this.isValidDropPoint(n, point, dd, e, data)){
36456 targetNode.ui.endDrop();
36459 // first try to find the drop node
36460 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36463 target: targetNode,
36468 dropNode: dropNode,
36471 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36472 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36473 targetNode.ui.endDrop();
36476 // allow target changing
36477 targetNode = dropEvent.target;
36478 if(point == "append" && !targetNode.isExpanded()){
36479 targetNode.expand(false, null, function(){
36480 this.completeDrop(dropEvent);
36481 }.createDelegate(this));
36483 this.completeDrop(dropEvent);
36488 completeDrop : function(de){
36489 var ns = de.dropNode, p = de.point, t = de.target;
36490 if(!(ns instanceof Array)){
36494 for(var i = 0, len = ns.length; i < len; i++){
36497 t.parentNode.insertBefore(n, t);
36498 }else if(p == "below"){
36499 t.parentNode.insertBefore(n, t.nextSibling);
36505 if(this.tree.hlDrop){
36509 this.tree.fireEvent("nodedrop", de);
36512 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36513 if(this.tree.hlDrop){
36514 dropNode.ui.focus();
36515 dropNode.ui.highlight();
36517 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36520 getTree : function(){
36524 removeDropIndicators : function(n){
36527 Roo.fly(el).removeClass([
36528 "x-tree-drag-insert-above",
36529 "x-tree-drag-insert-below",
36530 "x-tree-drag-append"]);
36531 this.lastInsertClass = "_noclass";
36535 beforeDragDrop : function(target, e, id){
36536 this.cancelExpand();
36540 afterRepair : function(data){
36541 if(data && Roo.enableFx){
36542 data.node.ui.highlight();
36552 * Ext JS Library 1.1.1
36553 * Copyright(c) 2006-2007, Ext JS, LLC.
36555 * Originally Released Under LGPL - original licence link has changed is not relivant.
36558 * <script type="text/javascript">
36562 if(Roo.dd.DragZone){
36563 Roo.tree.TreeDragZone = function(tree, config){
36564 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36568 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36569 ddGroup : "TreeDD",
36571 onBeforeDrag : function(data, e){
36573 return n && n.draggable && !n.disabled;
36577 onInitDrag : function(e){
36578 var data = this.dragData;
36579 this.tree.getSelectionModel().select(data.node);
36580 this.proxy.update("");
36581 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36582 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36585 getRepairXY : function(e, data){
36586 return data.node.ui.getDDRepairXY();
36589 onEndDrag : function(data, e){
36590 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36595 onValidDrop : function(dd, e, id){
36596 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36600 beforeInvalidDrop : function(e, id){
36601 // this scrolls the original position back into view
36602 var sm = this.tree.getSelectionModel();
36603 sm.clearSelections();
36604 sm.select(this.dragData.node);
36609 * Ext JS Library 1.1.1
36610 * Copyright(c) 2006-2007, Ext JS, LLC.
36612 * Originally Released Under LGPL - original licence link has changed is not relivant.
36615 * <script type="text/javascript">
36618 * @class Roo.tree.TreeEditor
36619 * @extends Roo.Editor
36620 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36621 * as the editor field.
36623 * @param {Object} config (used to be the tree panel.)
36624 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36626 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36627 * @cfg {Roo.form.TextField|Object} field The field configuration
36631 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36634 if (oldconfig) { // old style..
36635 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36638 tree = config.tree;
36639 config.field = config.field || {};
36640 config.field.xtype = 'TextField';
36641 field = Roo.factory(config.field, Roo.form);
36643 config = config || {};
36648 * @event beforenodeedit
36649 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36650 * false from the handler of this event.
36651 * @param {Editor} this
36652 * @param {Roo.tree.Node} node
36654 "beforenodeedit" : true
36658 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36662 tree.on('beforeclick', this.beforeNodeClick, this);
36663 tree.getTreeEl().on('mousedown', this.hide, this);
36664 this.on('complete', this.updateNode, this);
36665 this.on('beforestartedit', this.fitToTree, this);
36666 this.on('startedit', this.bindScroll, this, {delay:10});
36667 this.on('specialkey', this.onSpecialKey, this);
36670 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36672 * @cfg {String} alignment
36673 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36679 * @cfg {Boolean} hideEl
36680 * True to hide the bound element while the editor is displayed (defaults to false)
36684 * @cfg {String} cls
36685 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36687 cls: "x-small-editor x-tree-editor",
36689 * @cfg {Boolean} shim
36690 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36696 * @cfg {Number} maxWidth
36697 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36698 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36699 * scroll and client offsets into account prior to each edit.
36706 fitToTree : function(ed, el){
36707 var td = this.tree.getTreeEl().dom, nd = el.dom;
36708 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36709 td.scrollLeft = nd.offsetLeft;
36713 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36714 this.setSize(w, '');
36716 return this.fireEvent('beforenodeedit', this, this.editNode);
36721 triggerEdit : function(node){
36722 this.completeEdit();
36723 this.editNode = node;
36724 this.startEdit(node.ui.textNode, node.text);
36728 bindScroll : function(){
36729 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36733 beforeNodeClick : function(node, e){
36734 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36735 this.lastClick = new Date();
36736 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36738 this.triggerEdit(node);
36745 updateNode : function(ed, value){
36746 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36747 this.editNode.setText(value);
36751 onHide : function(){
36752 Roo.tree.TreeEditor.superclass.onHide.call(this);
36754 this.editNode.ui.focus();
36759 onSpecialKey : function(field, e){
36760 var k = e.getKey();
36764 }else if(k == e.ENTER && !e.hasModifier()){
36766 this.completeEdit();
36769 });//<Script type="text/javascript">
36772 * Ext JS Library 1.1.1
36773 * Copyright(c) 2006-2007, Ext JS, LLC.
36775 * Originally Released Under LGPL - original licence link has changed is not relivant.
36778 * <script type="text/javascript">
36782 * Not documented??? - probably should be...
36785 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36786 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36788 renderElements : function(n, a, targetNode, bulkRender){
36789 //consel.log("renderElements?");
36790 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36792 var t = n.getOwnerTree();
36793 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36795 var cols = t.columns;
36796 var bw = t.borderWidth;
36798 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36799 var cb = typeof a.checked == "boolean";
36800 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36801 var colcls = 'x-t-' + tid + '-c0';
36803 '<li class="x-tree-node">',
36806 '<div class="x-tree-node-el ', a.cls,'">',
36808 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36811 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36812 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36813 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36814 (a.icon ? ' x-tree-node-inline-icon' : ''),
36815 (a.iconCls ? ' '+a.iconCls : ''),
36816 '" unselectable="on" />',
36817 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36818 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36820 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36821 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36822 '<span unselectable="on" qtip="' + tx + '">',
36826 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36827 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36829 for(var i = 1, len = cols.length; i < len; i++){
36831 colcls = 'x-t-' + tid + '-c' +i;
36832 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36833 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
36834 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
36840 '<div class="x-clear"></div></div>',
36841 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36844 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36845 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36846 n.nextSibling.ui.getEl(), buf.join(""));
36848 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36850 var el = this.wrap.firstChild;
36852 this.elNode = el.firstChild;
36853 this.ranchor = el.childNodes[1];
36854 this.ctNode = this.wrap.childNodes[1];
36855 var cs = el.firstChild.childNodes;
36856 this.indentNode = cs[0];
36857 this.ecNode = cs[1];
36858 this.iconNode = cs[2];
36861 this.checkbox = cs[3];
36864 this.anchor = cs[index];
36866 this.textNode = cs[index].firstChild;
36868 //el.on("click", this.onClick, this);
36869 //el.on("dblclick", this.onDblClick, this);
36872 // console.log(this);
36874 initEvents : function(){
36875 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
36878 var a = this.ranchor;
36880 var el = Roo.get(a);
36882 if(Roo.isOpera){ // opera render bug ignores the CSS
36883 el.setStyle("text-decoration", "none");
36886 el.on("click", this.onClick, this);
36887 el.on("dblclick", this.onDblClick, this);
36888 el.on("contextmenu", this.onContextMenu, this);
36892 /*onSelectedChange : function(state){
36895 this.addClass("x-tree-selected");
36898 this.removeClass("x-tree-selected");
36901 addClass : function(cls){
36903 Roo.fly(this.elRow).addClass(cls);
36909 removeClass : function(cls){
36911 Roo.fly(this.elRow).removeClass(cls);
36917 });//<Script type="text/javascript">
36921 * Ext JS Library 1.1.1
36922 * Copyright(c) 2006-2007, Ext JS, LLC.
36924 * Originally Released Under LGPL - original licence link has changed is not relivant.
36927 * <script type="text/javascript">
36932 * @class Roo.tree.ColumnTree
36933 * @extends Roo.data.TreePanel
36934 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
36935 * @cfg {int} borderWidth compined right/left border allowance
36937 * @param {String/HTMLElement/Element} el The container element
36938 * @param {Object} config
36940 Roo.tree.ColumnTree = function(el, config)
36942 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
36946 * Fire this event on a container when it resizes
36947 * @param {int} w Width
36948 * @param {int} h Height
36952 this.on('resize', this.onResize, this);
36955 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
36959 borderWidth: Roo.isBorderBox ? 0 : 2,
36962 render : function(){
36963 // add the header.....
36965 Roo.tree.ColumnTree.superclass.render.apply(this);
36967 this.el.addClass('x-column-tree');
36969 this.headers = this.el.createChild(
36970 {cls:'x-tree-headers'},this.innerCt.dom);
36972 var cols = this.columns, c;
36973 var totalWidth = 0;
36975 var len = cols.length;
36976 for(var i = 0; i < len; i++){
36978 totalWidth += c.width;
36979 this.headEls.push(this.headers.createChild({
36980 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
36982 cls:'x-tree-hd-text',
36985 style:'width:'+(c.width-this.borderWidth)+'px;'
36988 this.headers.createChild({cls:'x-clear'});
36989 // prevent floats from wrapping when clipped
36990 this.headers.setWidth(totalWidth);
36991 //this.innerCt.setWidth(totalWidth);
36992 this.innerCt.setStyle({ overflow: 'auto' });
36993 this.onResize(this.width, this.height);
36997 onResize : function(w,h)
37002 this.innerCt.setWidth(this.width);
37003 this.innerCt.setHeight(this.height-20);
37006 var cols = this.columns, c;
37007 var totalWidth = 0;
37009 var len = cols.length;
37010 for(var i = 0; i < len; i++){
37012 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37013 // it's the expander..
37014 expEl = this.headEls[i];
37017 totalWidth += c.width;
37021 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37023 this.headers.setWidth(w-20);
37032 * Ext JS Library 1.1.1
37033 * Copyright(c) 2006-2007, Ext JS, LLC.
37035 * Originally Released Under LGPL - original licence link has changed is not relivant.
37038 * <script type="text/javascript">
37042 * @class Roo.menu.Menu
37043 * @extends Roo.util.Observable
37044 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37045 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37047 * Creates a new Menu
37048 * @param {Object} config Configuration options
37050 Roo.menu.Menu = function(config){
37051 Roo.apply(this, config);
37052 this.id = this.id || Roo.id();
37055 * @event beforeshow
37056 * Fires before this menu is displayed
37057 * @param {Roo.menu.Menu} this
37061 * @event beforehide
37062 * Fires before this menu is hidden
37063 * @param {Roo.menu.Menu} this
37068 * Fires after this menu is displayed
37069 * @param {Roo.menu.Menu} this
37074 * Fires after this menu is hidden
37075 * @param {Roo.menu.Menu} this
37080 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37081 * @param {Roo.menu.Menu} this
37082 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37083 * @param {Roo.EventObject} e
37088 * Fires when the mouse is hovering over this menu
37089 * @param {Roo.menu.Menu} this
37090 * @param {Roo.EventObject} e
37091 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37096 * Fires when the mouse exits this menu
37097 * @param {Roo.menu.Menu} this
37098 * @param {Roo.EventObject} e
37099 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37104 * Fires when a menu item contained in this menu is clicked
37105 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37106 * @param {Roo.EventObject} e
37110 if (this.registerMenu) {
37111 Roo.menu.MenuMgr.register(this);
37114 var mis = this.items;
37115 this.items = new Roo.util.MixedCollection();
37117 this.add.apply(this, mis);
37121 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37123 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37127 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37128 * for bottom-right shadow (defaults to "sides")
37132 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37133 * this menu (defaults to "tl-tr?")
37135 subMenuAlign : "tl-tr?",
37137 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37138 * relative to its element of origin (defaults to "tl-bl?")
37140 defaultAlign : "tl-bl?",
37142 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37144 allowOtherMenus : false,
37146 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37148 registerMenu : true,
37153 render : function(){
37157 var el = this.el = new Roo.Layer({
37159 shadow:this.shadow,
37161 parentEl: this.parentEl || document.body,
37165 this.keyNav = new Roo.menu.MenuNav(this);
37168 el.addClass("x-menu-plain");
37171 el.addClass(this.cls);
37173 // generic focus element
37174 this.focusEl = el.createChild({
37175 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37177 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37178 //disabling touch- as it's causing issues ..
37179 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37180 ul.on('click' , this.onClick, this);
37183 ul.on("mouseover", this.onMouseOver, this);
37184 ul.on("mouseout", this.onMouseOut, this);
37185 this.items.each(function(item){
37190 var li = document.createElement("li");
37191 li.className = "x-menu-list-item";
37192 ul.dom.appendChild(li);
37193 item.render(li, this);
37200 autoWidth : function(){
37201 var el = this.el, ul = this.ul;
37205 var w = this.width;
37208 }else if(Roo.isIE){
37209 el.setWidth(this.minWidth);
37210 var t = el.dom.offsetWidth; // force recalc
37211 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37216 delayAutoWidth : function(){
37219 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37221 this.awTask.delay(20);
37226 findTargetItem : function(e){
37227 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37228 if(t && t.menuItemId){
37229 return this.items.get(t.menuItemId);
37234 onClick : function(e){
37235 Roo.log("menu.onClick");
37236 var t = this.findTargetItem(e);
37241 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37242 if(t == this.activeItem && t.shouldDeactivate(e)){
37243 this.activeItem.deactivate();
37244 delete this.activeItem;
37248 this.setActiveItem(t, true);
37256 this.fireEvent("click", this, t, e);
37260 setActiveItem : function(item, autoExpand){
37261 if(item != this.activeItem){
37262 if(this.activeItem){
37263 this.activeItem.deactivate();
37265 this.activeItem = item;
37266 item.activate(autoExpand);
37267 }else if(autoExpand){
37273 tryActivate : function(start, step){
37274 var items = this.items;
37275 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37276 var item = items.get(i);
37277 if(!item.disabled && item.canActivate){
37278 this.setActiveItem(item, false);
37286 onMouseOver : function(e){
37288 if(t = this.findTargetItem(e)){
37289 if(t.canActivate && !t.disabled){
37290 this.setActiveItem(t, true);
37293 this.fireEvent("mouseover", this, e, t);
37297 onMouseOut : function(e){
37299 if(t = this.findTargetItem(e)){
37300 if(t == this.activeItem && t.shouldDeactivate(e)){
37301 this.activeItem.deactivate();
37302 delete this.activeItem;
37305 this.fireEvent("mouseout", this, e, t);
37309 * Read-only. Returns true if the menu is currently displayed, else false.
37312 isVisible : function(){
37313 return this.el && !this.hidden;
37317 * Displays this menu relative to another element
37318 * @param {String/HTMLElement/Roo.Element} element The element to align to
37319 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37320 * the element (defaults to this.defaultAlign)
37321 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37323 show : function(el, pos, parentMenu){
37324 this.parentMenu = parentMenu;
37328 this.fireEvent("beforeshow", this);
37329 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37333 * Displays this menu at a specific xy position
37334 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37335 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37337 showAt : function(xy, parentMenu, /* private: */_e){
37338 this.parentMenu = parentMenu;
37343 this.fireEvent("beforeshow", this);
37344 xy = this.el.adjustForConstraints(xy);
37348 this.hidden = false;
37350 this.fireEvent("show", this);
37353 focus : function(){
37355 this.doFocus.defer(50, this);
37359 doFocus : function(){
37361 this.focusEl.focus();
37366 * Hides this menu and optionally all parent menus
37367 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37369 hide : function(deep){
37370 if(this.el && this.isVisible()){
37371 this.fireEvent("beforehide", this);
37372 if(this.activeItem){
37373 this.activeItem.deactivate();
37374 this.activeItem = null;
37377 this.hidden = true;
37378 this.fireEvent("hide", this);
37380 if(deep === true && this.parentMenu){
37381 this.parentMenu.hide(true);
37386 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37387 * Any of the following are valid:
37389 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37390 * <li>An HTMLElement object which will be converted to a menu item</li>
37391 * <li>A menu item config object that will be created as a new menu item</li>
37392 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37393 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37398 var menu = new Roo.menu.Menu();
37400 // Create a menu item to add by reference
37401 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37403 // Add a bunch of items at once using different methods.
37404 // Only the last item added will be returned.
37405 var item = menu.add(
37406 menuItem, // add existing item by ref
37407 'Dynamic Item', // new TextItem
37408 '-', // new separator
37409 { text: 'Config Item' } // new item by config
37412 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37413 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37416 var a = arguments, l = a.length, item;
37417 for(var i = 0; i < l; i++){
37419 if ((typeof(el) == "object") && el.xtype && el.xns) {
37420 el = Roo.factory(el, Roo.menu);
37423 if(el.render){ // some kind of Item
37424 item = this.addItem(el);
37425 }else if(typeof el == "string"){ // string
37426 if(el == "separator" || el == "-"){
37427 item = this.addSeparator();
37429 item = this.addText(el);
37431 }else if(el.tagName || el.el){ // element
37432 item = this.addElement(el);
37433 }else if(typeof el == "object"){ // must be menu item config?
37434 item = this.addMenuItem(el);
37441 * Returns this menu's underlying {@link Roo.Element} object
37442 * @return {Roo.Element} The element
37444 getEl : function(){
37452 * Adds a separator bar to the menu
37453 * @return {Roo.menu.Item} The menu item that was added
37455 addSeparator : function(){
37456 return this.addItem(new Roo.menu.Separator());
37460 * Adds an {@link Roo.Element} object to the menu
37461 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37462 * @return {Roo.menu.Item} The menu item that was added
37464 addElement : function(el){
37465 return this.addItem(new Roo.menu.BaseItem(el));
37469 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37470 * @param {Roo.menu.Item} item The menu item to add
37471 * @return {Roo.menu.Item} The menu item that was added
37473 addItem : function(item){
37474 this.items.add(item);
37476 var li = document.createElement("li");
37477 li.className = "x-menu-list-item";
37478 this.ul.dom.appendChild(li);
37479 item.render(li, this);
37480 this.delayAutoWidth();
37486 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37487 * @param {Object} config A MenuItem config object
37488 * @return {Roo.menu.Item} The menu item that was added
37490 addMenuItem : function(config){
37491 if(!(config instanceof Roo.menu.Item)){
37492 if(typeof config.checked == "boolean"){ // must be check menu item config?
37493 config = new Roo.menu.CheckItem(config);
37495 config = new Roo.menu.Item(config);
37498 return this.addItem(config);
37502 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37503 * @param {String} text The text to display in the menu item
37504 * @return {Roo.menu.Item} The menu item that was added
37506 addText : function(text){
37507 return this.addItem(new Roo.menu.TextItem({ text : text }));
37511 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37512 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37513 * @param {Roo.menu.Item} item The menu item to add
37514 * @return {Roo.menu.Item} The menu item that was added
37516 insert : function(index, item){
37517 this.items.insert(index, item);
37519 var li = document.createElement("li");
37520 li.className = "x-menu-list-item";
37521 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37522 item.render(li, this);
37523 this.delayAutoWidth();
37529 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37530 * @param {Roo.menu.Item} item The menu item to remove
37532 remove : function(item){
37533 this.items.removeKey(item.id);
37538 * Removes and destroys all items in the menu
37540 removeAll : function(){
37542 while(f = this.items.first()){
37548 // MenuNav is a private utility class used internally by the Menu
37549 Roo.menu.MenuNav = function(menu){
37550 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37551 this.scope = this.menu = menu;
37554 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37555 doRelay : function(e, h){
37556 var k = e.getKey();
37557 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37558 this.menu.tryActivate(0, 1);
37561 return h.call(this.scope || this, e, this.menu);
37564 up : function(e, m){
37565 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37566 m.tryActivate(m.items.length-1, -1);
37570 down : function(e, m){
37571 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37572 m.tryActivate(0, 1);
37576 right : function(e, m){
37578 m.activeItem.expandMenu(true);
37582 left : function(e, m){
37584 if(m.parentMenu && m.parentMenu.activeItem){
37585 m.parentMenu.activeItem.activate();
37589 enter : function(e, m){
37591 e.stopPropagation();
37592 m.activeItem.onClick(e);
37593 m.fireEvent("click", this, m.activeItem);
37599 * Ext JS Library 1.1.1
37600 * Copyright(c) 2006-2007, Ext JS, LLC.
37602 * Originally Released Under LGPL - original licence link has changed is not relivant.
37605 * <script type="text/javascript">
37609 * @class Roo.menu.MenuMgr
37610 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37613 Roo.menu.MenuMgr = function(){
37614 var menus, active, groups = {}, attached = false, lastShow = new Date();
37616 // private - called when first menu is created
37619 active = new Roo.util.MixedCollection();
37620 Roo.get(document).addKeyListener(27, function(){
37621 if(active.length > 0){
37628 function hideAll(){
37629 if(active && active.length > 0){
37630 var c = active.clone();
37631 c.each(function(m){
37638 function onHide(m){
37640 if(active.length < 1){
37641 Roo.get(document).un("mousedown", onMouseDown);
37647 function onShow(m){
37648 var last = active.last();
37649 lastShow = new Date();
37652 Roo.get(document).on("mousedown", onMouseDown);
37656 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37657 m.parentMenu.activeChild = m;
37658 }else if(last && last.isVisible()){
37659 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37664 function onBeforeHide(m){
37666 m.activeChild.hide();
37668 if(m.autoHideTimer){
37669 clearTimeout(m.autoHideTimer);
37670 delete m.autoHideTimer;
37675 function onBeforeShow(m){
37676 var pm = m.parentMenu;
37677 if(!pm && !m.allowOtherMenus){
37679 }else if(pm && pm.activeChild && active != m){
37680 pm.activeChild.hide();
37685 function onMouseDown(e){
37686 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37692 function onBeforeCheck(mi, state){
37694 var g = groups[mi.group];
37695 for(var i = 0, l = g.length; i < l; i++){
37697 g[i].setChecked(false);
37706 * Hides all menus that are currently visible
37708 hideAll : function(){
37713 register : function(menu){
37717 menus[menu.id] = menu;
37718 menu.on("beforehide", onBeforeHide);
37719 menu.on("hide", onHide);
37720 menu.on("beforeshow", onBeforeShow);
37721 menu.on("show", onShow);
37722 var g = menu.group;
37723 if(g && menu.events["checkchange"]){
37727 groups[g].push(menu);
37728 menu.on("checkchange", onCheck);
37733 * Returns a {@link Roo.menu.Menu} object
37734 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37735 * be used to generate and return a new Menu instance.
37737 get : function(menu){
37738 if(typeof menu == "string"){ // menu id
37739 return menus[menu];
37740 }else if(menu.events){ // menu instance
37742 }else if(typeof menu.length == 'number'){ // array of menu items?
37743 return new Roo.menu.Menu({items:menu});
37744 }else{ // otherwise, must be a config
37745 return new Roo.menu.Menu(menu);
37750 unregister : function(menu){
37751 delete menus[menu.id];
37752 menu.un("beforehide", onBeforeHide);
37753 menu.un("hide", onHide);
37754 menu.un("beforeshow", onBeforeShow);
37755 menu.un("show", onShow);
37756 var g = menu.group;
37757 if(g && menu.events["checkchange"]){
37758 groups[g].remove(menu);
37759 menu.un("checkchange", onCheck);
37764 registerCheckable : function(menuItem){
37765 var g = menuItem.group;
37770 groups[g].push(menuItem);
37771 menuItem.on("beforecheckchange", onBeforeCheck);
37776 unregisterCheckable : function(menuItem){
37777 var g = menuItem.group;
37779 groups[g].remove(menuItem);
37780 menuItem.un("beforecheckchange", onBeforeCheck);
37786 * Ext JS Library 1.1.1
37787 * Copyright(c) 2006-2007, Ext JS, LLC.
37789 * Originally Released Under LGPL - original licence link has changed is not relivant.
37792 * <script type="text/javascript">
37797 * @class Roo.menu.BaseItem
37798 * @extends Roo.Component
37799 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37800 * management and base configuration options shared by all menu components.
37802 * Creates a new BaseItem
37803 * @param {Object} config Configuration options
37805 Roo.menu.BaseItem = function(config){
37806 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37811 * Fires when this item is clicked
37812 * @param {Roo.menu.BaseItem} this
37813 * @param {Roo.EventObject} e
37818 * Fires when this item is activated
37819 * @param {Roo.menu.BaseItem} this
37823 * @event deactivate
37824 * Fires when this item is deactivated
37825 * @param {Roo.menu.BaseItem} this
37831 this.on("click", this.handler, this.scope, true);
37835 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
37837 * @cfg {Function} handler
37838 * A function that will handle the click event of this menu item (defaults to undefined)
37841 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
37843 canActivate : false,
37846 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
37851 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
37853 activeClass : "x-menu-item-active",
37855 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
37857 hideOnClick : true,
37859 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
37864 ctype: "Roo.menu.BaseItem",
37867 actionMode : "container",
37870 render : function(container, parentMenu){
37871 this.parentMenu = parentMenu;
37872 Roo.menu.BaseItem.superclass.render.call(this, container);
37873 this.container.menuItemId = this.id;
37877 onRender : function(container, position){
37878 this.el = Roo.get(this.el);
37879 container.dom.appendChild(this.el.dom);
37883 onClick : function(e){
37884 if(!this.disabled && this.fireEvent("click", this, e) !== false
37885 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
37886 this.handleClick(e);
37893 activate : function(){
37897 var li = this.container;
37898 li.addClass(this.activeClass);
37899 this.region = li.getRegion().adjust(2, 2, -2, -2);
37900 this.fireEvent("activate", this);
37905 deactivate : function(){
37906 this.container.removeClass(this.activeClass);
37907 this.fireEvent("deactivate", this);
37911 shouldDeactivate : function(e){
37912 return !this.region || !this.region.contains(e.getPoint());
37916 handleClick : function(e){
37917 if(this.hideOnClick){
37918 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
37923 expandMenu : function(autoActivate){
37928 hideMenu : function(){
37933 * Ext JS Library 1.1.1
37934 * Copyright(c) 2006-2007, Ext JS, LLC.
37936 * Originally Released Under LGPL - original licence link has changed is not relivant.
37939 * <script type="text/javascript">
37943 * @class Roo.menu.Adapter
37944 * @extends Roo.menu.BaseItem
37945 * 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.
37946 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
37948 * Creates a new Adapter
37949 * @param {Object} config Configuration options
37951 Roo.menu.Adapter = function(component, config){
37952 Roo.menu.Adapter.superclass.constructor.call(this, config);
37953 this.component = component;
37955 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
37957 canActivate : true,
37960 onRender : function(container, position){
37961 this.component.render(container);
37962 this.el = this.component.getEl();
37966 activate : function(){
37970 this.component.focus();
37971 this.fireEvent("activate", this);
37976 deactivate : function(){
37977 this.fireEvent("deactivate", this);
37981 disable : function(){
37982 this.component.disable();
37983 Roo.menu.Adapter.superclass.disable.call(this);
37987 enable : function(){
37988 this.component.enable();
37989 Roo.menu.Adapter.superclass.enable.call(this);
37993 * Ext JS Library 1.1.1
37994 * Copyright(c) 2006-2007, Ext JS, LLC.
37996 * Originally Released Under LGPL - original licence link has changed is not relivant.
37999 * <script type="text/javascript">
38003 * @class Roo.menu.TextItem
38004 * @extends Roo.menu.BaseItem
38005 * Adds a static text string to a menu, usually used as either a heading or group separator.
38006 * Note: old style constructor with text is still supported.
38009 * Creates a new TextItem
38010 * @param {Object} cfg Configuration
38012 Roo.menu.TextItem = function(cfg){
38013 if (typeof(cfg) == 'string') {
38016 Roo.apply(this,cfg);
38019 Roo.menu.TextItem.superclass.constructor.call(this);
38022 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38024 * @cfg {Boolean} text Text to show on item.
38029 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38031 hideOnClick : false,
38033 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38035 itemCls : "x-menu-text",
38038 onRender : function(){
38039 var s = document.createElement("span");
38040 s.className = this.itemCls;
38041 s.innerHTML = this.text;
38043 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38047 * Ext JS Library 1.1.1
38048 * Copyright(c) 2006-2007, Ext JS, LLC.
38050 * Originally Released Under LGPL - original licence link has changed is not relivant.
38053 * <script type="text/javascript">
38057 * @class Roo.menu.Separator
38058 * @extends Roo.menu.BaseItem
38059 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38060 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38062 * @param {Object} config Configuration options
38064 Roo.menu.Separator = function(config){
38065 Roo.menu.Separator.superclass.constructor.call(this, config);
38068 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38070 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38072 itemCls : "x-menu-sep",
38074 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38076 hideOnClick : false,
38079 onRender : function(li){
38080 var s = document.createElement("span");
38081 s.className = this.itemCls;
38082 s.innerHTML = " ";
38084 li.addClass("x-menu-sep-li");
38085 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38089 * Ext JS Library 1.1.1
38090 * Copyright(c) 2006-2007, Ext JS, LLC.
38092 * Originally Released Under LGPL - original licence link has changed is not relivant.
38095 * <script type="text/javascript">
38098 * @class Roo.menu.Item
38099 * @extends Roo.menu.BaseItem
38100 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38101 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38102 * activation and click handling.
38104 * Creates a new Item
38105 * @param {Object} config Configuration options
38107 Roo.menu.Item = function(config){
38108 Roo.menu.Item.superclass.constructor.call(this, config);
38110 this.menu = Roo.menu.MenuMgr.get(this.menu);
38113 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38116 * @cfg {String} text
38117 * The text to show on the menu item.
38121 * @cfg {String} HTML to render in menu
38122 * The text to show on the menu item (HTML version).
38126 * @cfg {String} icon
38127 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38131 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38133 itemCls : "x-menu-item",
38135 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38137 canActivate : true,
38139 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38142 // doc'd in BaseItem
38146 ctype: "Roo.menu.Item",
38149 onRender : function(container, position){
38150 var el = document.createElement("a");
38151 el.hideFocus = true;
38152 el.unselectable = "on";
38153 el.href = this.href || "#";
38154 if(this.hrefTarget){
38155 el.target = this.hrefTarget;
38157 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38159 var html = this.html.length ? this.html : String.format('{0}',this.text);
38161 el.innerHTML = String.format(
38162 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38163 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38165 Roo.menu.Item.superclass.onRender.call(this, container, position);
38169 * Sets the text to display in this menu item
38170 * @param {String} text The text to display
38171 * @param {Boolean} isHTML true to indicate text is pure html.
38173 setText : function(text, isHTML){
38181 var html = this.html.length ? this.html : String.format('{0}',this.text);
38183 this.el.update(String.format(
38184 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38185 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38186 this.parentMenu.autoWidth();
38191 handleClick : function(e){
38192 if(!this.href){ // if no link defined, stop the event automatically
38195 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38199 activate : function(autoExpand){
38200 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38210 shouldDeactivate : function(e){
38211 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38212 if(this.menu && this.menu.isVisible()){
38213 return !this.menu.getEl().getRegion().contains(e.getPoint());
38221 deactivate : function(){
38222 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38227 expandMenu : function(autoActivate){
38228 if(!this.disabled && this.menu){
38229 clearTimeout(this.hideTimer);
38230 delete this.hideTimer;
38231 if(!this.menu.isVisible() && !this.showTimer){
38232 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38233 }else if (this.menu.isVisible() && autoActivate){
38234 this.menu.tryActivate(0, 1);
38240 deferExpand : function(autoActivate){
38241 delete this.showTimer;
38242 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38244 this.menu.tryActivate(0, 1);
38249 hideMenu : function(){
38250 clearTimeout(this.showTimer);
38251 delete this.showTimer;
38252 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38253 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38258 deferHide : function(){
38259 delete this.hideTimer;
38264 * Ext JS Library 1.1.1
38265 * Copyright(c) 2006-2007, Ext JS, LLC.
38267 * Originally Released Under LGPL - original licence link has changed is not relivant.
38270 * <script type="text/javascript">
38274 * @class Roo.menu.CheckItem
38275 * @extends Roo.menu.Item
38276 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38278 * Creates a new CheckItem
38279 * @param {Object} config Configuration options
38281 Roo.menu.CheckItem = function(config){
38282 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38285 * @event beforecheckchange
38286 * Fires before the checked value is set, providing an opportunity to cancel if needed
38287 * @param {Roo.menu.CheckItem} this
38288 * @param {Boolean} checked The new checked value that will be set
38290 "beforecheckchange" : true,
38292 * @event checkchange
38293 * Fires after the checked value has been set
38294 * @param {Roo.menu.CheckItem} this
38295 * @param {Boolean} checked The checked value that was set
38297 "checkchange" : true
38299 if(this.checkHandler){
38300 this.on('checkchange', this.checkHandler, this.scope);
38303 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38305 * @cfg {String} group
38306 * All check items with the same group name will automatically be grouped into a single-select
38307 * radio button group (defaults to '')
38310 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38312 itemCls : "x-menu-item x-menu-check-item",
38314 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38316 groupClass : "x-menu-group-item",
38319 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38320 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38321 * initialized with checked = true will be rendered as checked.
38326 ctype: "Roo.menu.CheckItem",
38329 onRender : function(c){
38330 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38332 this.el.addClass(this.groupClass);
38334 Roo.menu.MenuMgr.registerCheckable(this);
38336 this.checked = false;
38337 this.setChecked(true, true);
38342 destroy : function(){
38344 Roo.menu.MenuMgr.unregisterCheckable(this);
38346 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38350 * Set the checked state of this item
38351 * @param {Boolean} checked The new checked value
38352 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38354 setChecked : function(state, suppressEvent){
38355 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38356 if(this.container){
38357 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38359 this.checked = state;
38360 if(suppressEvent !== true){
38361 this.fireEvent("checkchange", this, state);
38367 handleClick : function(e){
38368 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38369 this.setChecked(!this.checked);
38371 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38375 * Ext JS Library 1.1.1
38376 * Copyright(c) 2006-2007, Ext JS, LLC.
38378 * Originally Released Under LGPL - original licence link has changed is not relivant.
38381 * <script type="text/javascript">
38385 * @class Roo.menu.DateItem
38386 * @extends Roo.menu.Adapter
38387 * A menu item that wraps the {@link Roo.DatPicker} component.
38389 * Creates a new DateItem
38390 * @param {Object} config Configuration options
38392 Roo.menu.DateItem = function(config){
38393 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38394 /** The Roo.DatePicker object @type Roo.DatePicker */
38395 this.picker = this.component;
38396 this.addEvents({select: true});
38398 this.picker.on("render", function(picker){
38399 picker.getEl().swallowEvent("click");
38400 picker.container.addClass("x-menu-date-item");
38403 this.picker.on("select", this.onSelect, this);
38406 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38408 onSelect : function(picker, date){
38409 this.fireEvent("select", this, date, picker);
38410 Roo.menu.DateItem.superclass.handleClick.call(this);
38414 * Ext JS Library 1.1.1
38415 * Copyright(c) 2006-2007, Ext JS, LLC.
38417 * Originally Released Under LGPL - original licence link has changed is not relivant.
38420 * <script type="text/javascript">
38424 * @class Roo.menu.ColorItem
38425 * @extends Roo.menu.Adapter
38426 * A menu item that wraps the {@link Roo.ColorPalette} component.
38428 * Creates a new ColorItem
38429 * @param {Object} config Configuration options
38431 Roo.menu.ColorItem = function(config){
38432 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38433 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38434 this.palette = this.component;
38435 this.relayEvents(this.palette, ["select"]);
38436 if(this.selectHandler){
38437 this.on('select', this.selectHandler, this.scope);
38440 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38442 * Ext JS Library 1.1.1
38443 * Copyright(c) 2006-2007, Ext JS, LLC.
38445 * Originally Released Under LGPL - original licence link has changed is not relivant.
38448 * <script type="text/javascript">
38453 * @class Roo.menu.DateMenu
38454 * @extends Roo.menu.Menu
38455 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38457 * Creates a new DateMenu
38458 * @param {Object} config Configuration options
38460 Roo.menu.DateMenu = function(config){
38461 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38463 var di = new Roo.menu.DateItem(config);
38466 * The {@link Roo.DatePicker} instance for this DateMenu
38469 this.picker = di.picker;
38472 * @param {DatePicker} picker
38473 * @param {Date} date
38475 this.relayEvents(di, ["select"]);
38476 this.on('beforeshow', function(){
38478 this.picker.hideMonthPicker(false);
38482 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38486 * Ext JS Library 1.1.1
38487 * Copyright(c) 2006-2007, Ext JS, LLC.
38489 * Originally Released Under LGPL - original licence link has changed is not relivant.
38492 * <script type="text/javascript">
38497 * @class Roo.menu.ColorMenu
38498 * @extends Roo.menu.Menu
38499 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38501 * Creates a new ColorMenu
38502 * @param {Object} config Configuration options
38504 Roo.menu.ColorMenu = function(config){
38505 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38507 var ci = new Roo.menu.ColorItem(config);
38510 * The {@link Roo.ColorPalette} instance for this ColorMenu
38511 * @type ColorPalette
38513 this.palette = ci.palette;
38516 * @param {ColorPalette} palette
38517 * @param {String} color
38519 this.relayEvents(ci, ["select"]);
38521 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38523 * Ext JS Library 1.1.1
38524 * Copyright(c) 2006-2007, Ext JS, LLC.
38526 * Originally Released Under LGPL - original licence link has changed is not relivant.
38529 * <script type="text/javascript">
38533 * @class Roo.form.Field
38534 * @extends Roo.BoxComponent
38535 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38537 * Creates a new Field
38538 * @param {Object} config Configuration options
38540 Roo.form.Field = function(config){
38541 Roo.form.Field.superclass.constructor.call(this, config);
38544 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38546 * @cfg {String} fieldLabel Label to use when rendering a form.
38549 * @cfg {String} qtip Mouse over tip
38553 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38555 invalidClass : "x-form-invalid",
38557 * @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")
38559 invalidText : "The value in this field is invalid",
38561 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38563 focusClass : "x-form-focus",
38565 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38566 automatic validation (defaults to "keyup").
38568 validationEvent : "keyup",
38570 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38572 validateOnBlur : true,
38574 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38576 validationDelay : 250,
38578 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38579 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38581 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38583 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38585 fieldClass : "x-form-field",
38587 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38590 ----------- ----------------------------------------------------------------------
38591 qtip Display a quick tip when the user hovers over the field
38592 title Display a default browser title attribute popup
38593 under Add a block div beneath the field containing the error text
38594 side Add an error icon to the right of the field with a popup on hover
38595 [element id] Add the error text directly to the innerHTML of the specified element
38598 msgTarget : 'qtip',
38600 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38605 * @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.
38610 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38615 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38617 inputType : undefined,
38620 * @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).
38622 tabIndex : undefined,
38625 isFormField : true,
38630 * @property {Roo.Element} fieldEl
38631 * Element Containing the rendered Field (with label etc.)
38634 * @cfg {Mixed} value A value to initialize this field with.
38639 * @cfg {String} name The field's HTML name attribute.
38642 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38645 loadedValue : false,
38649 initComponent : function(){
38650 Roo.form.Field.superclass.initComponent.call(this);
38654 * Fires when this field receives input focus.
38655 * @param {Roo.form.Field} this
38660 * Fires when this field loses input focus.
38661 * @param {Roo.form.Field} this
38665 * @event specialkey
38666 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38667 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38668 * @param {Roo.form.Field} this
38669 * @param {Roo.EventObject} e The event object
38674 * Fires just before the field blurs if the field value has changed.
38675 * @param {Roo.form.Field} this
38676 * @param {Mixed} newValue The new value
38677 * @param {Mixed} oldValue The original value
38682 * Fires after the field has been marked as invalid.
38683 * @param {Roo.form.Field} this
38684 * @param {String} msg The validation message
38689 * Fires after the field has been validated with no errors.
38690 * @param {Roo.form.Field} this
38695 * Fires after the key up
38696 * @param {Roo.form.Field} this
38697 * @param {Roo.EventObject} e The event Object
38704 * Returns the name attribute of the field if available
38705 * @return {String} name The field name
38707 getName: function(){
38708 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38712 onRender : function(ct, position){
38713 Roo.form.Field.superclass.onRender.call(this, ct, position);
38715 var cfg = this.getAutoCreate();
38717 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38719 if (!cfg.name.length) {
38722 if(this.inputType){
38723 cfg.type = this.inputType;
38725 this.el = ct.createChild(cfg, position);
38727 var type = this.el.dom.type;
38729 if(type == 'password'){
38732 this.el.addClass('x-form-'+type);
38735 this.el.dom.readOnly = true;
38737 if(this.tabIndex !== undefined){
38738 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38741 this.el.addClass([this.fieldClass, this.cls]);
38746 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38747 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38748 * @return {Roo.form.Field} this
38750 applyTo : function(target){
38751 this.allowDomMove = false;
38752 this.el = Roo.get(target);
38753 this.render(this.el.dom.parentNode);
38758 initValue : function(){
38759 if(this.value !== undefined){
38760 this.setValue(this.value);
38761 }else if(this.el.dom.value.length > 0){
38762 this.setValue(this.el.dom.value);
38767 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38768 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38770 isDirty : function() {
38771 if(this.disabled) {
38774 return String(this.getValue()) !== String(this.originalValue);
38778 * stores the current value in loadedValue
38780 resetHasChanged : function()
38782 this.loadedValue = String(this.getValue());
38785 * checks the current value against the 'loaded' value.
38786 * Note - will return false if 'resetHasChanged' has not been called first.
38788 hasChanged : function()
38790 if(this.disabled || this.readOnly) {
38793 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38799 afterRender : function(){
38800 Roo.form.Field.superclass.afterRender.call(this);
38805 fireKey : function(e){
38806 //Roo.log('field ' + e.getKey());
38807 if(e.isNavKeyPress()){
38808 this.fireEvent("specialkey", this, e);
38813 * Resets the current field value to the originally loaded value and clears any validation messages
38815 reset : function(){
38816 this.setValue(this.resetValue);
38817 this.clearInvalid();
38821 initEvents : function(){
38822 // safari killled keypress - so keydown is now used..
38823 this.el.on("keydown" , this.fireKey, this);
38824 this.el.on("focus", this.onFocus, this);
38825 this.el.on("blur", this.onBlur, this);
38826 this.el.relayEvent('keyup', this);
38828 // reference to original value for reset
38829 this.originalValue = this.getValue();
38830 this.resetValue = this.getValue();
38834 onFocus : function(){
38835 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38836 this.el.addClass(this.focusClass);
38838 if(!this.hasFocus){
38839 this.hasFocus = true;
38840 this.startValue = this.getValue();
38841 this.fireEvent("focus", this);
38845 beforeBlur : Roo.emptyFn,
38848 onBlur : function(){
38850 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38851 this.el.removeClass(this.focusClass);
38853 this.hasFocus = false;
38854 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
38857 var v = this.getValue();
38858 if(String(v) !== String(this.startValue)){
38859 this.fireEvent('change', this, v, this.startValue);
38861 this.fireEvent("blur", this);
38865 * Returns whether or not the field value is currently valid
38866 * @param {Boolean} preventMark True to disable marking the field invalid
38867 * @return {Boolean} True if the value is valid, else false
38869 isValid : function(preventMark){
38873 var restore = this.preventMark;
38874 this.preventMark = preventMark === true;
38875 var v = this.validateValue(this.processValue(this.getRawValue()));
38876 this.preventMark = restore;
38881 * Validates the field value
38882 * @return {Boolean} True if the value is valid, else false
38884 validate : function(){
38885 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
38886 this.clearInvalid();
38892 processValue : function(value){
38897 // Subclasses should provide the validation implementation by overriding this
38898 validateValue : function(value){
38903 * Mark this field as invalid
38904 * @param {String} msg The validation message
38906 markInvalid : function(msg){
38907 if(!this.rendered || this.preventMark){ // not rendered
38911 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38913 obj.el.addClass(this.invalidClass);
38914 msg = msg || this.invalidText;
38915 switch(this.msgTarget){
38917 obj.el.dom.qtip = msg;
38918 obj.el.dom.qclass = 'x-form-invalid-tip';
38919 if(Roo.QuickTips){ // fix for floating editors interacting with DND
38920 Roo.QuickTips.enable();
38924 this.el.dom.title = msg;
38928 var elp = this.el.findParent('.x-form-element', 5, true);
38929 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
38930 this.errorEl.setWidth(elp.getWidth(true)-20);
38932 this.errorEl.update(msg);
38933 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
38936 if(!this.errorIcon){
38937 var elp = this.el.findParent('.x-form-element', 5, true);
38938 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
38940 this.alignErrorIcon();
38941 this.errorIcon.dom.qtip = msg;
38942 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
38943 this.errorIcon.show();
38944 this.on('resize', this.alignErrorIcon, this);
38947 var t = Roo.getDom(this.msgTarget);
38949 t.style.display = this.msgDisplay;
38952 this.fireEvent('invalid', this, msg);
38956 alignErrorIcon : function(){
38957 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
38961 * Clear any invalid styles/messages for this field
38963 clearInvalid : function(){
38964 if(!this.rendered || this.preventMark){ // not rendered
38967 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38969 obj.el.removeClass(this.invalidClass);
38970 switch(this.msgTarget){
38972 obj.el.dom.qtip = '';
38975 this.el.dom.title = '';
38979 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
38983 if(this.errorIcon){
38984 this.errorIcon.dom.qtip = '';
38985 this.errorIcon.hide();
38986 this.un('resize', this.alignErrorIcon, this);
38990 var t = Roo.getDom(this.msgTarget);
38992 t.style.display = 'none';
38995 this.fireEvent('valid', this);
38999 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39000 * @return {Mixed} value The field value
39002 getRawValue : function(){
39003 var v = this.el.getValue();
39009 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39010 * @return {Mixed} value The field value
39012 getValue : function(){
39013 var v = this.el.getValue();
39019 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39020 * @param {Mixed} value The value to set
39022 setRawValue : function(v){
39023 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39027 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39028 * @param {Mixed} value The value to set
39030 setValue : function(v){
39033 this.el.dom.value = (v === null || v === undefined ? '' : v);
39038 adjustSize : function(w, h){
39039 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39040 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39044 adjustWidth : function(tag, w){
39045 tag = tag.toLowerCase();
39046 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39047 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39048 if(tag == 'input'){
39051 if(tag == 'textarea'){
39054 }else if(Roo.isOpera){
39055 if(tag == 'input'){
39058 if(tag == 'textarea'){
39068 // anything other than normal should be considered experimental
39069 Roo.form.Field.msgFx = {
39071 show: function(msgEl, f){
39072 msgEl.setDisplayed('block');
39075 hide : function(msgEl, f){
39076 msgEl.setDisplayed(false).update('');
39081 show: function(msgEl, f){
39082 msgEl.slideIn('t', {stopFx:true});
39085 hide : function(msgEl, f){
39086 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39091 show: function(msgEl, f){
39092 msgEl.fixDisplay();
39093 msgEl.alignTo(f.el, 'tl-tr');
39094 msgEl.slideIn('l', {stopFx:true});
39097 hide : function(msgEl, f){
39098 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39103 * Ext JS Library 1.1.1
39104 * Copyright(c) 2006-2007, Ext JS, LLC.
39106 * Originally Released Under LGPL - original licence link has changed is not relivant.
39109 * <script type="text/javascript">
39114 * @class Roo.form.TextField
39115 * @extends Roo.form.Field
39116 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39117 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39119 * Creates a new TextField
39120 * @param {Object} config Configuration options
39122 Roo.form.TextField = function(config){
39123 Roo.form.TextField.superclass.constructor.call(this, config);
39127 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39128 * according to the default logic, but this event provides a hook for the developer to apply additional
39129 * logic at runtime to resize the field if needed.
39130 * @param {Roo.form.Field} this This text field
39131 * @param {Number} width The new field width
39137 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39139 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39143 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39147 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39151 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39155 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39159 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39161 disableKeyFilter : false,
39163 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39167 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39171 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39173 maxLength : Number.MAX_VALUE,
39175 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39177 minLengthText : "The minimum length for this field is {0}",
39179 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39181 maxLengthText : "The maximum length for this field is {0}",
39183 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39185 selectOnFocus : false,
39187 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39189 blankText : "This field is required",
39191 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39192 * If available, this function will be called only after the basic validators all return true, and will be passed the
39193 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39197 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39198 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39199 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39203 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39207 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39213 initEvents : function()
39215 if (this.emptyText) {
39216 this.el.attr('placeholder', this.emptyText);
39219 Roo.form.TextField.superclass.initEvents.call(this);
39220 if(this.validationEvent == 'keyup'){
39221 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39222 this.el.on('keyup', this.filterValidation, this);
39224 else if(this.validationEvent !== false){
39225 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39228 if(this.selectOnFocus){
39229 this.on("focus", this.preFocus, this);
39232 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39233 this.el.on("keypress", this.filterKeys, this);
39236 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39237 this.el.on("click", this.autoSize, this);
39239 if(this.el.is('input[type=password]') && Roo.isSafari){
39240 this.el.on('keydown', this.SafariOnKeyDown, this);
39244 processValue : function(value){
39245 if(this.stripCharsRe){
39246 var newValue = value.replace(this.stripCharsRe, '');
39247 if(newValue !== value){
39248 this.setRawValue(newValue);
39255 filterValidation : function(e){
39256 if(!e.isNavKeyPress()){
39257 this.validationTask.delay(this.validationDelay);
39262 onKeyUp : function(e){
39263 if(!e.isNavKeyPress()){
39269 * Resets the current field value to the originally-loaded value and clears any validation messages.
39272 reset : function(){
39273 Roo.form.TextField.superclass.reset.call(this);
39279 preFocus : function(){
39281 if(this.selectOnFocus){
39282 this.el.dom.select();
39288 filterKeys : function(e){
39289 var k = e.getKey();
39290 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39293 var c = e.getCharCode(), cc = String.fromCharCode(c);
39294 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39297 if(!this.maskRe.test(cc)){
39302 setValue : function(v){
39304 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39310 * Validates a value according to the field's validation rules and marks the field as invalid
39311 * if the validation fails
39312 * @param {Mixed} value The value to validate
39313 * @return {Boolean} True if the value is valid, else false
39315 validateValue : function(value){
39316 if(value.length < 1) { // if it's blank
39317 if(this.allowBlank){
39318 this.clearInvalid();
39321 this.markInvalid(this.blankText);
39325 if(value.length < this.minLength){
39326 this.markInvalid(String.format(this.minLengthText, this.minLength));
39329 if(value.length > this.maxLength){
39330 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39334 var vt = Roo.form.VTypes;
39335 if(!vt[this.vtype](value, this)){
39336 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39340 if(typeof this.validator == "function"){
39341 var msg = this.validator(value);
39343 this.markInvalid(msg);
39347 if(this.regex && !this.regex.test(value)){
39348 this.markInvalid(this.regexText);
39355 * Selects text in this field
39356 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39357 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39359 selectText : function(start, end){
39360 var v = this.getRawValue();
39362 start = start === undefined ? 0 : start;
39363 end = end === undefined ? v.length : end;
39364 var d = this.el.dom;
39365 if(d.setSelectionRange){
39366 d.setSelectionRange(start, end);
39367 }else if(d.createTextRange){
39368 var range = d.createTextRange();
39369 range.moveStart("character", start);
39370 range.moveEnd("character", v.length-end);
39377 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39378 * This only takes effect if grow = true, and fires the autosize event.
39380 autoSize : function(){
39381 if(!this.grow || !this.rendered){
39385 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39388 var v = el.dom.value;
39389 var d = document.createElement('div');
39390 d.appendChild(document.createTextNode(v));
39394 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39395 this.el.setWidth(w);
39396 this.fireEvent("autosize", this, w);
39400 SafariOnKeyDown : function(event)
39402 // this is a workaround for a password hang bug on chrome/ webkit.
39404 var isSelectAll = false;
39406 if(this.el.dom.selectionEnd > 0){
39407 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39409 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39410 event.preventDefault();
39415 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39417 event.preventDefault();
39418 // this is very hacky as keydown always get's upper case.
39420 var cc = String.fromCharCode(event.getCharCode());
39423 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39431 * Ext JS Library 1.1.1
39432 * Copyright(c) 2006-2007, Ext JS, LLC.
39434 * Originally Released Under LGPL - original licence link has changed is not relivant.
39437 * <script type="text/javascript">
39441 * @class Roo.form.Hidden
39442 * @extends Roo.form.TextField
39443 * Simple Hidden element used on forms
39445 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39448 * Creates a new Hidden form element.
39449 * @param {Object} config Configuration options
39454 // easy hidden field...
39455 Roo.form.Hidden = function(config){
39456 Roo.form.Hidden.superclass.constructor.call(this, config);
39459 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39461 inputType: 'hidden',
39464 labelSeparator: '',
39466 itemCls : 'x-form-item-display-none'
39474 * Ext JS Library 1.1.1
39475 * Copyright(c) 2006-2007, Ext JS, LLC.
39477 * Originally Released Under LGPL - original licence link has changed is not relivant.
39480 * <script type="text/javascript">
39484 * @class Roo.form.TriggerField
39485 * @extends Roo.form.TextField
39486 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39487 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39488 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39489 * for which you can provide a custom implementation. For example:
39491 var trigger = new Roo.form.TriggerField();
39492 trigger.onTriggerClick = myTriggerFn;
39493 trigger.applyTo('my-field');
39496 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39497 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39498 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39499 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39501 * Create a new TriggerField.
39502 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39503 * to the base TextField)
39505 Roo.form.TriggerField = function(config){
39506 this.mimicing = false;
39507 Roo.form.TriggerField.superclass.constructor.call(this, config);
39510 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39512 * @cfg {String} triggerClass A CSS class to apply to the trigger
39515 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39516 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39518 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39520 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39524 /** @cfg {Boolean} grow @hide */
39525 /** @cfg {Number} growMin @hide */
39526 /** @cfg {Number} growMax @hide */
39532 autoSize: Roo.emptyFn,
39536 deferHeight : true,
39539 actionMode : 'wrap',
39541 onResize : function(w, h){
39542 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39543 if(typeof w == 'number'){
39544 var x = w - this.trigger.getWidth();
39545 this.el.setWidth(this.adjustWidth('input', x));
39546 this.trigger.setStyle('left', x+'px');
39551 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39554 getResizeEl : function(){
39559 getPositionEl : function(){
39564 alignErrorIcon : function(){
39565 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39569 onRender : function(ct, position){
39570 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39571 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39572 this.trigger = this.wrap.createChild(this.triggerConfig ||
39573 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39574 if(this.hideTrigger){
39575 this.trigger.setDisplayed(false);
39577 this.initTrigger();
39579 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39584 initTrigger : function(){
39585 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39586 this.trigger.addClassOnOver('x-form-trigger-over');
39587 this.trigger.addClassOnClick('x-form-trigger-click');
39591 onDestroy : function(){
39593 this.trigger.removeAllListeners();
39594 this.trigger.remove();
39597 this.wrap.remove();
39599 Roo.form.TriggerField.superclass.onDestroy.call(this);
39603 onFocus : function(){
39604 Roo.form.TriggerField.superclass.onFocus.call(this);
39605 if(!this.mimicing){
39606 this.wrap.addClass('x-trigger-wrap-focus');
39607 this.mimicing = true;
39608 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39609 if(this.monitorTab){
39610 this.el.on("keydown", this.checkTab, this);
39616 checkTab : function(e){
39617 if(e.getKey() == e.TAB){
39618 this.triggerBlur();
39623 onBlur : function(){
39628 mimicBlur : function(e, t){
39629 if(!this.wrap.contains(t) && this.validateBlur()){
39630 this.triggerBlur();
39635 triggerBlur : function(){
39636 this.mimicing = false;
39637 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39638 if(this.monitorTab){
39639 this.el.un("keydown", this.checkTab, this);
39641 this.wrap.removeClass('x-trigger-wrap-focus');
39642 Roo.form.TriggerField.superclass.onBlur.call(this);
39646 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39647 validateBlur : function(e, t){
39652 onDisable : function(){
39653 Roo.form.TriggerField.superclass.onDisable.call(this);
39655 this.wrap.addClass('x-item-disabled');
39660 onEnable : function(){
39661 Roo.form.TriggerField.superclass.onEnable.call(this);
39663 this.wrap.removeClass('x-item-disabled');
39668 onShow : function(){
39669 var ae = this.getActionEl();
39672 ae.dom.style.display = '';
39673 ae.dom.style.visibility = 'visible';
39679 onHide : function(){
39680 var ae = this.getActionEl();
39681 ae.dom.style.display = 'none';
39685 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39686 * by an implementing function.
39688 * @param {EventObject} e
39690 onTriggerClick : Roo.emptyFn
39693 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39694 // to be extended by an implementing class. For an example of implementing this class, see the custom
39695 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39696 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39697 initComponent : function(){
39698 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39700 this.triggerConfig = {
39701 tag:'span', cls:'x-form-twin-triggers', cn:[
39702 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39703 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39707 getTrigger : function(index){
39708 return this.triggers[index];
39711 initTrigger : function(){
39712 var ts = this.trigger.select('.x-form-trigger', true);
39713 this.wrap.setStyle('overflow', 'hidden');
39714 var triggerField = this;
39715 ts.each(function(t, all, index){
39716 t.hide = function(){
39717 var w = triggerField.wrap.getWidth();
39718 this.dom.style.display = 'none';
39719 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39721 t.show = function(){
39722 var w = triggerField.wrap.getWidth();
39723 this.dom.style.display = '';
39724 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39726 var triggerIndex = 'Trigger'+(index+1);
39728 if(this['hide'+triggerIndex]){
39729 t.dom.style.display = 'none';
39731 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39732 t.addClassOnOver('x-form-trigger-over');
39733 t.addClassOnClick('x-form-trigger-click');
39735 this.triggers = ts.elements;
39738 onTrigger1Click : Roo.emptyFn,
39739 onTrigger2Click : Roo.emptyFn
39742 * Ext JS Library 1.1.1
39743 * Copyright(c) 2006-2007, Ext JS, LLC.
39745 * Originally Released Under LGPL - original licence link has changed is not relivant.
39748 * <script type="text/javascript">
39752 * @class Roo.form.TextArea
39753 * @extends Roo.form.TextField
39754 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39755 * support for auto-sizing.
39757 * Creates a new TextArea
39758 * @param {Object} config Configuration options
39760 Roo.form.TextArea = function(config){
39761 Roo.form.TextArea.superclass.constructor.call(this, config);
39762 // these are provided exchanges for backwards compat
39763 // minHeight/maxHeight were replaced by growMin/growMax to be
39764 // compatible with TextField growing config values
39765 if(this.minHeight !== undefined){
39766 this.growMin = this.minHeight;
39768 if(this.maxHeight !== undefined){
39769 this.growMax = this.maxHeight;
39773 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39775 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39779 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39783 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39784 * in the field (equivalent to setting overflow: hidden, defaults to false)
39786 preventScrollbars: false,
39788 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39789 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39793 onRender : function(ct, position){
39795 this.defaultAutoCreate = {
39797 style:"width:300px;height:60px;",
39798 autocomplete: "new-password"
39801 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39803 this.textSizeEl = Roo.DomHelper.append(document.body, {
39804 tag: "pre", cls: "x-form-grow-sizer"
39806 if(this.preventScrollbars){
39807 this.el.setStyle("overflow", "hidden");
39809 this.el.setHeight(this.growMin);
39813 onDestroy : function(){
39814 if(this.textSizeEl){
39815 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39817 Roo.form.TextArea.superclass.onDestroy.call(this);
39821 onKeyUp : function(e){
39822 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39828 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39829 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39831 autoSize : function(){
39832 if(!this.grow || !this.textSizeEl){
39836 var v = el.dom.value;
39837 var ts = this.textSizeEl;
39840 ts.appendChild(document.createTextNode(v));
39843 Roo.fly(ts).setWidth(this.el.getWidth());
39845 v = "  ";
39848 v = v.replace(/\n/g, '<p> </p>');
39850 v += " \n ";
39853 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
39854 if(h != this.lastHeight){
39855 this.lastHeight = h;
39856 this.el.setHeight(h);
39857 this.fireEvent("autosize", this, h);
39862 * Ext JS Library 1.1.1
39863 * Copyright(c) 2006-2007, Ext JS, LLC.
39865 * Originally Released Under LGPL - original licence link has changed is not relivant.
39868 * <script type="text/javascript">
39873 * @class Roo.form.NumberField
39874 * @extends Roo.form.TextField
39875 * Numeric text field that provides automatic keystroke filtering and numeric validation.
39877 * Creates a new NumberField
39878 * @param {Object} config Configuration options
39880 Roo.form.NumberField = function(config){
39881 Roo.form.NumberField.superclass.constructor.call(this, config);
39884 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
39886 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
39888 fieldClass: "x-form-field x-form-num-field",
39890 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39892 allowDecimals : true,
39894 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39896 decimalSeparator : ".",
39898 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39900 decimalPrecision : 2,
39902 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39904 allowNegative : true,
39906 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39908 minValue : Number.NEGATIVE_INFINITY,
39910 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39912 maxValue : Number.MAX_VALUE,
39914 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39916 minText : "The minimum value for this field is {0}",
39918 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39920 maxText : "The maximum value for this field is {0}",
39922 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39923 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39925 nanText : "{0} is not a valid number",
39928 initEvents : function(){
39929 Roo.form.NumberField.superclass.initEvents.call(this);
39930 var allowed = "0123456789";
39931 if(this.allowDecimals){
39932 allowed += this.decimalSeparator;
39934 if(this.allowNegative){
39937 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
39938 var keyPress = function(e){
39939 var k = e.getKey();
39940 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39943 var c = e.getCharCode();
39944 if(allowed.indexOf(String.fromCharCode(c)) === -1){
39948 this.el.on("keypress", keyPress, this);
39952 validateValue : function(value){
39953 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
39956 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39959 var num = this.parseValue(value);
39961 this.markInvalid(String.format(this.nanText, value));
39964 if(num < this.minValue){
39965 this.markInvalid(String.format(this.minText, this.minValue));
39968 if(num > this.maxValue){
39969 this.markInvalid(String.format(this.maxText, this.maxValue));
39975 getValue : function(){
39976 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
39980 parseValue : function(value){
39981 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
39982 return isNaN(value) ? '' : value;
39986 fixPrecision : function(value){
39987 var nan = isNaN(value);
39988 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
39989 return nan ? '' : value;
39991 return parseFloat(value).toFixed(this.decimalPrecision);
39994 setValue : function(v){
39995 v = this.fixPrecision(v);
39996 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40000 decimalPrecisionFcn : function(v){
40001 return Math.floor(v);
40004 beforeBlur : function(){
40005 var v = this.parseValue(this.getRawValue());
40012 * Ext JS Library 1.1.1
40013 * Copyright(c) 2006-2007, Ext JS, LLC.
40015 * Originally Released Under LGPL - original licence link has changed is not relivant.
40018 * <script type="text/javascript">
40022 * @class Roo.form.DateField
40023 * @extends Roo.form.TriggerField
40024 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40026 * Create a new DateField
40027 * @param {Object} config
40029 Roo.form.DateField = function(config){
40030 Roo.form.DateField.superclass.constructor.call(this, config);
40036 * Fires when a date is selected
40037 * @param {Roo.form.DateField} combo This combo box
40038 * @param {Date} date The date selected
40045 if(typeof this.minValue == "string") {
40046 this.minValue = this.parseDate(this.minValue);
40048 if(typeof this.maxValue == "string") {
40049 this.maxValue = this.parseDate(this.maxValue);
40051 this.ddMatch = null;
40052 if(this.disabledDates){
40053 var dd = this.disabledDates;
40055 for(var i = 0; i < dd.length; i++){
40057 if(i != dd.length-1) {
40061 this.ddMatch = new RegExp(re + ")");
40065 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40067 * @cfg {String} format
40068 * The default date format string which can be overriden for localization support. The format must be
40069 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40073 * @cfg {String} altFormats
40074 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40075 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40077 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40079 * @cfg {Array} disabledDays
40080 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40082 disabledDays : null,
40084 * @cfg {String} disabledDaysText
40085 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40087 disabledDaysText : "Disabled",
40089 * @cfg {Array} disabledDates
40090 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40091 * expression so they are very powerful. Some examples:
40093 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40094 * <li>["03/08", "09/16"] would disable those days for every year</li>
40095 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40096 * <li>["03/../2006"] would disable every day in March 2006</li>
40097 * <li>["^03"] would disable every day in every March</li>
40099 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40100 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40102 disabledDates : null,
40104 * @cfg {String} disabledDatesText
40105 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40107 disabledDatesText : "Disabled",
40109 * @cfg {Date/String} minValue
40110 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40111 * valid format (defaults to null).
40115 * @cfg {Date/String} maxValue
40116 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40117 * valid format (defaults to null).
40121 * @cfg {String} minText
40122 * The error text to display when the date in the cell is before minValue (defaults to
40123 * 'The date in this field must be after {minValue}').
40125 minText : "The date in this field must be equal to or after {0}",
40127 * @cfg {String} maxText
40128 * The error text to display when the date in the cell is after maxValue (defaults to
40129 * 'The date in this field must be before {maxValue}').
40131 maxText : "The date in this field must be equal to or before {0}",
40133 * @cfg {String} invalidText
40134 * The error text to display when the date in the field is invalid (defaults to
40135 * '{value} is not a valid date - it must be in the format {format}').
40137 invalidText : "{0} is not a valid date - it must be in the format {1}",
40139 * @cfg {String} triggerClass
40140 * An additional CSS class used to style the trigger button. The trigger will always get the
40141 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40142 * which displays a calendar icon).
40144 triggerClass : 'x-form-date-trigger',
40148 * @cfg {Boolean} useIso
40149 * if enabled, then the date field will use a hidden field to store the
40150 * real value as iso formated date. default (false)
40154 * @cfg {String/Object} autoCreate
40155 * A DomHelper element spec, or true for a default element spec (defaults to
40156 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40159 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40162 hiddenField: false,
40164 onRender : function(ct, position)
40166 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40168 //this.el.dom.removeAttribute('name');
40169 Roo.log("Changing name?");
40170 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40171 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40173 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40174 // prevent input submission
40175 this.hiddenName = this.name;
40182 validateValue : function(value)
40184 value = this.formatDate(value);
40185 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40186 Roo.log('super failed');
40189 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40192 var svalue = value;
40193 value = this.parseDate(value);
40195 Roo.log('parse date failed' + svalue);
40196 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40199 var time = value.getTime();
40200 if(this.minValue && time < this.minValue.getTime()){
40201 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40204 if(this.maxValue && time > this.maxValue.getTime()){
40205 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40208 if(this.disabledDays){
40209 var day = value.getDay();
40210 for(var i = 0; i < this.disabledDays.length; i++) {
40211 if(day === this.disabledDays[i]){
40212 this.markInvalid(this.disabledDaysText);
40217 var fvalue = this.formatDate(value);
40218 if(this.ddMatch && this.ddMatch.test(fvalue)){
40219 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40226 // Provides logic to override the default TriggerField.validateBlur which just returns true
40227 validateBlur : function(){
40228 return !this.menu || !this.menu.isVisible();
40231 getName: function()
40233 // returns hidden if it's set..
40234 if (!this.rendered) {return ''};
40235 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40240 * Returns the current date value of the date field.
40241 * @return {Date} The date value
40243 getValue : function(){
40245 return this.hiddenField ?
40246 this.hiddenField.value :
40247 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40251 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40252 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40253 * (the default format used is "m/d/y").
40256 //All of these calls set the same date value (May 4, 2006)
40258 //Pass a date object:
40259 var dt = new Date('5/4/06');
40260 dateField.setValue(dt);
40262 //Pass a date string (default format):
40263 dateField.setValue('5/4/06');
40265 //Pass a date string (custom format):
40266 dateField.format = 'Y-m-d';
40267 dateField.setValue('2006-5-4');
40269 * @param {String/Date} date The date or valid date string
40271 setValue : function(date){
40272 if (this.hiddenField) {
40273 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40275 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40276 // make sure the value field is always stored as a date..
40277 this.value = this.parseDate(date);
40283 parseDate : function(value){
40284 if(!value || value instanceof Date){
40287 var v = Date.parseDate(value, this.format);
40288 if (!v && this.useIso) {
40289 v = Date.parseDate(value, 'Y-m-d');
40291 if(!v && this.altFormats){
40292 if(!this.altFormatsArray){
40293 this.altFormatsArray = this.altFormats.split("|");
40295 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40296 v = Date.parseDate(value, this.altFormatsArray[i]);
40303 formatDate : function(date, fmt){
40304 return (!date || !(date instanceof Date)) ?
40305 date : date.dateFormat(fmt || this.format);
40310 select: function(m, d){
40313 this.fireEvent('select', this, d);
40315 show : function(){ // retain focus styling
40319 this.focus.defer(10, this);
40320 var ml = this.menuListeners;
40321 this.menu.un("select", ml.select, this);
40322 this.menu.un("show", ml.show, this);
40323 this.menu.un("hide", ml.hide, this);
40328 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40329 onTriggerClick : function(){
40333 if(this.menu == null){
40334 this.menu = new Roo.menu.DateMenu();
40336 Roo.apply(this.menu.picker, {
40337 showClear: this.allowBlank,
40338 minDate : this.minValue,
40339 maxDate : this.maxValue,
40340 disabledDatesRE : this.ddMatch,
40341 disabledDatesText : this.disabledDatesText,
40342 disabledDays : this.disabledDays,
40343 disabledDaysText : this.disabledDaysText,
40344 format : this.useIso ? 'Y-m-d' : this.format,
40345 minText : String.format(this.minText, this.formatDate(this.minValue)),
40346 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40348 this.menu.on(Roo.apply({}, this.menuListeners, {
40351 this.menu.picker.setValue(this.getValue() || new Date());
40352 this.menu.show(this.el, "tl-bl?");
40355 beforeBlur : function(){
40356 var v = this.parseDate(this.getRawValue());
40366 isDirty : function() {
40367 if(this.disabled) {
40371 if(typeof(this.startValue) === 'undefined'){
40375 return String(this.getValue()) !== String(this.startValue);
40380 * Ext JS Library 1.1.1
40381 * Copyright(c) 2006-2007, Ext JS, LLC.
40383 * Originally Released Under LGPL - original licence link has changed is not relivant.
40386 * <script type="text/javascript">
40390 * @class Roo.form.MonthField
40391 * @extends Roo.form.TriggerField
40392 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40394 * Create a new MonthField
40395 * @param {Object} config
40397 Roo.form.MonthField = function(config){
40399 Roo.form.MonthField.superclass.constructor.call(this, config);
40405 * Fires when a date is selected
40406 * @param {Roo.form.MonthFieeld} combo This combo box
40407 * @param {Date} date The date selected
40414 if(typeof this.minValue == "string") {
40415 this.minValue = this.parseDate(this.minValue);
40417 if(typeof this.maxValue == "string") {
40418 this.maxValue = this.parseDate(this.maxValue);
40420 this.ddMatch = null;
40421 if(this.disabledDates){
40422 var dd = this.disabledDates;
40424 for(var i = 0; i < dd.length; i++){
40426 if(i != dd.length-1) {
40430 this.ddMatch = new RegExp(re + ")");
40434 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40436 * @cfg {String} format
40437 * The default date format string which can be overriden for localization support. The format must be
40438 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40442 * @cfg {String} altFormats
40443 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40444 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40446 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40448 * @cfg {Array} disabledDays
40449 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40451 disabledDays : [0,1,2,3,4,5,6],
40453 * @cfg {String} disabledDaysText
40454 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40456 disabledDaysText : "Disabled",
40458 * @cfg {Array} disabledDates
40459 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40460 * expression so they are very powerful. Some examples:
40462 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40463 * <li>["03/08", "09/16"] would disable those days for every year</li>
40464 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40465 * <li>["03/../2006"] would disable every day in March 2006</li>
40466 * <li>["^03"] would disable every day in every March</li>
40468 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40469 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40471 disabledDates : null,
40473 * @cfg {String} disabledDatesText
40474 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40476 disabledDatesText : "Disabled",
40478 * @cfg {Date/String} minValue
40479 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40480 * valid format (defaults to null).
40484 * @cfg {Date/String} maxValue
40485 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40486 * valid format (defaults to null).
40490 * @cfg {String} minText
40491 * The error text to display when the date in the cell is before minValue (defaults to
40492 * 'The date in this field must be after {minValue}').
40494 minText : "The date in this field must be equal to or after {0}",
40496 * @cfg {String} maxTextf
40497 * The error text to display when the date in the cell is after maxValue (defaults to
40498 * 'The date in this field must be before {maxValue}').
40500 maxText : "The date in this field must be equal to or before {0}",
40502 * @cfg {String} invalidText
40503 * The error text to display when the date in the field is invalid (defaults to
40504 * '{value} is not a valid date - it must be in the format {format}').
40506 invalidText : "{0} is not a valid date - it must be in the format {1}",
40508 * @cfg {String} triggerClass
40509 * An additional CSS class used to style the trigger button. The trigger will always get the
40510 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40511 * which displays a calendar icon).
40513 triggerClass : 'x-form-date-trigger',
40517 * @cfg {Boolean} useIso
40518 * if enabled, then the date field will use a hidden field to store the
40519 * real value as iso formated date. default (true)
40523 * @cfg {String/Object} autoCreate
40524 * A DomHelper element spec, or true for a default element spec (defaults to
40525 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40528 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40531 hiddenField: false,
40533 hideMonthPicker : false,
40535 onRender : function(ct, position)
40537 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40539 this.el.dom.removeAttribute('name');
40540 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40542 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40543 // prevent input submission
40544 this.hiddenName = this.name;
40551 validateValue : function(value)
40553 value = this.formatDate(value);
40554 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40557 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40560 var svalue = value;
40561 value = this.parseDate(value);
40563 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40566 var time = value.getTime();
40567 if(this.minValue && time < this.minValue.getTime()){
40568 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40571 if(this.maxValue && time > this.maxValue.getTime()){
40572 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40575 /*if(this.disabledDays){
40576 var day = value.getDay();
40577 for(var i = 0; i < this.disabledDays.length; i++) {
40578 if(day === this.disabledDays[i]){
40579 this.markInvalid(this.disabledDaysText);
40585 var fvalue = this.formatDate(value);
40586 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40587 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40595 // Provides logic to override the default TriggerField.validateBlur which just returns true
40596 validateBlur : function(){
40597 return !this.menu || !this.menu.isVisible();
40601 * Returns the current date value of the date field.
40602 * @return {Date} The date value
40604 getValue : function(){
40608 return this.hiddenField ?
40609 this.hiddenField.value :
40610 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40614 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40615 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40616 * (the default format used is "m/d/y").
40619 //All of these calls set the same date value (May 4, 2006)
40621 //Pass a date object:
40622 var dt = new Date('5/4/06');
40623 monthField.setValue(dt);
40625 //Pass a date string (default format):
40626 monthField.setValue('5/4/06');
40628 //Pass a date string (custom format):
40629 monthField.format = 'Y-m-d';
40630 monthField.setValue('2006-5-4');
40632 * @param {String/Date} date The date or valid date string
40634 setValue : function(date){
40635 Roo.log('month setValue' + date);
40636 // can only be first of month..
40638 var val = this.parseDate(date);
40640 if (this.hiddenField) {
40641 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40643 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40644 this.value = this.parseDate(date);
40648 parseDate : function(value){
40649 if(!value || value instanceof Date){
40650 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40653 var v = Date.parseDate(value, this.format);
40654 if (!v && this.useIso) {
40655 v = Date.parseDate(value, 'Y-m-d');
40659 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40663 if(!v && this.altFormats){
40664 if(!this.altFormatsArray){
40665 this.altFormatsArray = this.altFormats.split("|");
40667 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40668 v = Date.parseDate(value, this.altFormatsArray[i]);
40675 formatDate : function(date, fmt){
40676 return (!date || !(date instanceof Date)) ?
40677 date : date.dateFormat(fmt || this.format);
40682 select: function(m, d){
40684 this.fireEvent('select', this, d);
40686 show : function(){ // retain focus styling
40690 this.focus.defer(10, this);
40691 var ml = this.menuListeners;
40692 this.menu.un("select", ml.select, this);
40693 this.menu.un("show", ml.show, this);
40694 this.menu.un("hide", ml.hide, this);
40698 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40699 onTriggerClick : function(){
40703 if(this.menu == null){
40704 this.menu = new Roo.menu.DateMenu();
40708 Roo.apply(this.menu.picker, {
40710 showClear: this.allowBlank,
40711 minDate : this.minValue,
40712 maxDate : this.maxValue,
40713 disabledDatesRE : this.ddMatch,
40714 disabledDatesText : this.disabledDatesText,
40716 format : this.useIso ? 'Y-m-d' : this.format,
40717 minText : String.format(this.minText, this.formatDate(this.minValue)),
40718 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40721 this.menu.on(Roo.apply({}, this.menuListeners, {
40729 // hide month picker get's called when we called by 'before hide';
40731 var ignorehide = true;
40732 p.hideMonthPicker = function(disableAnim){
40736 if(this.monthPicker){
40737 Roo.log("hideMonthPicker called");
40738 if(disableAnim === true){
40739 this.monthPicker.hide();
40741 this.monthPicker.slideOut('t', {duration:.2});
40742 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40743 p.fireEvent("select", this, this.value);
40749 Roo.log('picker set value');
40750 Roo.log(this.getValue());
40751 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40752 m.show(this.el, 'tl-bl?');
40753 ignorehide = false;
40754 // this will trigger hideMonthPicker..
40757 // hidden the day picker
40758 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40764 p.showMonthPicker.defer(100, p);
40770 beforeBlur : function(){
40771 var v = this.parseDate(this.getRawValue());
40777 /** @cfg {Boolean} grow @hide */
40778 /** @cfg {Number} growMin @hide */
40779 /** @cfg {Number} growMax @hide */
40786 * Ext JS Library 1.1.1
40787 * Copyright(c) 2006-2007, Ext JS, LLC.
40789 * Originally Released Under LGPL - original licence link has changed is not relivant.
40792 * <script type="text/javascript">
40797 * @class Roo.form.ComboBox
40798 * @extends Roo.form.TriggerField
40799 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40801 * Create a new ComboBox.
40802 * @param {Object} config Configuration options
40804 Roo.form.ComboBox = function(config){
40805 Roo.form.ComboBox.superclass.constructor.call(this, config);
40809 * Fires when the dropdown list is expanded
40810 * @param {Roo.form.ComboBox} combo This combo box
40815 * Fires when the dropdown list is collapsed
40816 * @param {Roo.form.ComboBox} combo This combo box
40820 * @event beforeselect
40821 * Fires before a list item is selected. Return false to cancel the selection.
40822 * @param {Roo.form.ComboBox} combo This combo box
40823 * @param {Roo.data.Record} record The data record returned from the underlying store
40824 * @param {Number} index The index of the selected item in the dropdown list
40826 'beforeselect' : true,
40829 * Fires when a list item is selected
40830 * @param {Roo.form.ComboBox} combo This combo box
40831 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
40832 * @param {Number} index The index of the selected item in the dropdown list
40836 * @event beforequery
40837 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
40838 * The event object passed has these properties:
40839 * @param {Roo.form.ComboBox} combo This combo box
40840 * @param {String} query The query
40841 * @param {Boolean} forceAll true to force "all" query
40842 * @param {Boolean} cancel true to cancel the query
40843 * @param {Object} e The query event object
40845 'beforequery': true,
40848 * Fires when the 'add' icon is pressed (add a listener to enable add button)
40849 * @param {Roo.form.ComboBox} combo This combo box
40854 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
40855 * @param {Roo.form.ComboBox} combo This combo box
40856 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
40862 if(this.transform){
40863 this.allowDomMove = false;
40864 var s = Roo.getDom(this.transform);
40865 if(!this.hiddenName){
40866 this.hiddenName = s.name;
40869 this.mode = 'local';
40870 var d = [], opts = s.options;
40871 for(var i = 0, len = opts.length;i < len; i++){
40873 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
40875 this.value = value;
40877 d.push([value, o.text]);
40879 this.store = new Roo.data.SimpleStore({
40881 fields: ['value', 'text'],
40884 this.valueField = 'value';
40885 this.displayField = 'text';
40887 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
40888 if(!this.lazyRender){
40889 this.target = true;
40890 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
40891 s.parentNode.removeChild(s); // remove it
40892 this.render(this.el.parentNode);
40894 s.parentNode.removeChild(s); // remove it
40899 this.store = Roo.factory(this.store, Roo.data);
40902 this.selectedIndex = -1;
40903 if(this.mode == 'local'){
40904 if(config.queryDelay === undefined){
40905 this.queryDelay = 10;
40907 if(config.minChars === undefined){
40913 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
40915 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
40918 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
40919 * rendering into an Roo.Editor, defaults to false)
40922 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
40923 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
40926 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
40929 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
40930 * the dropdown list (defaults to undefined, with no header element)
40934 * @cfg {String/Roo.Template} tpl The template to use to render the output
40938 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
40940 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
40942 listWidth: undefined,
40944 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
40945 * mode = 'remote' or 'text' if mode = 'local')
40947 displayField: undefined,
40949 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
40950 * mode = 'remote' or 'value' if mode = 'local').
40951 * Note: use of a valueField requires the user make a selection
40952 * in order for a value to be mapped.
40954 valueField: undefined,
40958 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
40959 * field's data value (defaults to the underlying DOM element's name)
40961 hiddenName: undefined,
40963 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
40967 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
40969 selectedClass: 'x-combo-selected',
40971 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40972 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
40973 * which displays a downward arrow icon).
40975 triggerClass : 'x-form-arrow-trigger',
40977 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
40981 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
40982 * anchor positions (defaults to 'tl-bl')
40984 listAlign: 'tl-bl?',
40986 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
40990 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
40991 * query specified by the allQuery config option (defaults to 'query')
40993 triggerAction: 'query',
40995 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
40996 * (defaults to 4, does not apply if editable = false)
41000 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41001 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41005 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41006 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41010 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41011 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41015 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41016 * when editable = true (defaults to false)
41018 selectOnFocus:false,
41020 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41022 queryParam: 'query',
41024 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41025 * when mode = 'remote' (defaults to 'Loading...')
41027 loadingText: 'Loading...',
41029 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41033 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41037 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41038 * traditional select (defaults to true)
41042 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41046 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41050 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41051 * listWidth has a higher value)
41055 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41056 * allow the user to set arbitrary text into the field (defaults to false)
41058 forceSelection:false,
41060 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41061 * if typeAhead = true (defaults to 250)
41063 typeAheadDelay : 250,
41065 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41066 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41068 valueNotFoundText : undefined,
41070 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41072 blockFocus : false,
41075 * @cfg {Boolean} disableClear Disable showing of clear button.
41077 disableClear : false,
41079 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41081 alwaysQuery : false,
41087 // element that contains real text value.. (when hidden is used..)
41090 onRender : function(ct, position){
41091 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41092 if(this.hiddenName){
41093 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41095 this.hiddenField.value =
41096 this.hiddenValue !== undefined ? this.hiddenValue :
41097 this.value !== undefined ? this.value : '';
41099 // prevent input submission
41100 this.el.dom.removeAttribute('name');
41105 this.el.dom.setAttribute('autocomplete', 'off');
41108 var cls = 'x-combo-list';
41110 this.list = new Roo.Layer({
41111 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41114 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41115 this.list.setWidth(lw);
41116 this.list.swallowEvent('mousewheel');
41117 this.assetHeight = 0;
41120 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41121 this.assetHeight += this.header.getHeight();
41124 this.innerList = this.list.createChild({cls:cls+'-inner'});
41125 this.innerList.on('mouseover', this.onViewOver, this);
41126 this.innerList.on('mousemove', this.onViewMove, this);
41127 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41129 if(this.allowBlank && !this.pageSize && !this.disableClear){
41130 this.footer = this.list.createChild({cls:cls+'-ft'});
41131 this.pageTb = new Roo.Toolbar(this.footer);
41135 this.footer = this.list.createChild({cls:cls+'-ft'});
41136 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41137 {pageSize: this.pageSize});
41141 if (this.pageTb && this.allowBlank && !this.disableClear) {
41143 this.pageTb.add(new Roo.Toolbar.Fill(), {
41144 cls: 'x-btn-icon x-btn-clear',
41146 handler: function()
41149 _this.clearValue();
41150 _this.onSelect(false, -1);
41155 this.assetHeight += this.footer.getHeight();
41160 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41163 this.view = new Roo.View(this.innerList, this.tpl, {
41164 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41167 this.view.on('click', this.onViewClick, this);
41169 this.store.on('beforeload', this.onBeforeLoad, this);
41170 this.store.on('load', this.onLoad, this);
41171 this.store.on('loadexception', this.onLoadException, this);
41173 if(this.resizable){
41174 this.resizer = new Roo.Resizable(this.list, {
41175 pinned:true, handles:'se'
41177 this.resizer.on('resize', function(r, w, h){
41178 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41179 this.listWidth = w;
41180 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41181 this.restrictHeight();
41183 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41185 if(!this.editable){
41186 this.editable = true;
41187 this.setEditable(false);
41191 if (typeof(this.events.add.listeners) != 'undefined') {
41193 this.addicon = this.wrap.createChild(
41194 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41196 this.addicon.on('click', function(e) {
41197 this.fireEvent('add', this);
41200 if (typeof(this.events.edit.listeners) != 'undefined') {
41202 this.editicon = this.wrap.createChild(
41203 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41204 if (this.addicon) {
41205 this.editicon.setStyle('margin-left', '40px');
41207 this.editicon.on('click', function(e) {
41209 // we fire even if inothing is selected..
41210 this.fireEvent('edit', this, this.lastData );
41220 initEvents : function(){
41221 Roo.form.ComboBox.superclass.initEvents.call(this);
41223 this.keyNav = new Roo.KeyNav(this.el, {
41224 "up" : function(e){
41225 this.inKeyMode = true;
41229 "down" : function(e){
41230 if(!this.isExpanded()){
41231 this.onTriggerClick();
41233 this.inKeyMode = true;
41238 "enter" : function(e){
41239 this.onViewClick();
41243 "esc" : function(e){
41247 "tab" : function(e){
41248 this.onViewClick(false);
41249 this.fireEvent("specialkey", this, e);
41255 doRelay : function(foo, bar, hname){
41256 if(hname == 'down' || this.scope.isExpanded()){
41257 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41264 this.queryDelay = Math.max(this.queryDelay || 10,
41265 this.mode == 'local' ? 10 : 250);
41266 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41267 if(this.typeAhead){
41268 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41270 if(this.editable !== false){
41271 this.el.on("keyup", this.onKeyUp, this);
41273 if(this.forceSelection){
41274 this.on('blur', this.doForce, this);
41278 onDestroy : function(){
41280 this.view.setStore(null);
41281 this.view.el.removeAllListeners();
41282 this.view.el.remove();
41283 this.view.purgeListeners();
41286 this.list.destroy();
41289 this.store.un('beforeload', this.onBeforeLoad, this);
41290 this.store.un('load', this.onLoad, this);
41291 this.store.un('loadexception', this.onLoadException, this);
41293 Roo.form.ComboBox.superclass.onDestroy.call(this);
41297 fireKey : function(e){
41298 if(e.isNavKeyPress() && !this.list.isVisible()){
41299 this.fireEvent("specialkey", this, e);
41304 onResize: function(w, h){
41305 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41307 if(typeof w != 'number'){
41308 // we do not handle it!?!?
41311 var tw = this.trigger.getWidth();
41312 tw += this.addicon ? this.addicon.getWidth() : 0;
41313 tw += this.editicon ? this.editicon.getWidth() : 0;
41315 this.el.setWidth( this.adjustWidth('input', x));
41317 this.trigger.setStyle('left', x+'px');
41319 if(this.list && this.listWidth === undefined){
41320 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41321 this.list.setWidth(lw);
41322 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41330 * Allow or prevent the user from directly editing the field text. If false is passed,
41331 * the user will only be able to select from the items defined in the dropdown list. This method
41332 * is the runtime equivalent of setting the 'editable' config option at config time.
41333 * @param {Boolean} value True to allow the user to directly edit the field text
41335 setEditable : function(value){
41336 if(value == this.editable){
41339 this.editable = value;
41341 this.el.dom.setAttribute('readOnly', true);
41342 this.el.on('mousedown', this.onTriggerClick, this);
41343 this.el.addClass('x-combo-noedit');
41345 this.el.dom.setAttribute('readOnly', false);
41346 this.el.un('mousedown', this.onTriggerClick, this);
41347 this.el.removeClass('x-combo-noedit');
41352 onBeforeLoad : function(){
41353 if(!this.hasFocus){
41356 this.innerList.update(this.loadingText ?
41357 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41358 this.restrictHeight();
41359 this.selectedIndex = -1;
41363 onLoad : function(){
41364 if(!this.hasFocus){
41367 if(this.store.getCount() > 0){
41369 this.restrictHeight();
41370 if(this.lastQuery == this.allQuery){
41372 this.el.dom.select();
41374 if(!this.selectByValue(this.value, true)){
41375 this.select(0, true);
41379 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41380 this.taTask.delay(this.typeAheadDelay);
41384 this.onEmptyResults();
41389 onLoadException : function()
41392 Roo.log(this.store.reader.jsonData);
41393 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41394 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41400 onTypeAhead : function(){
41401 if(this.store.getCount() > 0){
41402 var r = this.store.getAt(0);
41403 var newValue = r.data[this.displayField];
41404 var len = newValue.length;
41405 var selStart = this.getRawValue().length;
41406 if(selStart != len){
41407 this.setRawValue(newValue);
41408 this.selectText(selStart, newValue.length);
41414 onSelect : function(record, index){
41415 if(this.fireEvent('beforeselect', this, record, index) !== false){
41416 this.setFromData(index > -1 ? record.data : false);
41418 this.fireEvent('select', this, record, index);
41423 * Returns the currently selected field value or empty string if no value is set.
41424 * @return {String} value The selected value
41426 getValue : function(){
41427 if(this.valueField){
41428 return typeof this.value != 'undefined' ? this.value : '';
41430 return Roo.form.ComboBox.superclass.getValue.call(this);
41434 * Clears any text/value currently set in the field
41436 clearValue : function(){
41437 if(this.hiddenField){
41438 this.hiddenField.value = '';
41441 this.setRawValue('');
41442 this.lastSelectionText = '';
41447 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41448 * will be displayed in the field. If the value does not match the data value of an existing item,
41449 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41450 * Otherwise the field will be blank (although the value will still be set).
41451 * @param {String} value The value to match
41453 setValue : function(v){
41455 if(this.valueField){
41456 var r = this.findRecord(this.valueField, v);
41458 text = r.data[this.displayField];
41459 }else if(this.valueNotFoundText !== undefined){
41460 text = this.valueNotFoundText;
41463 this.lastSelectionText = text;
41464 if(this.hiddenField){
41465 this.hiddenField.value = v;
41467 Roo.form.ComboBox.superclass.setValue.call(this, text);
41471 * @property {Object} the last set data for the element
41476 * Sets the value of the field based on a object which is related to the record format for the store.
41477 * @param {Object} value the value to set as. or false on reset?
41479 setFromData : function(o){
41480 var dv = ''; // display value
41481 var vv = ''; // value value..
41483 if (this.displayField) {
41484 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41486 // this is an error condition!!!
41487 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41490 if(this.valueField){
41491 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41493 if(this.hiddenField){
41494 this.hiddenField.value = vv;
41496 this.lastSelectionText = dv;
41497 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41501 // no hidden field.. - we store the value in 'value', but still display
41502 // display field!!!!
41503 this.lastSelectionText = dv;
41504 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41510 reset : function(){
41511 // overridden so that last data is reset..
41512 this.setValue(this.resetValue);
41513 this.clearInvalid();
41514 this.lastData = false;
41516 this.view.clearSelections();
41520 findRecord : function(prop, value){
41522 if(this.store.getCount() > 0){
41523 this.store.each(function(r){
41524 if(r.data[prop] == value){
41534 getName: function()
41536 // returns hidden if it's set..
41537 if (!this.rendered) {return ''};
41538 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41542 onViewMove : function(e, t){
41543 this.inKeyMode = false;
41547 onViewOver : function(e, t){
41548 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41551 var item = this.view.findItemFromChild(t);
41553 var index = this.view.indexOf(item);
41554 this.select(index, false);
41559 onViewClick : function(doFocus)
41561 var index = this.view.getSelectedIndexes()[0];
41562 var r = this.store.getAt(index);
41564 this.onSelect(r, index);
41566 if(doFocus !== false && !this.blockFocus){
41572 restrictHeight : function(){
41573 this.innerList.dom.style.height = '';
41574 var inner = this.innerList.dom;
41575 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41576 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41577 this.list.beginUpdate();
41578 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41579 this.list.alignTo(this.el, this.listAlign);
41580 this.list.endUpdate();
41584 onEmptyResults : function(){
41589 * Returns true if the dropdown list is expanded, else false.
41591 isExpanded : function(){
41592 return this.list.isVisible();
41596 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41597 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41598 * @param {String} value The data value of the item to select
41599 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41600 * selected item if it is not currently in view (defaults to true)
41601 * @return {Boolean} True if the value matched an item in the list, else false
41603 selectByValue : function(v, scrollIntoView){
41604 if(v !== undefined && v !== null){
41605 var r = this.findRecord(this.valueField || this.displayField, v);
41607 this.select(this.store.indexOf(r), scrollIntoView);
41615 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41616 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41617 * @param {Number} index The zero-based index of the list item to select
41618 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41619 * selected item if it is not currently in view (defaults to true)
41621 select : function(index, scrollIntoView){
41622 this.selectedIndex = index;
41623 this.view.select(index);
41624 if(scrollIntoView !== false){
41625 var el = this.view.getNode(index);
41627 this.innerList.scrollChildIntoView(el, false);
41633 selectNext : function(){
41634 var ct = this.store.getCount();
41636 if(this.selectedIndex == -1){
41638 }else if(this.selectedIndex < ct-1){
41639 this.select(this.selectedIndex+1);
41645 selectPrev : function(){
41646 var ct = this.store.getCount();
41648 if(this.selectedIndex == -1){
41650 }else if(this.selectedIndex != 0){
41651 this.select(this.selectedIndex-1);
41657 onKeyUp : function(e){
41658 if(this.editable !== false && !e.isSpecialKey()){
41659 this.lastKey = e.getKey();
41660 this.dqTask.delay(this.queryDelay);
41665 validateBlur : function(){
41666 return !this.list || !this.list.isVisible();
41670 initQuery : function(){
41671 this.doQuery(this.getRawValue());
41675 doForce : function(){
41676 if(this.el.dom.value.length > 0){
41677 this.el.dom.value =
41678 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41684 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41685 * query allowing the query action to be canceled if needed.
41686 * @param {String} query The SQL query to execute
41687 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41688 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41689 * saved in the current store (defaults to false)
41691 doQuery : function(q, forceAll){
41692 if(q === undefined || q === null){
41697 forceAll: forceAll,
41701 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41705 forceAll = qe.forceAll;
41706 if(forceAll === true || (q.length >= this.minChars)){
41707 if(this.lastQuery != q || this.alwaysQuery){
41708 this.lastQuery = q;
41709 if(this.mode == 'local'){
41710 this.selectedIndex = -1;
41712 this.store.clearFilter();
41714 this.store.filter(this.displayField, q);
41718 this.store.baseParams[this.queryParam] = q;
41720 params: this.getParams(q)
41725 this.selectedIndex = -1;
41732 getParams : function(q){
41734 //p[this.queryParam] = q;
41737 p.limit = this.pageSize;
41743 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41745 collapse : function(){
41746 if(!this.isExpanded()){
41750 Roo.get(document).un('mousedown', this.collapseIf, this);
41751 Roo.get(document).un('mousewheel', this.collapseIf, this);
41752 if (!this.editable) {
41753 Roo.get(document).un('keydown', this.listKeyPress, this);
41755 this.fireEvent('collapse', this);
41759 collapseIf : function(e){
41760 if(!e.within(this.wrap) && !e.within(this.list)){
41766 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41768 expand : function(){
41769 if(this.isExpanded() || !this.hasFocus){
41772 this.list.alignTo(this.el, this.listAlign);
41774 Roo.get(document).on('mousedown', this.collapseIf, this);
41775 Roo.get(document).on('mousewheel', this.collapseIf, this);
41776 if (!this.editable) {
41777 Roo.get(document).on('keydown', this.listKeyPress, this);
41780 this.fireEvent('expand', this);
41784 // Implements the default empty TriggerField.onTriggerClick function
41785 onTriggerClick : function(){
41789 if(this.isExpanded()){
41791 if (!this.blockFocus) {
41796 this.hasFocus = true;
41797 if(this.triggerAction == 'all') {
41798 this.doQuery(this.allQuery, true);
41800 this.doQuery(this.getRawValue());
41802 if (!this.blockFocus) {
41807 listKeyPress : function(e)
41809 //Roo.log('listkeypress');
41810 // scroll to first matching element based on key pres..
41811 if (e.isSpecialKey()) {
41814 var k = String.fromCharCode(e.getKey()).toUpperCase();
41817 var csel = this.view.getSelectedNodes();
41818 var cselitem = false;
41820 var ix = this.view.indexOf(csel[0]);
41821 cselitem = this.store.getAt(ix);
41822 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41828 this.store.each(function(v) {
41830 // start at existing selection.
41831 if (cselitem.id == v.id) {
41837 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
41838 match = this.store.indexOf(v);
41843 if (match === false) {
41844 return true; // no more action?
41847 this.view.select(match);
41848 var sn = Roo.get(this.view.getSelectedNodes()[0]);
41849 sn.scrollIntoView(sn.dom.parentNode, false);
41853 * @cfg {Boolean} grow
41857 * @cfg {Number} growMin
41861 * @cfg {Number} growMax
41869 * Copyright(c) 2010-2012, Roo J Solutions Limited
41876 * @class Roo.form.ComboBoxArray
41877 * @extends Roo.form.TextField
41878 * A facebook style adder... for lists of email / people / countries etc...
41879 * pick multiple items from a combo box, and shows each one.
41881 * Fred [x] Brian [x] [Pick another |v]
41884 * For this to work: it needs various extra information
41885 * - normal combo problay has
41887 * + displayField, valueField
41889 * For our purpose...
41892 * If we change from 'extends' to wrapping...
41899 * Create a new ComboBoxArray.
41900 * @param {Object} config Configuration options
41904 Roo.form.ComboBoxArray = function(config)
41908 * @event beforeremove
41909 * Fires before remove the value from the list
41910 * @param {Roo.form.ComboBoxArray} _self This combo box array
41911 * @param {Roo.form.ComboBoxArray.Item} item removed item
41913 'beforeremove' : true,
41916 * Fires when remove the value from the list
41917 * @param {Roo.form.ComboBoxArray} _self This combo box array
41918 * @param {Roo.form.ComboBoxArray.Item} item removed item
41925 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
41927 this.items = new Roo.util.MixedCollection(false);
41929 // construct the child combo...
41939 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
41942 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
41947 // behavies liek a hiddne field
41948 inputType: 'hidden',
41950 * @cfg {Number} width The width of the box that displays the selected element
41957 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
41961 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
41963 hiddenName : false,
41966 // private the array of items that are displayed..
41968 // private - the hidden field el.
41970 // private - the filed el..
41973 //validateValue : function() { return true; }, // all values are ok!
41974 //onAddClick: function() { },
41976 onRender : function(ct, position)
41979 // create the standard hidden element
41980 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
41983 // give fake names to child combo;
41984 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
41985 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
41987 this.combo = Roo.factory(this.combo, Roo.form);
41988 this.combo.onRender(ct, position);
41989 if (typeof(this.combo.width) != 'undefined') {
41990 this.combo.onResize(this.combo.width,0);
41993 this.combo.initEvents();
41995 // assigned so form know we need to do this..
41996 this.store = this.combo.store;
41997 this.valueField = this.combo.valueField;
41998 this.displayField = this.combo.displayField ;
42001 this.combo.wrap.addClass('x-cbarray-grp');
42003 var cbwrap = this.combo.wrap.createChild(
42004 {tag: 'div', cls: 'x-cbarray-cb'},
42009 this.hiddenEl = this.combo.wrap.createChild({
42010 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42012 this.el = this.combo.wrap.createChild({
42013 tag: 'input', type:'hidden' , name: this.name, value : ''
42015 // this.el.dom.removeAttribute("name");
42018 this.outerWrap = this.combo.wrap;
42019 this.wrap = cbwrap;
42021 this.outerWrap.setWidth(this.width);
42022 this.outerWrap.dom.removeChild(this.el.dom);
42024 this.wrap.dom.appendChild(this.el.dom);
42025 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42026 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42028 this.combo.trigger.setStyle('position','relative');
42029 this.combo.trigger.setStyle('left', '0px');
42030 this.combo.trigger.setStyle('top', '2px');
42032 this.combo.el.setStyle('vertical-align', 'text-bottom');
42034 //this.trigger.setStyle('vertical-align', 'top');
42036 // this should use the code from combo really... on('add' ....)
42040 this.adder = this.outerWrap.createChild(
42041 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42043 this.adder.on('click', function(e) {
42044 _t.fireEvent('adderclick', this, e);
42048 //this.adder.on('click', this.onAddClick, _t);
42051 this.combo.on('select', function(cb, rec, ix) {
42052 this.addItem(rec.data);
42055 cb.el.dom.value = '';
42056 //cb.lastData = rec.data;
42065 getName: function()
42067 // returns hidden if it's set..
42068 if (!this.rendered) {return ''};
42069 return this.hiddenName ? this.hiddenName : this.name;
42074 onResize: function(w, h){
42077 // not sure if this is needed..
42078 //this.combo.onResize(w,h);
42080 if(typeof w != 'number'){
42081 // we do not handle it!?!?
42084 var tw = this.combo.trigger.getWidth();
42085 tw += this.addicon ? this.addicon.getWidth() : 0;
42086 tw += this.editicon ? this.editicon.getWidth() : 0;
42088 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42090 this.combo.trigger.setStyle('left', '0px');
42092 if(this.list && this.listWidth === undefined){
42093 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42094 this.list.setWidth(lw);
42095 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42102 addItem: function(rec)
42104 var valueField = this.combo.valueField;
42105 var displayField = this.combo.displayField;
42106 if (this.items.indexOfKey(rec[valueField]) > -1) {
42107 //console.log("GOT " + rec.data.id);
42111 var x = new Roo.form.ComboBoxArray.Item({
42112 //id : rec[this.idField],
42114 displayField : displayField ,
42115 tipField : displayField ,
42119 this.items.add(rec[valueField],x);
42120 // add it before the element..
42121 this.updateHiddenEl();
42122 x.render(this.outerWrap, this.wrap.dom);
42123 // add the image handler..
42126 updateHiddenEl : function()
42129 if (!this.hiddenEl) {
42133 var idField = this.combo.valueField;
42135 this.items.each(function(f) {
42136 ar.push(f.data[idField]);
42139 this.hiddenEl.dom.value = ar.join(',');
42145 this.items.clear();
42147 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42151 this.el.dom.value = '';
42152 if (this.hiddenEl) {
42153 this.hiddenEl.dom.value = '';
42157 getValue: function()
42159 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42161 setValue: function(v) // not a valid action - must use addItems..
42168 if (this.store.isLocal && (typeof(v) == 'string')) {
42169 // then we can use the store to find the values..
42170 // comma seperated at present.. this needs to allow JSON based encoding..
42171 this.hiddenEl.value = v;
42173 Roo.each(v.split(','), function(k) {
42174 Roo.log("CHECK " + this.valueField + ',' + k);
42175 var li = this.store.query(this.valueField, k);
42180 add[this.valueField] = k;
42181 add[this.displayField] = li.item(0).data[this.displayField];
42187 if (typeof(v) == 'object' ) {
42188 // then let's assume it's an array of objects..
42189 Roo.each(v, function(l) {
42197 setFromData: function(v)
42199 // this recieves an object, if setValues is called.
42201 this.el.dom.value = v[this.displayField];
42202 this.hiddenEl.dom.value = v[this.valueField];
42203 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42206 var kv = v[this.valueField];
42207 var dv = v[this.displayField];
42208 kv = typeof(kv) != 'string' ? '' : kv;
42209 dv = typeof(dv) != 'string' ? '' : dv;
42212 var keys = kv.split(',');
42213 var display = dv.split(',');
42214 for (var i = 0 ; i < keys.length; i++) {
42217 add[this.valueField] = keys[i];
42218 add[this.displayField] = display[i];
42226 * Validates the combox array value
42227 * @return {Boolean} True if the value is valid, else false
42229 validate : function(){
42230 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42231 this.clearInvalid();
42237 validateValue : function(value){
42238 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42246 isDirty : function() {
42247 if(this.disabled) {
42252 var d = Roo.decode(String(this.originalValue));
42254 return String(this.getValue()) !== String(this.originalValue);
42257 var originalValue = [];
42259 for (var i = 0; i < d.length; i++){
42260 originalValue.push(d[i][this.valueField]);
42263 return String(this.getValue()) !== String(originalValue.join(','));
42272 * @class Roo.form.ComboBoxArray.Item
42273 * @extends Roo.BoxComponent
42274 * A selected item in the list
42275 * Fred [x] Brian [x] [Pick another |v]
42278 * Create a new item.
42279 * @param {Object} config Configuration options
42282 Roo.form.ComboBoxArray.Item = function(config) {
42283 config.id = Roo.id();
42284 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42287 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42290 displayField : false,
42294 defaultAutoCreate : {
42296 cls: 'x-cbarray-item',
42303 src : Roo.BLANK_IMAGE_URL ,
42311 onRender : function(ct, position)
42313 Roo.form.Field.superclass.onRender.call(this, ct, position);
42316 var cfg = this.getAutoCreate();
42317 this.el = ct.createChild(cfg, position);
42320 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42322 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42323 this.cb.renderer(this.data) :
42324 String.format('{0}',this.data[this.displayField]);
42327 this.el.child('div').dom.setAttribute('qtip',
42328 String.format('{0}',this.data[this.tipField])
42331 this.el.child('img').on('click', this.remove, this);
42335 remove : function()
42337 if(this.cb.disabled){
42341 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42342 this.cb.items.remove(this);
42343 this.el.child('img').un('click', this.remove, this);
42345 this.cb.updateHiddenEl();
42347 this.cb.fireEvent('remove', this.cb, this);
42353 * Ext JS Library 1.1.1
42354 * Copyright(c) 2006-2007, Ext JS, LLC.
42356 * Originally Released Under LGPL - original licence link has changed is not relivant.
42359 * <script type="text/javascript">
42362 * @class Roo.form.Checkbox
42363 * @extends Roo.form.Field
42364 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42366 * Creates a new Checkbox
42367 * @param {Object} config Configuration options
42369 Roo.form.Checkbox = function(config){
42370 Roo.form.Checkbox.superclass.constructor.call(this, config);
42374 * Fires when the checkbox is checked or unchecked.
42375 * @param {Roo.form.Checkbox} this This checkbox
42376 * @param {Boolean} checked The new checked value
42382 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42384 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42386 focusClass : undefined,
42388 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42390 fieldClass: "x-form-field",
42392 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42396 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42397 * {tag: "input", type: "checkbox", autocomplete: "off"})
42399 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42401 * @cfg {String} boxLabel The text that appears beside the checkbox
42405 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42409 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42411 valueOff: '0', // value when not checked..
42413 actionMode : 'viewEl',
42416 itemCls : 'x-menu-check-item x-form-item',
42417 groupClass : 'x-menu-group-item',
42418 inputType : 'hidden',
42421 inSetChecked: false, // check that we are not calling self...
42423 inputElement: false, // real input element?
42424 basedOn: false, // ????
42426 isFormField: true, // not sure where this is needed!!!!
42428 onResize : function(){
42429 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42430 if(!this.boxLabel){
42431 this.el.alignTo(this.wrap, 'c-c');
42435 initEvents : function(){
42436 Roo.form.Checkbox.superclass.initEvents.call(this);
42437 this.el.on("click", this.onClick, this);
42438 this.el.on("change", this.onClick, this);
42442 getResizeEl : function(){
42446 getPositionEl : function(){
42451 onRender : function(ct, position){
42452 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42454 if(this.inputValue !== undefined){
42455 this.el.dom.value = this.inputValue;
42458 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42459 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42460 var viewEl = this.wrap.createChild({
42461 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42462 this.viewEl = viewEl;
42463 this.wrap.on('click', this.onClick, this);
42465 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42466 this.el.on('propertychange', this.setFromHidden, this); //ie
42471 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42472 // viewEl.on('click', this.onClick, this);
42474 //if(this.checked){
42475 this.setChecked(this.checked);
42477 //this.checked = this.el.dom;
42483 initValue : Roo.emptyFn,
42486 * Returns the checked state of the checkbox.
42487 * @return {Boolean} True if checked, else false
42489 getValue : function(){
42491 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42493 return this.valueOff;
42498 onClick : function(){
42499 if (this.disabled) {
42502 this.setChecked(!this.checked);
42504 //if(this.el.dom.checked != this.checked){
42505 // this.setValue(this.el.dom.checked);
42510 * Sets the checked state of the checkbox.
42511 * On is always based on a string comparison between inputValue and the param.
42512 * @param {Boolean/String} value - the value to set
42513 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42515 setValue : function(v,suppressEvent){
42518 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42519 //if(this.el && this.el.dom){
42520 // this.el.dom.checked = this.checked;
42521 // this.el.dom.defaultChecked = this.checked;
42523 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42524 //this.fireEvent("check", this, this.checked);
42527 setChecked : function(state,suppressEvent)
42529 if (this.inSetChecked) {
42530 this.checked = state;
42536 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42538 this.checked = state;
42539 if(suppressEvent !== true){
42540 this.fireEvent('check', this, state);
42542 this.inSetChecked = true;
42543 this.el.dom.value = state ? this.inputValue : this.valueOff;
42544 this.inSetChecked = false;
42547 // handle setting of hidden value by some other method!!?!?
42548 setFromHidden: function()
42553 //console.log("SET FROM HIDDEN");
42554 //alert('setFrom hidden');
42555 this.setValue(this.el.dom.value);
42558 onDestroy : function()
42561 Roo.get(this.viewEl).remove();
42564 Roo.form.Checkbox.superclass.onDestroy.call(this);
42567 setBoxLabel : function(str)
42569 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42574 * Ext JS Library 1.1.1
42575 * Copyright(c) 2006-2007, Ext JS, LLC.
42577 * Originally Released Under LGPL - original licence link has changed is not relivant.
42580 * <script type="text/javascript">
42584 * @class Roo.form.Radio
42585 * @extends Roo.form.Checkbox
42586 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42587 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42589 * Creates a new Radio
42590 * @param {Object} config Configuration options
42592 Roo.form.Radio = function(){
42593 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42595 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42596 inputType: 'radio',
42599 * If this radio is part of a group, it will return the selected value
42602 getGroupValue : function(){
42603 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42607 onRender : function(ct, position){
42608 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42610 if(this.inputValue !== undefined){
42611 this.el.dom.value = this.inputValue;
42614 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42615 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42616 //var viewEl = this.wrap.createChild({
42617 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42618 //this.viewEl = viewEl;
42619 //this.wrap.on('click', this.onClick, this);
42621 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42622 //this.el.on('propertychange', this.setFromHidden, this); //ie
42627 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42628 // viewEl.on('click', this.onClick, this);
42631 this.el.dom.checked = 'checked' ;
42637 });//<script type="text/javascript">
42640 * Based Ext JS Library 1.1.1
42641 * Copyright(c) 2006-2007, Ext JS, LLC.
42647 * @class Roo.HtmlEditorCore
42648 * @extends Roo.Component
42649 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42651 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42654 Roo.HtmlEditorCore = function(config){
42657 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42662 * @event initialize
42663 * Fires when the editor is fully initialized (including the iframe)
42664 * @param {Roo.HtmlEditorCore} this
42669 * Fires when the editor is first receives the focus. Any insertion must wait
42670 * until after this event.
42671 * @param {Roo.HtmlEditorCore} this
42675 * @event beforesync
42676 * Fires before the textarea is updated with content from the editor iframe. Return false
42677 * to cancel the sync.
42678 * @param {Roo.HtmlEditorCore} this
42679 * @param {String} html
42683 * @event beforepush
42684 * Fires before the iframe editor is updated with content from the textarea. Return false
42685 * to cancel the push.
42686 * @param {Roo.HtmlEditorCore} this
42687 * @param {String} html
42692 * Fires when the textarea is updated with content from the editor iframe.
42693 * @param {Roo.HtmlEditorCore} this
42694 * @param {String} html
42699 * Fires when the iframe editor is updated with content from the textarea.
42700 * @param {Roo.HtmlEditorCore} this
42701 * @param {String} html
42706 * @event editorevent
42707 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42708 * @param {Roo.HtmlEditorCore} this
42714 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42716 // defaults : white / black...
42717 this.applyBlacklists();
42724 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42728 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42734 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42739 * @cfg {Number} height (in pixels)
42743 * @cfg {Number} width (in pixels)
42748 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42751 stylesheets: false,
42756 // private properties
42757 validationEvent : false,
42759 initialized : false,
42761 sourceEditMode : false,
42762 onFocus : Roo.emptyFn,
42764 hideMode:'offsets',
42768 // blacklist + whitelisted elements..
42775 * Protected method that will not generally be called directly. It
42776 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42777 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42779 getDocMarkup : function(){
42783 // inherit styels from page...??
42784 if (this.stylesheets === false) {
42786 Roo.get(document.head).select('style').each(function(node) {
42787 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42790 Roo.get(document.head).select('link').each(function(node) {
42791 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42794 } else if (!this.stylesheets.length) {
42796 st = '<style type="text/css">' +
42797 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42803 st += '<style type="text/css">' +
42804 'IMG { cursor: pointer } ' +
42808 return '<html><head>' + st +
42809 //<style type="text/css">' +
42810 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42812 ' </head><body class="roo-htmleditor-body"></body></html>';
42816 onRender : function(ct, position)
42819 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42820 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42823 this.el.dom.style.border = '0 none';
42824 this.el.dom.setAttribute('tabIndex', -1);
42825 this.el.addClass('x-hidden hide');
42829 if(Roo.isIE){ // fix IE 1px bogus margin
42830 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42834 this.frameId = Roo.id();
42838 var iframe = this.owner.wrap.createChild({
42840 cls: 'form-control', // bootstrap..
42842 name: this.frameId,
42843 frameBorder : 'no',
42844 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42849 this.iframe = iframe.dom;
42851 this.assignDocWin();
42853 this.doc.designMode = 'on';
42856 this.doc.write(this.getDocMarkup());
42860 var task = { // must defer to wait for browser to be ready
42862 //console.log("run task?" + this.doc.readyState);
42863 this.assignDocWin();
42864 if(this.doc.body || this.doc.readyState == 'complete'){
42866 this.doc.designMode="on";
42870 Roo.TaskMgr.stop(task);
42871 this.initEditor.defer(10, this);
42878 Roo.TaskMgr.start(task);
42883 onResize : function(w, h)
42885 Roo.log('resize: ' +w + ',' + h );
42886 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
42890 if(typeof w == 'number'){
42892 this.iframe.style.width = w + 'px';
42894 if(typeof h == 'number'){
42896 this.iframe.style.height = h + 'px';
42898 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
42905 * Toggles the editor between standard and source edit mode.
42906 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42908 toggleSourceEdit : function(sourceEditMode){
42910 this.sourceEditMode = sourceEditMode === true;
42912 if(this.sourceEditMode){
42914 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
42917 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
42918 //this.iframe.className = '';
42921 //this.setSize(this.owner.wrap.getSize());
42922 //this.fireEvent('editmodechange', this, this.sourceEditMode);
42929 * Protected method that will not generally be called directly. If you need/want
42930 * custom HTML cleanup, this is the method you should override.
42931 * @param {String} html The HTML to be cleaned
42932 * return {String} The cleaned HTML
42934 cleanHtml : function(html){
42935 html = String(html);
42936 if(html.length > 5){
42937 if(Roo.isSafari){ // strip safari nonsense
42938 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
42941 if(html == ' '){
42948 * HTML Editor -> Textarea
42949 * Protected method that will not generally be called directly. Syncs the contents
42950 * of the editor iframe with the textarea.
42952 syncValue : function(){
42953 if(this.initialized){
42954 var bd = (this.doc.body || this.doc.documentElement);
42955 //this.cleanUpPaste(); -- this is done else where and causes havoc..
42956 var html = bd.innerHTML;
42958 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
42959 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
42961 html = '<div style="'+m[0]+'">' + html + '</div>';
42964 html = this.cleanHtml(html);
42965 // fix up the special chars.. normaly like back quotes in word...
42966 // however we do not want to do this with chinese..
42967 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
42968 var cc = b.charCodeAt();
42970 (cc >= 0x4E00 && cc < 0xA000 ) ||
42971 (cc >= 0x3400 && cc < 0x4E00 ) ||
42972 (cc >= 0xf900 && cc < 0xfb00 )
42978 if(this.owner.fireEvent('beforesync', this, html) !== false){
42979 this.el.dom.value = html;
42980 this.owner.fireEvent('sync', this, html);
42986 * Protected method that will not generally be called directly. Pushes the value of the textarea
42987 * into the iframe editor.
42989 pushValue : function(){
42990 if(this.initialized){
42991 var v = this.el.dom.value.trim();
42993 // if(v.length < 1){
42997 if(this.owner.fireEvent('beforepush', this, v) !== false){
42998 var d = (this.doc.body || this.doc.documentElement);
43000 this.cleanUpPaste();
43001 this.el.dom.value = d.innerHTML;
43002 this.owner.fireEvent('push', this, v);
43008 deferFocus : function(){
43009 this.focus.defer(10, this);
43013 focus : function(){
43014 if(this.win && !this.sourceEditMode){
43021 assignDocWin: function()
43023 var iframe = this.iframe;
43026 this.doc = iframe.contentWindow.document;
43027 this.win = iframe.contentWindow;
43029 // if (!Roo.get(this.frameId)) {
43032 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43033 // this.win = Roo.get(this.frameId).dom.contentWindow;
43035 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43039 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43040 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43045 initEditor : function(){
43046 //console.log("INIT EDITOR");
43047 this.assignDocWin();
43051 this.doc.designMode="on";
43053 this.doc.write(this.getDocMarkup());
43056 var dbody = (this.doc.body || this.doc.documentElement);
43057 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43058 // this copies styles from the containing element into thsi one..
43059 // not sure why we need all of this..
43060 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43062 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43063 //ss['background-attachment'] = 'fixed'; // w3c
43064 dbody.bgProperties = 'fixed'; // ie
43065 //Roo.DomHelper.applyStyles(dbody, ss);
43066 Roo.EventManager.on(this.doc, {
43067 //'mousedown': this.onEditorEvent,
43068 'mouseup': this.onEditorEvent,
43069 'dblclick': this.onEditorEvent,
43070 'click': this.onEditorEvent,
43071 'keyup': this.onEditorEvent,
43076 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43078 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43079 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43081 this.initialized = true;
43083 this.owner.fireEvent('initialize', this);
43088 onDestroy : function(){
43094 //for (var i =0; i < this.toolbars.length;i++) {
43095 // // fixme - ask toolbars for heights?
43096 // this.toolbars[i].onDestroy();
43099 //this.wrap.dom.innerHTML = '';
43100 //this.wrap.remove();
43105 onFirstFocus : function(){
43107 this.assignDocWin();
43110 this.activated = true;
43113 if(Roo.isGecko){ // prevent silly gecko errors
43115 var s = this.win.getSelection();
43116 if(!s.focusNode || s.focusNode.nodeType != 3){
43117 var r = s.getRangeAt(0);
43118 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43123 this.execCmd('useCSS', true);
43124 this.execCmd('styleWithCSS', false);
43127 this.owner.fireEvent('activate', this);
43131 adjustFont: function(btn){
43132 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43133 //if(Roo.isSafari){ // safari
43136 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43137 if(Roo.isSafari){ // safari
43138 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43139 v = (v < 10) ? 10 : v;
43140 v = (v > 48) ? 48 : v;
43141 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43146 v = Math.max(1, v+adjust);
43148 this.execCmd('FontSize', v );
43151 onEditorEvent : function(e)
43153 this.owner.fireEvent('editorevent', this, e);
43154 // this.updateToolbar();
43155 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43158 insertTag : function(tg)
43160 // could be a bit smarter... -> wrap the current selected tRoo..
43161 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43163 range = this.createRange(this.getSelection());
43164 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43165 wrappingNode.appendChild(range.extractContents());
43166 range.insertNode(wrappingNode);
43173 this.execCmd("formatblock", tg);
43177 insertText : function(txt)
43181 var range = this.createRange();
43182 range.deleteContents();
43183 //alert(Sender.getAttribute('label'));
43185 range.insertNode(this.doc.createTextNode(txt));
43191 * Executes a Midas editor command on the editor document and performs necessary focus and
43192 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43193 * @param {String} cmd The Midas command
43194 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43196 relayCmd : function(cmd, value){
43198 this.execCmd(cmd, value);
43199 this.owner.fireEvent('editorevent', this);
43200 //this.updateToolbar();
43201 this.owner.deferFocus();
43205 * Executes a Midas editor command directly on the editor document.
43206 * For visual commands, you should use {@link #relayCmd} instead.
43207 * <b>This should only be called after the editor is initialized.</b>
43208 * @param {String} cmd The Midas command
43209 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43211 execCmd : function(cmd, value){
43212 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43219 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43221 * @param {String} text | dom node..
43223 insertAtCursor : function(text)
43228 if(!this.activated){
43234 var r = this.doc.selection.createRange();
43245 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43249 // from jquery ui (MIT licenced)
43251 var win = this.win;
43253 if (win.getSelection && win.getSelection().getRangeAt) {
43254 range = win.getSelection().getRangeAt(0);
43255 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43256 range.insertNode(node);
43257 } else if (win.document.selection && win.document.selection.createRange) {
43258 // no firefox support
43259 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43260 win.document.selection.createRange().pasteHTML(txt);
43262 // no firefox support
43263 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43264 this.execCmd('InsertHTML', txt);
43273 mozKeyPress : function(e){
43275 var c = e.getCharCode(), cmd;
43278 c = String.fromCharCode(c).toLowerCase();
43292 this.cleanUpPaste.defer(100, this);
43300 e.preventDefault();
43308 fixKeys : function(){ // load time branching for fastest keydown performance
43310 return function(e){
43311 var k = e.getKey(), r;
43314 r = this.doc.selection.createRange();
43317 r.pasteHTML('    ');
43324 r = this.doc.selection.createRange();
43326 var target = r.parentElement();
43327 if(!target || target.tagName.toLowerCase() != 'li'){
43329 r.pasteHTML('<br />');
43335 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43336 this.cleanUpPaste.defer(100, this);
43342 }else if(Roo.isOpera){
43343 return function(e){
43344 var k = e.getKey();
43348 this.execCmd('InsertHTML','    ');
43351 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43352 this.cleanUpPaste.defer(100, this);
43357 }else if(Roo.isSafari){
43358 return function(e){
43359 var k = e.getKey();
43363 this.execCmd('InsertText','\t');
43367 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43368 this.cleanUpPaste.defer(100, this);
43376 getAllAncestors: function()
43378 var p = this.getSelectedNode();
43381 a.push(p); // push blank onto stack..
43382 p = this.getParentElement();
43386 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43390 a.push(this.doc.body);
43394 lastSelNode : false,
43397 getSelection : function()
43399 this.assignDocWin();
43400 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43403 getSelectedNode: function()
43405 // this may only work on Gecko!!!
43407 // should we cache this!!!!
43412 var range = this.createRange(this.getSelection()).cloneRange();
43415 var parent = range.parentElement();
43417 var testRange = range.duplicate();
43418 testRange.moveToElementText(parent);
43419 if (testRange.inRange(range)) {
43422 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43425 parent = parent.parentElement;
43430 // is ancestor a text element.
43431 var ac = range.commonAncestorContainer;
43432 if (ac.nodeType == 3) {
43433 ac = ac.parentNode;
43436 var ar = ac.childNodes;
43439 var other_nodes = [];
43440 var has_other_nodes = false;
43441 for (var i=0;i<ar.length;i++) {
43442 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43445 // fullly contained node.
43447 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43452 // probably selected..
43453 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43454 other_nodes.push(ar[i]);
43458 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43463 has_other_nodes = true;
43465 if (!nodes.length && other_nodes.length) {
43466 nodes= other_nodes;
43468 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43474 createRange: function(sel)
43476 // this has strange effects when using with
43477 // top toolbar - not sure if it's a great idea.
43478 //this.editor.contentWindow.focus();
43479 if (typeof sel != "undefined") {
43481 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43483 return this.doc.createRange();
43486 return this.doc.createRange();
43489 getParentElement: function()
43492 this.assignDocWin();
43493 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43495 var range = this.createRange(sel);
43498 var p = range.commonAncestorContainer;
43499 while (p.nodeType == 3) { // text node
43510 * Range intersection.. the hard stuff...
43514 * [ -- selected range --- ]
43518 * if end is before start or hits it. fail.
43519 * if start is after end or hits it fail.
43521 * if either hits (but other is outside. - then it's not
43527 // @see http://www.thismuchiknow.co.uk/?p=64.
43528 rangeIntersectsNode : function(range, node)
43530 var nodeRange = node.ownerDocument.createRange();
43532 nodeRange.selectNode(node);
43534 nodeRange.selectNodeContents(node);
43537 var rangeStartRange = range.cloneRange();
43538 rangeStartRange.collapse(true);
43540 var rangeEndRange = range.cloneRange();
43541 rangeEndRange.collapse(false);
43543 var nodeStartRange = nodeRange.cloneRange();
43544 nodeStartRange.collapse(true);
43546 var nodeEndRange = nodeRange.cloneRange();
43547 nodeEndRange.collapse(false);
43549 return rangeStartRange.compareBoundaryPoints(
43550 Range.START_TO_START, nodeEndRange) == -1 &&
43551 rangeEndRange.compareBoundaryPoints(
43552 Range.START_TO_START, nodeStartRange) == 1;
43556 rangeCompareNode : function(range, node)
43558 var nodeRange = node.ownerDocument.createRange();
43560 nodeRange.selectNode(node);
43562 nodeRange.selectNodeContents(node);
43566 range.collapse(true);
43568 nodeRange.collapse(true);
43570 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43571 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43573 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43575 var nodeIsBefore = ss == 1;
43576 var nodeIsAfter = ee == -1;
43578 if (nodeIsBefore && nodeIsAfter) {
43581 if (!nodeIsBefore && nodeIsAfter) {
43582 return 1; //right trailed.
43585 if (nodeIsBefore && !nodeIsAfter) {
43586 return 2; // left trailed.
43592 // private? - in a new class?
43593 cleanUpPaste : function()
43595 // cleans up the whole document..
43596 Roo.log('cleanuppaste');
43598 this.cleanUpChildren(this.doc.body);
43599 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43600 if (clean != this.doc.body.innerHTML) {
43601 this.doc.body.innerHTML = clean;
43606 cleanWordChars : function(input) {// change the chars to hex code
43607 var he = Roo.HtmlEditorCore;
43609 var output = input;
43610 Roo.each(he.swapCodes, function(sw) {
43611 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43613 output = output.replace(swapper, sw[1]);
43620 cleanUpChildren : function (n)
43622 if (!n.childNodes.length) {
43625 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43626 this.cleanUpChild(n.childNodes[i]);
43633 cleanUpChild : function (node)
43636 //console.log(node);
43637 if (node.nodeName == "#text") {
43638 // clean up silly Windows -- stuff?
43641 if (node.nodeName == "#comment") {
43642 node.parentNode.removeChild(node);
43643 // clean up silly Windows -- stuff?
43646 var lcname = node.tagName.toLowerCase();
43647 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43648 // whitelist of tags..
43650 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43652 node.parentNode.removeChild(node);
43657 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43659 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43660 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43662 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43663 // remove_keep_children = true;
43666 if (remove_keep_children) {
43667 this.cleanUpChildren(node);
43668 // inserts everything just before this node...
43669 while (node.childNodes.length) {
43670 var cn = node.childNodes[0];
43671 node.removeChild(cn);
43672 node.parentNode.insertBefore(cn, node);
43674 node.parentNode.removeChild(node);
43678 if (!node.attributes || !node.attributes.length) {
43679 this.cleanUpChildren(node);
43683 function cleanAttr(n,v)
43686 if (v.match(/^\./) || v.match(/^\//)) {
43689 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
43692 if (v.match(/^#/)) {
43695 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43696 node.removeAttribute(n);
43700 var cwhite = this.cwhite;
43701 var cblack = this.cblack;
43703 function cleanStyle(n,v)
43705 if (v.match(/expression/)) { //XSS?? should we even bother..
43706 node.removeAttribute(n);
43710 var parts = v.split(/;/);
43713 Roo.each(parts, function(p) {
43714 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43718 var l = p.split(':').shift().replace(/\s+/g,'');
43719 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43721 if ( cwhite.length && cblack.indexOf(l) > -1) {
43722 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43723 //node.removeAttribute(n);
43727 // only allow 'c whitelisted system attributes'
43728 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43729 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43730 //node.removeAttribute(n);
43740 if (clean.length) {
43741 node.setAttribute(n, clean.join(';'));
43743 node.removeAttribute(n);
43749 for (var i = node.attributes.length-1; i > -1 ; i--) {
43750 var a = node.attributes[i];
43753 if (a.name.toLowerCase().substr(0,2)=='on') {
43754 node.removeAttribute(a.name);
43757 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43758 node.removeAttribute(a.name);
43761 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43762 cleanAttr(a.name,a.value); // fixme..
43765 if (a.name == 'style') {
43766 cleanStyle(a.name,a.value);
43769 /// clean up MS crap..
43770 // tecnically this should be a list of valid class'es..
43773 if (a.name == 'class') {
43774 if (a.value.match(/^Mso/)) {
43775 node.className = '';
43778 if (a.value.match(/body/)) {
43779 node.className = '';
43790 this.cleanUpChildren(node);
43796 * Clean up MS wordisms...
43798 cleanWord : function(node)
43803 this.cleanWord(this.doc.body);
43806 if (node.nodeName == "#text") {
43807 // clean up silly Windows -- stuff?
43810 if (node.nodeName == "#comment") {
43811 node.parentNode.removeChild(node);
43812 // clean up silly Windows -- stuff?
43816 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43817 node.parentNode.removeChild(node);
43821 // remove - but keep children..
43822 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43823 while (node.childNodes.length) {
43824 var cn = node.childNodes[0];
43825 node.removeChild(cn);
43826 node.parentNode.insertBefore(cn, node);
43828 node.parentNode.removeChild(node);
43829 this.iterateChildren(node, this.cleanWord);
43833 if (node.className.length) {
43835 var cn = node.className.split(/\W+/);
43837 Roo.each(cn, function(cls) {
43838 if (cls.match(/Mso[a-zA-Z]+/)) {
43843 node.className = cna.length ? cna.join(' ') : '';
43845 node.removeAttribute("class");
43849 if (node.hasAttribute("lang")) {
43850 node.removeAttribute("lang");
43853 if (node.hasAttribute("style")) {
43855 var styles = node.getAttribute("style").split(";");
43857 Roo.each(styles, function(s) {
43858 if (!s.match(/:/)) {
43861 var kv = s.split(":");
43862 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
43865 // what ever is left... we allow.
43868 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43869 if (!nstyle.length) {
43870 node.removeAttribute('style');
43873 this.iterateChildren(node, this.cleanWord);
43879 * iterateChildren of a Node, calling fn each time, using this as the scole..
43880 * @param {DomNode} node node to iterate children of.
43881 * @param {Function} fn method of this class to call on each item.
43883 iterateChildren : function(node, fn)
43885 if (!node.childNodes.length) {
43888 for (var i = node.childNodes.length-1; i > -1 ; i--) {
43889 fn.call(this, node.childNodes[i])
43895 * cleanTableWidths.
43897 * Quite often pasting from word etc.. results in tables with column and widths.
43898 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
43901 cleanTableWidths : function(node)
43906 this.cleanTableWidths(this.doc.body);
43911 if (node.nodeName == "#text" || node.nodeName == "#comment") {
43914 Roo.log(node.tagName);
43915 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
43916 this.iterateChildren(node, this.cleanTableWidths);
43919 if (node.hasAttribute('width')) {
43920 node.removeAttribute('width');
43924 if (node.hasAttribute("style")) {
43927 var styles = node.getAttribute("style").split(";");
43929 Roo.each(styles, function(s) {
43930 if (!s.match(/:/)) {
43933 var kv = s.split(":");
43934 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
43937 // what ever is left... we allow.
43940 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43941 if (!nstyle.length) {
43942 node.removeAttribute('style');
43946 this.iterateChildren(node, this.cleanTableWidths);
43954 domToHTML : function(currentElement, depth, nopadtext) {
43956 depth = depth || 0;
43957 nopadtext = nopadtext || false;
43959 if (!currentElement) {
43960 return this.domToHTML(this.doc.body);
43963 //Roo.log(currentElement);
43965 var allText = false;
43966 var nodeName = currentElement.nodeName;
43967 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
43969 if (nodeName == '#text') {
43971 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
43976 if (nodeName != 'BODY') {
43979 // Prints the node tagName, such as <A>, <IMG>, etc
43982 for(i = 0; i < currentElement.attributes.length;i++) {
43984 var aname = currentElement.attributes.item(i).name;
43985 if (!currentElement.attributes.item(i).value.length) {
43988 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
43991 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44000 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44003 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44008 // Traverse the tree
44010 var currentElementChild = currentElement.childNodes.item(i);
44011 var allText = true;
44012 var innerHTML = '';
44014 while (currentElementChild) {
44015 // Formatting code (indent the tree so it looks nice on the screen)
44016 var nopad = nopadtext;
44017 if (lastnode == 'SPAN') {
44021 if (currentElementChild.nodeName == '#text') {
44022 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44023 toadd = nopadtext ? toadd : toadd.trim();
44024 if (!nopad && toadd.length > 80) {
44025 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44027 innerHTML += toadd;
44030 currentElementChild = currentElement.childNodes.item(i);
44036 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44038 // Recursively traverse the tree structure of the child node
44039 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44040 lastnode = currentElementChild.nodeName;
44042 currentElementChild=currentElement.childNodes.item(i);
44048 // The remaining code is mostly for formatting the tree
44049 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44054 ret+= "</"+tagName+">";
44060 applyBlacklists : function()
44062 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44063 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44067 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44068 if (b.indexOf(tag) > -1) {
44071 this.white.push(tag);
44075 Roo.each(w, function(tag) {
44076 if (b.indexOf(tag) > -1) {
44079 if (this.white.indexOf(tag) > -1) {
44082 this.white.push(tag);
44087 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44088 if (w.indexOf(tag) > -1) {
44091 this.black.push(tag);
44095 Roo.each(b, function(tag) {
44096 if (w.indexOf(tag) > -1) {
44099 if (this.black.indexOf(tag) > -1) {
44102 this.black.push(tag);
44107 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44108 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44112 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44113 if (b.indexOf(tag) > -1) {
44116 this.cwhite.push(tag);
44120 Roo.each(w, function(tag) {
44121 if (b.indexOf(tag) > -1) {
44124 if (this.cwhite.indexOf(tag) > -1) {
44127 this.cwhite.push(tag);
44132 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44133 if (w.indexOf(tag) > -1) {
44136 this.cblack.push(tag);
44140 Roo.each(b, function(tag) {
44141 if (w.indexOf(tag) > -1) {
44144 if (this.cblack.indexOf(tag) > -1) {
44147 this.cblack.push(tag);
44152 setStylesheets : function(stylesheets)
44154 if(typeof(stylesheets) == 'string'){
44155 Roo.get(this.iframe.contentDocument.head).createChild({
44157 rel : 'stylesheet',
44166 Roo.each(stylesheets, function(s) {
44171 Roo.get(_this.iframe.contentDocument.head).createChild({
44173 rel : 'stylesheet',
44182 removeStylesheets : function()
44186 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44191 // hide stuff that is not compatible
44205 * @event specialkey
44209 * @cfg {String} fieldClass @hide
44212 * @cfg {String} focusClass @hide
44215 * @cfg {String} autoCreate @hide
44218 * @cfg {String} inputType @hide
44221 * @cfg {String} invalidClass @hide
44224 * @cfg {String} invalidText @hide
44227 * @cfg {String} msgFx @hide
44230 * @cfg {String} validateOnBlur @hide
44234 Roo.HtmlEditorCore.white = [
44235 'area', 'br', 'img', 'input', 'hr', 'wbr',
44237 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44238 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44239 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44240 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44241 'table', 'ul', 'xmp',
44243 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44246 'dir', 'menu', 'ol', 'ul', 'dl',
44252 Roo.HtmlEditorCore.black = [
44253 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44255 'base', 'basefont', 'bgsound', 'blink', 'body',
44256 'frame', 'frameset', 'head', 'html', 'ilayer',
44257 'iframe', 'layer', 'link', 'meta', 'object',
44258 'script', 'style' ,'title', 'xml' // clean later..
44260 Roo.HtmlEditorCore.clean = [
44261 'script', 'style', 'title', 'xml'
44263 Roo.HtmlEditorCore.remove = [
44268 Roo.HtmlEditorCore.ablack = [
44272 Roo.HtmlEditorCore.aclean = [
44273 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44277 Roo.HtmlEditorCore.pwhite= [
44278 'http', 'https', 'mailto'
44281 // white listed style attributes.
44282 Roo.HtmlEditorCore.cwhite= [
44283 // 'text-align', /// default is to allow most things..
44289 // black listed style attributes.
44290 Roo.HtmlEditorCore.cblack= [
44291 // 'font-size' -- this can be set by the project
44295 Roo.HtmlEditorCore.swapCodes =[
44306 //<script type="text/javascript">
44309 * Ext JS Library 1.1.1
44310 * Copyright(c) 2006-2007, Ext JS, LLC.
44316 Roo.form.HtmlEditor = function(config){
44320 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44322 if (!this.toolbars) {
44323 this.toolbars = [];
44325 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44331 * @class Roo.form.HtmlEditor
44332 * @extends Roo.form.Field
44333 * Provides a lightweight HTML Editor component.
44335 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44337 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44338 * supported by this editor.</b><br/><br/>
44339 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44340 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44342 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44344 * @cfg {Boolean} clearUp
44348 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44353 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44358 * @cfg {Number} height (in pixels)
44362 * @cfg {Number} width (in pixels)
44367 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44370 stylesheets: false,
44374 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44379 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44385 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44390 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44398 // private properties
44399 validationEvent : false,
44401 initialized : false,
44404 onFocus : Roo.emptyFn,
44406 hideMode:'offsets',
44408 actionMode : 'container', // defaults to hiding it...
44410 defaultAutoCreate : { // modified by initCompnoent..
44412 style:"width:500px;height:300px;",
44413 autocomplete: "new-password"
44417 initComponent : function(){
44420 * @event initialize
44421 * Fires when the editor is fully initialized (including the iframe)
44422 * @param {HtmlEditor} this
44427 * Fires when the editor is first receives the focus. Any insertion must wait
44428 * until after this event.
44429 * @param {HtmlEditor} this
44433 * @event beforesync
44434 * Fires before the textarea is updated with content from the editor iframe. Return false
44435 * to cancel the sync.
44436 * @param {HtmlEditor} this
44437 * @param {String} html
44441 * @event beforepush
44442 * Fires before the iframe editor is updated with content from the textarea. Return false
44443 * to cancel the push.
44444 * @param {HtmlEditor} this
44445 * @param {String} html
44450 * Fires when the textarea is updated with content from the editor iframe.
44451 * @param {HtmlEditor} this
44452 * @param {String} html
44457 * Fires when the iframe editor is updated with content from the textarea.
44458 * @param {HtmlEditor} this
44459 * @param {String} html
44463 * @event editmodechange
44464 * Fires when the editor switches edit modes
44465 * @param {HtmlEditor} this
44466 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44468 editmodechange: true,
44470 * @event editorevent
44471 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44472 * @param {HtmlEditor} this
44476 * @event firstfocus
44477 * Fires when on first focus - needed by toolbars..
44478 * @param {HtmlEditor} this
44483 * Auto save the htmlEditor value as a file into Events
44484 * @param {HtmlEditor} this
44488 * @event savedpreview
44489 * preview the saved version of htmlEditor
44490 * @param {HtmlEditor} this
44492 savedpreview: true,
44495 * @event stylesheetsclick
44496 * Fires when press the Sytlesheets button
44497 * @param {Roo.HtmlEditorCore} this
44499 stylesheetsclick: true
44501 this.defaultAutoCreate = {
44503 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44504 autocomplete: "new-password"
44509 * Protected method that will not generally be called directly. It
44510 * is called when the editor creates its toolbar. Override this method if you need to
44511 * add custom toolbar buttons.
44512 * @param {HtmlEditor} editor
44514 createToolbar : function(editor){
44515 Roo.log("create toolbars");
44516 if (!editor.toolbars || !editor.toolbars.length) {
44517 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44520 for (var i =0 ; i < editor.toolbars.length;i++) {
44521 editor.toolbars[i] = Roo.factory(
44522 typeof(editor.toolbars[i]) == 'string' ?
44523 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44524 Roo.form.HtmlEditor);
44525 editor.toolbars[i].init(editor);
44533 onRender : function(ct, position)
44536 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44538 this.wrap = this.el.wrap({
44539 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44542 this.editorcore.onRender(ct, position);
44544 if (this.resizable) {
44545 this.resizeEl = new Roo.Resizable(this.wrap, {
44549 minHeight : this.height,
44550 height: this.height,
44551 handles : this.resizable,
44554 resize : function(r, w, h) {
44555 _t.onResize(w,h); // -something
44561 this.createToolbar(this);
44565 this.setSize(this.wrap.getSize());
44567 if (this.resizeEl) {
44568 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44569 // should trigger onReize..
44572 this.keyNav = new Roo.KeyNav(this.el, {
44574 "tab" : function(e){
44575 e.preventDefault();
44577 var value = this.getValue();
44579 var start = this.el.dom.selectionStart;
44580 var end = this.el.dom.selectionEnd;
44584 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44585 this.el.dom.setSelectionRange(end + 1, end + 1);
44589 var f = value.substring(0, start).split("\t");
44591 if(f.pop().length != 0){
44595 this.setValue(f.join("\t") + value.substring(end));
44596 this.el.dom.setSelectionRange(start - 1, start - 1);
44600 "home" : function(e){
44601 e.preventDefault();
44603 var curr = this.el.dom.selectionStart;
44604 var lines = this.getValue().split("\n");
44611 this.el.dom.setSelectionRange(0, 0);
44617 for (var i = 0; i < lines.length;i++) {
44618 pos += lines[i].length;
44628 pos -= lines[i].length;
44634 this.el.dom.setSelectionRange(pos, pos);
44638 this.el.dom.selectionStart = pos;
44639 this.el.dom.selectionEnd = curr;
44642 "end" : function(e){
44643 e.preventDefault();
44645 var curr = this.el.dom.selectionStart;
44646 var lines = this.getValue().split("\n");
44653 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44659 for (var i = 0; i < lines.length;i++) {
44661 pos += lines[i].length;
44675 this.el.dom.setSelectionRange(pos, pos);
44679 this.el.dom.selectionStart = curr;
44680 this.el.dom.selectionEnd = pos;
44685 doRelay : function(foo, bar, hname){
44686 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44692 // if(this.autosave && this.w){
44693 // this.autoSaveFn = setInterval(this.autosave, 1000);
44698 onResize : function(w, h)
44700 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44705 if(typeof w == 'number'){
44706 var aw = w - this.wrap.getFrameWidth('lr');
44707 this.el.setWidth(this.adjustWidth('textarea', aw));
44710 if(typeof h == 'number'){
44712 for (var i =0; i < this.toolbars.length;i++) {
44713 // fixme - ask toolbars for heights?
44714 tbh += this.toolbars[i].tb.el.getHeight();
44715 if (this.toolbars[i].footer) {
44716 tbh += this.toolbars[i].footer.el.getHeight();
44723 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44724 ah -= 5; // knock a few pixes off for look..
44726 this.el.setHeight(this.adjustWidth('textarea', ah));
44730 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44731 this.editorcore.onResize(ew,eh);
44736 * Toggles the editor between standard and source edit mode.
44737 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44739 toggleSourceEdit : function(sourceEditMode)
44741 this.editorcore.toggleSourceEdit(sourceEditMode);
44743 if(this.editorcore.sourceEditMode){
44744 Roo.log('editor - showing textarea');
44747 // Roo.log(this.syncValue());
44748 this.editorcore.syncValue();
44749 this.el.removeClass('x-hidden');
44750 this.el.dom.removeAttribute('tabIndex');
44753 for (var i = 0; i < this.toolbars.length; i++) {
44754 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44755 this.toolbars[i].tb.hide();
44756 this.toolbars[i].footer.hide();
44761 Roo.log('editor - hiding textarea');
44763 // Roo.log(this.pushValue());
44764 this.editorcore.pushValue();
44766 this.el.addClass('x-hidden');
44767 this.el.dom.setAttribute('tabIndex', -1);
44769 for (var i = 0; i < this.toolbars.length; i++) {
44770 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44771 this.toolbars[i].tb.show();
44772 this.toolbars[i].footer.show();
44776 //this.deferFocus();
44779 this.setSize(this.wrap.getSize());
44780 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44782 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44785 // private (for BoxComponent)
44786 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44788 // private (for BoxComponent)
44789 getResizeEl : function(){
44793 // private (for BoxComponent)
44794 getPositionEl : function(){
44799 initEvents : function(){
44800 this.originalValue = this.getValue();
44804 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44807 markInvalid : Roo.emptyFn,
44809 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44812 clearInvalid : Roo.emptyFn,
44814 setValue : function(v){
44815 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44816 this.editorcore.pushValue();
44821 deferFocus : function(){
44822 this.focus.defer(10, this);
44826 focus : function(){
44827 this.editorcore.focus();
44833 onDestroy : function(){
44839 for (var i =0; i < this.toolbars.length;i++) {
44840 // fixme - ask toolbars for heights?
44841 this.toolbars[i].onDestroy();
44844 this.wrap.dom.innerHTML = '';
44845 this.wrap.remove();
44850 onFirstFocus : function(){
44851 //Roo.log("onFirstFocus");
44852 this.editorcore.onFirstFocus();
44853 for (var i =0; i < this.toolbars.length;i++) {
44854 this.toolbars[i].onFirstFocus();
44860 syncValue : function()
44862 this.editorcore.syncValue();
44865 pushValue : function()
44867 this.editorcore.pushValue();
44870 setStylesheets : function(stylesheets)
44872 this.editorcore.setStylesheets(stylesheets);
44875 removeStylesheets : function()
44877 this.editorcore.removeStylesheets();
44881 // hide stuff that is not compatible
44895 * @event specialkey
44899 * @cfg {String} fieldClass @hide
44902 * @cfg {String} focusClass @hide
44905 * @cfg {String} autoCreate @hide
44908 * @cfg {String} inputType @hide
44911 * @cfg {String} invalidClass @hide
44914 * @cfg {String} invalidText @hide
44917 * @cfg {String} msgFx @hide
44920 * @cfg {String} validateOnBlur @hide
44924 // <script type="text/javascript">
44927 * Ext JS Library 1.1.1
44928 * Copyright(c) 2006-2007, Ext JS, LLC.
44934 * @class Roo.form.HtmlEditorToolbar1
44939 new Roo.form.HtmlEditor({
44942 new Roo.form.HtmlEditorToolbar1({
44943 disable : { fonts: 1 , format: 1, ..., ... , ...],
44949 * @cfg {Object} disable List of elements to disable..
44950 * @cfg {Array} btns List of additional buttons.
44954 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
44957 Roo.form.HtmlEditor.ToolbarStandard = function(config)
44960 Roo.apply(this, config);
44962 // default disabled, based on 'good practice'..
44963 this.disable = this.disable || {};
44964 Roo.applyIf(this.disable, {
44967 specialElements : true
44971 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44972 // dont call parent... till later.
44975 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
44982 editorcore : false,
44984 * @cfg {Object} disable List of toolbar elements to disable
44991 * @cfg {String} createLinkText The default text for the create link prompt
44993 createLinkText : 'Please enter the URL for the link:',
44995 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
44997 defaultLinkValue : 'http:/'+'/',
45001 * @cfg {Array} fontFamilies An array of available font families
45019 // "á" , ?? a acute?
45024 "°" // , // degrees
45026 // "é" , // e ecute
45027 // "ú" , // u ecute?
45030 specialElements : [
45032 text: "Insert Table",
45035 ihtml : '<table><tr><td>Cell</td></tr></table>'
45039 text: "Insert Image",
45042 ihtml : '<img src="about:blank"/>'
45051 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45052 "input:submit", "input:button", "select", "textarea", "label" ],
45055 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45057 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45065 * @cfg {String} defaultFont default font to use.
45067 defaultFont: 'tahoma',
45069 fontSelect : false,
45072 formatCombo : false,
45074 init : function(editor)
45076 this.editor = editor;
45077 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45078 var editorcore = this.editorcore;
45082 var fid = editorcore.frameId;
45084 function btn(id, toggle, handler){
45085 var xid = fid + '-'+ id ;
45089 cls : 'x-btn-icon x-edit-'+id,
45090 enableToggle:toggle !== false,
45091 scope: _t, // was editor...
45092 handler:handler||_t.relayBtnCmd,
45093 clickEvent:'mousedown',
45094 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45101 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45103 // stop form submits
45104 tb.el.on('click', function(e){
45105 e.preventDefault(); // what does this do?
45108 if(!this.disable.font) { // && !Roo.isSafari){
45109 /* why no safari for fonts
45110 editor.fontSelect = tb.el.createChild({
45113 cls:'x-font-select',
45114 html: this.createFontOptions()
45117 editor.fontSelect.on('change', function(){
45118 var font = editor.fontSelect.dom.value;
45119 editor.relayCmd('fontname', font);
45120 editor.deferFocus();
45124 editor.fontSelect.dom,
45130 if(!this.disable.formats){
45131 this.formatCombo = new Roo.form.ComboBox({
45132 store: new Roo.data.SimpleStore({
45135 data : this.formats // from states.js
45139 //autoCreate : {tag: "div", size: "20"},
45140 displayField:'tag',
45144 triggerAction: 'all',
45145 emptyText:'Add tag',
45146 selectOnFocus:true,
45149 'select': function(c, r, i) {
45150 editorcore.insertTag(r.get('tag'));
45156 tb.addField(this.formatCombo);
45160 if(!this.disable.format){
45165 btn('strikethrough')
45168 if(!this.disable.fontSize){
45173 btn('increasefontsize', false, editorcore.adjustFont),
45174 btn('decreasefontsize', false, editorcore.adjustFont)
45179 if(!this.disable.colors){
45182 id:editorcore.frameId +'-forecolor',
45183 cls:'x-btn-icon x-edit-forecolor',
45184 clickEvent:'mousedown',
45185 tooltip: this.buttonTips['forecolor'] || undefined,
45187 menu : new Roo.menu.ColorMenu({
45188 allowReselect: true,
45189 focus: Roo.emptyFn,
45192 selectHandler: function(cp, color){
45193 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45194 editor.deferFocus();
45197 clickEvent:'mousedown'
45200 id:editorcore.frameId +'backcolor',
45201 cls:'x-btn-icon x-edit-backcolor',
45202 clickEvent:'mousedown',
45203 tooltip: this.buttonTips['backcolor'] || undefined,
45205 menu : new Roo.menu.ColorMenu({
45206 focus: Roo.emptyFn,
45209 allowReselect: true,
45210 selectHandler: function(cp, color){
45212 editorcore.execCmd('useCSS', false);
45213 editorcore.execCmd('hilitecolor', color);
45214 editorcore.execCmd('useCSS', true);
45215 editor.deferFocus();
45217 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45218 Roo.isSafari || Roo.isIE ? '#'+color : color);
45219 editor.deferFocus();
45223 clickEvent:'mousedown'
45228 // now add all the items...
45231 if(!this.disable.alignments){
45234 btn('justifyleft'),
45235 btn('justifycenter'),
45236 btn('justifyright')
45240 //if(!Roo.isSafari){
45241 if(!this.disable.links){
45244 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45248 if(!this.disable.lists){
45251 btn('insertorderedlist'),
45252 btn('insertunorderedlist')
45255 if(!this.disable.sourceEdit){
45258 btn('sourceedit', true, function(btn){
45259 this.toggleSourceEdit(btn.pressed);
45266 // special menu.. - needs to be tidied up..
45267 if (!this.disable.special) {
45270 cls: 'x-edit-none',
45276 for (var i =0; i < this.specialChars.length; i++) {
45277 smenu.menu.items.push({
45279 html: this.specialChars[i],
45280 handler: function(a,b) {
45281 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45282 //editor.insertAtCursor(a.html);
45296 if (!this.disable.cleanStyles) {
45298 cls: 'x-btn-icon x-btn-clear',
45304 for (var i =0; i < this.cleanStyles.length; i++) {
45305 cmenu.menu.items.push({
45306 actiontype : this.cleanStyles[i],
45307 html: 'Remove ' + this.cleanStyles[i],
45308 handler: function(a,b) {
45311 var c = Roo.get(editorcore.doc.body);
45312 c.select('[style]').each(function(s) {
45313 s.dom.style.removeProperty(a.actiontype);
45315 editorcore.syncValue();
45320 cmenu.menu.items.push({
45321 actiontype : 'tablewidths',
45322 html: 'Remove Table Widths',
45323 handler: function(a,b) {
45324 editorcore.cleanTableWidths();
45325 editorcore.syncValue();
45329 cmenu.menu.items.push({
45330 actiontype : 'word',
45331 html: 'Remove MS Word Formating',
45332 handler: function(a,b) {
45333 editorcore.cleanWord();
45334 editorcore.syncValue();
45339 cmenu.menu.items.push({
45340 actiontype : 'all',
45341 html: 'Remove All Styles',
45342 handler: function(a,b) {
45344 var c = Roo.get(editorcore.doc.body);
45345 c.select('[style]').each(function(s) {
45346 s.dom.removeAttribute('style');
45348 editorcore.syncValue();
45353 cmenu.menu.items.push({
45354 actiontype : 'all',
45355 html: 'Remove All CSS Classes',
45356 handler: function(a,b) {
45358 var c = Roo.get(editorcore.doc.body);
45359 c.select('[class]').each(function(s) {
45360 s.dom.className = '';
45362 editorcore.syncValue();
45367 cmenu.menu.items.push({
45368 actiontype : 'tidy',
45369 html: 'Tidy HTML Source',
45370 handler: function(a,b) {
45371 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45372 editorcore.syncValue();
45381 if (!this.disable.specialElements) {
45384 cls: 'x-edit-none',
45389 for (var i =0; i < this.specialElements.length; i++) {
45390 semenu.menu.items.push(
45392 handler: function(a,b) {
45393 editor.insertAtCursor(this.ihtml);
45395 }, this.specialElements[i])
45407 for(var i =0; i< this.btns.length;i++) {
45408 var b = Roo.factory(this.btns[i],Roo.form);
45409 b.cls = 'x-edit-none';
45411 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45412 b.cls += ' x-init-enable';
45415 b.scope = editorcore;
45423 // disable everything...
45425 this.tb.items.each(function(item){
45428 item.id != editorcore.frameId+ '-sourceedit' &&
45429 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45435 this.rendered = true;
45437 // the all the btns;
45438 editor.on('editorevent', this.updateToolbar, this);
45439 // other toolbars need to implement this..
45440 //editor.on('editmodechange', this.updateToolbar, this);
45444 relayBtnCmd : function(btn) {
45445 this.editorcore.relayCmd(btn.cmd);
45447 // private used internally
45448 createLink : function(){
45449 Roo.log("create link?");
45450 var url = prompt(this.createLinkText, this.defaultLinkValue);
45451 if(url && url != 'http:/'+'/'){
45452 this.editorcore.relayCmd('createlink', url);
45458 * Protected method that will not generally be called directly. It triggers
45459 * a toolbar update by reading the markup state of the current selection in the editor.
45461 updateToolbar: function(){
45463 if(!this.editorcore.activated){
45464 this.editor.onFirstFocus();
45468 var btns = this.tb.items.map,
45469 doc = this.editorcore.doc,
45470 frameId = this.editorcore.frameId;
45472 if(!this.disable.font && !Roo.isSafari){
45474 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45475 if(name != this.fontSelect.dom.value){
45476 this.fontSelect.dom.value = name;
45480 if(!this.disable.format){
45481 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45482 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45483 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45484 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45486 if(!this.disable.alignments){
45487 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45488 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45489 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45491 if(!Roo.isSafari && !this.disable.lists){
45492 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45493 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45496 var ans = this.editorcore.getAllAncestors();
45497 if (this.formatCombo) {
45500 var store = this.formatCombo.store;
45501 this.formatCombo.setValue("");
45502 for (var i =0; i < ans.length;i++) {
45503 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45505 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45513 // hides menus... - so this cant be on a menu...
45514 Roo.menu.MenuMgr.hideAll();
45516 //this.editorsyncValue();
45520 createFontOptions : function(){
45521 var buf = [], fs = this.fontFamilies, ff, lc;
45525 for(var i = 0, len = fs.length; i< len; i++){
45527 lc = ff.toLowerCase();
45529 '<option value="',lc,'" style="font-family:',ff,';"',
45530 (this.defaultFont == lc ? ' selected="true">' : '>'),
45535 return buf.join('');
45538 toggleSourceEdit : function(sourceEditMode){
45540 Roo.log("toolbar toogle");
45541 if(sourceEditMode === undefined){
45542 sourceEditMode = !this.sourceEditMode;
45544 this.sourceEditMode = sourceEditMode === true;
45545 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45546 // just toggle the button?
45547 if(btn.pressed !== this.sourceEditMode){
45548 btn.toggle(this.sourceEditMode);
45552 if(sourceEditMode){
45553 Roo.log("disabling buttons");
45554 this.tb.items.each(function(item){
45555 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45561 Roo.log("enabling buttons");
45562 if(this.editorcore.initialized){
45563 this.tb.items.each(function(item){
45569 Roo.log("calling toggole on editor");
45570 // tell the editor that it's been pressed..
45571 this.editor.toggleSourceEdit(sourceEditMode);
45575 * Object collection of toolbar tooltips for the buttons in the editor. The key
45576 * is the command id associated with that button and the value is a valid QuickTips object.
45581 title: 'Bold (Ctrl+B)',
45582 text: 'Make the selected text bold.',
45583 cls: 'x-html-editor-tip'
45586 title: 'Italic (Ctrl+I)',
45587 text: 'Make the selected text italic.',
45588 cls: 'x-html-editor-tip'
45596 title: 'Bold (Ctrl+B)',
45597 text: 'Make the selected text bold.',
45598 cls: 'x-html-editor-tip'
45601 title: 'Italic (Ctrl+I)',
45602 text: 'Make the selected text italic.',
45603 cls: 'x-html-editor-tip'
45606 title: 'Underline (Ctrl+U)',
45607 text: 'Underline the selected text.',
45608 cls: 'x-html-editor-tip'
45611 title: 'Strikethrough',
45612 text: 'Strikethrough the selected text.',
45613 cls: 'x-html-editor-tip'
45615 increasefontsize : {
45616 title: 'Grow Text',
45617 text: 'Increase the font size.',
45618 cls: 'x-html-editor-tip'
45620 decreasefontsize : {
45621 title: 'Shrink Text',
45622 text: 'Decrease the font size.',
45623 cls: 'x-html-editor-tip'
45626 title: 'Text Highlight Color',
45627 text: 'Change the background color of the selected text.',
45628 cls: 'x-html-editor-tip'
45631 title: 'Font Color',
45632 text: 'Change the color of the selected text.',
45633 cls: 'x-html-editor-tip'
45636 title: 'Align Text Left',
45637 text: 'Align text to the left.',
45638 cls: 'x-html-editor-tip'
45641 title: 'Center Text',
45642 text: 'Center text in the editor.',
45643 cls: 'x-html-editor-tip'
45646 title: 'Align Text Right',
45647 text: 'Align text to the right.',
45648 cls: 'x-html-editor-tip'
45650 insertunorderedlist : {
45651 title: 'Bullet List',
45652 text: 'Start a bulleted list.',
45653 cls: 'x-html-editor-tip'
45655 insertorderedlist : {
45656 title: 'Numbered List',
45657 text: 'Start a numbered list.',
45658 cls: 'x-html-editor-tip'
45661 title: 'Hyperlink',
45662 text: 'Make the selected text a hyperlink.',
45663 cls: 'x-html-editor-tip'
45666 title: 'Source Edit',
45667 text: 'Switch to source editing mode.',
45668 cls: 'x-html-editor-tip'
45672 onDestroy : function(){
45675 this.tb.items.each(function(item){
45677 item.menu.removeAll();
45679 item.menu.el.destroy();
45687 onFirstFocus: function() {
45688 this.tb.items.each(function(item){
45697 // <script type="text/javascript">
45700 * Ext JS Library 1.1.1
45701 * Copyright(c) 2006-2007, Ext JS, LLC.
45708 * @class Roo.form.HtmlEditor.ToolbarContext
45713 new Roo.form.HtmlEditor({
45716 { xtype: 'ToolbarStandard', styles : {} }
45717 { xtype: 'ToolbarContext', disable : {} }
45723 * @config : {Object} disable List of elements to disable.. (not done yet.)
45724 * @config : {Object} styles Map of styles available.
45728 Roo.form.HtmlEditor.ToolbarContext = function(config)
45731 Roo.apply(this, config);
45732 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45733 // dont call parent... till later.
45734 this.styles = this.styles || {};
45739 Roo.form.HtmlEditor.ToolbarContext.types = {
45751 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45817 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45822 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45832 style : 'fontFamily',
45833 displayField: 'display',
45834 optname : 'font-family',
45883 // should we really allow this??
45884 // should this just be
45895 style : 'fontFamily',
45896 displayField: 'display',
45897 optname : 'font-family',
45904 style : 'fontFamily',
45905 displayField: 'display',
45906 optname : 'font-family',
45913 style : 'fontFamily',
45914 displayField: 'display',
45915 optname : 'font-family',
45926 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
45927 Roo.form.HtmlEditor.ToolbarContext.stores = false;
45929 Roo.form.HtmlEditor.ToolbarContext.options = {
45931 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
45932 [ 'Courier New', 'Courier New'],
45933 [ 'Tahoma', 'Tahoma'],
45934 [ 'Times New Roman,serif', 'Times'],
45935 [ 'Verdana','Verdana' ]
45939 // fixme - these need to be configurable..
45942 //Roo.form.HtmlEditor.ToolbarContext.types
45945 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
45952 editorcore : false,
45954 * @cfg {Object} disable List of toolbar elements to disable
45959 * @cfg {Object} styles List of styles
45960 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
45962 * These must be defined in the page, so they get rendered correctly..
45973 init : function(editor)
45975 this.editor = editor;
45976 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45977 var editorcore = this.editorcore;
45979 var fid = editorcore.frameId;
45981 function btn(id, toggle, handler){
45982 var xid = fid + '-'+ id ;
45986 cls : 'x-btn-icon x-edit-'+id,
45987 enableToggle:toggle !== false,
45988 scope: editorcore, // was editor...
45989 handler:handler||editorcore.relayBtnCmd,
45990 clickEvent:'mousedown',
45991 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45995 // create a new element.
45996 var wdiv = editor.wrap.createChild({
45998 }, editor.wrap.dom.firstChild.nextSibling, true);
46000 // can we do this more than once??
46002 // stop form submits
46005 // disable everything...
46006 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46007 this.toolbars = {};
46009 for (var i in ty) {
46011 this.toolbars[i] = this.buildToolbar(ty[i],i);
46013 this.tb = this.toolbars.BODY;
46015 this.buildFooter();
46016 this.footer.show();
46017 editor.on('hide', function( ) { this.footer.hide() }, this);
46018 editor.on('show', function( ) { this.footer.show() }, this);
46021 this.rendered = true;
46023 // the all the btns;
46024 editor.on('editorevent', this.updateToolbar, this);
46025 // other toolbars need to implement this..
46026 //editor.on('editmodechange', this.updateToolbar, this);
46032 * Protected method that will not generally be called directly. It triggers
46033 * a toolbar update by reading the markup state of the current selection in the editor.
46035 * Note you can force an update by calling on('editorevent', scope, false)
46037 updateToolbar: function(editor,ev,sel){
46040 // capture mouse up - this is handy for selecting images..
46041 // perhaps should go somewhere else...
46042 if(!this.editorcore.activated){
46043 this.editor.onFirstFocus();
46049 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46050 // selectNode - might want to handle IE?
46052 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46053 ev.target && ev.target.tagName == 'IMG') {
46054 // they have click on an image...
46055 // let's see if we can change the selection...
46058 var nodeRange = sel.ownerDocument.createRange();
46060 nodeRange.selectNode(sel);
46062 nodeRange.selectNodeContents(sel);
46064 //nodeRange.collapse(true);
46065 var s = this.editorcore.win.getSelection();
46066 s.removeAllRanges();
46067 s.addRange(nodeRange);
46071 var updateFooter = sel ? false : true;
46074 var ans = this.editorcore.getAllAncestors();
46077 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46080 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46081 sel = sel ? sel : this.editorcore.doc.body;
46082 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46085 // pick a menu that exists..
46086 var tn = sel.tagName.toUpperCase();
46087 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46089 tn = sel.tagName.toUpperCase();
46091 var lastSel = this.tb.selectedNode;
46093 this.tb.selectedNode = sel;
46095 // if current menu does not match..
46097 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46100 ///console.log("show: " + tn);
46101 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46104 this.tb.items.first().el.innerHTML = tn + ': ';
46107 // update attributes
46108 if (this.tb.fields) {
46109 this.tb.fields.each(function(e) {
46111 e.setValue(sel.style[e.stylename]);
46114 e.setValue(sel.getAttribute(e.attrname));
46118 var hasStyles = false;
46119 for(var i in this.styles) {
46126 var st = this.tb.fields.item(0);
46128 st.store.removeAll();
46131 var cn = sel.className.split(/\s+/);
46134 if (this.styles['*']) {
46136 Roo.each(this.styles['*'], function(v) {
46137 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46140 if (this.styles[tn]) {
46141 Roo.each(this.styles[tn], function(v) {
46142 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46146 st.store.loadData(avs);
46150 // flag our selected Node.
46151 this.tb.selectedNode = sel;
46154 Roo.menu.MenuMgr.hideAll();
46158 if (!updateFooter) {
46159 //this.footDisp.dom.innerHTML = '';
46162 // update the footer
46166 this.footerEls = ans.reverse();
46167 Roo.each(this.footerEls, function(a,i) {
46168 if (!a) { return; }
46169 html += html.length ? ' > ' : '';
46171 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46176 var sz = this.footDisp.up('td').getSize();
46177 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46178 this.footDisp.dom.style.marginLeft = '5px';
46180 this.footDisp.dom.style.overflow = 'hidden';
46182 this.footDisp.dom.innerHTML = html;
46184 //this.editorsyncValue();
46191 onDestroy : function(){
46194 this.tb.items.each(function(item){
46196 item.menu.removeAll();
46198 item.menu.el.destroy();
46206 onFirstFocus: function() {
46207 // need to do this for all the toolbars..
46208 this.tb.items.each(function(item){
46212 buildToolbar: function(tlist, nm)
46214 var editor = this.editor;
46215 var editorcore = this.editorcore;
46216 // create a new element.
46217 var wdiv = editor.wrap.createChild({
46219 }, editor.wrap.dom.firstChild.nextSibling, true);
46222 var tb = new Roo.Toolbar(wdiv);
46225 tb.add(nm+ ": ");
46228 for(var i in this.styles) {
46233 if (styles && styles.length) {
46235 // this needs a multi-select checkbox...
46236 tb.addField( new Roo.form.ComboBox({
46237 store: new Roo.data.SimpleStore({
46239 fields: ['val', 'selected'],
46242 name : '-roo-edit-className',
46243 attrname : 'className',
46244 displayField: 'val',
46248 triggerAction: 'all',
46249 emptyText:'Select Style',
46250 selectOnFocus:true,
46253 'select': function(c, r, i) {
46254 // initial support only for on class per el..
46255 tb.selectedNode.className = r ? r.get('val') : '';
46256 editorcore.syncValue();
46263 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46264 var tbops = tbc.options;
46266 for (var i in tlist) {
46268 var item = tlist[i];
46269 tb.add(item.title + ": ");
46272 //optname == used so you can configure the options available..
46273 var opts = item.opts ? item.opts : false;
46274 if (item.optname) {
46275 opts = tbops[item.optname];
46280 // opts == pulldown..
46281 tb.addField( new Roo.form.ComboBox({
46282 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46284 fields: ['val', 'display'],
46287 name : '-roo-edit-' + i,
46289 stylename : item.style ? item.style : false,
46290 displayField: item.displayField ? item.displayField : 'val',
46291 valueField : 'val',
46293 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46295 triggerAction: 'all',
46296 emptyText:'Select',
46297 selectOnFocus:true,
46298 width: item.width ? item.width : 130,
46300 'select': function(c, r, i) {
46302 tb.selectedNode.style[c.stylename] = r.get('val');
46305 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46314 tb.addField( new Roo.form.TextField({
46317 //allowBlank:false,
46322 tb.addField( new Roo.form.TextField({
46323 name: '-roo-edit-' + i,
46330 'change' : function(f, nv, ov) {
46331 tb.selectedNode.setAttribute(f.attrname, nv);
46332 editorcore.syncValue();
46345 text: 'Stylesheets',
46348 click : function ()
46350 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46358 text: 'Remove Tag',
46361 click : function ()
46364 // undo does not work.
46366 var sn = tb.selectedNode;
46368 var pn = sn.parentNode;
46370 var stn = sn.childNodes[0];
46371 var en = sn.childNodes[sn.childNodes.length - 1 ];
46372 while (sn.childNodes.length) {
46373 var node = sn.childNodes[0];
46374 sn.removeChild(node);
46376 pn.insertBefore(node, sn);
46379 pn.removeChild(sn);
46380 var range = editorcore.createRange();
46382 range.setStart(stn,0);
46383 range.setEnd(en,0); //????
46384 //range.selectNode(sel);
46387 var selection = editorcore.getSelection();
46388 selection.removeAllRanges();
46389 selection.addRange(range);
46393 //_this.updateToolbar(null, null, pn);
46394 _this.updateToolbar(null, null, null);
46395 _this.footDisp.dom.innerHTML = '';
46405 tb.el.on('click', function(e){
46406 e.preventDefault(); // what does this do?
46408 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46411 // dont need to disable them... as they will get hidden
46416 buildFooter : function()
46419 var fel = this.editor.wrap.createChild();
46420 this.footer = new Roo.Toolbar(fel);
46421 // toolbar has scrolly on left / right?
46422 var footDisp= new Roo.Toolbar.Fill();
46428 handler : function() {
46429 _t.footDisp.scrollTo('left',0,true)
46433 this.footer.add( footDisp );
46438 handler : function() {
46440 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46444 var fel = Roo.get(footDisp.el);
46445 fel.addClass('x-editor-context');
46446 this.footDispWrap = fel;
46447 this.footDispWrap.overflow = 'hidden';
46449 this.footDisp = fel.createChild();
46450 this.footDispWrap.on('click', this.onContextClick, this)
46454 onContextClick : function (ev,dom)
46456 ev.preventDefault();
46457 var cn = dom.className;
46459 if (!cn.match(/x-ed-loc-/)) {
46462 var n = cn.split('-').pop();
46463 var ans = this.footerEls;
46467 var range = this.editorcore.createRange();
46469 range.selectNodeContents(sel);
46470 //range.selectNode(sel);
46473 var selection = this.editorcore.getSelection();
46474 selection.removeAllRanges();
46475 selection.addRange(range);
46479 this.updateToolbar(null, null, sel);
46496 * Ext JS Library 1.1.1
46497 * Copyright(c) 2006-2007, Ext JS, LLC.
46499 * Originally Released Under LGPL - original licence link has changed is not relivant.
46502 * <script type="text/javascript">
46506 * @class Roo.form.BasicForm
46507 * @extends Roo.util.Observable
46508 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46510 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46511 * @param {Object} config Configuration options
46513 Roo.form.BasicForm = function(el, config){
46514 this.allItems = [];
46515 this.childForms = [];
46516 Roo.apply(this, config);
46518 * The Roo.form.Field items in this form.
46519 * @type MixedCollection
46523 this.items = new Roo.util.MixedCollection(false, function(o){
46524 return o.id || (o.id = Roo.id());
46528 * @event beforeaction
46529 * Fires before any action is performed. Return false to cancel the action.
46530 * @param {Form} this
46531 * @param {Action} action The action to be performed
46533 beforeaction: true,
46535 * @event actionfailed
46536 * Fires when an action fails.
46537 * @param {Form} this
46538 * @param {Action} action The action that failed
46540 actionfailed : true,
46542 * @event actioncomplete
46543 * Fires when an action is completed.
46544 * @param {Form} this
46545 * @param {Action} action The action that completed
46547 actioncomplete : true
46552 Roo.form.BasicForm.superclass.constructor.call(this);
46555 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46557 * @cfg {String} method
46558 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46561 * @cfg {DataReader} reader
46562 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46563 * This is optional as there is built-in support for processing JSON.
46566 * @cfg {DataReader} errorReader
46567 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46568 * This is completely optional as there is built-in support for processing JSON.
46571 * @cfg {String} url
46572 * The URL to use for form actions if one isn't supplied in the action options.
46575 * @cfg {Boolean} fileUpload
46576 * Set to true if this form is a file upload.
46580 * @cfg {Object} baseParams
46581 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46586 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46591 activeAction : null,
46594 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46595 * or setValues() data instead of when the form was first created.
46597 trackResetOnLoad : false,
46601 * childForms - used for multi-tab forms
46604 childForms : false,
46607 * allItems - full list of fields.
46613 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46614 * element by passing it or its id or mask the form itself by passing in true.
46617 waitMsgTarget : false,
46620 initEl : function(el){
46621 this.el = Roo.get(el);
46622 this.id = this.el.id || Roo.id();
46623 this.el.on('submit', this.onSubmit, this);
46624 this.el.addClass('x-form');
46628 onSubmit : function(e){
46633 * Returns true if client-side validation on the form is successful.
46636 isValid : function(){
46638 this.items.each(function(f){
46647 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46650 isDirty : function(){
46652 this.items.each(function(f){
46662 * Returns true if any fields in this form have changed since their original load. (New version)
46666 hasChanged : function()
46669 this.items.each(function(f){
46670 if(f.hasChanged()){
46679 * Resets all hasChanged to 'false' -
46680 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46681 * So hasChanged storage is only to be used for this purpose
46684 resetHasChanged : function()
46686 this.items.each(function(f){
46687 f.resetHasChanged();
46694 * Performs a predefined action (submit or load) or custom actions you define on this form.
46695 * @param {String} actionName The name of the action type
46696 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46697 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46698 * accept other config options):
46700 Property Type Description
46701 ---------------- --------------- ----------------------------------------------------------------------------------
46702 url String The url for the action (defaults to the form's url)
46703 method String The form method to use (defaults to the form's method, or POST if not defined)
46704 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46705 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46706 validate the form on the client (defaults to false)
46708 * @return {BasicForm} this
46710 doAction : function(action, options){
46711 if(typeof action == 'string'){
46712 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46714 if(this.fireEvent('beforeaction', this, action) !== false){
46715 this.beforeAction(action);
46716 action.run.defer(100, action);
46722 * Shortcut to do a submit action.
46723 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46724 * @return {BasicForm} this
46726 submit : function(options){
46727 this.doAction('submit', options);
46732 * Shortcut to do a load action.
46733 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46734 * @return {BasicForm} this
46736 load : function(options){
46737 this.doAction('load', options);
46742 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46743 * @param {Record} record The record to edit
46744 * @return {BasicForm} this
46746 updateRecord : function(record){
46747 record.beginEdit();
46748 var fs = record.fields;
46749 fs.each(function(f){
46750 var field = this.findField(f.name);
46752 record.set(f.name, field.getValue());
46760 * Loads an Roo.data.Record into this form.
46761 * @param {Record} record The record to load
46762 * @return {BasicForm} this
46764 loadRecord : function(record){
46765 this.setValues(record.data);
46770 beforeAction : function(action){
46771 var o = action.options;
46774 if(this.waitMsgTarget === true){
46775 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46776 }else if(this.waitMsgTarget){
46777 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46778 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46780 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46786 afterAction : function(action, success){
46787 this.activeAction = null;
46788 var o = action.options;
46790 if(this.waitMsgTarget === true){
46792 }else if(this.waitMsgTarget){
46793 this.waitMsgTarget.unmask();
46795 Roo.MessageBox.updateProgress(1);
46796 Roo.MessageBox.hide();
46803 Roo.callback(o.success, o.scope, [this, action]);
46804 this.fireEvent('actioncomplete', this, action);
46808 // failure condition..
46809 // we have a scenario where updates need confirming.
46810 // eg. if a locking scenario exists..
46811 // we look for { errors : { needs_confirm : true }} in the response.
46813 (typeof(action.result) != 'undefined') &&
46814 (typeof(action.result.errors) != 'undefined') &&
46815 (typeof(action.result.errors.needs_confirm) != 'undefined')
46818 Roo.MessageBox.confirm(
46819 "Change requires confirmation",
46820 action.result.errorMsg,
46825 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46835 Roo.callback(o.failure, o.scope, [this, action]);
46836 // show an error message if no failed handler is set..
46837 if (!this.hasListener('actionfailed')) {
46838 Roo.MessageBox.alert("Error",
46839 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46840 action.result.errorMsg :
46841 "Saving Failed, please check your entries or try again"
46845 this.fireEvent('actionfailed', this, action);
46851 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46852 * @param {String} id The value to search for
46855 findField : function(id){
46856 var field = this.items.get(id);
46858 this.items.each(function(f){
46859 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
46865 return field || null;
46869 * Add a secondary form to this one,
46870 * Used to provide tabbed forms. One form is primary, with hidden values
46871 * which mirror the elements from the other forms.
46873 * @param {Roo.form.Form} form to add.
46876 addForm : function(form)
46879 if (this.childForms.indexOf(form) > -1) {
46883 this.childForms.push(form);
46885 Roo.each(form.allItems, function (fe) {
46887 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
46888 if (this.findField(n)) { // already added..
46891 var add = new Roo.form.Hidden({
46894 add.render(this.el);
46901 * Mark fields in this form invalid in bulk.
46902 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
46903 * @return {BasicForm} this
46905 markInvalid : function(errors){
46906 if(errors instanceof Array){
46907 for(var i = 0, len = errors.length; i < len; i++){
46908 var fieldError = errors[i];
46909 var f = this.findField(fieldError.id);
46911 f.markInvalid(fieldError.msg);
46917 if(typeof errors[id] != 'function' && (field = this.findField(id))){
46918 field.markInvalid(errors[id]);
46922 Roo.each(this.childForms || [], function (f) {
46923 f.markInvalid(errors);
46930 * Set values for fields in this form in bulk.
46931 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
46932 * @return {BasicForm} this
46934 setValues : function(values){
46935 if(values instanceof Array){ // array of objects
46936 for(var i = 0, len = values.length; i < len; i++){
46938 var f = this.findField(v.id);
46940 f.setValue(v.value);
46941 if(this.trackResetOnLoad){
46942 f.originalValue = f.getValue();
46946 }else{ // object hash
46949 if(typeof values[id] != 'function' && (field = this.findField(id))){
46951 if (field.setFromData &&
46952 field.valueField &&
46953 field.displayField &&
46954 // combos' with local stores can
46955 // be queried via setValue()
46956 // to set their value..
46957 (field.store && !field.store.isLocal)
46961 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
46962 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
46963 field.setFromData(sd);
46966 field.setValue(values[id]);
46970 if(this.trackResetOnLoad){
46971 field.originalValue = field.getValue();
46976 this.resetHasChanged();
46979 Roo.each(this.childForms || [], function (f) {
46980 f.setValues(values);
46981 f.resetHasChanged();
46988 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
46989 * they are returned as an array.
46990 * @param {Boolean} asString
46993 getValues : function(asString){
46994 if (this.childForms) {
46995 // copy values from the child forms
46996 Roo.each(this.childForms, function (f) {
46997 this.setValues(f.getValues());
47003 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47004 if(asString === true){
47007 return Roo.urlDecode(fs);
47011 * Returns the fields in this form as an object with key/value pairs.
47012 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47015 getFieldValues : function(with_hidden)
47017 if (this.childForms) {
47018 // copy values from the child forms
47019 // should this call getFieldValues - probably not as we do not currently copy
47020 // hidden fields when we generate..
47021 Roo.each(this.childForms, function (f) {
47022 this.setValues(f.getValues());
47027 this.items.each(function(f){
47028 if (!f.getName()) {
47031 var v = f.getValue();
47032 if (f.inputType =='radio') {
47033 if (typeof(ret[f.getName()]) == 'undefined') {
47034 ret[f.getName()] = ''; // empty..
47037 if (!f.el.dom.checked) {
47041 v = f.el.dom.value;
47045 // not sure if this supported any more..
47046 if ((typeof(v) == 'object') && f.getRawValue) {
47047 v = f.getRawValue() ; // dates..
47049 // combo boxes where name != hiddenName...
47050 if (f.name != f.getName()) {
47051 ret[f.name] = f.getRawValue();
47053 ret[f.getName()] = v;
47060 * Clears all invalid messages in this form.
47061 * @return {BasicForm} this
47063 clearInvalid : function(){
47064 this.items.each(function(f){
47068 Roo.each(this.childForms || [], function (f) {
47077 * Resets this form.
47078 * @return {BasicForm} this
47080 reset : function(){
47081 this.items.each(function(f){
47085 Roo.each(this.childForms || [], function (f) {
47088 this.resetHasChanged();
47094 * Add Roo.form components to this form.
47095 * @param {Field} field1
47096 * @param {Field} field2 (optional)
47097 * @param {Field} etc (optional)
47098 * @return {BasicForm} this
47101 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47107 * Removes a field from the items collection (does NOT remove its markup).
47108 * @param {Field} field
47109 * @return {BasicForm} this
47111 remove : function(field){
47112 this.items.remove(field);
47117 * Looks at the fields in this form, checks them for an id attribute,
47118 * and calls applyTo on the existing dom element with that id.
47119 * @return {BasicForm} this
47121 render : function(){
47122 this.items.each(function(f){
47123 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47131 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47132 * @param {Object} values
47133 * @return {BasicForm} this
47135 applyToFields : function(o){
47136 this.items.each(function(f){
47143 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47144 * @param {Object} values
47145 * @return {BasicForm} this
47147 applyIfToFields : function(o){
47148 this.items.each(function(f){
47156 Roo.BasicForm = Roo.form.BasicForm;/*
47158 * Ext JS Library 1.1.1
47159 * Copyright(c) 2006-2007, Ext JS, LLC.
47161 * Originally Released Under LGPL - original licence link has changed is not relivant.
47164 * <script type="text/javascript">
47168 * @class Roo.form.Form
47169 * @extends Roo.form.BasicForm
47170 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47172 * @param {Object} config Configuration options
47174 Roo.form.Form = function(config){
47176 if (config.items) {
47177 xitems = config.items;
47178 delete config.items;
47182 Roo.form.Form.superclass.constructor.call(this, null, config);
47183 this.url = this.url || this.action;
47185 this.root = new Roo.form.Layout(Roo.applyIf({
47189 this.active = this.root;
47191 * Array of all the buttons that have been added to this form via {@link addButton}
47195 this.allItems = [];
47198 * @event clientvalidation
47199 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47200 * @param {Form} this
47201 * @param {Boolean} valid true if the form has passed client-side validation
47203 clientvalidation: true,
47206 * Fires when the form is rendered
47207 * @param {Roo.form.Form} form
47212 if (this.progressUrl) {
47213 // push a hidden field onto the list of fields..
47217 name : 'UPLOAD_IDENTIFIER'
47222 Roo.each(xitems, this.addxtype, this);
47228 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47230 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47233 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47236 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47238 buttonAlign:'center',
47241 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47246 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47247 * This property cascades to child containers if not set.
47252 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47253 * fires a looping event with that state. This is required to bind buttons to the valid
47254 * state using the config value formBind:true on the button.
47256 monitorValid : false,
47259 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47264 * @cfg {String} progressUrl - Url to return progress data
47267 progressUrl : false,
47270 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47271 * fields are added and the column is closed. If no fields are passed the column remains open
47272 * until end() is called.
47273 * @param {Object} config The config to pass to the column
47274 * @param {Field} field1 (optional)
47275 * @param {Field} field2 (optional)
47276 * @param {Field} etc (optional)
47277 * @return Column The column container object
47279 column : function(c){
47280 var col = new Roo.form.Column(c);
47282 if(arguments.length > 1){ // duplicate code required because of Opera
47283 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47290 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47291 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47292 * until end() is called.
47293 * @param {Object} config The config to pass to the fieldset
47294 * @param {Field} field1 (optional)
47295 * @param {Field} field2 (optional)
47296 * @param {Field} etc (optional)
47297 * @return FieldSet The fieldset container object
47299 fieldset : function(c){
47300 var fs = new Roo.form.FieldSet(c);
47302 if(arguments.length > 1){ // duplicate code required because of Opera
47303 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47310 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47311 * fields are added and the container is closed. If no fields are passed the container remains open
47312 * until end() is called.
47313 * @param {Object} config The config to pass to the Layout
47314 * @param {Field} field1 (optional)
47315 * @param {Field} field2 (optional)
47316 * @param {Field} etc (optional)
47317 * @return Layout The container object
47319 container : function(c){
47320 var l = new Roo.form.Layout(c);
47322 if(arguments.length > 1){ // duplicate code required because of Opera
47323 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47330 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47331 * @param {Object} container A Roo.form.Layout or subclass of Layout
47332 * @return {Form} this
47334 start : function(c){
47335 // cascade label info
47336 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47337 this.active.stack.push(c);
47338 c.ownerCt = this.active;
47344 * Closes the current open container
47345 * @return {Form} this
47348 if(this.active == this.root){
47351 this.active = this.active.ownerCt;
47356 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47357 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47358 * as the label of the field.
47359 * @param {Field} field1
47360 * @param {Field} field2 (optional)
47361 * @param {Field} etc. (optional)
47362 * @return {Form} this
47365 this.active.stack.push.apply(this.active.stack, arguments);
47366 this.allItems.push.apply(this.allItems,arguments);
47368 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47369 if(a[i].isFormField){
47374 Roo.form.Form.superclass.add.apply(this, r);
47384 * Find any element that has been added to a form, using it's ID or name
47385 * This can include framesets, columns etc. along with regular fields..
47386 * @param {String} id - id or name to find.
47388 * @return {Element} e - or false if nothing found.
47390 findbyId : function(id)
47396 Roo.each(this.allItems, function(f){
47397 if (f.id == id || f.name == id ){
47408 * Render this form into the passed container. This should only be called once!
47409 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47410 * @return {Form} this
47412 render : function(ct)
47418 var o = this.autoCreate || {
47420 method : this.method || 'POST',
47421 id : this.id || Roo.id()
47423 this.initEl(ct.createChild(o));
47425 this.root.render(this.el);
47429 this.items.each(function(f){
47430 f.render('x-form-el-'+f.id);
47433 if(this.buttons.length > 0){
47434 // tables are required to maintain order and for correct IE layout
47435 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47436 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47437 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47439 var tr = tb.getElementsByTagName('tr')[0];
47440 for(var i = 0, len = this.buttons.length; i < len; i++) {
47441 var b = this.buttons[i];
47442 var td = document.createElement('td');
47443 td.className = 'x-form-btn-td';
47444 b.render(tr.appendChild(td));
47447 if(this.monitorValid){ // initialize after render
47448 this.startMonitoring();
47450 this.fireEvent('rendered', this);
47455 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47456 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47457 * object or a valid Roo.DomHelper element config
47458 * @param {Function} handler The function called when the button is clicked
47459 * @param {Object} scope (optional) The scope of the handler function
47460 * @return {Roo.Button}
47462 addButton : function(config, handler, scope){
47466 minWidth: this.minButtonWidth,
47469 if(typeof config == "string"){
47472 Roo.apply(bc, config);
47474 var btn = new Roo.Button(null, bc);
47475 this.buttons.push(btn);
47480 * Adds a series of form elements (using the xtype property as the factory method.
47481 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47482 * @param {Object} config
47485 addxtype : function()
47487 var ar = Array.prototype.slice.call(arguments, 0);
47489 for(var i = 0; i < ar.length; i++) {
47491 continue; // skip -- if this happends something invalid got sent, we
47492 // should ignore it, as basically that interface element will not show up
47493 // and that should be pretty obvious!!
47496 if (Roo.form[ar[i].xtype]) {
47498 var fe = Roo.factory(ar[i], Roo.form);
47504 fe.store.form = this;
47509 this.allItems.push(fe);
47510 if (fe.items && fe.addxtype) {
47511 fe.addxtype.apply(fe, fe.items);
47521 // console.log('adding ' + ar[i].xtype);
47523 if (ar[i].xtype == 'Button') {
47524 //console.log('adding button');
47525 //console.log(ar[i]);
47526 this.addButton(ar[i]);
47527 this.allItems.push(fe);
47531 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47532 alert('end is not supported on xtype any more, use items');
47534 // //console.log('adding end');
47542 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47543 * option "monitorValid"
47545 startMonitoring : function(){
47548 Roo.TaskMgr.start({
47549 run : this.bindHandler,
47550 interval : this.monitorPoll || 200,
47557 * Stops monitoring of the valid state of this form
47559 stopMonitoring : function(){
47560 this.bound = false;
47564 bindHandler : function(){
47566 return false; // stops binding
47569 this.items.each(function(f){
47570 if(!f.isValid(true)){
47575 for(var i = 0, len = this.buttons.length; i < len; i++){
47576 var btn = this.buttons[i];
47577 if(btn.formBind === true && btn.disabled === valid){
47578 btn.setDisabled(!valid);
47581 this.fireEvent('clientvalidation', this, valid);
47595 Roo.Form = Roo.form.Form;
47598 * Ext JS Library 1.1.1
47599 * Copyright(c) 2006-2007, Ext JS, LLC.
47601 * Originally Released Under LGPL - original licence link has changed is not relivant.
47604 * <script type="text/javascript">
47607 // as we use this in bootstrap.
47608 Roo.namespace('Roo.form');
47610 * @class Roo.form.Action
47611 * Internal Class used to handle form actions
47613 * @param {Roo.form.BasicForm} el The form element or its id
47614 * @param {Object} config Configuration options
47619 // define the action interface
47620 Roo.form.Action = function(form, options){
47622 this.options = options || {};
47625 * Client Validation Failed
47628 Roo.form.Action.CLIENT_INVALID = 'client';
47630 * Server Validation Failed
47633 Roo.form.Action.SERVER_INVALID = 'server';
47635 * Connect to Server Failed
47638 Roo.form.Action.CONNECT_FAILURE = 'connect';
47640 * Reading Data from Server Failed
47643 Roo.form.Action.LOAD_FAILURE = 'load';
47645 Roo.form.Action.prototype = {
47647 failureType : undefined,
47648 response : undefined,
47649 result : undefined,
47651 // interface method
47652 run : function(options){
47656 // interface method
47657 success : function(response){
47661 // interface method
47662 handleResponse : function(response){
47666 // default connection failure
47667 failure : function(response){
47669 this.response = response;
47670 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47671 this.form.afterAction(this, false);
47674 processResponse : function(response){
47675 this.response = response;
47676 if(!response.responseText){
47679 this.result = this.handleResponse(response);
47680 return this.result;
47683 // utility functions used internally
47684 getUrl : function(appendParams){
47685 var url = this.options.url || this.form.url || this.form.el.dom.action;
47687 var p = this.getParams();
47689 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47695 getMethod : function(){
47696 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47699 getParams : function(){
47700 var bp = this.form.baseParams;
47701 var p = this.options.params;
47703 if(typeof p == "object"){
47704 p = Roo.urlEncode(Roo.applyIf(p, bp));
47705 }else if(typeof p == 'string' && bp){
47706 p += '&' + Roo.urlEncode(bp);
47709 p = Roo.urlEncode(bp);
47714 createCallback : function(){
47716 success: this.success,
47717 failure: this.failure,
47719 timeout: (this.form.timeout*1000),
47720 upload: this.form.fileUpload ? this.success : undefined
47725 Roo.form.Action.Submit = function(form, options){
47726 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47729 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47732 haveProgress : false,
47733 uploadComplete : false,
47735 // uploadProgress indicator.
47736 uploadProgress : function()
47738 if (!this.form.progressUrl) {
47742 if (!this.haveProgress) {
47743 Roo.MessageBox.progress("Uploading", "Uploading");
47745 if (this.uploadComplete) {
47746 Roo.MessageBox.hide();
47750 this.haveProgress = true;
47752 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47754 var c = new Roo.data.Connection();
47756 url : this.form.progressUrl,
47761 success : function(req){
47762 //console.log(data);
47766 rdata = Roo.decode(req.responseText)
47768 Roo.log("Invalid data from server..");
47772 if (!rdata || !rdata.success) {
47774 Roo.MessageBox.alert(Roo.encode(rdata));
47777 var data = rdata.data;
47779 if (this.uploadComplete) {
47780 Roo.MessageBox.hide();
47785 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47786 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47789 this.uploadProgress.defer(2000,this);
47792 failure: function(data) {
47793 Roo.log('progress url failed ');
47804 // run get Values on the form, so it syncs any secondary forms.
47805 this.form.getValues();
47807 var o = this.options;
47808 var method = this.getMethod();
47809 var isPost = method == 'POST';
47810 if(o.clientValidation === false || this.form.isValid()){
47812 if (this.form.progressUrl) {
47813 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47814 (new Date() * 1) + '' + Math.random());
47819 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47820 form:this.form.el.dom,
47821 url:this.getUrl(!isPost),
47823 params:isPost ? this.getParams() : null,
47824 isUpload: this.form.fileUpload
47827 this.uploadProgress();
47829 }else if (o.clientValidation !== false){ // client validation failed
47830 this.failureType = Roo.form.Action.CLIENT_INVALID;
47831 this.form.afterAction(this, false);
47835 success : function(response)
47837 this.uploadComplete= true;
47838 if (this.haveProgress) {
47839 Roo.MessageBox.hide();
47843 var result = this.processResponse(response);
47844 if(result === true || result.success){
47845 this.form.afterAction(this, true);
47849 this.form.markInvalid(result.errors);
47850 this.failureType = Roo.form.Action.SERVER_INVALID;
47852 this.form.afterAction(this, false);
47854 failure : function(response)
47856 this.uploadComplete= true;
47857 if (this.haveProgress) {
47858 Roo.MessageBox.hide();
47861 this.response = response;
47862 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47863 this.form.afterAction(this, false);
47866 handleResponse : function(response){
47867 if(this.form.errorReader){
47868 var rs = this.form.errorReader.read(response);
47871 for(var i = 0, len = rs.records.length; i < len; i++) {
47872 var r = rs.records[i];
47873 errors[i] = r.data;
47876 if(errors.length < 1){
47880 success : rs.success,
47886 ret = Roo.decode(response.responseText);
47890 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
47900 Roo.form.Action.Load = function(form, options){
47901 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
47902 this.reader = this.form.reader;
47905 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
47910 Roo.Ajax.request(Roo.apply(
47911 this.createCallback(), {
47912 method:this.getMethod(),
47913 url:this.getUrl(false),
47914 params:this.getParams()
47918 success : function(response){
47920 var result = this.processResponse(response);
47921 if(result === true || !result.success || !result.data){
47922 this.failureType = Roo.form.Action.LOAD_FAILURE;
47923 this.form.afterAction(this, false);
47926 this.form.clearInvalid();
47927 this.form.setValues(result.data);
47928 this.form.afterAction(this, true);
47931 handleResponse : function(response){
47932 if(this.form.reader){
47933 var rs = this.form.reader.read(response);
47934 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
47936 success : rs.success,
47940 return Roo.decode(response.responseText);
47944 Roo.form.Action.ACTION_TYPES = {
47945 'load' : Roo.form.Action.Load,
47946 'submit' : Roo.form.Action.Submit
47949 * Ext JS Library 1.1.1
47950 * Copyright(c) 2006-2007, Ext JS, LLC.
47952 * Originally Released Under LGPL - original licence link has changed is not relivant.
47955 * <script type="text/javascript">
47959 * @class Roo.form.Layout
47960 * @extends Roo.Component
47961 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
47963 * @param {Object} config Configuration options
47965 Roo.form.Layout = function(config){
47967 if (config.items) {
47968 xitems = config.items;
47969 delete config.items;
47971 Roo.form.Layout.superclass.constructor.call(this, config);
47973 Roo.each(xitems, this.addxtype, this);
47977 Roo.extend(Roo.form.Layout, Roo.Component, {
47979 * @cfg {String/Object} autoCreate
47980 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
47983 * @cfg {String/Object/Function} style
47984 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
47985 * a function which returns such a specification.
47988 * @cfg {String} labelAlign
47989 * Valid values are "left," "top" and "right" (defaults to "left")
47992 * @cfg {Number} labelWidth
47993 * Fixed width in pixels of all field labels (defaults to undefined)
47996 * @cfg {Boolean} clear
47997 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
48001 * @cfg {String} labelSeparator
48002 * The separator to use after field labels (defaults to ':')
48004 labelSeparator : ':',
48006 * @cfg {Boolean} hideLabels
48007 * True to suppress the display of field labels in this layout (defaults to false)
48009 hideLabels : false,
48012 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48017 onRender : function(ct, position){
48018 if(this.el){ // from markup
48019 this.el = Roo.get(this.el);
48020 }else { // generate
48021 var cfg = this.getAutoCreate();
48022 this.el = ct.createChild(cfg, position);
48025 this.el.applyStyles(this.style);
48027 if(this.labelAlign){
48028 this.el.addClass('x-form-label-'+this.labelAlign);
48030 if(this.hideLabels){
48031 this.labelStyle = "display:none";
48032 this.elementStyle = "padding-left:0;";
48034 if(typeof this.labelWidth == 'number'){
48035 this.labelStyle = "width:"+this.labelWidth+"px;";
48036 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48038 if(this.labelAlign == 'top'){
48039 this.labelStyle = "width:auto;";
48040 this.elementStyle = "padding-left:0;";
48043 var stack = this.stack;
48044 var slen = stack.length;
48046 if(!this.fieldTpl){
48047 var t = new Roo.Template(
48048 '<div class="x-form-item {5}">',
48049 '<label for="{0}" style="{2}">{1}{4}</label>',
48050 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48052 '</div><div class="x-form-clear-left"></div>'
48054 t.disableFormats = true;
48056 Roo.form.Layout.prototype.fieldTpl = t;
48058 for(var i = 0; i < slen; i++) {
48059 if(stack[i].isFormField){
48060 this.renderField(stack[i]);
48062 this.renderComponent(stack[i]);
48067 this.el.createChild({cls:'x-form-clear'});
48072 renderField : function(f){
48073 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48076 f.labelStyle||this.labelStyle||'', //2
48077 this.elementStyle||'', //3
48078 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48079 f.itemCls||this.itemCls||'' //5
48080 ], true).getPrevSibling());
48084 renderComponent : function(c){
48085 c.render(c.isLayout ? this.el : this.el.createChild());
48088 * Adds a object form elements (using the xtype property as the factory method.)
48089 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48090 * @param {Object} config
48092 addxtype : function(o)
48094 // create the lement.
48095 o.form = this.form;
48096 var fe = Roo.factory(o, Roo.form);
48097 this.form.allItems.push(fe);
48098 this.stack.push(fe);
48100 if (fe.isFormField) {
48101 this.form.items.add(fe);
48109 * @class Roo.form.Column
48110 * @extends Roo.form.Layout
48111 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48113 * @param {Object} config Configuration options
48115 Roo.form.Column = function(config){
48116 Roo.form.Column.superclass.constructor.call(this, config);
48119 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48121 * @cfg {Number/String} width
48122 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48125 * @cfg {String/Object} autoCreate
48126 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48130 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48133 onRender : function(ct, position){
48134 Roo.form.Column.superclass.onRender.call(this, ct, position);
48136 this.el.setWidth(this.width);
48143 * @class Roo.form.Row
48144 * @extends Roo.form.Layout
48145 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48147 * @param {Object} config Configuration options
48151 Roo.form.Row = function(config){
48152 Roo.form.Row.superclass.constructor.call(this, config);
48155 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48157 * @cfg {Number/String} width
48158 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48161 * @cfg {Number/String} height
48162 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48164 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48168 onRender : function(ct, position){
48169 //console.log('row render');
48171 var t = new Roo.Template(
48172 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48173 '<label for="{0}" style="{2}">{1}{4}</label>',
48174 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48178 t.disableFormats = true;
48180 Roo.form.Layout.prototype.rowTpl = t;
48182 this.fieldTpl = this.rowTpl;
48184 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48185 var labelWidth = 100;
48187 if ((this.labelAlign != 'top')) {
48188 if (typeof this.labelWidth == 'number') {
48189 labelWidth = this.labelWidth
48191 this.padWidth = 20 + labelWidth;
48195 Roo.form.Column.superclass.onRender.call(this, ct, position);
48197 this.el.setWidth(this.width);
48200 this.el.setHeight(this.height);
48205 renderField : function(f){
48206 f.fieldEl = this.fieldTpl.append(this.el, [
48207 f.id, f.fieldLabel,
48208 f.labelStyle||this.labelStyle||'',
48209 this.elementStyle||'',
48210 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48211 f.itemCls||this.itemCls||'',
48212 f.width ? f.width + this.padWidth : 160 + this.padWidth
48219 * @class Roo.form.FieldSet
48220 * @extends Roo.form.Layout
48221 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48223 * @param {Object} config Configuration options
48225 Roo.form.FieldSet = function(config){
48226 Roo.form.FieldSet.superclass.constructor.call(this, config);
48229 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48231 * @cfg {String} legend
48232 * The text to display as the legend for the FieldSet (defaults to '')
48235 * @cfg {String/Object} autoCreate
48236 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48240 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48243 onRender : function(ct, position){
48244 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48246 this.setLegend(this.legend);
48251 setLegend : function(text){
48253 this.el.child('legend').update(text);
48258 * Ext JS Library 1.1.1
48259 * Copyright(c) 2006-2007, Ext JS, LLC.
48261 * Originally Released Under LGPL - original licence link has changed is not relivant.
48264 * <script type="text/javascript">
48267 * @class Roo.form.VTypes
48268 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48271 Roo.form.VTypes = function(){
48272 // closure these in so they are only created once.
48273 var alpha = /^[a-zA-Z_]+$/;
48274 var alphanum = /^[a-zA-Z0-9_]+$/;
48275 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48276 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48278 // All these messages and functions are configurable
48281 * The function used to validate email addresses
48282 * @param {String} value The email address
48284 'email' : function(v){
48285 return email.test(v);
48288 * The error text to display when the email validation function returns false
48291 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48293 * The keystroke filter mask to be applied on email input
48296 'emailMask' : /[a-z0-9_\.\-@]/i,
48299 * The function used to validate URLs
48300 * @param {String} value The URL
48302 'url' : function(v){
48303 return url.test(v);
48306 * The error text to display when the url validation function returns false
48309 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48312 * The function used to validate alpha values
48313 * @param {String} value The value
48315 'alpha' : function(v){
48316 return alpha.test(v);
48319 * The error text to display when the alpha validation function returns false
48322 'alphaText' : 'This field should only contain letters and _',
48324 * The keystroke filter mask to be applied on alpha input
48327 'alphaMask' : /[a-z_]/i,
48330 * The function used to validate alphanumeric values
48331 * @param {String} value The value
48333 'alphanum' : function(v){
48334 return alphanum.test(v);
48337 * The error text to display when the alphanumeric validation function returns false
48340 'alphanumText' : 'This field should only contain letters, numbers and _',
48342 * The keystroke filter mask to be applied on alphanumeric input
48345 'alphanumMask' : /[a-z0-9_]/i
48347 }();//<script type="text/javascript">
48350 * @class Roo.form.FCKeditor
48351 * @extends Roo.form.TextArea
48352 * Wrapper around the FCKEditor http://www.fckeditor.net
48354 * Creates a new FCKeditor
48355 * @param {Object} config Configuration options
48357 Roo.form.FCKeditor = function(config){
48358 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48361 * @event editorinit
48362 * Fired when the editor is initialized - you can add extra handlers here..
48363 * @param {FCKeditor} this
48364 * @param {Object} the FCK object.
48371 Roo.form.FCKeditor.editors = { };
48372 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48374 //defaultAutoCreate : {
48375 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48379 * @cfg {Object} fck options - see fck manual for details.
48384 * @cfg {Object} fck toolbar set (Basic or Default)
48386 toolbarSet : 'Basic',
48388 * @cfg {Object} fck BasePath
48390 basePath : '/fckeditor/',
48398 onRender : function(ct, position)
48401 this.defaultAutoCreate = {
48403 style:"width:300px;height:60px;",
48404 autocomplete: "new-password"
48407 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48410 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48411 if(this.preventScrollbars){
48412 this.el.setStyle("overflow", "hidden");
48414 this.el.setHeight(this.growMin);
48417 //console.log('onrender' + this.getId() );
48418 Roo.form.FCKeditor.editors[this.getId()] = this;
48421 this.replaceTextarea() ;
48425 getEditor : function() {
48426 return this.fckEditor;
48429 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48430 * @param {Mixed} value The value to set
48434 setValue : function(value)
48436 //console.log('setValue: ' + value);
48438 if(typeof(value) == 'undefined') { // not sure why this is happending...
48441 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48443 //if(!this.el || !this.getEditor()) {
48444 // this.value = value;
48445 //this.setValue.defer(100,this,[value]);
48449 if(!this.getEditor()) {
48453 this.getEditor().SetData(value);
48460 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48461 * @return {Mixed} value The field value
48463 getValue : function()
48466 if (this.frame && this.frame.dom.style.display == 'none') {
48467 return Roo.form.FCKeditor.superclass.getValue.call(this);
48470 if(!this.el || !this.getEditor()) {
48472 // this.getValue.defer(100,this);
48477 var value=this.getEditor().GetData();
48478 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48479 return Roo.form.FCKeditor.superclass.getValue.call(this);
48485 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48486 * @return {Mixed} value The field value
48488 getRawValue : function()
48490 if (this.frame && this.frame.dom.style.display == 'none') {
48491 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48494 if(!this.el || !this.getEditor()) {
48495 //this.getRawValue.defer(100,this);
48502 var value=this.getEditor().GetData();
48503 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48504 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48508 setSize : function(w,h) {
48512 //if (this.frame && this.frame.dom.style.display == 'none') {
48513 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48516 //if(!this.el || !this.getEditor()) {
48517 // this.setSize.defer(100,this, [w,h]);
48523 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48525 this.frame.dom.setAttribute('width', w);
48526 this.frame.dom.setAttribute('height', h);
48527 this.frame.setSize(w,h);
48531 toggleSourceEdit : function(value) {
48535 this.el.dom.style.display = value ? '' : 'none';
48536 this.frame.dom.style.display = value ? 'none' : '';
48541 focus: function(tag)
48543 if (this.frame.dom.style.display == 'none') {
48544 return Roo.form.FCKeditor.superclass.focus.call(this);
48546 if(!this.el || !this.getEditor()) {
48547 this.focus.defer(100,this, [tag]);
48554 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48555 this.getEditor().Focus();
48557 if (!this.getEditor().Selection.GetSelection()) {
48558 this.focus.defer(100,this, [tag]);
48563 var r = this.getEditor().EditorDocument.createRange();
48564 r.setStart(tgs[0],0);
48565 r.setEnd(tgs[0],0);
48566 this.getEditor().Selection.GetSelection().removeAllRanges();
48567 this.getEditor().Selection.GetSelection().addRange(r);
48568 this.getEditor().Focus();
48575 replaceTextarea : function()
48577 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48580 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48582 // We must check the elements firstly using the Id and then the name.
48583 var oTextarea = document.getElementById( this.getId() );
48585 var colElementsByName = document.getElementsByName( this.getId() ) ;
48587 oTextarea.style.display = 'none' ;
48589 if ( oTextarea.tabIndex ) {
48590 this.TabIndex = oTextarea.tabIndex ;
48593 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48594 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48595 this.frame = Roo.get(this.getId() + '___Frame')
48598 _getConfigHtml : function()
48602 for ( var o in this.fckconfig ) {
48603 sConfig += sConfig.length > 0 ? '&' : '';
48604 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48607 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48611 _getIFrameHtml : function()
48613 var sFile = 'fckeditor.html' ;
48614 /* no idea what this is about..
48617 if ( (/fcksource=true/i).test( window.top.location.search ) )
48618 sFile = 'fckeditor.original.html' ;
48623 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48624 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48627 var html = '<iframe id="' + this.getId() +
48628 '___Frame" src="' + sLink +
48629 '" width="' + this.width +
48630 '" height="' + this.height + '"' +
48631 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48632 ' frameborder="0" scrolling="no"></iframe>' ;
48637 _insertHtmlBefore : function( html, element )
48639 if ( element.insertAdjacentHTML ) {
48641 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48643 var oRange = document.createRange() ;
48644 oRange.setStartBefore( element ) ;
48645 var oFragment = oRange.createContextualFragment( html );
48646 element.parentNode.insertBefore( oFragment, element ) ;
48659 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48661 function FCKeditor_OnComplete(editorInstance){
48662 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48663 f.fckEditor = editorInstance;
48664 //console.log("loaded");
48665 f.fireEvent('editorinit', f, editorInstance);
48685 //<script type="text/javascript">
48687 * @class Roo.form.GridField
48688 * @extends Roo.form.Field
48689 * Embed a grid (or editable grid into a form)
48692 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48694 * xgrid.store = Roo.data.Store
48695 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48696 * xgrid.store.reader = Roo.data.JsonReader
48700 * Creates a new GridField
48701 * @param {Object} config Configuration options
48703 Roo.form.GridField = function(config){
48704 Roo.form.GridField.superclass.constructor.call(this, config);
48708 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48710 * @cfg {Number} width - used to restrict width of grid..
48714 * @cfg {Number} height - used to restrict height of grid..
48718 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48724 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48725 * {tag: "input", type: "checkbox", autocomplete: "off"})
48727 // defaultAutoCreate : { tag: 'div' },
48728 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48730 * @cfg {String} addTitle Text to include for adding a title.
48734 onResize : function(){
48735 Roo.form.Field.superclass.onResize.apply(this, arguments);
48738 initEvents : function(){
48739 // Roo.form.Checkbox.superclass.initEvents.call(this);
48740 // has no events...
48745 getResizeEl : function(){
48749 getPositionEl : function(){
48754 onRender : function(ct, position){
48756 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48757 var style = this.style;
48760 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48761 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48762 this.viewEl = this.wrap.createChild({ tag: 'div' });
48764 this.viewEl.applyStyles(style);
48767 this.viewEl.setWidth(this.width);
48770 this.viewEl.setHeight(this.height);
48772 //if(this.inputValue !== undefined){
48773 //this.setValue(this.value);
48776 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48779 this.grid.render();
48780 this.grid.getDataSource().on('remove', this.refreshValue, this);
48781 this.grid.getDataSource().on('update', this.refreshValue, this);
48782 this.grid.on('afteredit', this.refreshValue, this);
48788 * Sets the value of the item.
48789 * @param {String} either an object or a string..
48791 setValue : function(v){
48793 v = v || []; // empty set..
48794 // this does not seem smart - it really only affects memoryproxy grids..
48795 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48796 var ds = this.grid.getDataSource();
48797 // assumes a json reader..
48799 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48800 ds.loadData( data);
48802 // clear selection so it does not get stale.
48803 if (this.grid.sm) {
48804 this.grid.sm.clearSelections();
48807 Roo.form.GridField.superclass.setValue.call(this, v);
48808 this.refreshValue();
48809 // should load data in the grid really....
48813 refreshValue: function() {
48815 this.grid.getDataSource().each(function(r) {
48818 this.el.dom.value = Roo.encode(val);
48826 * Ext JS Library 1.1.1
48827 * Copyright(c) 2006-2007, Ext JS, LLC.
48829 * Originally Released Under LGPL - original licence link has changed is not relivant.
48832 * <script type="text/javascript">
48835 * @class Roo.form.DisplayField
48836 * @extends Roo.form.Field
48837 * A generic Field to display non-editable data.
48838 * @cfg {Boolean} closable (true|false) default false
48840 * Creates a new Display Field item.
48841 * @param {Object} config Configuration options
48843 Roo.form.DisplayField = function(config){
48844 Roo.form.DisplayField.superclass.constructor.call(this, config);
48849 * Fires after the click the close btn
48850 * @param {Roo.form.DisplayField} this
48856 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
48857 inputType: 'hidden',
48863 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48865 focusClass : undefined,
48867 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48869 fieldClass: 'x-form-field',
48872 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
48874 valueRenderer: undefined,
48878 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48879 * {tag: "input", type: "checkbox", autocomplete: "off"})
48882 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
48886 onResize : function(){
48887 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
48891 initEvents : function(){
48892 // Roo.form.Checkbox.superclass.initEvents.call(this);
48893 // has no events...
48896 this.closeEl.on('click', this.onClose, this);
48902 getResizeEl : function(){
48906 getPositionEl : function(){
48911 onRender : function(ct, position){
48913 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
48914 //if(this.inputValue !== undefined){
48915 this.wrap = this.el.wrap();
48917 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
48920 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
48923 if (this.bodyStyle) {
48924 this.viewEl.applyStyles(this.bodyStyle);
48926 //this.viewEl.setStyle('padding', '2px');
48928 this.setValue(this.value);
48933 initValue : Roo.emptyFn,
48938 onClick : function(){
48943 * Sets the checked state of the checkbox.
48944 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
48946 setValue : function(v){
48948 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
48949 // this might be called before we have a dom element..
48950 if (!this.viewEl) {
48953 this.viewEl.dom.innerHTML = html;
48954 Roo.form.DisplayField.superclass.setValue.call(this, v);
48958 onClose : function(e)
48960 e.preventDefault();
48962 this.fireEvent('close', this);
48971 * @class Roo.form.DayPicker
48972 * @extends Roo.form.Field
48973 * A Day picker show [M] [T] [W] ....
48975 * Creates a new Day Picker
48976 * @param {Object} config Configuration options
48978 Roo.form.DayPicker= function(config){
48979 Roo.form.DayPicker.superclass.constructor.call(this, config);
48983 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
48985 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48987 focusClass : undefined,
48989 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48991 fieldClass: "x-form-field",
48994 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48995 * {tag: "input", type: "checkbox", autocomplete: "off"})
48997 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
49000 actionMode : 'viewEl',
49004 inputType : 'hidden',
49007 inputElement: false, // real input element?
49008 basedOn: false, // ????
49010 isFormField: true, // not sure where this is needed!!!!
49012 onResize : function(){
49013 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49014 if(!this.boxLabel){
49015 this.el.alignTo(this.wrap, 'c-c');
49019 initEvents : function(){
49020 Roo.form.Checkbox.superclass.initEvents.call(this);
49021 this.el.on("click", this.onClick, this);
49022 this.el.on("change", this.onClick, this);
49026 getResizeEl : function(){
49030 getPositionEl : function(){
49036 onRender : function(ct, position){
49037 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49039 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49041 var r1 = '<table><tr>';
49042 var r2 = '<tr class="x-form-daypick-icons">';
49043 for (var i=0; i < 7; i++) {
49044 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49045 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49048 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49049 viewEl.select('img').on('click', this.onClick, this);
49050 this.viewEl = viewEl;
49053 // this will not work on Chrome!!!
49054 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49055 this.el.on('propertychange', this.setFromHidden, this); //ie
49063 initValue : Roo.emptyFn,
49066 * Returns the checked state of the checkbox.
49067 * @return {Boolean} True if checked, else false
49069 getValue : function(){
49070 return this.el.dom.value;
49075 onClick : function(e){
49076 //this.setChecked(!this.checked);
49077 Roo.get(e.target).toggleClass('x-menu-item-checked');
49078 this.refreshValue();
49079 //if(this.el.dom.checked != this.checked){
49080 // this.setValue(this.el.dom.checked);
49085 refreshValue : function()
49088 this.viewEl.select('img',true).each(function(e,i,n) {
49089 val += e.is(".x-menu-item-checked") ? String(n) : '';
49091 this.setValue(val, true);
49095 * Sets the checked state of the checkbox.
49096 * On is always based on a string comparison between inputValue and the param.
49097 * @param {Boolean/String} value - the value to set
49098 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49100 setValue : function(v,suppressEvent){
49101 if (!this.el.dom) {
49104 var old = this.el.dom.value ;
49105 this.el.dom.value = v;
49106 if (suppressEvent) {
49110 // update display..
49111 this.viewEl.select('img',true).each(function(e,i,n) {
49113 var on = e.is(".x-menu-item-checked");
49114 var newv = v.indexOf(String(n)) > -1;
49116 e.toggleClass('x-menu-item-checked');
49122 this.fireEvent('change', this, v, old);
49127 // handle setting of hidden value by some other method!!?!?
49128 setFromHidden: function()
49133 //console.log("SET FROM HIDDEN");
49134 //alert('setFrom hidden');
49135 this.setValue(this.el.dom.value);
49138 onDestroy : function()
49141 Roo.get(this.viewEl).remove();
49144 Roo.form.DayPicker.superclass.onDestroy.call(this);
49148 * RooJS Library 1.1.1
49149 * Copyright(c) 2008-2011 Alan Knowles
49156 * @class Roo.form.ComboCheck
49157 * @extends Roo.form.ComboBox
49158 * A combobox for multiple select items.
49160 * FIXME - could do with a reset button..
49163 * Create a new ComboCheck
49164 * @param {Object} config Configuration options
49166 Roo.form.ComboCheck = function(config){
49167 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49168 // should verify some data...
49170 // hiddenName = required..
49171 // displayField = required
49172 // valudField == required
49173 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49175 Roo.each(req, function(e) {
49176 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49177 throw "Roo.form.ComboCheck : missing value for: " + e;
49184 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49189 selectedClass: 'x-menu-item-checked',
49192 onRender : function(ct, position){
49198 var cls = 'x-combo-list';
49201 this.tpl = new Roo.Template({
49202 html : '<div class="'+cls+'-item x-menu-check-item">' +
49203 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49204 '<span>{' + this.displayField + '}</span>' +
49211 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49212 this.view.singleSelect = false;
49213 this.view.multiSelect = true;
49214 this.view.toggleSelect = true;
49215 this.pageTb.add(new Roo.Toolbar.Fill(), {
49218 handler: function()
49225 onViewOver : function(e, t){
49231 onViewClick : function(doFocus,index){
49235 select: function () {
49236 //Roo.log("SELECT CALLED");
49239 selectByValue : function(xv, scrollIntoView){
49240 var ar = this.getValueArray();
49243 Roo.each(ar, function(v) {
49244 if(v === undefined || v === null){
49247 var r = this.findRecord(this.valueField, v);
49249 sels.push(this.store.indexOf(r))
49253 this.view.select(sels);
49259 onSelect : function(record, index){
49260 // Roo.log("onselect Called");
49261 // this is only called by the clear button now..
49262 this.view.clearSelections();
49263 this.setValue('[]');
49264 if (this.value != this.valueBefore) {
49265 this.fireEvent('change', this, this.value, this.valueBefore);
49266 this.valueBefore = this.value;
49269 getValueArray : function()
49274 //Roo.log(this.value);
49275 if (typeof(this.value) == 'undefined') {
49278 var ar = Roo.decode(this.value);
49279 return ar instanceof Array ? ar : []; //?? valid?
49282 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49287 expand : function ()
49290 Roo.form.ComboCheck.superclass.expand.call(this);
49291 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49292 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49297 collapse : function(){
49298 Roo.form.ComboCheck.superclass.collapse.call(this);
49299 var sl = this.view.getSelectedIndexes();
49300 var st = this.store;
49304 Roo.each(sl, function(i) {
49306 nv.push(r.get(this.valueField));
49308 this.setValue(Roo.encode(nv));
49309 if (this.value != this.valueBefore) {
49311 this.fireEvent('change', this, this.value, this.valueBefore);
49312 this.valueBefore = this.value;
49317 setValue : function(v){
49321 var vals = this.getValueArray();
49323 Roo.each(vals, function(k) {
49324 var r = this.findRecord(this.valueField, k);
49326 tv.push(r.data[this.displayField]);
49327 }else if(this.valueNotFoundText !== undefined){
49328 tv.push( this.valueNotFoundText );
49333 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49334 this.hiddenField.value = v;
49340 * Ext JS Library 1.1.1
49341 * Copyright(c) 2006-2007, Ext JS, LLC.
49343 * Originally Released Under LGPL - original licence link has changed is not relivant.
49346 * <script type="text/javascript">
49350 * @class Roo.form.Signature
49351 * @extends Roo.form.Field
49355 * @param {Object} config Configuration options
49358 Roo.form.Signature = function(config){
49359 Roo.form.Signature.superclass.constructor.call(this, config);
49361 this.addEvents({// not in used??
49364 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49365 * @param {Roo.form.Signature} combo This combo box
49370 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49371 * @param {Roo.form.ComboBox} combo This combo box
49372 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49378 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49380 * @cfg {Object} labels Label to use when rendering a form.
49384 * confirm : "Confirm"
49389 confirm : "Confirm"
49392 * @cfg {Number} width The signature panel width (defaults to 300)
49396 * @cfg {Number} height The signature panel height (defaults to 100)
49400 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49402 allowBlank : false,
49405 // {Object} signPanel The signature SVG panel element (defaults to {})
49407 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49408 isMouseDown : false,
49409 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49410 isConfirmed : false,
49411 // {String} signatureTmp SVG mapping string (defaults to empty string)
49415 defaultAutoCreate : { // modified by initCompnoent..
49421 onRender : function(ct, position){
49423 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49425 this.wrap = this.el.wrap({
49426 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49429 this.createToolbar(this);
49430 this.signPanel = this.wrap.createChild({
49432 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49436 this.svgID = Roo.id();
49437 this.svgEl = this.signPanel.createChild({
49438 xmlns : 'http://www.w3.org/2000/svg',
49440 id : this.svgID + "-svg",
49442 height: this.height,
49443 viewBox: '0 0 '+this.width+' '+this.height,
49447 id: this.svgID + "-svg-r",
49449 height: this.height,
49454 id: this.svgID + "-svg-l",
49456 y1: (this.height*0.8), // start set the line in 80% of height
49457 x2: this.width, // end
49458 y2: (this.height*0.8), // end set the line in 80% of height
49460 'stroke-width': "1",
49461 'stroke-dasharray': "3",
49462 'shape-rendering': "crispEdges",
49463 'pointer-events': "none"
49467 id: this.svgID + "-svg-p",
49469 'stroke-width': "3",
49471 'pointer-events': 'none'
49476 this.svgBox = this.svgEl.dom.getScreenCTM();
49478 createSVG : function(){
49479 var svg = this.signPanel;
49480 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49483 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49484 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49485 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49486 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49487 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49488 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49489 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49492 isTouchEvent : function(e){
49493 return e.type.match(/^touch/);
49495 getCoords : function (e) {
49496 var pt = this.svgEl.dom.createSVGPoint();
49499 if (this.isTouchEvent(e)) {
49500 pt.x = e.targetTouches[0].clientX;
49501 pt.y = e.targetTouches[0].clientY;
49503 var a = this.svgEl.dom.getScreenCTM();
49504 var b = a.inverse();
49505 var mx = pt.matrixTransform(b);
49506 return mx.x + ',' + mx.y;
49508 //mouse event headler
49509 down : function (e) {
49510 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49511 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49513 this.isMouseDown = true;
49515 e.preventDefault();
49517 move : function (e) {
49518 if (this.isMouseDown) {
49519 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49520 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49523 e.preventDefault();
49525 up : function (e) {
49526 this.isMouseDown = false;
49527 var sp = this.signatureTmp.split(' ');
49530 if(!sp[sp.length-2].match(/^L/)){
49534 this.signatureTmp = sp.join(" ");
49537 if(this.getValue() != this.signatureTmp){
49538 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49539 this.isConfirmed = false;
49541 e.preventDefault();
49545 * Protected method that will not generally be called directly. It
49546 * is called when the editor creates its toolbar. Override this method if you need to
49547 * add custom toolbar buttons.
49548 * @param {HtmlEditor} editor
49550 createToolbar : function(editor){
49551 function btn(id, toggle, handler){
49552 var xid = fid + '-'+ id ;
49556 cls : 'x-btn-icon x-edit-'+id,
49557 enableToggle:toggle !== false,
49558 scope: editor, // was editor...
49559 handler:handler||editor.relayBtnCmd,
49560 clickEvent:'mousedown',
49561 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49567 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49571 cls : ' x-signature-btn x-signature-'+id,
49572 scope: editor, // was editor...
49573 handler: this.reset,
49574 clickEvent:'mousedown',
49575 text: this.labels.clear
49582 cls : ' x-signature-btn x-signature-'+id,
49583 scope: editor, // was editor...
49584 handler: this.confirmHandler,
49585 clickEvent:'mousedown',
49586 text: this.labels.confirm
49593 * when user is clicked confirm then show this image.....
49595 * @return {String} Image Data URI
49597 getImageDataURI : function(){
49598 var svg = this.svgEl.dom.parentNode.innerHTML;
49599 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49604 * @return {Boolean} this.isConfirmed
49606 getConfirmed : function(){
49607 return this.isConfirmed;
49611 * @return {Number} this.width
49613 getWidth : function(){
49618 * @return {Number} this.height
49620 getHeight : function(){
49621 return this.height;
49624 getSignature : function(){
49625 return this.signatureTmp;
49628 reset : function(){
49629 this.signatureTmp = '';
49630 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49631 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49632 this.isConfirmed = false;
49633 Roo.form.Signature.superclass.reset.call(this);
49635 setSignature : function(s){
49636 this.signatureTmp = s;
49637 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49638 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49640 this.isConfirmed = false;
49641 Roo.form.Signature.superclass.reset.call(this);
49644 // Roo.log(this.signPanel.dom.contentWindow.up())
49647 setConfirmed : function(){
49651 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49654 confirmHandler : function(){
49655 if(!this.getSignature()){
49659 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49660 this.setValue(this.getSignature());
49661 this.isConfirmed = true;
49663 this.fireEvent('confirm', this);
49666 // Subclasses should provide the validation implementation by overriding this
49667 validateValue : function(value){
49668 if(this.allowBlank){
49672 if(this.isConfirmed){
49679 * Ext JS Library 1.1.1
49680 * Copyright(c) 2006-2007, Ext JS, LLC.
49682 * Originally Released Under LGPL - original licence link has changed is not relivant.
49685 * <script type="text/javascript">
49690 * @class Roo.form.ComboBox
49691 * @extends Roo.form.TriggerField
49692 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49694 * Create a new ComboBox.
49695 * @param {Object} config Configuration options
49697 Roo.form.Select = function(config){
49698 Roo.form.Select.superclass.constructor.call(this, config);
49702 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49704 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49707 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49708 * rendering into an Roo.Editor, defaults to false)
49711 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49712 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49715 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49718 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49719 * the dropdown list (defaults to undefined, with no header element)
49723 * @cfg {String/Roo.Template} tpl The template to use to render the output
49727 defaultAutoCreate : {tag: "select" },
49729 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49731 listWidth: undefined,
49733 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49734 * mode = 'remote' or 'text' if mode = 'local')
49736 displayField: undefined,
49738 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49739 * mode = 'remote' or 'value' if mode = 'local').
49740 * Note: use of a valueField requires the user make a selection
49741 * in order for a value to be mapped.
49743 valueField: undefined,
49747 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49748 * field's data value (defaults to the underlying DOM element's name)
49750 hiddenName: undefined,
49752 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49756 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49758 selectedClass: 'x-combo-selected',
49760 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49761 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49762 * which displays a downward arrow icon).
49764 triggerClass : 'x-form-arrow-trigger',
49766 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49770 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49771 * anchor positions (defaults to 'tl-bl')
49773 listAlign: 'tl-bl?',
49775 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49779 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49780 * query specified by the allQuery config option (defaults to 'query')
49782 triggerAction: 'query',
49784 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49785 * (defaults to 4, does not apply if editable = false)
49789 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49790 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49794 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49795 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49799 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49800 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49804 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49805 * when editable = true (defaults to false)
49807 selectOnFocus:false,
49809 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49811 queryParam: 'query',
49813 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49814 * when mode = 'remote' (defaults to 'Loading...')
49816 loadingText: 'Loading...',
49818 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49822 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49826 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49827 * traditional select (defaults to true)
49831 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49835 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49839 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49840 * listWidth has a higher value)
49844 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49845 * allow the user to set arbitrary text into the field (defaults to false)
49847 forceSelection:false,
49849 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49850 * if typeAhead = true (defaults to 250)
49852 typeAheadDelay : 250,
49854 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
49855 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
49857 valueNotFoundText : undefined,
49860 * @cfg {String} defaultValue The value displayed after loading the store.
49865 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
49867 blockFocus : false,
49870 * @cfg {Boolean} disableClear Disable showing of clear button.
49872 disableClear : false,
49874 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
49876 alwaysQuery : false,
49882 // element that contains real text value.. (when hidden is used..)
49885 onRender : function(ct, position){
49886 Roo.form.Field.prototype.onRender.call(this, ct, position);
49889 this.store.on('beforeload', this.onBeforeLoad, this);
49890 this.store.on('load', this.onLoad, this);
49891 this.store.on('loadexception', this.onLoadException, this);
49892 this.store.load({});
49900 initEvents : function(){
49901 //Roo.form.ComboBox.superclass.initEvents.call(this);
49905 onDestroy : function(){
49908 this.store.un('beforeload', this.onBeforeLoad, this);
49909 this.store.un('load', this.onLoad, this);
49910 this.store.un('loadexception', this.onLoadException, this);
49912 //Roo.form.ComboBox.superclass.onDestroy.call(this);
49916 fireKey : function(e){
49917 if(e.isNavKeyPress() && !this.list.isVisible()){
49918 this.fireEvent("specialkey", this, e);
49923 onResize: function(w, h){
49931 * Allow or prevent the user from directly editing the field text. If false is passed,
49932 * the user will only be able to select from the items defined in the dropdown list. This method
49933 * is the runtime equivalent of setting the 'editable' config option at config time.
49934 * @param {Boolean} value True to allow the user to directly edit the field text
49936 setEditable : function(value){
49941 onBeforeLoad : function(){
49943 Roo.log("Select before load");
49946 this.innerList.update(this.loadingText ?
49947 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
49948 //this.restrictHeight();
49949 this.selectedIndex = -1;
49953 onLoad : function(){
49956 var dom = this.el.dom;
49957 dom.innerHTML = '';
49958 var od = dom.ownerDocument;
49960 if (this.emptyText) {
49961 var op = od.createElement('option');
49962 op.setAttribute('value', '');
49963 op.innerHTML = String.format('{0}', this.emptyText);
49964 dom.appendChild(op);
49966 if(this.store.getCount() > 0){
49968 var vf = this.valueField;
49969 var df = this.displayField;
49970 this.store.data.each(function(r) {
49971 // which colmsn to use... testing - cdoe / title..
49972 var op = od.createElement('option');
49973 op.setAttribute('value', r.data[vf]);
49974 op.innerHTML = String.format('{0}', r.data[df]);
49975 dom.appendChild(op);
49977 if (typeof(this.defaultValue != 'undefined')) {
49978 this.setValue(this.defaultValue);
49983 //this.onEmptyResults();
49988 onLoadException : function()
49990 dom.innerHTML = '';
49992 Roo.log("Select on load exception");
49996 Roo.log(this.store.reader.jsonData);
49997 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
49998 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50004 onTypeAhead : function(){
50009 onSelect : function(record, index){
50010 Roo.log('on select?');
50012 if(this.fireEvent('beforeselect', this, record, index) !== false){
50013 this.setFromData(index > -1 ? record.data : false);
50015 this.fireEvent('select', this, record, index);
50020 * Returns the currently selected field value or empty string if no value is set.
50021 * @return {String} value The selected value
50023 getValue : function(){
50024 var dom = this.el.dom;
50025 this.value = dom.options[dom.selectedIndex].value;
50031 * Clears any text/value currently set in the field
50033 clearValue : function(){
50035 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50040 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50041 * will be displayed in the field. If the value does not match the data value of an existing item,
50042 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50043 * Otherwise the field will be blank (although the value will still be set).
50044 * @param {String} value The value to match
50046 setValue : function(v){
50047 var d = this.el.dom;
50048 for (var i =0; i < d.options.length;i++) {
50049 if (v == d.options[i].value) {
50050 d.selectedIndex = i;
50058 * @property {Object} the last set data for the element
50063 * Sets the value of the field based on a object which is related to the record format for the store.
50064 * @param {Object} value the value to set as. or false on reset?
50066 setFromData : function(o){
50067 Roo.log('setfrom data?');
50073 reset : function(){
50077 findRecord : function(prop, value){
50082 if(this.store.getCount() > 0){
50083 this.store.each(function(r){
50084 if(r.data[prop] == value){
50094 getName: function()
50096 // returns hidden if it's set..
50097 if (!this.rendered) {return ''};
50098 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50106 onEmptyResults : function(){
50107 Roo.log('empty results');
50112 * Returns true if the dropdown list is expanded, else false.
50114 isExpanded : function(){
50119 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50120 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50121 * @param {String} value The data value of the item to select
50122 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50123 * selected item if it is not currently in view (defaults to true)
50124 * @return {Boolean} True if the value matched an item in the list, else false
50126 selectByValue : function(v, scrollIntoView){
50127 Roo.log('select By Value');
50130 if(v !== undefined && v !== null){
50131 var r = this.findRecord(this.valueField || this.displayField, v);
50133 this.select(this.store.indexOf(r), scrollIntoView);
50141 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50142 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50143 * @param {Number} index The zero-based index of the list item to select
50144 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50145 * selected item if it is not currently in view (defaults to true)
50147 select : function(index, scrollIntoView){
50148 Roo.log('select ');
50151 this.selectedIndex = index;
50152 this.view.select(index);
50153 if(scrollIntoView !== false){
50154 var el = this.view.getNode(index);
50156 this.innerList.scrollChildIntoView(el, false);
50164 validateBlur : function(){
50171 initQuery : function(){
50172 this.doQuery(this.getRawValue());
50176 doForce : function(){
50177 if(this.el.dom.value.length > 0){
50178 this.el.dom.value =
50179 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50185 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50186 * query allowing the query action to be canceled if needed.
50187 * @param {String} query The SQL query to execute
50188 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50189 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50190 * saved in the current store (defaults to false)
50192 doQuery : function(q, forceAll){
50194 Roo.log('doQuery?');
50195 if(q === undefined || q === null){
50200 forceAll: forceAll,
50204 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50208 forceAll = qe.forceAll;
50209 if(forceAll === true || (q.length >= this.minChars)){
50210 if(this.lastQuery != q || this.alwaysQuery){
50211 this.lastQuery = q;
50212 if(this.mode == 'local'){
50213 this.selectedIndex = -1;
50215 this.store.clearFilter();
50217 this.store.filter(this.displayField, q);
50221 this.store.baseParams[this.queryParam] = q;
50223 params: this.getParams(q)
50228 this.selectedIndex = -1;
50235 getParams : function(q){
50237 //p[this.queryParam] = q;
50240 p.limit = this.pageSize;
50246 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50248 collapse : function(){
50253 collapseIf : function(e){
50258 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50260 expand : function(){
50268 * @cfg {Boolean} grow
50272 * @cfg {Number} growMin
50276 * @cfg {Number} growMax
50284 setWidth : function()
50288 getResizeEl : function(){
50291 });//<script type="text/javasscript">
50295 * @class Roo.DDView
50296 * A DnD enabled version of Roo.View.
50297 * @param {Element/String} container The Element in which to create the View.
50298 * @param {String} tpl The template string used to create the markup for each element of the View
50299 * @param {Object} config The configuration properties. These include all the config options of
50300 * {@link Roo.View} plus some specific to this class.<br>
50302 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50303 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50305 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50306 .x-view-drag-insert-above {
50307 border-top:1px dotted #3366cc;
50309 .x-view-drag-insert-below {
50310 border-bottom:1px dotted #3366cc;
50316 Roo.DDView = function(container, tpl, config) {
50317 Roo.DDView.superclass.constructor.apply(this, arguments);
50318 this.getEl().setStyle("outline", "0px none");
50319 this.getEl().unselectable();
50320 if (this.dragGroup) {
50321 this.setDraggable(this.dragGroup.split(","));
50323 if (this.dropGroup) {
50324 this.setDroppable(this.dropGroup.split(","));
50326 if (this.deletable) {
50327 this.setDeletable();
50329 this.isDirtyFlag = false;
50335 Roo.extend(Roo.DDView, Roo.View, {
50336 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50337 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50338 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50339 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50343 reset: Roo.emptyFn,
50345 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50347 validate: function() {
50351 destroy: function() {
50352 this.purgeListeners();
50353 this.getEl.removeAllListeners();
50354 this.getEl().remove();
50355 if (this.dragZone) {
50356 if (this.dragZone.destroy) {
50357 this.dragZone.destroy();
50360 if (this.dropZone) {
50361 if (this.dropZone.destroy) {
50362 this.dropZone.destroy();
50367 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50368 getName: function() {
50372 /** Loads the View from a JSON string representing the Records to put into the Store. */
50373 setValue: function(v) {
50375 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50378 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50379 this.store.proxy = new Roo.data.MemoryProxy(data);
50383 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50384 getValue: function() {
50386 this.store.each(function(rec) {
50387 result += rec.id + ',';
50389 return result.substr(0, result.length - 1) + ')';
50392 getIds: function() {
50393 var i = 0, result = new Array(this.store.getCount());
50394 this.store.each(function(rec) {
50395 result[i++] = rec.id;
50400 isDirty: function() {
50401 return this.isDirtyFlag;
50405 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50406 * whole Element becomes the target, and this causes the drop gesture to append.
50408 getTargetFromEvent : function(e) {
50409 var target = e.getTarget();
50410 while ((target !== null) && (target.parentNode != this.el.dom)) {
50411 target = target.parentNode;
50414 target = this.el.dom.lastChild || this.el.dom;
50420 * Create the drag data which consists of an object which has the property "ddel" as
50421 * the drag proxy element.
50423 getDragData : function(e) {
50424 var target = this.findItemFromChild(e.getTarget());
50426 this.handleSelection(e);
50427 var selNodes = this.getSelectedNodes();
50430 copy: this.copy || (this.allowCopy && e.ctrlKey),
50434 var selectedIndices = this.getSelectedIndexes();
50435 for (var i = 0; i < selectedIndices.length; i++) {
50436 dragData.records.push(this.store.getAt(selectedIndices[i]));
50438 if (selNodes.length == 1) {
50439 dragData.ddel = target.cloneNode(true); // the div element
50441 var div = document.createElement('div'); // create the multi element drag "ghost"
50442 div.className = 'multi-proxy';
50443 for (var i = 0, len = selNodes.length; i < len; i++) {
50444 div.appendChild(selNodes[i].cloneNode(true));
50446 dragData.ddel = div;
50448 //console.log(dragData)
50449 //console.log(dragData.ddel.innerHTML)
50452 //console.log('nodragData')
50456 /** Specify to which ddGroup items in this DDView may be dragged. */
50457 setDraggable: function(ddGroup) {
50458 if (ddGroup instanceof Array) {
50459 Roo.each(ddGroup, this.setDraggable, this);
50462 if (this.dragZone) {
50463 this.dragZone.addToGroup(ddGroup);
50465 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50466 containerScroll: true,
50470 // Draggability implies selection. DragZone's mousedown selects the element.
50471 if (!this.multiSelect) { this.singleSelect = true; }
50473 // Wire the DragZone's handlers up to methods in *this*
50474 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50478 /** Specify from which ddGroup this DDView accepts drops. */
50479 setDroppable: function(ddGroup) {
50480 if (ddGroup instanceof Array) {
50481 Roo.each(ddGroup, this.setDroppable, this);
50484 if (this.dropZone) {
50485 this.dropZone.addToGroup(ddGroup);
50487 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50488 containerScroll: true,
50492 // Wire the DropZone's handlers up to methods in *this*
50493 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50494 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50495 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50496 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50497 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50501 /** Decide whether to drop above or below a View node. */
50502 getDropPoint : function(e, n, dd){
50503 if (n == this.el.dom) { return "above"; }
50504 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50505 var c = t + (b - t) / 2;
50506 var y = Roo.lib.Event.getPageY(e);
50514 onNodeEnter : function(n, dd, e, data){
50518 onNodeOver : function(n, dd, e, data){
50519 var pt = this.getDropPoint(e, n, dd);
50520 // set the insert point style on the target node
50521 var dragElClass = this.dropNotAllowed;
50524 if (pt == "above"){
50525 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50526 targetElClass = "x-view-drag-insert-above";
50528 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50529 targetElClass = "x-view-drag-insert-below";
50531 if (this.lastInsertClass != targetElClass){
50532 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50533 this.lastInsertClass = targetElClass;
50536 return dragElClass;
50539 onNodeOut : function(n, dd, e, data){
50540 this.removeDropIndicators(n);
50543 onNodeDrop : function(n, dd, e, data){
50544 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50547 var pt = this.getDropPoint(e, n, dd);
50548 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50549 if (pt == "below") { insertAt++; }
50550 for (var i = 0; i < data.records.length; i++) {
50551 var r = data.records[i];
50552 var dup = this.store.getById(r.id);
50553 if (dup && (dd != this.dragZone)) {
50554 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50557 this.store.insert(insertAt++, r.copy());
50559 data.source.isDirtyFlag = true;
50561 this.store.insert(insertAt++, r);
50563 this.isDirtyFlag = true;
50566 this.dragZone.cachedTarget = null;
50570 removeDropIndicators : function(n){
50572 Roo.fly(n).removeClass([
50573 "x-view-drag-insert-above",
50574 "x-view-drag-insert-below"]);
50575 this.lastInsertClass = "_noclass";
50580 * Utility method. Add a delete option to the DDView's context menu.
50581 * @param {String} imageUrl The URL of the "delete" icon image.
50583 setDeletable: function(imageUrl) {
50584 if (!this.singleSelect && !this.multiSelect) {
50585 this.singleSelect = true;
50587 var c = this.getContextMenu();
50588 this.contextMenu.on("itemclick", function(item) {
50591 this.remove(this.getSelectedIndexes());
50595 this.contextMenu.add({
50602 /** Return the context menu for this DDView. */
50603 getContextMenu: function() {
50604 if (!this.contextMenu) {
50605 // Create the View's context menu
50606 this.contextMenu = new Roo.menu.Menu({
50607 id: this.id + "-contextmenu"
50609 this.el.on("contextmenu", this.showContextMenu, this);
50611 return this.contextMenu;
50614 disableContextMenu: function() {
50615 if (this.contextMenu) {
50616 this.el.un("contextmenu", this.showContextMenu, this);
50620 showContextMenu: function(e, item) {
50621 item = this.findItemFromChild(e.getTarget());
50624 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50625 this.contextMenu.showAt(e.getXY());
50630 * Remove {@link Roo.data.Record}s at the specified indices.
50631 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50633 remove: function(selectedIndices) {
50634 selectedIndices = [].concat(selectedIndices);
50635 for (var i = 0; i < selectedIndices.length; i++) {
50636 var rec = this.store.getAt(selectedIndices[i]);
50637 this.store.remove(rec);
50642 * Double click fires the event, but also, if this is draggable, and there is only one other
50643 * related DropZone, it transfers the selected node.
50645 onDblClick : function(e){
50646 var item = this.findItemFromChild(e.getTarget());
50648 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50651 if (this.dragGroup) {
50652 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50653 while (targets.indexOf(this.dropZone) > -1) {
50654 targets.remove(this.dropZone);
50656 if (targets.length == 1) {
50657 this.dragZone.cachedTarget = null;
50658 var el = Roo.get(targets[0].getEl());
50659 var box = el.getBox(true);
50660 targets[0].onNodeDrop(el.dom, {
50662 xy: [box.x, box.y + box.height - 1]
50663 }, null, this.getDragData(e));
50669 handleSelection: function(e) {
50670 this.dragZone.cachedTarget = null;
50671 var item = this.findItemFromChild(e.getTarget());
50673 this.clearSelections(true);
50676 if (item && (this.multiSelect || this.singleSelect)){
50677 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50678 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50679 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50680 this.unselect(item);
50682 this.select(item, this.multiSelect && e.ctrlKey);
50683 this.lastSelection = item;
50688 onItemClick : function(item, index, e){
50689 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50695 unselect : function(nodeInfo, suppressEvent){
50696 var node = this.getNode(nodeInfo);
50697 if(node && this.isSelected(node)){
50698 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50699 Roo.fly(node).removeClass(this.selectedClass);
50700 this.selections.remove(node);
50701 if(!suppressEvent){
50702 this.fireEvent("selectionchange", this, this.selections);
50710 * Ext JS Library 1.1.1
50711 * Copyright(c) 2006-2007, Ext JS, LLC.
50713 * Originally Released Under LGPL - original licence link has changed is not relivant.
50716 * <script type="text/javascript">
50720 * @class Roo.LayoutManager
50721 * @extends Roo.util.Observable
50722 * Base class for layout managers.
50724 Roo.LayoutManager = function(container, config){
50725 Roo.LayoutManager.superclass.constructor.call(this);
50726 this.el = Roo.get(container);
50727 // ie scrollbar fix
50728 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50729 document.body.scroll = "no";
50730 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50731 this.el.position('relative');
50733 this.id = this.el.id;
50734 this.el.addClass("x-layout-container");
50735 /** false to disable window resize monitoring @type Boolean */
50736 this.monitorWindowResize = true;
50741 * Fires when a layout is performed.
50742 * @param {Roo.LayoutManager} this
50746 * @event regionresized
50747 * Fires when the user resizes a region.
50748 * @param {Roo.LayoutRegion} region The resized region
50749 * @param {Number} newSize The new size (width for east/west, height for north/south)
50751 "regionresized" : true,
50753 * @event regioncollapsed
50754 * Fires when a region is collapsed.
50755 * @param {Roo.LayoutRegion} region The collapsed region
50757 "regioncollapsed" : true,
50759 * @event regionexpanded
50760 * Fires when a region is expanded.
50761 * @param {Roo.LayoutRegion} region The expanded region
50763 "regionexpanded" : true
50765 this.updating = false;
50766 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50769 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50771 * Returns true if this layout is currently being updated
50772 * @return {Boolean}
50774 isUpdating : function(){
50775 return this.updating;
50779 * Suspend the LayoutManager from doing auto-layouts while
50780 * making multiple add or remove calls
50782 beginUpdate : function(){
50783 this.updating = true;
50787 * Restore auto-layouts and optionally disable the manager from performing a layout
50788 * @param {Boolean} noLayout true to disable a layout update
50790 endUpdate : function(noLayout){
50791 this.updating = false;
50797 layout: function(){
50801 onRegionResized : function(region, newSize){
50802 this.fireEvent("regionresized", region, newSize);
50806 onRegionCollapsed : function(region){
50807 this.fireEvent("regioncollapsed", region);
50810 onRegionExpanded : function(region){
50811 this.fireEvent("regionexpanded", region);
50815 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50816 * performs box-model adjustments.
50817 * @return {Object} The size as an object {width: (the width), height: (the height)}
50819 getViewSize : function(){
50821 if(this.el.dom != document.body){
50822 size = this.el.getSize();
50824 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50826 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50827 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50832 * Returns the Element this layout is bound to.
50833 * @return {Roo.Element}
50835 getEl : function(){
50840 * Returns the specified region.
50841 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50842 * @return {Roo.LayoutRegion}
50844 getRegion : function(target){
50845 return this.regions[target.toLowerCase()];
50848 onWindowResize : function(){
50849 if(this.monitorWindowResize){
50855 * Ext JS Library 1.1.1
50856 * Copyright(c) 2006-2007, Ext JS, LLC.
50858 * Originally Released Under LGPL - original licence link has changed is not relivant.
50861 * <script type="text/javascript">
50864 * @class Roo.BorderLayout
50865 * @extends Roo.LayoutManager
50866 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
50867 * please see: <br><br>
50868 * <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>
50869 * <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>
50872 var layout = new Roo.BorderLayout(document.body, {
50906 preferredTabWidth: 150
50911 var CP = Roo.ContentPanel;
50913 layout.beginUpdate();
50914 layout.add("north", new CP("north", "North"));
50915 layout.add("south", new CP("south", {title: "South", closable: true}));
50916 layout.add("west", new CP("west", {title: "West"}));
50917 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
50918 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
50919 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
50920 layout.getRegion("center").showPanel("center1");
50921 layout.endUpdate();
50924 <b>The container the layout is rendered into can be either the body element or any other element.
50925 If it is not the body element, the container needs to either be an absolute positioned element,
50926 or you will need to add "position:relative" to the css of the container. You will also need to specify
50927 the container size if it is not the body element.</b>
50930 * Create a new BorderLayout
50931 * @param {String/HTMLElement/Element} container The container this layout is bound to
50932 * @param {Object} config Configuration options
50934 Roo.BorderLayout = function(container, config){
50935 config = config || {};
50936 Roo.BorderLayout.superclass.constructor.call(this, container, config);
50937 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
50938 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
50939 var target = this.factory.validRegions[i];
50940 if(config[target]){
50941 this.addRegion(target, config[target]);
50946 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
50948 * Creates and adds a new region if it doesn't already exist.
50949 * @param {String} target The target region key (north, south, east, west or center).
50950 * @param {Object} config The regions config object
50951 * @return {BorderLayoutRegion} The new region
50953 addRegion : function(target, config){
50954 if(!this.regions[target]){
50955 var r = this.factory.create(target, this, config);
50956 this.bindRegion(target, r);
50958 return this.regions[target];
50962 bindRegion : function(name, r){
50963 this.regions[name] = r;
50964 r.on("visibilitychange", this.layout, this);
50965 r.on("paneladded", this.layout, this);
50966 r.on("panelremoved", this.layout, this);
50967 r.on("invalidated", this.layout, this);
50968 r.on("resized", this.onRegionResized, this);
50969 r.on("collapsed", this.onRegionCollapsed, this);
50970 r.on("expanded", this.onRegionExpanded, this);
50974 * Performs a layout update.
50976 layout : function(){
50977 if(this.updating) {
50980 var size = this.getViewSize();
50981 var w = size.width;
50982 var h = size.height;
50987 //var x = 0, y = 0;
50989 var rs = this.regions;
50990 var north = rs["north"];
50991 var south = rs["south"];
50992 var west = rs["west"];
50993 var east = rs["east"];
50994 var center = rs["center"];
50995 //if(this.hideOnLayout){ // not supported anymore
50996 //c.el.setStyle("display", "none");
50998 if(north && north.isVisible()){
50999 var b = north.getBox();
51000 var m = north.getMargins();
51001 b.width = w - (m.left+m.right);
51004 centerY = b.height + b.y + m.bottom;
51005 centerH -= centerY;
51006 north.updateBox(this.safeBox(b));
51008 if(south && south.isVisible()){
51009 var b = south.getBox();
51010 var m = south.getMargins();
51011 b.width = w - (m.left+m.right);
51013 var totalHeight = (b.height + m.top + m.bottom);
51014 b.y = h - totalHeight + m.top;
51015 centerH -= totalHeight;
51016 south.updateBox(this.safeBox(b));
51018 if(west && west.isVisible()){
51019 var b = west.getBox();
51020 var m = west.getMargins();
51021 b.height = centerH - (m.top+m.bottom);
51023 b.y = centerY + m.top;
51024 var totalWidth = (b.width + m.left + m.right);
51025 centerX += totalWidth;
51026 centerW -= totalWidth;
51027 west.updateBox(this.safeBox(b));
51029 if(east && east.isVisible()){
51030 var b = east.getBox();
51031 var m = east.getMargins();
51032 b.height = centerH - (m.top+m.bottom);
51033 var totalWidth = (b.width + m.left + m.right);
51034 b.x = w - totalWidth + m.left;
51035 b.y = centerY + m.top;
51036 centerW -= totalWidth;
51037 east.updateBox(this.safeBox(b));
51040 var m = center.getMargins();
51042 x: centerX + m.left,
51043 y: centerY + m.top,
51044 width: centerW - (m.left+m.right),
51045 height: centerH - (m.top+m.bottom)
51047 //if(this.hideOnLayout){
51048 //center.el.setStyle("display", "block");
51050 center.updateBox(this.safeBox(centerBox));
51053 this.fireEvent("layout", this);
51057 safeBox : function(box){
51058 box.width = Math.max(0, box.width);
51059 box.height = Math.max(0, box.height);
51064 * Adds a ContentPanel (or subclass) to this layout.
51065 * @param {String} target The target region key (north, south, east, west or center).
51066 * @param {Roo.ContentPanel} panel The panel to add
51067 * @return {Roo.ContentPanel} The added panel
51069 add : function(target, panel){
51071 target = target.toLowerCase();
51072 return this.regions[target].add(panel);
51076 * Remove a ContentPanel (or subclass) to this layout.
51077 * @param {String} target The target region key (north, south, east, west or center).
51078 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51079 * @return {Roo.ContentPanel} The removed panel
51081 remove : function(target, panel){
51082 target = target.toLowerCase();
51083 return this.regions[target].remove(panel);
51087 * Searches all regions for a panel with the specified id
51088 * @param {String} panelId
51089 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51091 findPanel : function(panelId){
51092 var rs = this.regions;
51093 for(var target in rs){
51094 if(typeof rs[target] != "function"){
51095 var p = rs[target].getPanel(panelId);
51105 * Searches all regions for a panel with the specified id and activates (shows) it.
51106 * @param {String/ContentPanel} panelId The panels id or the panel itself
51107 * @return {Roo.ContentPanel} The shown panel or null
51109 showPanel : function(panelId) {
51110 var rs = this.regions;
51111 for(var target in rs){
51112 var r = rs[target];
51113 if(typeof r != "function"){
51114 if(r.hasPanel(panelId)){
51115 return r.showPanel(panelId);
51123 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51124 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51126 restoreState : function(provider){
51128 provider = Roo.state.Manager;
51130 var sm = new Roo.LayoutStateManager();
51131 sm.init(this, provider);
51135 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51136 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51137 * a valid ContentPanel config object. Example:
51139 // Create the main layout
51140 var layout = new Roo.BorderLayout('main-ct', {
51151 // Create and add multiple ContentPanels at once via configs
51154 id: 'source-files',
51156 title:'Ext Source Files',
51169 * @param {Object} regions An object containing ContentPanel configs by region name
51171 batchAdd : function(regions){
51172 this.beginUpdate();
51173 for(var rname in regions){
51174 var lr = this.regions[rname];
51176 this.addTypedPanels(lr, regions[rname]);
51183 addTypedPanels : function(lr, ps){
51184 if(typeof ps == 'string'){
51185 lr.add(new Roo.ContentPanel(ps));
51187 else if(ps instanceof Array){
51188 for(var i =0, len = ps.length; i < len; i++){
51189 this.addTypedPanels(lr, ps[i]);
51192 else if(!ps.events){ // raw config?
51194 delete ps.el; // prevent conflict
51195 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51197 else { // panel object assumed!
51202 * Adds a xtype elements to the layout.
51206 xtype : 'ContentPanel',
51213 xtype : 'NestedLayoutPanel',
51219 items : [ ... list of content panels or nested layout panels.. ]
51223 * @param {Object} cfg Xtype definition of item to add.
51225 addxtype : function(cfg)
51227 // basically accepts a pannel...
51228 // can accept a layout region..!?!?
51229 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51231 if (!cfg.xtype.match(/Panel$/)) {
51236 if (typeof(cfg.region) == 'undefined') {
51237 Roo.log("Failed to add Panel, region was not set");
51241 var region = cfg.region;
51247 xitems = cfg.items;
51254 case 'ContentPanel': // ContentPanel (el, cfg)
51255 case 'ScrollPanel': // ContentPanel (el, cfg)
51257 if(cfg.autoCreate) {
51258 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51260 var el = this.el.createChild();
51261 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51264 this.add(region, ret);
51268 case 'TreePanel': // our new panel!
51269 cfg.el = this.el.createChild();
51270 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51271 this.add(region, ret);
51274 case 'NestedLayoutPanel':
51275 // create a new Layout (which is a Border Layout...
51276 var el = this.el.createChild();
51277 var clayout = cfg.layout;
51279 clayout.items = clayout.items || [];
51280 // replace this exitems with the clayout ones..
51281 xitems = clayout.items;
51284 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51285 cfg.background = false;
51287 var layout = new Roo.BorderLayout(el, clayout);
51289 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51290 //console.log('adding nested layout panel ' + cfg.toSource());
51291 this.add(region, ret);
51292 nb = {}; /// find first...
51297 // needs grid and region
51299 //var el = this.getRegion(region).el.createChild();
51300 var el = this.el.createChild();
51301 // create the grid first...
51303 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51305 if (region == 'center' && this.active ) {
51306 cfg.background = false;
51308 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51310 this.add(region, ret);
51311 if (cfg.background) {
51312 ret.on('activate', function(gp) {
51313 if (!gp.grid.rendered) {
51328 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51330 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51331 this.add(region, ret);
51334 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51338 // GridPanel (grid, cfg)
51341 this.beginUpdate();
51345 Roo.each(xitems, function(i) {
51346 region = nb && i.region ? i.region : false;
51348 var add = ret.addxtype(i);
51351 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51352 if (!i.background) {
51353 abn[region] = nb[region] ;
51360 // make the last non-background panel active..
51361 //if (nb) { Roo.log(abn); }
51364 for(var r in abn) {
51365 region = this.getRegion(r);
51367 // tried using nb[r], but it does not work..
51369 region.showPanel(abn[r]);
51380 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51381 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51382 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51383 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51386 var CP = Roo.ContentPanel;
51388 var layout = Roo.BorderLayout.create({
51392 panels: [new CP("north", "North")]
51401 panels: [new CP("west", {title: "West"})]
51410 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51419 panels: [new CP("south", {title: "South", closable: true})]
51426 preferredTabWidth: 150,
51428 new CP("center1", {title: "Close Me", closable: true}),
51429 new CP("center2", {title: "Center Panel", closable: false})
51434 layout.getRegion("center").showPanel("center1");
51439 Roo.BorderLayout.create = function(config, targetEl){
51440 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51441 layout.beginUpdate();
51442 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51443 for(var j = 0, jlen = regions.length; j < jlen; j++){
51444 var lr = regions[j];
51445 if(layout.regions[lr] && config[lr].panels){
51446 var r = layout.regions[lr];
51447 var ps = config[lr].panels;
51448 layout.addTypedPanels(r, ps);
51451 layout.endUpdate();
51456 Roo.BorderLayout.RegionFactory = {
51458 validRegions : ["north","south","east","west","center"],
51461 create : function(target, mgr, config){
51462 target = target.toLowerCase();
51463 if(config.lightweight || config.basic){
51464 return new Roo.BasicLayoutRegion(mgr, config, target);
51468 return new Roo.NorthLayoutRegion(mgr, config);
51470 return new Roo.SouthLayoutRegion(mgr, config);
51472 return new Roo.EastLayoutRegion(mgr, config);
51474 return new Roo.WestLayoutRegion(mgr, config);
51476 return new Roo.CenterLayoutRegion(mgr, config);
51478 throw 'Layout region "'+target+'" not supported.';
51482 * Ext JS Library 1.1.1
51483 * Copyright(c) 2006-2007, Ext JS, LLC.
51485 * Originally Released Under LGPL - original licence link has changed is not relivant.
51488 * <script type="text/javascript">
51492 * @class Roo.BasicLayoutRegion
51493 * @extends Roo.util.Observable
51494 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51495 * and does not have a titlebar, tabs or any other features. All it does is size and position
51496 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51498 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51500 this.position = pos;
51503 * @scope Roo.BasicLayoutRegion
51507 * @event beforeremove
51508 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51509 * @param {Roo.LayoutRegion} this
51510 * @param {Roo.ContentPanel} panel The panel
51511 * @param {Object} e The cancel event object
51513 "beforeremove" : true,
51515 * @event invalidated
51516 * Fires when the layout for this region is changed.
51517 * @param {Roo.LayoutRegion} this
51519 "invalidated" : true,
51521 * @event visibilitychange
51522 * Fires when this region is shown or hidden
51523 * @param {Roo.LayoutRegion} this
51524 * @param {Boolean} visibility true or false
51526 "visibilitychange" : true,
51528 * @event paneladded
51529 * Fires when a panel is added.
51530 * @param {Roo.LayoutRegion} this
51531 * @param {Roo.ContentPanel} panel The panel
51533 "paneladded" : true,
51535 * @event panelremoved
51536 * Fires when a panel is removed.
51537 * @param {Roo.LayoutRegion} this
51538 * @param {Roo.ContentPanel} panel The panel
51540 "panelremoved" : true,
51542 * @event beforecollapse
51543 * Fires when this region before collapse.
51544 * @param {Roo.LayoutRegion} this
51546 "beforecollapse" : true,
51549 * Fires when this region is collapsed.
51550 * @param {Roo.LayoutRegion} this
51552 "collapsed" : true,
51555 * Fires when this region is expanded.
51556 * @param {Roo.LayoutRegion} this
51561 * Fires when this region is slid into view.
51562 * @param {Roo.LayoutRegion} this
51564 "slideshow" : true,
51567 * Fires when this region slides out of view.
51568 * @param {Roo.LayoutRegion} this
51570 "slidehide" : true,
51572 * @event panelactivated
51573 * Fires when a panel is activated.
51574 * @param {Roo.LayoutRegion} this
51575 * @param {Roo.ContentPanel} panel The activated panel
51577 "panelactivated" : true,
51580 * Fires when the user resizes this region.
51581 * @param {Roo.LayoutRegion} this
51582 * @param {Number} newSize The new size (width for east/west, height for north/south)
51586 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51587 this.panels = new Roo.util.MixedCollection();
51588 this.panels.getKey = this.getPanelId.createDelegate(this);
51590 this.activePanel = null;
51591 // ensure listeners are added...
51593 if (config.listeners || config.events) {
51594 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51595 listeners : config.listeners || {},
51596 events : config.events || {}
51600 if(skipConfig !== true){
51601 this.applyConfig(config);
51605 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51606 getPanelId : function(p){
51610 applyConfig : function(config){
51611 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51612 this.config = config;
51617 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51618 * the width, for horizontal (north, south) the height.
51619 * @param {Number} newSize The new width or height
51621 resizeTo : function(newSize){
51622 var el = this.el ? this.el :
51623 (this.activePanel ? this.activePanel.getEl() : null);
51625 switch(this.position){
51628 el.setWidth(newSize);
51629 this.fireEvent("resized", this, newSize);
51633 el.setHeight(newSize);
51634 this.fireEvent("resized", this, newSize);
51640 getBox : function(){
51641 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51644 getMargins : function(){
51645 return this.margins;
51648 updateBox : function(box){
51650 var el = this.activePanel.getEl();
51651 el.dom.style.left = box.x + "px";
51652 el.dom.style.top = box.y + "px";
51653 this.activePanel.setSize(box.width, box.height);
51657 * Returns the container element for this region.
51658 * @return {Roo.Element}
51660 getEl : function(){
51661 return this.activePanel;
51665 * Returns true if this region is currently visible.
51666 * @return {Boolean}
51668 isVisible : function(){
51669 return this.activePanel ? true : false;
51672 setActivePanel : function(panel){
51673 panel = this.getPanel(panel);
51674 if(this.activePanel && this.activePanel != panel){
51675 this.activePanel.setActiveState(false);
51676 this.activePanel.getEl().setLeftTop(-10000,-10000);
51678 this.activePanel = panel;
51679 panel.setActiveState(true);
51681 panel.setSize(this.box.width, this.box.height);
51683 this.fireEvent("panelactivated", this, panel);
51684 this.fireEvent("invalidated");
51688 * Show the specified panel.
51689 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51690 * @return {Roo.ContentPanel} The shown panel or null
51692 showPanel : function(panel){
51693 if(panel = this.getPanel(panel)){
51694 this.setActivePanel(panel);
51700 * Get the active panel for this region.
51701 * @return {Roo.ContentPanel} The active panel or null
51703 getActivePanel : function(){
51704 return this.activePanel;
51708 * Add the passed ContentPanel(s)
51709 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51710 * @return {Roo.ContentPanel} The panel added (if only one was added)
51712 add : function(panel){
51713 if(arguments.length > 1){
51714 for(var i = 0, len = arguments.length; i < len; i++) {
51715 this.add(arguments[i]);
51719 if(this.hasPanel(panel)){
51720 this.showPanel(panel);
51723 var el = panel.getEl();
51724 if(el.dom.parentNode != this.mgr.el.dom){
51725 this.mgr.el.dom.appendChild(el.dom);
51727 if(panel.setRegion){
51728 panel.setRegion(this);
51730 this.panels.add(panel);
51731 el.setStyle("position", "absolute");
51732 if(!panel.background){
51733 this.setActivePanel(panel);
51734 if(this.config.initialSize && this.panels.getCount()==1){
51735 this.resizeTo(this.config.initialSize);
51738 this.fireEvent("paneladded", this, panel);
51743 * Returns true if the panel is in this region.
51744 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51745 * @return {Boolean}
51747 hasPanel : function(panel){
51748 if(typeof panel == "object"){ // must be panel obj
51749 panel = panel.getId();
51751 return this.getPanel(panel) ? true : false;
51755 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51756 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51757 * @param {Boolean} preservePanel Overrides the config preservePanel option
51758 * @return {Roo.ContentPanel} The panel that was removed
51760 remove : function(panel, preservePanel){
51761 panel = this.getPanel(panel);
51766 this.fireEvent("beforeremove", this, panel, e);
51767 if(e.cancel === true){
51770 var panelId = panel.getId();
51771 this.panels.removeKey(panelId);
51776 * Returns the panel specified or null if it's not in this region.
51777 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51778 * @return {Roo.ContentPanel}
51780 getPanel : function(id){
51781 if(typeof id == "object"){ // must be panel obj
51784 return this.panels.get(id);
51788 * Returns this regions position (north/south/east/west/center).
51791 getPosition: function(){
51792 return this.position;
51796 * Ext JS Library 1.1.1
51797 * Copyright(c) 2006-2007, Ext JS, LLC.
51799 * Originally Released Under LGPL - original licence link has changed is not relivant.
51802 * <script type="text/javascript">
51806 * @class Roo.LayoutRegion
51807 * @extends Roo.BasicLayoutRegion
51808 * This class represents a region in a layout manager.
51809 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51810 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51811 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51812 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51813 * @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})
51814 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51815 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51816 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51817 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51818 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51819 * @cfg {String} title The title for the region (overrides panel titles)
51820 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51821 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51822 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51823 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51824 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51825 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51826 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51827 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51828 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51829 * @cfg {Boolean} showPin True to show a pin button
51830 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51831 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51832 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51833 * @cfg {Number} width For East/West panels
51834 * @cfg {Number} height For North/South panels
51835 * @cfg {Boolean} split To show the splitter
51836 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51838 Roo.LayoutRegion = function(mgr, config, pos){
51839 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51840 var dh = Roo.DomHelper;
51841 /** This region's container element
51842 * @type Roo.Element */
51843 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51844 /** This region's title element
51845 * @type Roo.Element */
51847 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51848 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51849 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51851 this.titleEl.enableDisplayMode();
51852 /** This region's title text element
51853 * @type HTMLElement */
51854 this.titleTextEl = this.titleEl.dom.firstChild;
51855 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
51856 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
51857 this.closeBtn.enableDisplayMode();
51858 this.closeBtn.on("click", this.closeClicked, this);
51859 this.closeBtn.hide();
51861 this.createBody(config);
51862 this.visible = true;
51863 this.collapsed = false;
51865 if(config.hideWhenEmpty){
51867 this.on("paneladded", this.validateVisibility, this);
51868 this.on("panelremoved", this.validateVisibility, this);
51870 this.applyConfig(config);
51873 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
51875 createBody : function(){
51876 /** This region's body element
51877 * @type Roo.Element */
51878 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
51881 applyConfig : function(c){
51882 if(c.collapsible && this.position != "center" && !this.collapsedEl){
51883 var dh = Roo.DomHelper;
51884 if(c.titlebar !== false){
51885 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
51886 this.collapseBtn.on("click", this.collapse, this);
51887 this.collapseBtn.enableDisplayMode();
51889 if(c.showPin === true || this.showPin){
51890 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
51891 this.stickBtn.enableDisplayMode();
51892 this.stickBtn.on("click", this.expand, this);
51893 this.stickBtn.hide();
51896 /** This region's collapsed element
51897 * @type Roo.Element */
51898 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
51899 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
51901 if(c.floatable !== false){
51902 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
51903 this.collapsedEl.on("click", this.collapseClick, this);
51906 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
51907 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
51908 id: "message", unselectable: "on", style:{"float":"left"}});
51909 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
51911 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
51912 this.expandBtn.on("click", this.expand, this);
51914 if(this.collapseBtn){
51915 this.collapseBtn.setVisible(c.collapsible == true);
51917 this.cmargins = c.cmargins || this.cmargins ||
51918 (this.position == "west" || this.position == "east" ?
51919 {top: 0, left: 2, right:2, bottom: 0} :
51920 {top: 2, left: 0, right:0, bottom: 2});
51921 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51922 this.bottomTabs = c.tabPosition != "top";
51923 this.autoScroll = c.autoScroll || false;
51924 if(this.autoScroll){
51925 this.bodyEl.setStyle("overflow", "auto");
51927 this.bodyEl.setStyle("overflow", "hidden");
51929 //if(c.titlebar !== false){
51930 if((!c.titlebar && !c.title) || c.titlebar === false){
51931 this.titleEl.hide();
51933 this.titleEl.show();
51935 this.titleTextEl.innerHTML = c.title;
51939 this.duration = c.duration || .30;
51940 this.slideDuration = c.slideDuration || .45;
51943 this.collapse(true);
51950 * Returns true if this region is currently visible.
51951 * @return {Boolean}
51953 isVisible : function(){
51954 return this.visible;
51958 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
51959 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
51961 setCollapsedTitle : function(title){
51962 title = title || " ";
51963 if(this.collapsedTitleTextEl){
51964 this.collapsedTitleTextEl.innerHTML = title;
51968 getBox : function(){
51970 if(!this.collapsed){
51971 b = this.el.getBox(false, true);
51973 b = this.collapsedEl.getBox(false, true);
51978 getMargins : function(){
51979 return this.collapsed ? this.cmargins : this.margins;
51982 highlight : function(){
51983 this.el.addClass("x-layout-panel-dragover");
51986 unhighlight : function(){
51987 this.el.removeClass("x-layout-panel-dragover");
51990 updateBox : function(box){
51992 if(!this.collapsed){
51993 this.el.dom.style.left = box.x + "px";
51994 this.el.dom.style.top = box.y + "px";
51995 this.updateBody(box.width, box.height);
51997 this.collapsedEl.dom.style.left = box.x + "px";
51998 this.collapsedEl.dom.style.top = box.y + "px";
51999 this.collapsedEl.setSize(box.width, box.height);
52002 this.tabs.autoSizeTabs();
52006 updateBody : function(w, h){
52008 this.el.setWidth(w);
52009 w -= this.el.getBorderWidth("rl");
52010 if(this.config.adjustments){
52011 w += this.config.adjustments[0];
52015 this.el.setHeight(h);
52016 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52017 h -= this.el.getBorderWidth("tb");
52018 if(this.config.adjustments){
52019 h += this.config.adjustments[1];
52021 this.bodyEl.setHeight(h);
52023 h = this.tabs.syncHeight(h);
52026 if(this.panelSize){
52027 w = w !== null ? w : this.panelSize.width;
52028 h = h !== null ? h : this.panelSize.height;
52030 if(this.activePanel){
52031 var el = this.activePanel.getEl();
52032 w = w !== null ? w : el.getWidth();
52033 h = h !== null ? h : el.getHeight();
52034 this.panelSize = {width: w, height: h};
52035 this.activePanel.setSize(w, h);
52037 if(Roo.isIE && this.tabs){
52038 this.tabs.el.repaint();
52043 * Returns the container element for this region.
52044 * @return {Roo.Element}
52046 getEl : function(){
52051 * Hides this region.
52054 if(!this.collapsed){
52055 this.el.dom.style.left = "-2000px";
52058 this.collapsedEl.dom.style.left = "-2000px";
52059 this.collapsedEl.hide();
52061 this.visible = false;
52062 this.fireEvent("visibilitychange", this, false);
52066 * Shows this region if it was previously hidden.
52069 if(!this.collapsed){
52072 this.collapsedEl.show();
52074 this.visible = true;
52075 this.fireEvent("visibilitychange", this, true);
52078 closeClicked : function(){
52079 if(this.activePanel){
52080 this.remove(this.activePanel);
52084 collapseClick : function(e){
52086 e.stopPropagation();
52089 e.stopPropagation();
52095 * Collapses this region.
52096 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52098 collapse : function(skipAnim, skipCheck = false){
52099 if(this.collapsed) {
52103 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52105 this.collapsed = true;
52107 this.split.el.hide();
52109 if(this.config.animate && skipAnim !== true){
52110 this.fireEvent("invalidated", this);
52111 this.animateCollapse();
52113 this.el.setLocation(-20000,-20000);
52115 this.collapsedEl.show();
52116 this.fireEvent("collapsed", this);
52117 this.fireEvent("invalidated", this);
52123 animateCollapse : function(){
52128 * Expands this region if it was previously collapsed.
52129 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52130 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52132 expand : function(e, skipAnim){
52134 e.stopPropagation();
52136 if(!this.collapsed || this.el.hasActiveFx()) {
52140 this.afterSlideIn();
52143 this.collapsed = false;
52144 if(this.config.animate && skipAnim !== true){
52145 this.animateExpand();
52149 this.split.el.show();
52151 this.collapsedEl.setLocation(-2000,-2000);
52152 this.collapsedEl.hide();
52153 this.fireEvent("invalidated", this);
52154 this.fireEvent("expanded", this);
52158 animateExpand : function(){
52162 initTabs : function()
52164 this.bodyEl.setStyle("overflow", "hidden");
52165 var ts = new Roo.TabPanel(
52168 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52169 disableTooltips: this.config.disableTabTips,
52170 toolbar : this.config.toolbar
52173 if(this.config.hideTabs){
52174 ts.stripWrap.setDisplayed(false);
52177 ts.resizeTabs = this.config.resizeTabs === true;
52178 ts.minTabWidth = this.config.minTabWidth || 40;
52179 ts.maxTabWidth = this.config.maxTabWidth || 250;
52180 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52181 ts.monitorResize = false;
52182 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52183 ts.bodyEl.addClass('x-layout-tabs-body');
52184 this.panels.each(this.initPanelAsTab, this);
52187 initPanelAsTab : function(panel){
52188 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52189 this.config.closeOnTab && panel.isClosable());
52190 if(panel.tabTip !== undefined){
52191 ti.setTooltip(panel.tabTip);
52193 ti.on("activate", function(){
52194 this.setActivePanel(panel);
52196 if(this.config.closeOnTab){
52197 ti.on("beforeclose", function(t, e){
52199 this.remove(panel);
52205 updatePanelTitle : function(panel, title){
52206 if(this.activePanel == panel){
52207 this.updateTitle(title);
52210 var ti = this.tabs.getTab(panel.getEl().id);
52212 if(panel.tabTip !== undefined){
52213 ti.setTooltip(panel.tabTip);
52218 updateTitle : function(title){
52219 if(this.titleTextEl && !this.config.title){
52220 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52224 setActivePanel : function(panel){
52225 panel = this.getPanel(panel);
52226 if(this.activePanel && this.activePanel != panel){
52227 this.activePanel.setActiveState(false);
52229 this.activePanel = panel;
52230 panel.setActiveState(true);
52231 if(this.panelSize){
52232 panel.setSize(this.panelSize.width, this.panelSize.height);
52235 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52237 this.updateTitle(panel.getTitle());
52239 this.fireEvent("invalidated", this);
52241 this.fireEvent("panelactivated", this, panel);
52245 * Shows the specified panel.
52246 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52247 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52249 showPanel : function(panel)
52251 panel = this.getPanel(panel);
52254 var tab = this.tabs.getTab(panel.getEl().id);
52255 if(tab.isHidden()){
52256 this.tabs.unhideTab(tab.id);
52260 this.setActivePanel(panel);
52267 * Get the active panel for this region.
52268 * @return {Roo.ContentPanel} The active panel or null
52270 getActivePanel : function(){
52271 return this.activePanel;
52274 validateVisibility : function(){
52275 if(this.panels.getCount() < 1){
52276 this.updateTitle(" ");
52277 this.closeBtn.hide();
52280 if(!this.isVisible()){
52287 * Adds the passed ContentPanel(s) to this region.
52288 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52289 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52291 add : function(panel){
52292 if(arguments.length > 1){
52293 for(var i = 0, len = arguments.length; i < len; i++) {
52294 this.add(arguments[i]);
52298 if(this.hasPanel(panel)){
52299 this.showPanel(panel);
52302 panel.setRegion(this);
52303 this.panels.add(panel);
52304 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52305 this.bodyEl.dom.appendChild(panel.getEl().dom);
52306 if(panel.background !== true){
52307 this.setActivePanel(panel);
52309 this.fireEvent("paneladded", this, panel);
52315 this.initPanelAsTab(panel);
52317 if(panel.background !== true){
52318 this.tabs.activate(panel.getEl().id);
52320 this.fireEvent("paneladded", this, panel);
52325 * Hides the tab for the specified panel.
52326 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52328 hidePanel : function(panel){
52329 if(this.tabs && (panel = this.getPanel(panel))){
52330 this.tabs.hideTab(panel.getEl().id);
52335 * Unhides the tab for a previously hidden panel.
52336 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52338 unhidePanel : function(panel){
52339 if(this.tabs && (panel = this.getPanel(panel))){
52340 this.tabs.unhideTab(panel.getEl().id);
52344 clearPanels : function(){
52345 while(this.panels.getCount() > 0){
52346 this.remove(this.panels.first());
52351 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52352 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52353 * @param {Boolean} preservePanel Overrides the config preservePanel option
52354 * @return {Roo.ContentPanel} The panel that was removed
52356 remove : function(panel, preservePanel){
52357 panel = this.getPanel(panel);
52362 this.fireEvent("beforeremove", this, panel, e);
52363 if(e.cancel === true){
52366 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52367 var panelId = panel.getId();
52368 this.panels.removeKey(panelId);
52370 document.body.appendChild(panel.getEl().dom);
52373 this.tabs.removeTab(panel.getEl().id);
52374 }else if (!preservePanel){
52375 this.bodyEl.dom.removeChild(panel.getEl().dom);
52377 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52378 var p = this.panels.first();
52379 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52380 tempEl.appendChild(p.getEl().dom);
52381 this.bodyEl.update("");
52382 this.bodyEl.dom.appendChild(p.getEl().dom);
52384 this.updateTitle(p.getTitle());
52386 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52387 this.setActivePanel(p);
52389 panel.setRegion(null);
52390 if(this.activePanel == panel){
52391 this.activePanel = null;
52393 if(this.config.autoDestroy !== false && preservePanel !== true){
52394 try{panel.destroy();}catch(e){}
52396 this.fireEvent("panelremoved", this, panel);
52401 * Returns the TabPanel component used by this region
52402 * @return {Roo.TabPanel}
52404 getTabs : function(){
52408 createTool : function(parentEl, className){
52409 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52410 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52411 btn.addClassOnOver("x-layout-tools-button-over");
52416 * Ext JS Library 1.1.1
52417 * Copyright(c) 2006-2007, Ext JS, LLC.
52419 * Originally Released Under LGPL - original licence link has changed is not relivant.
52422 * <script type="text/javascript">
52428 * @class Roo.SplitLayoutRegion
52429 * @extends Roo.LayoutRegion
52430 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52432 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52433 this.cursor = cursor;
52434 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52437 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52438 splitTip : "Drag to resize.",
52439 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52440 useSplitTips : false,
52442 applyConfig : function(config){
52443 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52446 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52447 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52448 /** The SplitBar for this region
52449 * @type Roo.SplitBar */
52450 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52451 this.split.on("moved", this.onSplitMove, this);
52452 this.split.useShim = config.useShim === true;
52453 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52454 if(this.useSplitTips){
52455 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52457 if(config.collapsible){
52458 this.split.el.on("dblclick", this.collapse, this);
52461 if(typeof config.minSize != "undefined"){
52462 this.split.minSize = config.minSize;
52464 if(typeof config.maxSize != "undefined"){
52465 this.split.maxSize = config.maxSize;
52467 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52468 this.hideSplitter();
52473 getHMaxSize : function(){
52474 var cmax = this.config.maxSize || 10000;
52475 var center = this.mgr.getRegion("center");
52476 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52479 getVMaxSize : function(){
52480 var cmax = this.config.maxSize || 10000;
52481 var center = this.mgr.getRegion("center");
52482 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52485 onSplitMove : function(split, newSize){
52486 this.fireEvent("resized", this, newSize);
52490 * Returns the {@link Roo.SplitBar} for this region.
52491 * @return {Roo.SplitBar}
52493 getSplitBar : function(){
52498 this.hideSplitter();
52499 Roo.SplitLayoutRegion.superclass.hide.call(this);
52502 hideSplitter : function(){
52504 this.split.el.setLocation(-2000,-2000);
52505 this.split.el.hide();
52511 this.split.el.show();
52513 Roo.SplitLayoutRegion.superclass.show.call(this);
52516 beforeSlide: function(){
52517 if(Roo.isGecko){// firefox overflow auto bug workaround
52518 this.bodyEl.clip();
52520 this.tabs.bodyEl.clip();
52522 if(this.activePanel){
52523 this.activePanel.getEl().clip();
52525 if(this.activePanel.beforeSlide){
52526 this.activePanel.beforeSlide();
52532 afterSlide : function(){
52533 if(Roo.isGecko){// firefox overflow auto bug workaround
52534 this.bodyEl.unclip();
52536 this.tabs.bodyEl.unclip();
52538 if(this.activePanel){
52539 this.activePanel.getEl().unclip();
52540 if(this.activePanel.afterSlide){
52541 this.activePanel.afterSlide();
52547 initAutoHide : function(){
52548 if(this.autoHide !== false){
52549 if(!this.autoHideHd){
52550 var st = new Roo.util.DelayedTask(this.slideIn, this);
52551 this.autoHideHd = {
52552 "mouseout": function(e){
52553 if(!e.within(this.el, true)){
52557 "mouseover" : function(e){
52563 this.el.on(this.autoHideHd);
52567 clearAutoHide : function(){
52568 if(this.autoHide !== false){
52569 this.el.un("mouseout", this.autoHideHd.mouseout);
52570 this.el.un("mouseover", this.autoHideHd.mouseover);
52574 clearMonitor : function(){
52575 Roo.get(document).un("click", this.slideInIf, this);
52578 // these names are backwards but not changed for compat
52579 slideOut : function(){
52580 if(this.isSlid || this.el.hasActiveFx()){
52583 this.isSlid = true;
52584 if(this.collapseBtn){
52585 this.collapseBtn.hide();
52587 this.closeBtnState = this.closeBtn.getStyle('display');
52588 this.closeBtn.hide();
52590 this.stickBtn.show();
52593 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52594 this.beforeSlide();
52595 this.el.setStyle("z-index", 10001);
52596 this.el.slideIn(this.getSlideAnchor(), {
52597 callback: function(){
52599 this.initAutoHide();
52600 Roo.get(document).on("click", this.slideInIf, this);
52601 this.fireEvent("slideshow", this);
52608 afterSlideIn : function(){
52609 this.clearAutoHide();
52610 this.isSlid = false;
52611 this.clearMonitor();
52612 this.el.setStyle("z-index", "");
52613 if(this.collapseBtn){
52614 this.collapseBtn.show();
52616 this.closeBtn.setStyle('display', this.closeBtnState);
52618 this.stickBtn.hide();
52620 this.fireEvent("slidehide", this);
52623 slideIn : function(cb){
52624 if(!this.isSlid || this.el.hasActiveFx()){
52628 this.isSlid = false;
52629 this.beforeSlide();
52630 this.el.slideOut(this.getSlideAnchor(), {
52631 callback: function(){
52632 this.el.setLeftTop(-10000, -10000);
52634 this.afterSlideIn();
52642 slideInIf : function(e){
52643 if(!e.within(this.el)){
52648 animateCollapse : function(){
52649 this.beforeSlide();
52650 this.el.setStyle("z-index", 20000);
52651 var anchor = this.getSlideAnchor();
52652 this.el.slideOut(anchor, {
52653 callback : function(){
52654 this.el.setStyle("z-index", "");
52655 this.collapsedEl.slideIn(anchor, {duration:.3});
52657 this.el.setLocation(-10000,-10000);
52659 this.fireEvent("collapsed", this);
52666 animateExpand : function(){
52667 this.beforeSlide();
52668 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52669 this.el.setStyle("z-index", 20000);
52670 this.collapsedEl.hide({
52673 this.el.slideIn(this.getSlideAnchor(), {
52674 callback : function(){
52675 this.el.setStyle("z-index", "");
52678 this.split.el.show();
52680 this.fireEvent("invalidated", this);
52681 this.fireEvent("expanded", this);
52709 getAnchor : function(){
52710 return this.anchors[this.position];
52713 getCollapseAnchor : function(){
52714 return this.canchors[this.position];
52717 getSlideAnchor : function(){
52718 return this.sanchors[this.position];
52721 getAlignAdj : function(){
52722 var cm = this.cmargins;
52723 switch(this.position){
52739 getExpandAdj : function(){
52740 var c = this.collapsedEl, cm = this.cmargins;
52741 switch(this.position){
52743 return [-(cm.right+c.getWidth()+cm.left), 0];
52746 return [cm.right+c.getWidth()+cm.left, 0];
52749 return [0, -(cm.top+cm.bottom+c.getHeight())];
52752 return [0, cm.top+cm.bottom+c.getHeight()];
52758 * Ext JS Library 1.1.1
52759 * Copyright(c) 2006-2007, Ext JS, LLC.
52761 * Originally Released Under LGPL - original licence link has changed is not relivant.
52764 * <script type="text/javascript">
52767 * These classes are private internal classes
52769 Roo.CenterLayoutRegion = function(mgr, config){
52770 Roo.LayoutRegion.call(this, mgr, config, "center");
52771 this.visible = true;
52772 this.minWidth = config.minWidth || 20;
52773 this.minHeight = config.minHeight || 20;
52776 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52778 // center panel can't be hidden
52782 // center panel can't be hidden
52785 getMinWidth: function(){
52786 return this.minWidth;
52789 getMinHeight: function(){
52790 return this.minHeight;
52795 Roo.NorthLayoutRegion = function(mgr, config){
52796 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52798 this.split.placement = Roo.SplitBar.TOP;
52799 this.split.orientation = Roo.SplitBar.VERTICAL;
52800 this.split.el.addClass("x-layout-split-v");
52802 var size = config.initialSize || config.height;
52803 if(typeof size != "undefined"){
52804 this.el.setHeight(size);
52807 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52808 orientation: Roo.SplitBar.VERTICAL,
52809 getBox : function(){
52810 if(this.collapsed){
52811 return this.collapsedEl.getBox();
52813 var box = this.el.getBox();
52815 box.height += this.split.el.getHeight();
52820 updateBox : function(box){
52821 if(this.split && !this.collapsed){
52822 box.height -= this.split.el.getHeight();
52823 this.split.el.setLeft(box.x);
52824 this.split.el.setTop(box.y+box.height);
52825 this.split.el.setWidth(box.width);
52827 if(this.collapsed){
52828 this.updateBody(box.width, null);
52830 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52834 Roo.SouthLayoutRegion = function(mgr, config){
52835 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52837 this.split.placement = Roo.SplitBar.BOTTOM;
52838 this.split.orientation = Roo.SplitBar.VERTICAL;
52839 this.split.el.addClass("x-layout-split-v");
52841 var size = config.initialSize || config.height;
52842 if(typeof size != "undefined"){
52843 this.el.setHeight(size);
52846 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52847 orientation: Roo.SplitBar.VERTICAL,
52848 getBox : function(){
52849 if(this.collapsed){
52850 return this.collapsedEl.getBox();
52852 var box = this.el.getBox();
52854 var sh = this.split.el.getHeight();
52861 updateBox : function(box){
52862 if(this.split && !this.collapsed){
52863 var sh = this.split.el.getHeight();
52866 this.split.el.setLeft(box.x);
52867 this.split.el.setTop(box.y-sh);
52868 this.split.el.setWidth(box.width);
52870 if(this.collapsed){
52871 this.updateBody(box.width, null);
52873 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52877 Roo.EastLayoutRegion = function(mgr, config){
52878 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
52880 this.split.placement = Roo.SplitBar.RIGHT;
52881 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52882 this.split.el.addClass("x-layout-split-h");
52884 var size = config.initialSize || config.width;
52885 if(typeof size != "undefined"){
52886 this.el.setWidth(size);
52889 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
52890 orientation: Roo.SplitBar.HORIZONTAL,
52891 getBox : function(){
52892 if(this.collapsed){
52893 return this.collapsedEl.getBox();
52895 var box = this.el.getBox();
52897 var sw = this.split.el.getWidth();
52904 updateBox : function(box){
52905 if(this.split && !this.collapsed){
52906 var sw = this.split.el.getWidth();
52908 this.split.el.setLeft(box.x);
52909 this.split.el.setTop(box.y);
52910 this.split.el.setHeight(box.height);
52913 if(this.collapsed){
52914 this.updateBody(null, box.height);
52916 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52920 Roo.WestLayoutRegion = function(mgr, config){
52921 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
52923 this.split.placement = Roo.SplitBar.LEFT;
52924 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52925 this.split.el.addClass("x-layout-split-h");
52927 var size = config.initialSize || config.width;
52928 if(typeof size != "undefined"){
52929 this.el.setWidth(size);
52932 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
52933 orientation: Roo.SplitBar.HORIZONTAL,
52934 getBox : function(){
52935 if(this.collapsed){
52936 return this.collapsedEl.getBox();
52938 var box = this.el.getBox();
52940 box.width += this.split.el.getWidth();
52945 updateBox : function(box){
52946 if(this.split && !this.collapsed){
52947 var sw = this.split.el.getWidth();
52949 this.split.el.setLeft(box.x+box.width);
52950 this.split.el.setTop(box.y);
52951 this.split.el.setHeight(box.height);
52953 if(this.collapsed){
52954 this.updateBody(null, box.height);
52956 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52961 * Ext JS Library 1.1.1
52962 * Copyright(c) 2006-2007, Ext JS, LLC.
52964 * Originally Released Under LGPL - original licence link has changed is not relivant.
52967 * <script type="text/javascript">
52972 * Private internal class for reading and applying state
52974 Roo.LayoutStateManager = function(layout){
52975 // default empty state
52984 Roo.LayoutStateManager.prototype = {
52985 init : function(layout, provider){
52986 this.provider = provider;
52987 var state = provider.get(layout.id+"-layout-state");
52989 var wasUpdating = layout.isUpdating();
52991 layout.beginUpdate();
52993 for(var key in state){
52994 if(typeof state[key] != "function"){
52995 var rstate = state[key];
52996 var r = layout.getRegion(key);
52999 r.resizeTo(rstate.size);
53001 if(rstate.collapsed == true){
53004 r.expand(null, true);
53010 layout.endUpdate();
53012 this.state = state;
53014 this.layout = layout;
53015 layout.on("regionresized", this.onRegionResized, this);
53016 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53017 layout.on("regionexpanded", this.onRegionExpanded, this);
53020 storeState : function(){
53021 this.provider.set(this.layout.id+"-layout-state", this.state);
53024 onRegionResized : function(region, newSize){
53025 this.state[region.getPosition()].size = newSize;
53029 onRegionCollapsed : function(region){
53030 this.state[region.getPosition()].collapsed = true;
53034 onRegionExpanded : function(region){
53035 this.state[region.getPosition()].collapsed = false;
53040 * Ext JS Library 1.1.1
53041 * Copyright(c) 2006-2007, Ext JS, LLC.
53043 * Originally Released Under LGPL - original licence link has changed is not relivant.
53046 * <script type="text/javascript">
53049 * @class Roo.ContentPanel
53050 * @extends Roo.util.Observable
53051 * A basic ContentPanel element.
53052 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53053 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53054 * @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
53055 * @cfg {Boolean} closable True if the panel can be closed/removed
53056 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53057 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53058 * @cfg {Toolbar} toolbar A toolbar for this panel
53059 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53060 * @cfg {String} title The title for this panel
53061 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53062 * @cfg {String} url Calls {@link #setUrl} with this value
53063 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53064 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53065 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53066 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53069 * Create a new ContentPanel.
53070 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53071 * @param {String/Object} config A string to set only the title or a config object
53072 * @param {String} content (optional) Set the HTML content for this panel
53073 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53075 Roo.ContentPanel = function(el, config, content){
53079 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53083 if (config && config.parentLayout) {
53084 el = config.parentLayout.el.createChild();
53087 if(el.autoCreate){ // xtype is available if this is called from factory
53091 this.el = Roo.get(el);
53092 if(!this.el && config && config.autoCreate){
53093 if(typeof config.autoCreate == "object"){
53094 if(!config.autoCreate.id){
53095 config.autoCreate.id = config.id||el;
53097 this.el = Roo.DomHelper.append(document.body,
53098 config.autoCreate, true);
53100 this.el = Roo.DomHelper.append(document.body,
53101 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53104 this.closable = false;
53105 this.loaded = false;
53106 this.active = false;
53107 if(typeof config == "string"){
53108 this.title = config;
53110 Roo.apply(this, config);
53113 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53114 this.wrapEl = this.el.wrap();
53115 this.toolbar.container = this.el.insertSibling(false, 'before');
53116 this.toolbar = new Roo.Toolbar(this.toolbar);
53119 // xtype created footer. - not sure if will work as we normally have to render first..
53120 if (this.footer && !this.footer.el && this.footer.xtype) {
53121 if (!this.wrapEl) {
53122 this.wrapEl = this.el.wrap();
53125 this.footer.container = this.wrapEl.createChild();
53127 this.footer = Roo.factory(this.footer, Roo);
53132 this.resizeEl = Roo.get(this.resizeEl, true);
53134 this.resizeEl = this.el;
53136 // handle view.xtype
53144 * Fires when this panel is activated.
53145 * @param {Roo.ContentPanel} this
53149 * @event deactivate
53150 * Fires when this panel is activated.
53151 * @param {Roo.ContentPanel} this
53153 "deactivate" : true,
53157 * Fires when this panel is resized if fitToFrame is true.
53158 * @param {Roo.ContentPanel} this
53159 * @param {Number} width The width after any component adjustments
53160 * @param {Number} height The height after any component adjustments
53166 * Fires when this tab is created
53167 * @param {Roo.ContentPanel} this
53178 if(this.autoScroll){
53179 this.resizeEl.setStyle("overflow", "auto");
53181 // fix randome scrolling
53182 this.el.on('scroll', function() {
53183 Roo.log('fix random scolling');
53184 this.scrollTo('top',0);
53187 content = content || this.content;
53189 this.setContent(content);
53191 if(config && config.url){
53192 this.setUrl(this.url, this.params, this.loadOnce);
53197 Roo.ContentPanel.superclass.constructor.call(this);
53199 if (this.view && typeof(this.view.xtype) != 'undefined') {
53200 this.view.el = this.el.appendChild(document.createElement("div"));
53201 this.view = Roo.factory(this.view);
53202 this.view.render && this.view.render(false, '');
53206 this.fireEvent('render', this);
53209 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53211 setRegion : function(region){
53212 this.region = region;
53214 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53216 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53221 * Returns the toolbar for this Panel if one was configured.
53222 * @return {Roo.Toolbar}
53224 getToolbar : function(){
53225 return this.toolbar;
53228 setActiveState : function(active){
53229 this.active = active;
53231 this.fireEvent("deactivate", this);
53233 this.fireEvent("activate", this);
53237 * Updates this panel's element
53238 * @param {String} content The new content
53239 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53241 setContent : function(content, loadScripts){
53242 this.el.update(content, loadScripts);
53245 ignoreResize : function(w, h){
53246 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53249 this.lastSize = {width: w, height: h};
53254 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53255 * @return {Roo.UpdateManager} The UpdateManager
53257 getUpdateManager : function(){
53258 return this.el.getUpdateManager();
53261 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53262 * @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:
53265 url: "your-url.php",
53266 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53267 callback: yourFunction,
53268 scope: yourObject, //(optional scope)
53271 text: "Loading...",
53276 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53277 * 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.
53278 * @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}
53279 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53280 * @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.
53281 * @return {Roo.ContentPanel} this
53284 var um = this.el.getUpdateManager();
53285 um.update.apply(um, arguments);
53291 * 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.
53292 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53293 * @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)
53294 * @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)
53295 * @return {Roo.UpdateManager} The UpdateManager
53297 setUrl : function(url, params, loadOnce){
53298 if(this.refreshDelegate){
53299 this.removeListener("activate", this.refreshDelegate);
53301 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53302 this.on("activate", this.refreshDelegate);
53303 return this.el.getUpdateManager();
53306 _handleRefresh : function(url, params, loadOnce){
53307 if(!loadOnce || !this.loaded){
53308 var updater = this.el.getUpdateManager();
53309 updater.update(url, params, this._setLoaded.createDelegate(this));
53313 _setLoaded : function(){
53314 this.loaded = true;
53318 * Returns this panel's id
53321 getId : function(){
53326 * Returns this panel's element - used by regiosn to add.
53327 * @return {Roo.Element}
53329 getEl : function(){
53330 return this.wrapEl || this.el;
53333 adjustForComponents : function(width, height)
53335 //Roo.log('adjustForComponents ');
53336 if(this.resizeEl != this.el){
53337 width -= this.el.getFrameWidth('lr');
53338 height -= this.el.getFrameWidth('tb');
53341 var te = this.toolbar.getEl();
53342 height -= te.getHeight();
53343 te.setWidth(width);
53346 var te = this.footer.getEl();
53347 Roo.log("footer:" + te.getHeight());
53349 height -= te.getHeight();
53350 te.setWidth(width);
53354 if(this.adjustments){
53355 width += this.adjustments[0];
53356 height += this.adjustments[1];
53358 return {"width": width, "height": height};
53361 setSize : function(width, height){
53362 if(this.fitToFrame && !this.ignoreResize(width, height)){
53363 if(this.fitContainer && this.resizeEl != this.el){
53364 this.el.setSize(width, height);
53366 var size = this.adjustForComponents(width, height);
53367 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53368 this.fireEvent('resize', this, size.width, size.height);
53373 * Returns this panel's title
53376 getTitle : function(){
53381 * Set this panel's title
53382 * @param {String} title
53384 setTitle : function(title){
53385 this.title = title;
53387 this.region.updatePanelTitle(this, title);
53392 * Returns true is this panel was configured to be closable
53393 * @return {Boolean}
53395 isClosable : function(){
53396 return this.closable;
53399 beforeSlide : function(){
53401 this.resizeEl.clip();
53404 afterSlide : function(){
53406 this.resizeEl.unclip();
53410 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53411 * Will fail silently if the {@link #setUrl} method has not been called.
53412 * This does not activate the panel, just updates its content.
53414 refresh : function(){
53415 if(this.refreshDelegate){
53416 this.loaded = false;
53417 this.refreshDelegate();
53422 * Destroys this panel
53424 destroy : function(){
53425 this.el.removeAllListeners();
53426 var tempEl = document.createElement("span");
53427 tempEl.appendChild(this.el.dom);
53428 tempEl.innerHTML = "";
53434 * form - if the content panel contains a form - this is a reference to it.
53435 * @type {Roo.form.Form}
53439 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53440 * This contains a reference to it.
53446 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53456 * @param {Object} cfg Xtype definition of item to add.
53459 addxtype : function(cfg) {
53461 if (cfg.xtype.match(/^Form$/)) {
53464 //if (this.footer) {
53465 // el = this.footer.container.insertSibling(false, 'before');
53467 el = this.el.createChild();
53470 this.form = new Roo.form.Form(cfg);
53473 if ( this.form.allItems.length) {
53474 this.form.render(el.dom);
53478 // should only have one of theses..
53479 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53480 // views.. should not be just added - used named prop 'view''
53482 cfg.el = this.el.appendChild(document.createElement("div"));
53485 var ret = new Roo.factory(cfg);
53487 ret.render && ret.render(false, ''); // render blank..
53496 * @class Roo.GridPanel
53497 * @extends Roo.ContentPanel
53499 * Create a new GridPanel.
53500 * @param {Roo.grid.Grid} grid The grid for this panel
53501 * @param {String/Object} config A string to set only the panel's title, or a config object
53503 Roo.GridPanel = function(grid, config){
53506 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53507 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53509 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53511 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53514 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53516 // xtype created footer. - not sure if will work as we normally have to render first..
53517 if (this.footer && !this.footer.el && this.footer.xtype) {
53519 this.footer.container = this.grid.getView().getFooterPanel(true);
53520 this.footer.dataSource = this.grid.dataSource;
53521 this.footer = Roo.factory(this.footer, Roo);
53525 grid.monitorWindowResize = false; // turn off autosizing
53526 grid.autoHeight = false;
53527 grid.autoWidth = false;
53529 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53532 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53533 getId : function(){
53534 return this.grid.id;
53538 * Returns the grid for this panel
53539 * @return {Roo.grid.Grid}
53541 getGrid : function(){
53545 setSize : function(width, height){
53546 if(!this.ignoreResize(width, height)){
53547 var grid = this.grid;
53548 var size = this.adjustForComponents(width, height);
53549 grid.getGridEl().setSize(size.width, size.height);
53554 beforeSlide : function(){
53555 this.grid.getView().scroller.clip();
53558 afterSlide : function(){
53559 this.grid.getView().scroller.unclip();
53562 destroy : function(){
53563 this.grid.destroy();
53565 Roo.GridPanel.superclass.destroy.call(this);
53571 * @class Roo.NestedLayoutPanel
53572 * @extends Roo.ContentPanel
53574 * Create a new NestedLayoutPanel.
53577 * @param {Roo.BorderLayout} layout The layout for this panel
53578 * @param {String/Object} config A string to set only the title or a config object
53580 Roo.NestedLayoutPanel = function(layout, config)
53582 // construct with only one argument..
53583 /* FIXME - implement nicer consturctors
53584 if (layout.layout) {
53586 layout = config.layout;
53587 delete config.layout;
53589 if (layout.xtype && !layout.getEl) {
53590 // then layout needs constructing..
53591 layout = Roo.factory(layout, Roo);
53596 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53598 layout.monitorWindowResize = false; // turn off autosizing
53599 this.layout = layout;
53600 this.layout.getEl().addClass("x-layout-nested-layout");
53607 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53609 setSize : function(width, height){
53610 if(!this.ignoreResize(width, height)){
53611 var size = this.adjustForComponents(width, height);
53612 var el = this.layout.getEl();
53613 el.setSize(size.width, size.height);
53614 var touch = el.dom.offsetWidth;
53615 this.layout.layout();
53616 // ie requires a double layout on the first pass
53617 if(Roo.isIE && !this.initialized){
53618 this.initialized = true;
53619 this.layout.layout();
53624 // activate all subpanels if not currently active..
53626 setActiveState : function(active){
53627 this.active = active;
53629 this.fireEvent("deactivate", this);
53633 this.fireEvent("activate", this);
53634 // not sure if this should happen before or after..
53635 if (!this.layout) {
53636 return; // should not happen..
53639 for (var r in this.layout.regions) {
53640 reg = this.layout.getRegion(r);
53641 if (reg.getActivePanel()) {
53642 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53643 reg.setActivePanel(reg.getActivePanel());
53646 if (!reg.panels.length) {
53649 reg.showPanel(reg.getPanel(0));
53658 * Returns the nested BorderLayout for this panel
53659 * @return {Roo.BorderLayout}
53661 getLayout : function(){
53662 return this.layout;
53666 * Adds a xtype elements to the layout of the nested panel
53670 xtype : 'ContentPanel',
53677 xtype : 'NestedLayoutPanel',
53683 items : [ ... list of content panels or nested layout panels.. ]
53687 * @param {Object} cfg Xtype definition of item to add.
53689 addxtype : function(cfg) {
53690 return this.layout.addxtype(cfg);
53695 Roo.ScrollPanel = function(el, config, content){
53696 config = config || {};
53697 config.fitToFrame = true;
53698 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53700 this.el.dom.style.overflow = "hidden";
53701 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53702 this.el.removeClass("x-layout-inactive-content");
53703 this.el.on("mousewheel", this.onWheel, this);
53705 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53706 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53707 up.unselectable(); down.unselectable();
53708 up.on("click", this.scrollUp, this);
53709 down.on("click", this.scrollDown, this);
53710 up.addClassOnOver("x-scroller-btn-over");
53711 down.addClassOnOver("x-scroller-btn-over");
53712 up.addClassOnClick("x-scroller-btn-click");
53713 down.addClassOnClick("x-scroller-btn-click");
53714 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53716 this.resizeEl = this.el;
53717 this.el = wrap; this.up = up; this.down = down;
53720 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53722 wheelIncrement : 5,
53723 scrollUp : function(){
53724 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53727 scrollDown : function(){
53728 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53731 afterScroll : function(){
53732 var el = this.resizeEl;
53733 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53734 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53735 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53738 setSize : function(){
53739 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53740 this.afterScroll();
53743 onWheel : function(e){
53744 var d = e.getWheelDelta();
53745 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53746 this.afterScroll();
53750 setContent : function(content, loadScripts){
53751 this.resizeEl.update(content, loadScripts);
53765 * @class Roo.TreePanel
53766 * @extends Roo.ContentPanel
53768 * Create a new TreePanel. - defaults to fit/scoll contents.
53769 * @param {String/Object} config A string to set only the panel's title, or a config object
53770 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53772 Roo.TreePanel = function(config){
53773 var el = config.el;
53774 var tree = config.tree;
53775 delete config.tree;
53776 delete config.el; // hopefull!
53778 // wrapper for IE7 strict & safari scroll issue
53780 var treeEl = el.createChild();
53781 config.resizeEl = treeEl;
53785 Roo.TreePanel.superclass.constructor.call(this, el, config);
53788 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53789 //console.log(tree);
53790 this.on('activate', function()
53792 if (this.tree.rendered) {
53795 //console.log('render tree');
53796 this.tree.render();
53798 // this should not be needed.. - it's actually the 'el' that resizes?
53799 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53801 //this.on('resize', function (cp, w, h) {
53802 // this.tree.innerCt.setWidth(w);
53803 // this.tree.innerCt.setHeight(h);
53804 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53811 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53828 * Ext JS Library 1.1.1
53829 * Copyright(c) 2006-2007, Ext JS, LLC.
53831 * Originally Released Under LGPL - original licence link has changed is not relivant.
53834 * <script type="text/javascript">
53839 * @class Roo.ReaderLayout
53840 * @extends Roo.BorderLayout
53841 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53842 * center region containing two nested regions (a top one for a list view and one for item preview below),
53843 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53844 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53845 * expedites the setup of the overall layout and regions for this common application style.
53848 var reader = new Roo.ReaderLayout();
53849 var CP = Roo.ContentPanel; // shortcut for adding
53851 reader.beginUpdate();
53852 reader.add("north", new CP("north", "North"));
53853 reader.add("west", new CP("west", {title: "West"}));
53854 reader.add("east", new CP("east", {title: "East"}));
53856 reader.regions.listView.add(new CP("listView", "List"));
53857 reader.regions.preview.add(new CP("preview", "Preview"));
53858 reader.endUpdate();
53861 * Create a new ReaderLayout
53862 * @param {Object} config Configuration options
53863 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
53864 * document.body if omitted)
53866 Roo.ReaderLayout = function(config, renderTo){
53867 var c = config || {size:{}};
53868 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
53869 north: c.north !== false ? Roo.apply({
53873 }, c.north) : false,
53874 west: c.west !== false ? Roo.apply({
53882 margins:{left:5,right:0,bottom:5,top:5},
53883 cmargins:{left:5,right:5,bottom:5,top:5}
53884 }, c.west) : false,
53885 east: c.east !== false ? Roo.apply({
53893 margins:{left:0,right:5,bottom:5,top:5},
53894 cmargins:{left:5,right:5,bottom:5,top:5}
53895 }, c.east) : false,
53896 center: Roo.apply({
53897 tabPosition: 'top',
53901 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
53905 this.el.addClass('x-reader');
53907 this.beginUpdate();
53909 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
53910 south: c.preview !== false ? Roo.apply({
53917 cmargins:{top:5,left:0, right:0, bottom:0}
53918 }, c.preview) : false,
53919 center: Roo.apply({
53925 this.add('center', new Roo.NestedLayoutPanel(inner,
53926 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
53930 this.regions.preview = inner.getRegion('south');
53931 this.regions.listView = inner.getRegion('center');
53934 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
53936 * Ext JS Library 1.1.1
53937 * Copyright(c) 2006-2007, Ext JS, LLC.
53939 * Originally Released Under LGPL - original licence link has changed is not relivant.
53942 * <script type="text/javascript">
53946 * @class Roo.grid.Grid
53947 * @extends Roo.util.Observable
53948 * This class represents the primary interface of a component based grid control.
53949 * <br><br>Usage:<pre><code>
53950 var grid = new Roo.grid.Grid("my-container-id", {
53953 selModel: mySelectionModel,
53954 autoSizeColumns: true,
53955 monitorWindowResize: false,
53956 trackMouseOver: true
53961 * <b>Common Problems:</b><br/>
53962 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
53963 * element will correct this<br/>
53964 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
53965 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
53966 * are unpredictable.<br/>
53967 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
53968 * grid to calculate dimensions/offsets.<br/>
53970 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53971 * The container MUST have some type of size defined for the grid to fill. The container will be
53972 * automatically set to position relative if it isn't already.
53973 * @param {Object} config A config object that sets properties on this grid.
53975 Roo.grid.Grid = function(container, config){
53976 // initialize the container
53977 this.container = Roo.get(container);
53978 this.container.update("");
53979 this.container.setStyle("overflow", "hidden");
53980 this.container.addClass('x-grid-container');
53982 this.id = this.container.id;
53984 Roo.apply(this, config);
53985 // check and correct shorthanded configs
53987 this.dataSource = this.ds;
53991 this.colModel = this.cm;
53995 this.selModel = this.sm;
53999 if (this.selModel) {
54000 this.selModel = Roo.factory(this.selModel, Roo.grid);
54001 this.sm = this.selModel;
54002 this.sm.xmodule = this.xmodule || false;
54004 if (typeof(this.colModel.config) == 'undefined') {
54005 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54006 this.cm = this.colModel;
54007 this.cm.xmodule = this.xmodule || false;
54009 if (this.dataSource) {
54010 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54011 this.ds = this.dataSource;
54012 this.ds.xmodule = this.xmodule || false;
54019 this.container.setWidth(this.width);
54023 this.container.setHeight(this.height);
54030 * The raw click event for the entire grid.
54031 * @param {Roo.EventObject} e
54036 * The raw dblclick event for the entire grid.
54037 * @param {Roo.EventObject} e
54041 * @event contextmenu
54042 * The raw contextmenu event for the entire grid.
54043 * @param {Roo.EventObject} e
54045 "contextmenu" : true,
54048 * The raw mousedown event for the entire grid.
54049 * @param {Roo.EventObject} e
54051 "mousedown" : true,
54054 * The raw mouseup event for the entire grid.
54055 * @param {Roo.EventObject} e
54060 * The raw mouseover event for the entire grid.
54061 * @param {Roo.EventObject} e
54063 "mouseover" : true,
54066 * The raw mouseout event for the entire grid.
54067 * @param {Roo.EventObject} e
54072 * The raw keypress event for the entire grid.
54073 * @param {Roo.EventObject} e
54078 * The raw keydown event for the entire grid.
54079 * @param {Roo.EventObject} e
54087 * Fires when a cell is clicked
54088 * @param {Grid} this
54089 * @param {Number} rowIndex
54090 * @param {Number} columnIndex
54091 * @param {Roo.EventObject} e
54093 "cellclick" : true,
54095 * @event celldblclick
54096 * Fires when a cell is double clicked
54097 * @param {Grid} this
54098 * @param {Number} rowIndex
54099 * @param {Number} columnIndex
54100 * @param {Roo.EventObject} e
54102 "celldblclick" : true,
54105 * Fires when a row is clicked
54106 * @param {Grid} this
54107 * @param {Number} rowIndex
54108 * @param {Roo.EventObject} e
54112 * @event rowdblclick
54113 * Fires when a row is double clicked
54114 * @param {Grid} this
54115 * @param {Number} rowIndex
54116 * @param {Roo.EventObject} e
54118 "rowdblclick" : true,
54120 * @event headerclick
54121 * Fires when a header is clicked
54122 * @param {Grid} this
54123 * @param {Number} columnIndex
54124 * @param {Roo.EventObject} e
54126 "headerclick" : true,
54128 * @event headerdblclick
54129 * Fires when a header cell is double clicked
54130 * @param {Grid} this
54131 * @param {Number} columnIndex
54132 * @param {Roo.EventObject} e
54134 "headerdblclick" : true,
54136 * @event rowcontextmenu
54137 * Fires when a row is right clicked
54138 * @param {Grid} this
54139 * @param {Number} rowIndex
54140 * @param {Roo.EventObject} e
54142 "rowcontextmenu" : true,
54144 * @event cellcontextmenu
54145 * Fires when a cell is right clicked
54146 * @param {Grid} this
54147 * @param {Number} rowIndex
54148 * @param {Number} cellIndex
54149 * @param {Roo.EventObject} e
54151 "cellcontextmenu" : true,
54153 * @event headercontextmenu
54154 * Fires when a header is right clicked
54155 * @param {Grid} this
54156 * @param {Number} columnIndex
54157 * @param {Roo.EventObject} e
54159 "headercontextmenu" : true,
54161 * @event bodyscroll
54162 * Fires when the body element is scrolled
54163 * @param {Number} scrollLeft
54164 * @param {Number} scrollTop
54166 "bodyscroll" : true,
54168 * @event columnresize
54169 * Fires when the user resizes a column
54170 * @param {Number} columnIndex
54171 * @param {Number} newSize
54173 "columnresize" : true,
54175 * @event columnmove
54176 * Fires when the user moves a column
54177 * @param {Number} oldIndex
54178 * @param {Number} newIndex
54180 "columnmove" : true,
54183 * Fires when row(s) start being dragged
54184 * @param {Grid} this
54185 * @param {Roo.GridDD} dd The drag drop object
54186 * @param {event} e The raw browser event
54188 "startdrag" : true,
54191 * Fires when a drag operation is complete
54192 * @param {Grid} this
54193 * @param {Roo.GridDD} dd The drag drop object
54194 * @param {event} e The raw browser event
54199 * Fires when dragged row(s) are dropped on a valid DD target
54200 * @param {Grid} this
54201 * @param {Roo.GridDD} dd The drag drop object
54202 * @param {String} targetId The target drag drop object
54203 * @param {event} e The raw browser event
54208 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54209 * @param {Grid} this
54210 * @param {Roo.GridDD} dd The drag drop object
54211 * @param {String} targetId The target drag drop object
54212 * @param {event} e The raw browser event
54217 * Fires when the dragged row(s) first cross another DD target while being dragged
54218 * @param {Grid} this
54219 * @param {Roo.GridDD} dd The drag drop object
54220 * @param {String} targetId The target drag drop object
54221 * @param {event} e The raw browser event
54223 "dragenter" : true,
54226 * Fires when the dragged row(s) leave another DD target while being dragged
54227 * @param {Grid} this
54228 * @param {Roo.GridDD} dd The drag drop object
54229 * @param {String} targetId The target drag drop object
54230 * @param {event} e The raw browser event
54235 * Fires when a row is rendered, so you can change add a style to it.
54236 * @param {GridView} gridview The grid view
54237 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54243 * Fires when the grid is rendered
54244 * @param {Grid} grid
54249 Roo.grid.Grid.superclass.constructor.call(this);
54251 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54254 * @cfg {String} ddGroup - drag drop group.
54258 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54260 minColumnWidth : 25,
54263 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54264 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54265 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54267 autoSizeColumns : false,
54270 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54272 autoSizeHeaders : true,
54275 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54277 monitorWindowResize : true,
54280 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54281 * rows measured to get a columns size. Default is 0 (all rows).
54283 maxRowsToMeasure : 0,
54286 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54288 trackMouseOver : true,
54291 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54295 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54297 enableDragDrop : false,
54300 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54302 enableColumnMove : true,
54305 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54307 enableColumnHide : true,
54310 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54312 enableRowHeightSync : false,
54315 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54320 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54322 autoHeight : false,
54325 * @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.
54327 autoExpandColumn : false,
54330 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54333 autoExpandMin : 50,
54336 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54338 autoExpandMax : 1000,
54341 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54346 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54350 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54360 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54361 * of a fixed width. Default is false.
54364 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54367 * Called once after all setup has been completed and the grid is ready to be rendered.
54368 * @return {Roo.grid.Grid} this
54370 render : function()
54372 var c = this.container;
54373 // try to detect autoHeight/width mode
54374 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54375 this.autoHeight = true;
54377 var view = this.getView();
54380 c.on("click", this.onClick, this);
54381 c.on("dblclick", this.onDblClick, this);
54382 c.on("contextmenu", this.onContextMenu, this);
54383 c.on("keydown", this.onKeyDown, this);
54385 c.on("touchstart", this.onTouchStart, this);
54388 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54390 this.getSelectionModel().init(this);
54395 this.loadMask = new Roo.LoadMask(this.container,
54396 Roo.apply({store:this.dataSource}, this.loadMask));
54400 if (this.toolbar && this.toolbar.xtype) {
54401 this.toolbar.container = this.getView().getHeaderPanel(true);
54402 this.toolbar = new Roo.Toolbar(this.toolbar);
54404 if (this.footer && this.footer.xtype) {
54405 this.footer.dataSource = this.getDataSource();
54406 this.footer.container = this.getView().getFooterPanel(true);
54407 this.footer = Roo.factory(this.footer, Roo);
54409 if (this.dropTarget && this.dropTarget.xtype) {
54410 delete this.dropTarget.xtype;
54411 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54415 this.rendered = true;
54416 this.fireEvent('render', this);
54421 * Reconfigures the grid to use a different Store and Column Model.
54422 * The View will be bound to the new objects and refreshed.
54423 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54424 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54426 reconfigure : function(dataSource, colModel){
54428 this.loadMask.destroy();
54429 this.loadMask = new Roo.LoadMask(this.container,
54430 Roo.apply({store:dataSource}, this.loadMask));
54432 this.view.bind(dataSource, colModel);
54433 this.dataSource = dataSource;
54434 this.colModel = colModel;
54435 this.view.refresh(true);
54439 onKeyDown : function(e){
54440 this.fireEvent("keydown", e);
54444 * Destroy this grid.
54445 * @param {Boolean} removeEl True to remove the element
54447 destroy : function(removeEl, keepListeners){
54449 this.loadMask.destroy();
54451 var c = this.container;
54452 c.removeAllListeners();
54453 this.view.destroy();
54454 this.colModel.purgeListeners();
54455 if(!keepListeners){
54456 this.purgeListeners();
54459 if(removeEl === true){
54465 processEvent : function(name, e){
54466 // does this fire select???
54467 //Roo.log('grid:processEvent ' + name);
54469 if (name != 'touchstart' ) {
54470 this.fireEvent(name, e);
54473 var t = e.getTarget();
54475 var header = v.findHeaderIndex(t);
54476 if(header !== false){
54477 var ename = name == 'touchstart' ? 'click' : name;
54479 this.fireEvent("header" + ename, this, header, e);
54481 var row = v.findRowIndex(t);
54482 var cell = v.findCellIndex(t);
54483 if (name == 'touchstart') {
54484 // first touch is always a click.
54485 // hopefull this happens after selection is updated.?
54488 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54489 var cs = this.selModel.getSelectedCell();
54490 if (row == cs[0] && cell == cs[1]){
54494 if (typeof(this.selModel.getSelections) != 'undefined') {
54495 var cs = this.selModel.getSelections();
54496 var ds = this.dataSource;
54497 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54508 this.fireEvent("row" + name, this, row, e);
54509 if(cell !== false){
54510 this.fireEvent("cell" + name, this, row, cell, e);
54517 onClick : function(e){
54518 this.processEvent("click", e);
54521 onTouchStart : function(e){
54522 this.processEvent("touchstart", e);
54526 onContextMenu : function(e, t){
54527 this.processEvent("contextmenu", e);
54531 onDblClick : function(e){
54532 this.processEvent("dblclick", e);
54536 walkCells : function(row, col, step, fn, scope){
54537 var cm = this.colModel, clen = cm.getColumnCount();
54538 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54550 if(fn.call(scope || this, row, col, cm) === true){
54568 if(fn.call(scope || this, row, col, cm) === true){
54580 getSelections : function(){
54581 return this.selModel.getSelections();
54585 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54586 * but if manual update is required this method will initiate it.
54588 autoSize : function(){
54590 this.view.layout();
54591 if(this.view.adjustForScroll){
54592 this.view.adjustForScroll();
54598 * Returns the grid's underlying element.
54599 * @return {Element} The element
54601 getGridEl : function(){
54602 return this.container;
54605 // private for compatibility, overridden by editor grid
54606 stopEditing : function(){},
54609 * Returns the grid's SelectionModel.
54610 * @return {SelectionModel}
54612 getSelectionModel : function(){
54613 if(!this.selModel){
54614 this.selModel = new Roo.grid.RowSelectionModel();
54616 return this.selModel;
54620 * Returns the grid's DataSource.
54621 * @return {DataSource}
54623 getDataSource : function(){
54624 return this.dataSource;
54628 * Returns the grid's ColumnModel.
54629 * @return {ColumnModel}
54631 getColumnModel : function(){
54632 return this.colModel;
54636 * Returns the grid's GridView object.
54637 * @return {GridView}
54639 getView : function(){
54641 this.view = new Roo.grid.GridView(this.viewConfig);
54646 * Called to get grid's drag proxy text, by default returns this.ddText.
54649 getDragDropText : function(){
54650 var count = this.selModel.getCount();
54651 return String.format(this.ddText, count, count == 1 ? '' : 's');
54655 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54656 * %0 is replaced with the number of selected rows.
54659 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54661 * Ext JS Library 1.1.1
54662 * Copyright(c) 2006-2007, Ext JS, LLC.
54664 * Originally Released Under LGPL - original licence link has changed is not relivant.
54667 * <script type="text/javascript">
54670 Roo.grid.AbstractGridView = function(){
54674 "beforerowremoved" : true,
54675 "beforerowsinserted" : true,
54676 "beforerefresh" : true,
54677 "rowremoved" : true,
54678 "rowsinserted" : true,
54679 "rowupdated" : true,
54682 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54685 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54686 rowClass : "x-grid-row",
54687 cellClass : "x-grid-cell",
54688 tdClass : "x-grid-td",
54689 hdClass : "x-grid-hd",
54690 splitClass : "x-grid-hd-split",
54692 init: function(grid){
54694 var cid = this.grid.getGridEl().id;
54695 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54696 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54697 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54698 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54701 getColumnRenderers : function(){
54702 var renderers = [];
54703 var cm = this.grid.colModel;
54704 var colCount = cm.getColumnCount();
54705 for(var i = 0; i < colCount; i++){
54706 renderers[i] = cm.getRenderer(i);
54711 getColumnIds : function(){
54713 var cm = this.grid.colModel;
54714 var colCount = cm.getColumnCount();
54715 for(var i = 0; i < colCount; i++){
54716 ids[i] = cm.getColumnId(i);
54721 getDataIndexes : function(){
54722 if(!this.indexMap){
54723 this.indexMap = this.buildIndexMap();
54725 return this.indexMap.colToData;
54728 getColumnIndexByDataIndex : function(dataIndex){
54729 if(!this.indexMap){
54730 this.indexMap = this.buildIndexMap();
54732 return this.indexMap.dataToCol[dataIndex];
54736 * Set a css style for a column dynamically.
54737 * @param {Number} colIndex The index of the column
54738 * @param {String} name The css property name
54739 * @param {String} value The css value
54741 setCSSStyle : function(colIndex, name, value){
54742 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54743 Roo.util.CSS.updateRule(selector, name, value);
54746 generateRules : function(cm){
54747 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54748 Roo.util.CSS.removeStyleSheet(rulesId);
54749 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54750 var cid = cm.getColumnId(i);
54751 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54752 this.tdSelector, cid, " {\n}\n",
54753 this.hdSelector, cid, " {\n}\n",
54754 this.splitSelector, cid, " {\n}\n");
54756 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54760 * Ext JS Library 1.1.1
54761 * Copyright(c) 2006-2007, Ext JS, LLC.
54763 * Originally Released Under LGPL - original licence link has changed is not relivant.
54766 * <script type="text/javascript">
54770 // This is a support class used internally by the Grid components
54771 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54773 this.view = grid.getView();
54774 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54775 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54777 this.setHandleElId(Roo.id(hd));
54778 this.setOuterHandleElId(Roo.id(hd2));
54780 this.scroll = false;
54782 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54784 getDragData : function(e){
54785 var t = Roo.lib.Event.getTarget(e);
54786 var h = this.view.findHeaderCell(t);
54788 return {ddel: h.firstChild, header:h};
54793 onInitDrag : function(e){
54794 this.view.headersDisabled = true;
54795 var clone = this.dragData.ddel.cloneNode(true);
54796 clone.id = Roo.id();
54797 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54798 this.proxy.update(clone);
54802 afterValidDrop : function(){
54804 setTimeout(function(){
54805 v.headersDisabled = false;
54809 afterInvalidDrop : function(){
54811 setTimeout(function(){
54812 v.headersDisabled = false;
54818 * Ext JS Library 1.1.1
54819 * Copyright(c) 2006-2007, Ext JS, LLC.
54821 * Originally Released Under LGPL - original licence link has changed is not relivant.
54824 * <script type="text/javascript">
54827 // This is a support class used internally by the Grid components
54828 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54830 this.view = grid.getView();
54831 // split the proxies so they don't interfere with mouse events
54832 this.proxyTop = Roo.DomHelper.append(document.body, {
54833 cls:"col-move-top", html:" "
54835 this.proxyBottom = Roo.DomHelper.append(document.body, {
54836 cls:"col-move-bottom", html:" "
54838 this.proxyTop.hide = this.proxyBottom.hide = function(){
54839 this.setLeftTop(-100,-100);
54840 this.setStyle("visibility", "hidden");
54842 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54843 // temporarily disabled
54844 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54845 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54847 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54848 proxyOffsets : [-4, -9],
54849 fly: Roo.Element.fly,
54851 getTargetFromEvent : function(e){
54852 var t = Roo.lib.Event.getTarget(e);
54853 var cindex = this.view.findCellIndex(t);
54854 if(cindex !== false){
54855 return this.view.getHeaderCell(cindex);
54860 nextVisible : function(h){
54861 var v = this.view, cm = this.grid.colModel;
54864 if(!cm.isHidden(v.getCellIndex(h))){
54872 prevVisible : function(h){
54873 var v = this.view, cm = this.grid.colModel;
54876 if(!cm.isHidden(v.getCellIndex(h))){
54884 positionIndicator : function(h, n, e){
54885 var x = Roo.lib.Event.getPageX(e);
54886 var r = Roo.lib.Dom.getRegion(n.firstChild);
54887 var px, pt, py = r.top + this.proxyOffsets[1];
54888 if((r.right - x) <= (r.right-r.left)/2){
54889 px = r.right+this.view.borderWidth;
54895 var oldIndex = this.view.getCellIndex(h);
54896 var newIndex = this.view.getCellIndex(n);
54898 if(this.grid.colModel.isFixed(newIndex)){
54902 var locked = this.grid.colModel.isLocked(newIndex);
54907 if(oldIndex < newIndex){
54910 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
54913 px += this.proxyOffsets[0];
54914 this.proxyTop.setLeftTop(px, py);
54915 this.proxyTop.show();
54916 if(!this.bottomOffset){
54917 this.bottomOffset = this.view.mainHd.getHeight();
54919 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
54920 this.proxyBottom.show();
54924 onNodeEnter : function(n, dd, e, data){
54925 if(data.header != n){
54926 this.positionIndicator(data.header, n, e);
54930 onNodeOver : function(n, dd, e, data){
54931 var result = false;
54932 if(data.header != n){
54933 result = this.positionIndicator(data.header, n, e);
54936 this.proxyTop.hide();
54937 this.proxyBottom.hide();
54939 return result ? this.dropAllowed : this.dropNotAllowed;
54942 onNodeOut : function(n, dd, e, data){
54943 this.proxyTop.hide();
54944 this.proxyBottom.hide();
54947 onNodeDrop : function(n, dd, e, data){
54948 var h = data.header;
54950 var cm = this.grid.colModel;
54951 var x = Roo.lib.Event.getPageX(e);
54952 var r = Roo.lib.Dom.getRegion(n.firstChild);
54953 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
54954 var oldIndex = this.view.getCellIndex(h);
54955 var newIndex = this.view.getCellIndex(n);
54956 var locked = cm.isLocked(newIndex);
54960 if(oldIndex < newIndex){
54963 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
54966 cm.setLocked(oldIndex, locked, true);
54967 cm.moveColumn(oldIndex, newIndex);
54968 this.grid.fireEvent("columnmove", oldIndex, newIndex);
54976 * Ext JS Library 1.1.1
54977 * Copyright(c) 2006-2007, Ext JS, LLC.
54979 * Originally Released Under LGPL - original licence link has changed is not relivant.
54982 * <script type="text/javascript">
54986 * @class Roo.grid.GridView
54987 * @extends Roo.util.Observable
54990 * @param {Object} config
54992 Roo.grid.GridView = function(config){
54993 Roo.grid.GridView.superclass.constructor.call(this);
54996 Roo.apply(this, config);
54999 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
55001 unselectable : 'unselectable="on"',
55002 unselectableCls : 'x-unselectable',
55005 rowClass : "x-grid-row",
55007 cellClass : "x-grid-col",
55009 tdClass : "x-grid-td",
55011 hdClass : "x-grid-hd",
55013 splitClass : "x-grid-split",
55015 sortClasses : ["sort-asc", "sort-desc"],
55017 enableMoveAnim : false,
55021 dh : Roo.DomHelper,
55023 fly : Roo.Element.fly,
55025 css : Roo.util.CSS,
55031 scrollIncrement : 22,
55033 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55035 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55037 bind : function(ds, cm){
55039 this.ds.un("load", this.onLoad, this);
55040 this.ds.un("datachanged", this.onDataChange, this);
55041 this.ds.un("add", this.onAdd, this);
55042 this.ds.un("remove", this.onRemove, this);
55043 this.ds.un("update", this.onUpdate, this);
55044 this.ds.un("clear", this.onClear, this);
55047 ds.on("load", this.onLoad, this);
55048 ds.on("datachanged", this.onDataChange, this);
55049 ds.on("add", this.onAdd, this);
55050 ds.on("remove", this.onRemove, this);
55051 ds.on("update", this.onUpdate, this);
55052 ds.on("clear", this.onClear, this);
55057 this.cm.un("widthchange", this.onColWidthChange, this);
55058 this.cm.un("headerchange", this.onHeaderChange, this);
55059 this.cm.un("hiddenchange", this.onHiddenChange, this);
55060 this.cm.un("columnmoved", this.onColumnMove, this);
55061 this.cm.un("columnlockchange", this.onColumnLock, this);
55064 this.generateRules(cm);
55065 cm.on("widthchange", this.onColWidthChange, this);
55066 cm.on("headerchange", this.onHeaderChange, this);
55067 cm.on("hiddenchange", this.onHiddenChange, this);
55068 cm.on("columnmoved", this.onColumnMove, this);
55069 cm.on("columnlockchange", this.onColumnLock, this);
55074 init: function(grid){
55075 Roo.grid.GridView.superclass.init.call(this, grid);
55077 this.bind(grid.dataSource, grid.colModel);
55079 grid.on("headerclick", this.handleHeaderClick, this);
55081 if(grid.trackMouseOver){
55082 grid.on("mouseover", this.onRowOver, this);
55083 grid.on("mouseout", this.onRowOut, this);
55085 grid.cancelTextSelection = function(){};
55086 this.gridId = grid.id;
55088 var tpls = this.templates || {};
55091 tpls.master = new Roo.Template(
55092 '<div class="x-grid" hidefocus="true">',
55093 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55094 '<div class="x-grid-topbar"></div>',
55095 '<div class="x-grid-scroller"><div></div></div>',
55096 '<div class="x-grid-locked">',
55097 '<div class="x-grid-header">{lockedHeader}</div>',
55098 '<div class="x-grid-body">{lockedBody}</div>',
55100 '<div class="x-grid-viewport">',
55101 '<div class="x-grid-header">{header}</div>',
55102 '<div class="x-grid-body">{body}</div>',
55104 '<div class="x-grid-bottombar"></div>',
55106 '<div class="x-grid-resize-proxy"> </div>',
55109 tpls.master.disableformats = true;
55113 tpls.header = new Roo.Template(
55114 '<table border="0" cellspacing="0" cellpadding="0">',
55115 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55118 tpls.header.disableformats = true;
55120 tpls.header.compile();
55123 tpls.hcell = new Roo.Template(
55124 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55125 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55128 tpls.hcell.disableFormats = true;
55130 tpls.hcell.compile();
55133 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55134 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55135 tpls.hsplit.disableFormats = true;
55137 tpls.hsplit.compile();
55140 tpls.body = new Roo.Template(
55141 '<table border="0" cellspacing="0" cellpadding="0">',
55142 "<tbody>{rows}</tbody>",
55145 tpls.body.disableFormats = true;
55147 tpls.body.compile();
55150 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55151 tpls.row.disableFormats = true;
55153 tpls.row.compile();
55156 tpls.cell = new Roo.Template(
55157 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55158 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55159 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55162 tpls.cell.disableFormats = true;
55164 tpls.cell.compile();
55166 this.templates = tpls;
55169 // remap these for backwards compat
55170 onColWidthChange : function(){
55171 this.updateColumns.apply(this, arguments);
55173 onHeaderChange : function(){
55174 this.updateHeaders.apply(this, arguments);
55176 onHiddenChange : function(){
55177 this.handleHiddenChange.apply(this, arguments);
55179 onColumnMove : function(){
55180 this.handleColumnMove.apply(this, arguments);
55182 onColumnLock : function(){
55183 this.handleLockChange.apply(this, arguments);
55186 onDataChange : function(){
55188 this.updateHeaderSortState();
55191 onClear : function(){
55195 onUpdate : function(ds, record){
55196 this.refreshRow(record);
55199 refreshRow : function(record){
55200 var ds = this.ds, index;
55201 if(typeof record == 'number'){
55203 record = ds.getAt(index);
55205 index = ds.indexOf(record);
55207 this.insertRows(ds, index, index, true);
55208 this.onRemove(ds, record, index+1, true);
55209 this.syncRowHeights(index, index);
55211 this.fireEvent("rowupdated", this, index, record);
55214 onAdd : function(ds, records, index){
55215 this.insertRows(ds, index, index + (records.length-1));
55218 onRemove : function(ds, record, index, isUpdate){
55219 if(isUpdate !== true){
55220 this.fireEvent("beforerowremoved", this, index, record);
55222 var bt = this.getBodyTable(), lt = this.getLockedTable();
55223 if(bt.rows[index]){
55224 bt.firstChild.removeChild(bt.rows[index]);
55226 if(lt.rows[index]){
55227 lt.firstChild.removeChild(lt.rows[index]);
55229 if(isUpdate !== true){
55230 this.stripeRows(index);
55231 this.syncRowHeights(index, index);
55233 this.fireEvent("rowremoved", this, index, record);
55237 onLoad : function(){
55238 this.scrollToTop();
55242 * Scrolls the grid to the top
55244 scrollToTop : function(){
55246 this.scroller.dom.scrollTop = 0;
55252 * Gets a panel in the header of the grid that can be used for toolbars etc.
55253 * After modifying the contents of this panel a call to grid.autoSize() may be
55254 * required to register any changes in size.
55255 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55256 * @return Roo.Element
55258 getHeaderPanel : function(doShow){
55260 this.headerPanel.show();
55262 return this.headerPanel;
55266 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55267 * After modifying the contents of this panel a call to grid.autoSize() may be
55268 * required to register any changes in size.
55269 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55270 * @return Roo.Element
55272 getFooterPanel : function(doShow){
55274 this.footerPanel.show();
55276 return this.footerPanel;
55279 initElements : function(){
55280 var E = Roo.Element;
55281 var el = this.grid.getGridEl().dom.firstChild;
55282 var cs = el.childNodes;
55284 this.el = new E(el);
55286 this.focusEl = new E(el.firstChild);
55287 this.focusEl.swallowEvent("click", true);
55289 this.headerPanel = new E(cs[1]);
55290 this.headerPanel.enableDisplayMode("block");
55292 this.scroller = new E(cs[2]);
55293 this.scrollSizer = new E(this.scroller.dom.firstChild);
55295 this.lockedWrap = new E(cs[3]);
55296 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55297 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55299 this.mainWrap = new E(cs[4]);
55300 this.mainHd = new E(this.mainWrap.dom.firstChild);
55301 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55303 this.footerPanel = new E(cs[5]);
55304 this.footerPanel.enableDisplayMode("block");
55306 this.resizeProxy = new E(cs[6]);
55308 this.headerSelector = String.format(
55309 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55310 this.lockedHd.id, this.mainHd.id
55313 this.splitterSelector = String.format(
55314 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55315 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55318 idToCssName : function(s)
55320 return s.replace(/[^a-z0-9]+/ig, '-');
55323 getHeaderCell : function(index){
55324 return Roo.DomQuery.select(this.headerSelector)[index];
55327 getHeaderCellMeasure : function(index){
55328 return this.getHeaderCell(index).firstChild;
55331 getHeaderCellText : function(index){
55332 return this.getHeaderCell(index).firstChild.firstChild;
55335 getLockedTable : function(){
55336 return this.lockedBody.dom.firstChild;
55339 getBodyTable : function(){
55340 return this.mainBody.dom.firstChild;
55343 getLockedRow : function(index){
55344 return this.getLockedTable().rows[index];
55347 getRow : function(index){
55348 return this.getBodyTable().rows[index];
55351 getRowComposite : function(index){
55353 this.rowEl = new Roo.CompositeElementLite();
55355 var els = [], lrow, mrow;
55356 if(lrow = this.getLockedRow(index)){
55359 if(mrow = this.getRow(index)){
55362 this.rowEl.elements = els;
55366 * Gets the 'td' of the cell
55368 * @param {Integer} rowIndex row to select
55369 * @param {Integer} colIndex column to select
55373 getCell : function(rowIndex, colIndex){
55374 var locked = this.cm.getLockedCount();
55376 if(colIndex < locked){
55377 source = this.lockedBody.dom.firstChild;
55379 source = this.mainBody.dom.firstChild;
55380 colIndex -= locked;
55382 return source.rows[rowIndex].childNodes[colIndex];
55385 getCellText : function(rowIndex, colIndex){
55386 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55389 getCellBox : function(cell){
55390 var b = this.fly(cell).getBox();
55391 if(Roo.isOpera){ // opera fails to report the Y
55392 b.y = cell.offsetTop + this.mainBody.getY();
55397 getCellIndex : function(cell){
55398 var id = String(cell.className).match(this.cellRE);
55400 return parseInt(id[1], 10);
55405 findHeaderIndex : function(n){
55406 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55407 return r ? this.getCellIndex(r) : false;
55410 findHeaderCell : function(n){
55411 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55412 return r ? r : false;
55415 findRowIndex : function(n){
55419 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55420 return r ? r.rowIndex : false;
55423 findCellIndex : function(node){
55424 var stop = this.el.dom;
55425 while(node && node != stop){
55426 if(this.findRE.test(node.className)){
55427 return this.getCellIndex(node);
55429 node = node.parentNode;
55434 getColumnId : function(index){
55435 return this.cm.getColumnId(index);
55438 getSplitters : function()
55440 if(this.splitterSelector){
55441 return Roo.DomQuery.select(this.splitterSelector);
55447 getSplitter : function(index){
55448 return this.getSplitters()[index];
55451 onRowOver : function(e, t){
55453 if((row = this.findRowIndex(t)) !== false){
55454 this.getRowComposite(row).addClass("x-grid-row-over");
55458 onRowOut : function(e, t){
55460 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55461 this.getRowComposite(row).removeClass("x-grid-row-over");
55465 renderHeaders : function(){
55467 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55468 var cb = [], lb = [], sb = [], lsb = [], p = {};
55469 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55470 p.cellId = "x-grid-hd-0-" + i;
55471 p.splitId = "x-grid-csplit-0-" + i;
55472 p.id = cm.getColumnId(i);
55473 p.value = cm.getColumnHeader(i) || "";
55474 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55475 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55476 if(!cm.isLocked(i)){
55477 cb[cb.length] = ct.apply(p);
55478 sb[sb.length] = st.apply(p);
55480 lb[lb.length] = ct.apply(p);
55481 lsb[lsb.length] = st.apply(p);
55484 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55485 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55488 updateHeaders : function(){
55489 var html = this.renderHeaders();
55490 this.lockedHd.update(html[0]);
55491 this.mainHd.update(html[1]);
55495 * Focuses the specified row.
55496 * @param {Number} row The row index
55498 focusRow : function(row)
55500 //Roo.log('GridView.focusRow');
55501 var x = this.scroller.dom.scrollLeft;
55502 this.focusCell(row, 0, false);
55503 this.scroller.dom.scrollLeft = x;
55507 * Focuses the specified cell.
55508 * @param {Number} row The row index
55509 * @param {Number} col The column index
55510 * @param {Boolean} hscroll false to disable horizontal scrolling
55512 focusCell : function(row, col, hscroll)
55514 //Roo.log('GridView.focusCell');
55515 var el = this.ensureVisible(row, col, hscroll);
55516 this.focusEl.alignTo(el, "tl-tl");
55518 this.focusEl.focus();
55520 this.focusEl.focus.defer(1, this.focusEl);
55525 * Scrolls the specified cell into view
55526 * @param {Number} row The row index
55527 * @param {Number} col The column index
55528 * @param {Boolean} hscroll false to disable horizontal scrolling
55530 ensureVisible : function(row, col, hscroll)
55532 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55533 //return null; //disable for testing.
55534 if(typeof row != "number"){
55535 row = row.rowIndex;
55537 if(row < 0 && row >= this.ds.getCount()){
55540 col = (col !== undefined ? col : 0);
55541 var cm = this.grid.colModel;
55542 while(cm.isHidden(col)){
55546 var el = this.getCell(row, col);
55550 var c = this.scroller.dom;
55552 var ctop = parseInt(el.offsetTop, 10);
55553 var cleft = parseInt(el.offsetLeft, 10);
55554 var cbot = ctop + el.offsetHeight;
55555 var cright = cleft + el.offsetWidth;
55557 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55558 var stop = parseInt(c.scrollTop, 10);
55559 var sleft = parseInt(c.scrollLeft, 10);
55560 var sbot = stop + ch;
55561 var sright = sleft + c.clientWidth;
55563 Roo.log('GridView.ensureVisible:' +
55565 ' c.clientHeight:' + c.clientHeight +
55566 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55574 c.scrollTop = ctop;
55575 //Roo.log("set scrolltop to ctop DISABLE?");
55576 }else if(cbot > sbot){
55577 //Roo.log("set scrolltop to cbot-ch");
55578 c.scrollTop = cbot-ch;
55581 if(hscroll !== false){
55583 c.scrollLeft = cleft;
55584 }else if(cright > sright){
55585 c.scrollLeft = cright-c.clientWidth;
55592 updateColumns : function(){
55593 this.grid.stopEditing();
55594 var cm = this.grid.colModel, colIds = this.getColumnIds();
55595 //var totalWidth = cm.getTotalWidth();
55597 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55598 //if(cm.isHidden(i)) continue;
55599 var w = cm.getColumnWidth(i);
55600 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55601 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55603 this.updateSplitters();
55606 generateRules : function(cm){
55607 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55608 Roo.util.CSS.removeStyleSheet(rulesId);
55609 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55610 var cid = cm.getColumnId(i);
55612 if(cm.config[i].align){
55613 align = 'text-align:'+cm.config[i].align+';';
55616 if(cm.isHidden(i)){
55617 hidden = 'display:none;';
55619 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55621 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55622 this.hdSelector, cid, " {\n", align, width, "}\n",
55623 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55624 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55626 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55629 updateSplitters : function(){
55630 var cm = this.cm, s = this.getSplitters();
55631 if(s){ // splitters not created yet
55632 var pos = 0, locked = true;
55633 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55634 if(cm.isHidden(i)) {
55637 var w = cm.getColumnWidth(i); // make sure it's a number
55638 if(!cm.isLocked(i) && locked){
55643 s[i].style.left = (pos-this.splitOffset) + "px";
55648 handleHiddenChange : function(colModel, colIndex, hidden){
55650 this.hideColumn(colIndex);
55652 this.unhideColumn(colIndex);
55656 hideColumn : function(colIndex){
55657 var cid = this.getColumnId(colIndex);
55658 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55659 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55661 this.updateHeaders();
55663 this.updateSplitters();
55667 unhideColumn : function(colIndex){
55668 var cid = this.getColumnId(colIndex);
55669 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55670 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55673 this.updateHeaders();
55675 this.updateSplitters();
55679 insertRows : function(dm, firstRow, lastRow, isUpdate){
55680 if(firstRow == 0 && lastRow == dm.getCount()-1){
55684 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55686 var s = this.getScrollState();
55687 var markup = this.renderRows(firstRow, lastRow);
55688 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55689 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55690 this.restoreScroll(s);
55692 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55693 this.syncRowHeights(firstRow, lastRow);
55694 this.stripeRows(firstRow);
55700 bufferRows : function(markup, target, index){
55701 var before = null, trows = target.rows, tbody = target.tBodies[0];
55702 if(index < trows.length){
55703 before = trows[index];
55705 var b = document.createElement("div");
55706 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55707 var rows = b.firstChild.rows;
55708 for(var i = 0, len = rows.length; i < len; i++){
55710 tbody.insertBefore(rows[0], before);
55712 tbody.appendChild(rows[0]);
55719 deleteRows : function(dm, firstRow, lastRow){
55720 if(dm.getRowCount()<1){
55721 this.fireEvent("beforerefresh", this);
55722 this.mainBody.update("");
55723 this.lockedBody.update("");
55724 this.fireEvent("refresh", this);
55726 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55727 var bt = this.getBodyTable();
55728 var tbody = bt.firstChild;
55729 var rows = bt.rows;
55730 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55731 tbody.removeChild(rows[firstRow]);
55733 this.stripeRows(firstRow);
55734 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55738 updateRows : function(dataSource, firstRow, lastRow){
55739 var s = this.getScrollState();
55741 this.restoreScroll(s);
55744 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55748 this.updateHeaderSortState();
55751 getScrollState : function(){
55753 var sb = this.scroller.dom;
55754 return {left: sb.scrollLeft, top: sb.scrollTop};
55757 stripeRows : function(startRow){
55758 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55761 startRow = startRow || 0;
55762 var rows = this.getBodyTable().rows;
55763 var lrows = this.getLockedTable().rows;
55764 var cls = ' x-grid-row-alt ';
55765 for(var i = startRow, len = rows.length; i < len; i++){
55766 var row = rows[i], lrow = lrows[i];
55767 var isAlt = ((i+1) % 2 == 0);
55768 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55769 if(isAlt == hasAlt){
55773 row.className += " x-grid-row-alt";
55775 row.className = row.className.replace("x-grid-row-alt", "");
55778 lrow.className = row.className;
55783 restoreScroll : function(state){
55784 //Roo.log('GridView.restoreScroll');
55785 var sb = this.scroller.dom;
55786 sb.scrollLeft = state.left;
55787 sb.scrollTop = state.top;
55791 syncScroll : function(){
55792 //Roo.log('GridView.syncScroll');
55793 var sb = this.scroller.dom;
55794 var sh = this.mainHd.dom;
55795 var bs = this.mainBody.dom;
55796 var lv = this.lockedBody.dom;
55797 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55798 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55801 handleScroll : function(e){
55803 var sb = this.scroller.dom;
55804 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55808 handleWheel : function(e){
55809 var d = e.getWheelDelta();
55810 this.scroller.dom.scrollTop -= d*22;
55811 // set this here to prevent jumpy scrolling on large tables
55812 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55816 renderRows : function(startRow, endRow){
55817 // pull in all the crap needed to render rows
55818 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55819 var colCount = cm.getColumnCount();
55821 if(ds.getCount() < 1){
55825 // build a map for all the columns
55827 for(var i = 0; i < colCount; i++){
55828 var name = cm.getDataIndex(i);
55830 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55831 renderer : cm.getRenderer(i),
55832 id : cm.getColumnId(i),
55833 locked : cm.isLocked(i),
55834 has_editor : cm.isCellEditable(i)
55838 startRow = startRow || 0;
55839 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55841 // records to render
55842 var rs = ds.getRange(startRow, endRow);
55844 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55847 // As much as I hate to duplicate code, this was branched because FireFox really hates
55848 // [].join("") on strings. The performance difference was substantial enough to
55849 // branch this function
55850 doRender : Roo.isGecko ?
55851 function(cs, rs, ds, startRow, colCount, stripe){
55852 var ts = this.templates, ct = ts.cell, rt = ts.row;
55854 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55856 var hasListener = this.grid.hasListener('rowclass');
55858 for(var j = 0, len = rs.length; j < len; j++){
55859 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
55860 for(var i = 0; i < colCount; i++){
55862 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55864 p.css = p.attr = "";
55865 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55866 if(p.value == undefined || p.value === "") {
55867 p.value = " ";
55870 p.css += ' x-grid-editable-cell';
55872 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
55873 p.css += ' x-grid-dirty-cell';
55875 var markup = ct.apply(p);
55883 if(stripe && ((rowIndex+1) % 2 == 0)){
55884 alt.push("x-grid-row-alt")
55887 alt.push( " x-grid-dirty-row");
55890 if(this.getRowClass){
55891 alt.push(this.getRowClass(r, rowIndex));
55897 rowIndex : rowIndex,
55900 this.grid.fireEvent('rowclass', this, rowcfg);
55901 alt.push(rowcfg.rowClass);
55903 rp.alt = alt.join(" ");
55904 lbuf+= rt.apply(rp);
55906 buf+= rt.apply(rp);
55908 return [lbuf, buf];
55910 function(cs, rs, ds, startRow, colCount, stripe){
55911 var ts = this.templates, ct = ts.cell, rt = ts.row;
55913 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55914 var hasListener = this.grid.hasListener('rowclass');
55917 for(var j = 0, len = rs.length; j < len; j++){
55918 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
55919 for(var i = 0; i < colCount; i++){
55921 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55923 p.css = p.attr = "";
55924 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55925 if(p.value == undefined || p.value === "") {
55926 p.value = " ";
55930 p.css += ' x-grid-editable-cell';
55932 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
55933 p.css += ' x-grid-dirty-cell'
55936 var markup = ct.apply(p);
55938 cb[cb.length] = markup;
55940 lcb[lcb.length] = markup;
55944 if(stripe && ((rowIndex+1) % 2 == 0)){
55945 alt.push( "x-grid-row-alt");
55948 alt.push(" x-grid-dirty-row");
55951 if(this.getRowClass){
55952 alt.push( this.getRowClass(r, rowIndex));
55958 rowIndex : rowIndex,
55961 this.grid.fireEvent('rowclass', this, rowcfg);
55962 alt.push(rowcfg.rowClass);
55965 rp.alt = alt.join(" ");
55966 rp.cells = lcb.join("");
55967 lbuf[lbuf.length] = rt.apply(rp);
55968 rp.cells = cb.join("");
55969 buf[buf.length] = rt.apply(rp);
55971 return [lbuf.join(""), buf.join("")];
55974 renderBody : function(){
55975 var markup = this.renderRows();
55976 var bt = this.templates.body;
55977 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
55981 * Refreshes the grid
55982 * @param {Boolean} headersToo
55984 refresh : function(headersToo){
55985 this.fireEvent("beforerefresh", this);
55986 this.grid.stopEditing();
55987 var result = this.renderBody();
55988 this.lockedBody.update(result[0]);
55989 this.mainBody.update(result[1]);
55990 if(headersToo === true){
55991 this.updateHeaders();
55992 this.updateColumns();
55993 this.updateSplitters();
55994 this.updateHeaderSortState();
55996 this.syncRowHeights();
55998 this.fireEvent("refresh", this);
56001 handleColumnMove : function(cm, oldIndex, newIndex){
56002 this.indexMap = null;
56003 var s = this.getScrollState();
56004 this.refresh(true);
56005 this.restoreScroll(s);
56006 this.afterMove(newIndex);
56009 afterMove : function(colIndex){
56010 if(this.enableMoveAnim && Roo.enableFx){
56011 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56013 // if multisort - fix sortOrder, and reload..
56014 if (this.grid.dataSource.multiSort) {
56015 // the we can call sort again..
56016 var dm = this.grid.dataSource;
56017 var cm = this.grid.colModel;
56019 for(var i = 0; i < cm.config.length; i++ ) {
56021 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56022 continue; // dont' bother, it's not in sort list or being set.
56025 so.push(cm.config[i].dataIndex);
56028 dm.load(dm.lastOptions);
56035 updateCell : function(dm, rowIndex, dataIndex){
56036 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56037 if(typeof colIndex == "undefined"){ // not present in grid
56040 var cm = this.grid.colModel;
56041 var cell = this.getCell(rowIndex, colIndex);
56042 var cellText = this.getCellText(rowIndex, colIndex);
56045 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56046 id : cm.getColumnId(colIndex),
56047 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56049 var renderer = cm.getRenderer(colIndex);
56050 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56051 if(typeof val == "undefined" || val === "") {
56054 cellText.innerHTML = val;
56055 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56056 this.syncRowHeights(rowIndex, rowIndex);
56059 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56061 if(this.grid.autoSizeHeaders){
56062 var h = this.getHeaderCellMeasure(colIndex);
56063 maxWidth = Math.max(maxWidth, h.scrollWidth);
56066 if(this.cm.isLocked(colIndex)){
56067 tb = this.getLockedTable();
56070 tb = this.getBodyTable();
56071 index = colIndex - this.cm.getLockedCount();
56074 var rows = tb.rows;
56075 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56076 for(var i = 0; i < stopIndex; i++){
56077 var cell = rows[i].childNodes[index].firstChild;
56078 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56081 return maxWidth + /*margin for error in IE*/ 5;
56084 * Autofit a column to its content.
56085 * @param {Number} colIndex
56086 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56088 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56089 if(this.cm.isHidden(colIndex)){
56090 return; // can't calc a hidden column
56093 var cid = this.cm.getColumnId(colIndex);
56094 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56095 if(this.grid.autoSizeHeaders){
56096 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56099 var newWidth = this.calcColumnWidth(colIndex);
56100 this.cm.setColumnWidth(colIndex,
56101 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56102 if(!suppressEvent){
56103 this.grid.fireEvent("columnresize", colIndex, newWidth);
56108 * Autofits all columns to their content and then expands to fit any extra space in the grid
56110 autoSizeColumns : function(){
56111 var cm = this.grid.colModel;
56112 var colCount = cm.getColumnCount();
56113 for(var i = 0; i < colCount; i++){
56114 this.autoSizeColumn(i, true, true);
56116 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56119 this.updateColumns();
56125 * Autofits all columns to the grid's width proportionate with their current size
56126 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56128 fitColumns : function(reserveScrollSpace){
56129 var cm = this.grid.colModel;
56130 var colCount = cm.getColumnCount();
56134 for (i = 0; i < colCount; i++){
56135 if(!cm.isHidden(i) && !cm.isFixed(i)){
56136 w = cm.getColumnWidth(i);
56142 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56143 if(reserveScrollSpace){
56146 var frac = (avail - cm.getTotalWidth())/width;
56147 while (cols.length){
56150 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56152 this.updateColumns();
56156 onRowSelect : function(rowIndex){
56157 var row = this.getRowComposite(rowIndex);
56158 row.addClass("x-grid-row-selected");
56161 onRowDeselect : function(rowIndex){
56162 var row = this.getRowComposite(rowIndex);
56163 row.removeClass("x-grid-row-selected");
56166 onCellSelect : function(row, col){
56167 var cell = this.getCell(row, col);
56169 Roo.fly(cell).addClass("x-grid-cell-selected");
56173 onCellDeselect : function(row, col){
56174 var cell = this.getCell(row, col);
56176 Roo.fly(cell).removeClass("x-grid-cell-selected");
56180 updateHeaderSortState : function(){
56182 // sort state can be single { field: xxx, direction : yyy}
56183 // or { xxx=>ASC , yyy : DESC ..... }
56186 if (!this.ds.multiSort) {
56187 var state = this.ds.getSortState();
56191 mstate[state.field] = state.direction;
56192 // FIXME... - this is not used here.. but might be elsewhere..
56193 this.sortState = state;
56196 mstate = this.ds.sortToggle;
56198 //remove existing sort classes..
56200 var sc = this.sortClasses;
56201 var hds = this.el.select(this.headerSelector).removeClass(sc);
56203 for(var f in mstate) {
56205 var sortColumn = this.cm.findColumnIndex(f);
56207 if(sortColumn != -1){
56208 var sortDir = mstate[f];
56209 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56218 handleHeaderClick : function(g, index,e){
56220 Roo.log("header click");
56223 // touch events on header are handled by context
56224 this.handleHdCtx(g,index,e);
56229 if(this.headersDisabled){
56232 var dm = g.dataSource, cm = g.colModel;
56233 if(!cm.isSortable(index)){
56238 if (dm.multiSort) {
56239 // update the sortOrder
56241 for(var i = 0; i < cm.config.length; i++ ) {
56243 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56244 continue; // dont' bother, it's not in sort list or being set.
56247 so.push(cm.config[i].dataIndex);
56253 dm.sort(cm.getDataIndex(index));
56257 destroy : function(){
56259 this.colMenu.removeAll();
56260 Roo.menu.MenuMgr.unregister(this.colMenu);
56261 this.colMenu.getEl().remove();
56262 delete this.colMenu;
56265 this.hmenu.removeAll();
56266 Roo.menu.MenuMgr.unregister(this.hmenu);
56267 this.hmenu.getEl().remove();
56270 if(this.grid.enableColumnMove){
56271 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56273 for(var dd in dds){
56274 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56275 var elid = dds[dd].dragElId;
56277 Roo.get(elid).remove();
56278 } else if(dds[dd].config.isTarget){
56279 dds[dd].proxyTop.remove();
56280 dds[dd].proxyBottom.remove();
56283 if(Roo.dd.DDM.locationCache[dd]){
56284 delete Roo.dd.DDM.locationCache[dd];
56287 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56290 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56291 this.bind(null, null);
56292 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56295 handleLockChange : function(){
56296 this.refresh(true);
56299 onDenyColumnLock : function(){
56303 onDenyColumnHide : function(){
56307 handleHdMenuClick : function(item){
56308 var index = this.hdCtxIndex;
56309 var cm = this.cm, ds = this.ds;
56312 ds.sort(cm.getDataIndex(index), "ASC");
56315 ds.sort(cm.getDataIndex(index), "DESC");
56318 var lc = cm.getLockedCount();
56319 if(cm.getColumnCount(true) <= lc+1){
56320 this.onDenyColumnLock();
56324 cm.setLocked(index, true, true);
56325 cm.moveColumn(index, lc);
56326 this.grid.fireEvent("columnmove", index, lc);
56328 cm.setLocked(index, true);
56332 var lc = cm.getLockedCount();
56333 if((lc-1) != index){
56334 cm.setLocked(index, false, true);
56335 cm.moveColumn(index, lc-1);
56336 this.grid.fireEvent("columnmove", index, lc-1);
56338 cm.setLocked(index, false);
56341 case 'wider': // used to expand cols on touch..
56343 var cw = cm.getColumnWidth(index);
56344 cw += (item.id == 'wider' ? 1 : -1) * 50;
56345 cw = Math.max(0, cw);
56346 cw = Math.min(cw,4000);
56347 cm.setColumnWidth(index, cw);
56351 index = cm.getIndexById(item.id.substr(4));
56353 if(item.checked && cm.getColumnCount(true) <= 1){
56354 this.onDenyColumnHide();
56357 cm.setHidden(index, item.checked);
56363 beforeColMenuShow : function(){
56364 var cm = this.cm, colCount = cm.getColumnCount();
56365 this.colMenu.removeAll();
56366 for(var i = 0; i < colCount; i++){
56367 this.colMenu.add(new Roo.menu.CheckItem({
56368 id: "col-"+cm.getColumnId(i),
56369 text: cm.getColumnHeader(i),
56370 checked: !cm.isHidden(i),
56376 handleHdCtx : function(g, index, e){
56378 var hd = this.getHeaderCell(index);
56379 this.hdCtxIndex = index;
56380 var ms = this.hmenu.items, cm = this.cm;
56381 ms.get("asc").setDisabled(!cm.isSortable(index));
56382 ms.get("desc").setDisabled(!cm.isSortable(index));
56383 if(this.grid.enableColLock !== false){
56384 ms.get("lock").setDisabled(cm.isLocked(index));
56385 ms.get("unlock").setDisabled(!cm.isLocked(index));
56387 this.hmenu.show(hd, "tl-bl");
56390 handleHdOver : function(e){
56391 var hd = this.findHeaderCell(e.getTarget());
56392 if(hd && !this.headersDisabled){
56393 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56394 this.fly(hd).addClass("x-grid-hd-over");
56399 handleHdOut : function(e){
56400 var hd = this.findHeaderCell(e.getTarget());
56402 this.fly(hd).removeClass("x-grid-hd-over");
56406 handleSplitDblClick : function(e, t){
56407 var i = this.getCellIndex(t);
56408 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56409 this.autoSizeColumn(i, true);
56414 render : function(){
56417 var colCount = cm.getColumnCount();
56419 if(this.grid.monitorWindowResize === true){
56420 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56422 var header = this.renderHeaders();
56423 var body = this.templates.body.apply({rows:""});
56424 var html = this.templates.master.apply({
56427 lockedHeader: header[0],
56431 //this.updateColumns();
56433 this.grid.getGridEl().dom.innerHTML = html;
56435 this.initElements();
56437 // a kludge to fix the random scolling effect in webkit
56438 this.el.on("scroll", function() {
56439 this.el.dom.scrollTop=0; // hopefully not recursive..
56442 this.scroller.on("scroll", this.handleScroll, this);
56443 this.lockedBody.on("mousewheel", this.handleWheel, this);
56444 this.mainBody.on("mousewheel", this.handleWheel, this);
56446 this.mainHd.on("mouseover", this.handleHdOver, this);
56447 this.mainHd.on("mouseout", this.handleHdOut, this);
56448 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56449 {delegate: "."+this.splitClass});
56451 this.lockedHd.on("mouseover", this.handleHdOver, this);
56452 this.lockedHd.on("mouseout", this.handleHdOut, this);
56453 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56454 {delegate: "."+this.splitClass});
56456 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56457 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56460 this.updateSplitters();
56462 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56463 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56464 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56467 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56468 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56470 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56471 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56473 if(this.grid.enableColLock !== false){
56474 this.hmenu.add('-',
56475 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56476 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56480 this.hmenu.add('-',
56481 {id:"wider", text: this.columnsWiderText},
56482 {id:"narrow", text: this.columnsNarrowText }
56488 if(this.grid.enableColumnHide !== false){
56490 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56491 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56492 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56494 this.hmenu.add('-',
56495 {id:"columns", text: this.columnsText, menu: this.colMenu}
56498 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56500 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56503 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56504 this.dd = new Roo.grid.GridDragZone(this.grid, {
56505 ddGroup : this.grid.ddGroup || 'GridDD'
56511 for(var i = 0; i < colCount; i++){
56512 if(cm.isHidden(i)){
56513 this.hideColumn(i);
56515 if(cm.config[i].align){
56516 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56517 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56521 this.updateHeaderSortState();
56523 this.beforeInitialResize();
56526 // two part rendering gives faster view to the user
56527 this.renderPhase2.defer(1, this);
56530 renderPhase2 : function(){
56531 // render the rows now
56533 if(this.grid.autoSizeColumns){
56534 this.autoSizeColumns();
56538 beforeInitialResize : function(){
56542 onColumnSplitterMoved : function(i, w){
56543 this.userResized = true;
56544 var cm = this.grid.colModel;
56545 cm.setColumnWidth(i, w, true);
56546 var cid = cm.getColumnId(i);
56547 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56548 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56549 this.updateSplitters();
56551 this.grid.fireEvent("columnresize", i, w);
56554 syncRowHeights : function(startIndex, endIndex){
56555 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56556 startIndex = startIndex || 0;
56557 var mrows = this.getBodyTable().rows;
56558 var lrows = this.getLockedTable().rows;
56559 var len = mrows.length-1;
56560 endIndex = Math.min(endIndex || len, len);
56561 for(var i = startIndex; i <= endIndex; i++){
56562 var m = mrows[i], l = lrows[i];
56563 var h = Math.max(m.offsetHeight, l.offsetHeight);
56564 m.style.height = l.style.height = h + "px";
56569 layout : function(initialRender, is2ndPass){
56571 var auto = g.autoHeight;
56572 var scrollOffset = 16;
56573 var c = g.getGridEl(), cm = this.cm,
56574 expandCol = g.autoExpandColumn,
56576 //c.beginMeasure();
56578 if(!c.dom.offsetWidth){ // display:none?
56580 this.lockedWrap.show();
56581 this.mainWrap.show();
56586 var hasLock = this.cm.isLocked(0);
56588 var tbh = this.headerPanel.getHeight();
56589 var bbh = this.footerPanel.getHeight();
56592 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56593 var newHeight = ch + c.getBorderWidth("tb");
56595 newHeight = Math.min(g.maxHeight, newHeight);
56597 c.setHeight(newHeight);
56601 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56604 var s = this.scroller;
56606 var csize = c.getSize(true);
56608 this.el.setSize(csize.width, csize.height);
56610 this.headerPanel.setWidth(csize.width);
56611 this.footerPanel.setWidth(csize.width);
56613 var hdHeight = this.mainHd.getHeight();
56614 var vw = csize.width;
56615 var vh = csize.height - (tbh + bbh);
56619 var bt = this.getBodyTable();
56621 if(cm.getLockedCount() == cm.config.length){
56622 bt = this.getLockedTable();
56625 var ltWidth = hasLock ?
56626 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56628 var scrollHeight = bt.offsetHeight;
56629 var scrollWidth = ltWidth + bt.offsetWidth;
56630 var vscroll = false, hscroll = false;
56632 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56634 var lw = this.lockedWrap, mw = this.mainWrap;
56635 var lb = this.lockedBody, mb = this.mainBody;
56637 setTimeout(function(){
56638 var t = s.dom.offsetTop;
56639 var w = s.dom.clientWidth,
56640 h = s.dom.clientHeight;
56643 lw.setSize(ltWidth, h);
56645 mw.setLeftTop(ltWidth, t);
56646 mw.setSize(w-ltWidth, h);
56648 lb.setHeight(h-hdHeight);
56649 mb.setHeight(h-hdHeight);
56651 if(is2ndPass !== true && !gv.userResized && expandCol){
56652 // high speed resize without full column calculation
56654 var ci = cm.getIndexById(expandCol);
56656 ci = cm.findColumnIndex(expandCol);
56658 ci = Math.max(0, ci); // make sure it's got at least the first col.
56659 var expandId = cm.getColumnId(ci);
56660 var tw = cm.getTotalWidth(false);
56661 var currentWidth = cm.getColumnWidth(ci);
56662 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56663 if(currentWidth != cw){
56664 cm.setColumnWidth(ci, cw, true);
56665 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56666 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56667 gv.updateSplitters();
56668 gv.layout(false, true);
56680 onWindowResize : function(){
56681 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56687 appendFooter : function(parentEl){
56691 sortAscText : "Sort Ascending",
56692 sortDescText : "Sort Descending",
56693 lockText : "Lock Column",
56694 unlockText : "Unlock Column",
56695 columnsText : "Columns",
56697 columnsWiderText : "Wider",
56698 columnsNarrowText : "Thinner"
56702 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56703 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56704 this.proxy.el.addClass('x-grid3-col-dd');
56707 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56708 handleMouseDown : function(e){
56712 callHandleMouseDown : function(e){
56713 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56718 * Ext JS Library 1.1.1
56719 * Copyright(c) 2006-2007, Ext JS, LLC.
56721 * Originally Released Under LGPL - original licence link has changed is not relivant.
56724 * <script type="text/javascript">
56728 // This is a support class used internally by the Grid components
56729 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56731 this.view = grid.getView();
56732 this.proxy = this.view.resizeProxy;
56733 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56734 "gridSplitters" + this.grid.getGridEl().id, {
56735 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56737 this.setHandleElId(Roo.id(hd));
56738 this.setOuterHandleElId(Roo.id(hd2));
56739 this.scroll = false;
56741 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56742 fly: Roo.Element.fly,
56744 b4StartDrag : function(x, y){
56745 this.view.headersDisabled = true;
56746 this.proxy.setHeight(this.view.mainWrap.getHeight());
56747 var w = this.cm.getColumnWidth(this.cellIndex);
56748 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56749 this.resetConstraints();
56750 this.setXConstraint(minw, 1000);
56751 this.setYConstraint(0, 0);
56752 this.minX = x - minw;
56753 this.maxX = x + 1000;
56755 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56759 handleMouseDown : function(e){
56760 ev = Roo.EventObject.setEvent(e);
56761 var t = this.fly(ev.getTarget());
56762 if(t.hasClass("x-grid-split")){
56763 this.cellIndex = this.view.getCellIndex(t.dom);
56764 this.split = t.dom;
56765 this.cm = this.grid.colModel;
56766 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56767 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56772 endDrag : function(e){
56773 this.view.headersDisabled = false;
56774 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56775 var diff = endX - this.startPos;
56776 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56779 autoOffset : function(){
56780 this.setDelta(0,0);
56784 * Ext JS Library 1.1.1
56785 * Copyright(c) 2006-2007, Ext JS, LLC.
56787 * Originally Released Under LGPL - original licence link has changed is not relivant.
56790 * <script type="text/javascript">
56794 // This is a support class used internally by the Grid components
56795 Roo.grid.GridDragZone = function(grid, config){
56796 this.view = grid.getView();
56797 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56798 if(this.view.lockedBody){
56799 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56800 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56802 this.scroll = false;
56804 this.ddel = document.createElement('div');
56805 this.ddel.className = 'x-grid-dd-wrap';
56808 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56809 ddGroup : "GridDD",
56811 getDragData : function(e){
56812 var t = Roo.lib.Event.getTarget(e);
56813 var rowIndex = this.view.findRowIndex(t);
56814 var sm = this.grid.selModel;
56816 //Roo.log(rowIndex);
56818 if (sm.getSelectedCell) {
56819 // cell selection..
56820 if (!sm.getSelectedCell()) {
56823 if (rowIndex != sm.getSelectedCell()[0]) {
56829 if(rowIndex !== false){
56834 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56836 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56839 if (e.hasModifier()){
56840 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56843 Roo.log("getDragData");
56848 rowIndex: rowIndex,
56849 selections:sm.getSelections ? sm.getSelections() : (
56850 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
56857 onInitDrag : function(e){
56858 var data = this.dragData;
56859 this.ddel.innerHTML = this.grid.getDragDropText();
56860 this.proxy.update(this.ddel);
56861 // fire start drag?
56864 afterRepair : function(){
56865 this.dragging = false;
56868 getRepairXY : function(e, data){
56872 onEndDrag : function(data, e){
56876 onValidDrop : function(dd, e, id){
56881 beforeInvalidDrop : function(e, id){
56886 * Ext JS Library 1.1.1
56887 * Copyright(c) 2006-2007, Ext JS, LLC.
56889 * Originally Released Under LGPL - original licence link has changed is not relivant.
56892 * <script type="text/javascript">
56897 * @class Roo.grid.ColumnModel
56898 * @extends Roo.util.Observable
56899 * This is the default implementation of a ColumnModel used by the Grid. It defines
56900 * the columns in the grid.
56903 var colModel = new Roo.grid.ColumnModel([
56904 {header: "Ticker", width: 60, sortable: true, locked: true},
56905 {header: "Company Name", width: 150, sortable: true},
56906 {header: "Market Cap.", width: 100, sortable: true},
56907 {header: "$ Sales", width: 100, sortable: true, renderer: money},
56908 {header: "Employees", width: 100, sortable: true, resizable: false}
56913 * The config options listed for this class are options which may appear in each
56914 * individual column definition.
56915 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
56917 * @param {Object} config An Array of column config objects. See this class's
56918 * config objects for details.
56920 Roo.grid.ColumnModel = function(config){
56922 * The config passed into the constructor
56924 this.config = config;
56927 // if no id, create one
56928 // if the column does not have a dataIndex mapping,
56929 // map it to the order it is in the config
56930 for(var i = 0, len = config.length; i < len; i++){
56932 if(typeof c.dataIndex == "undefined"){
56935 if(typeof c.renderer == "string"){
56936 c.renderer = Roo.util.Format[c.renderer];
56938 if(typeof c.id == "undefined"){
56941 if(c.editor && c.editor.xtype){
56942 c.editor = Roo.factory(c.editor, Roo.grid);
56944 if(c.editor && c.editor.isFormField){
56945 c.editor = new Roo.grid.GridEditor(c.editor);
56947 this.lookup[c.id] = c;
56951 * The width of columns which have no width specified (defaults to 100)
56954 this.defaultWidth = 100;
56957 * Default sortable of columns which have no sortable specified (defaults to false)
56960 this.defaultSortable = false;
56964 * @event widthchange
56965 * Fires when the width of a column changes.
56966 * @param {ColumnModel} this
56967 * @param {Number} columnIndex The column index
56968 * @param {Number} newWidth The new width
56970 "widthchange": true,
56972 * @event headerchange
56973 * Fires when the text of a header changes.
56974 * @param {ColumnModel} this
56975 * @param {Number} columnIndex The column index
56976 * @param {Number} newText The new header text
56978 "headerchange": true,
56980 * @event hiddenchange
56981 * Fires when a column is hidden or "unhidden".
56982 * @param {ColumnModel} this
56983 * @param {Number} columnIndex The column index
56984 * @param {Boolean} hidden true if hidden, false otherwise
56986 "hiddenchange": true,
56988 * @event columnmoved
56989 * Fires when a column is moved.
56990 * @param {ColumnModel} this
56991 * @param {Number} oldIndex
56992 * @param {Number} newIndex
56994 "columnmoved" : true,
56996 * @event columlockchange
56997 * Fires when a column's locked state is changed
56998 * @param {ColumnModel} this
56999 * @param {Number} colIndex
57000 * @param {Boolean} locked true if locked
57002 "columnlockchange" : true
57004 Roo.grid.ColumnModel.superclass.constructor.call(this);
57006 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57008 * @cfg {String} header The header text to display in the Grid view.
57011 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57012 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57013 * specified, the column's index is used as an index into the Record's data Array.
57016 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57017 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57020 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57021 * Defaults to the value of the {@link #defaultSortable} property.
57022 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57025 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57028 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57031 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57034 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57037 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57038 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57039 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57040 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57043 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57046 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57049 * @cfg {String} cursor (Optional)
57052 * @cfg {String} tooltip (Optional)
57055 * @cfg {Number} xs (Optional)
57058 * @cfg {Number} sm (Optional)
57061 * @cfg {Number} md (Optional)
57064 * @cfg {Number} lg (Optional)
57067 * Returns the id of the column at the specified index.
57068 * @param {Number} index The column index
57069 * @return {String} the id
57071 getColumnId : function(index){
57072 return this.config[index].id;
57076 * Returns the column for a specified id.
57077 * @param {String} id The column id
57078 * @return {Object} the column
57080 getColumnById : function(id){
57081 return this.lookup[id];
57086 * Returns the column for a specified dataIndex.
57087 * @param {String} dataIndex The column dataIndex
57088 * @return {Object|Boolean} the column or false if not found
57090 getColumnByDataIndex: function(dataIndex){
57091 var index = this.findColumnIndex(dataIndex);
57092 return index > -1 ? this.config[index] : false;
57096 * Returns the index for a specified column id.
57097 * @param {String} id The column id
57098 * @return {Number} the index, or -1 if not found
57100 getIndexById : function(id){
57101 for(var i = 0, len = this.config.length; i < len; i++){
57102 if(this.config[i].id == id){
57110 * Returns the index for a specified column dataIndex.
57111 * @param {String} dataIndex The column dataIndex
57112 * @return {Number} the index, or -1 if not found
57115 findColumnIndex : function(dataIndex){
57116 for(var i = 0, len = this.config.length; i < len; i++){
57117 if(this.config[i].dataIndex == dataIndex){
57125 moveColumn : function(oldIndex, newIndex){
57126 var c = this.config[oldIndex];
57127 this.config.splice(oldIndex, 1);
57128 this.config.splice(newIndex, 0, c);
57129 this.dataMap = null;
57130 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57133 isLocked : function(colIndex){
57134 return this.config[colIndex].locked === true;
57137 setLocked : function(colIndex, value, suppressEvent){
57138 if(this.isLocked(colIndex) == value){
57141 this.config[colIndex].locked = value;
57142 if(!suppressEvent){
57143 this.fireEvent("columnlockchange", this, colIndex, value);
57147 getTotalLockedWidth : function(){
57148 var totalWidth = 0;
57149 for(var i = 0; i < this.config.length; i++){
57150 if(this.isLocked(i) && !this.isHidden(i)){
57151 this.totalWidth += this.getColumnWidth(i);
57157 getLockedCount : function(){
57158 for(var i = 0, len = this.config.length; i < len; i++){
57159 if(!this.isLocked(i)){
57164 return this.config.length;
57168 * Returns the number of columns.
57171 getColumnCount : function(visibleOnly){
57172 if(visibleOnly === true){
57174 for(var i = 0, len = this.config.length; i < len; i++){
57175 if(!this.isHidden(i)){
57181 return this.config.length;
57185 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57186 * @param {Function} fn
57187 * @param {Object} scope (optional)
57188 * @return {Array} result
57190 getColumnsBy : function(fn, scope){
57192 for(var i = 0, len = this.config.length; i < len; i++){
57193 var c = this.config[i];
57194 if(fn.call(scope||this, c, i) === true){
57202 * Returns true if the specified column is sortable.
57203 * @param {Number} col The column index
57204 * @return {Boolean}
57206 isSortable : function(col){
57207 if(typeof this.config[col].sortable == "undefined"){
57208 return this.defaultSortable;
57210 return this.config[col].sortable;
57214 * Returns the rendering (formatting) function defined for the column.
57215 * @param {Number} col The column index.
57216 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57218 getRenderer : function(col){
57219 if(!this.config[col].renderer){
57220 return Roo.grid.ColumnModel.defaultRenderer;
57222 return this.config[col].renderer;
57226 * Sets the rendering (formatting) function for a column.
57227 * @param {Number} col The column index
57228 * @param {Function} fn The function to use to process the cell's raw data
57229 * to return HTML markup for the grid view. The render function is called with
57230 * the following parameters:<ul>
57231 * <li>Data value.</li>
57232 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57233 * <li>css A CSS style string to apply to the table cell.</li>
57234 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57235 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57236 * <li>Row index</li>
57237 * <li>Column index</li>
57238 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57240 setRenderer : function(col, fn){
57241 this.config[col].renderer = fn;
57245 * Returns the width for the specified column.
57246 * @param {Number} col The column index
57249 getColumnWidth : function(col){
57250 return this.config[col].width * 1 || this.defaultWidth;
57254 * Sets the width for a column.
57255 * @param {Number} col The column index
57256 * @param {Number} width The new width
57258 setColumnWidth : function(col, width, suppressEvent){
57259 this.config[col].width = width;
57260 this.totalWidth = null;
57261 if(!suppressEvent){
57262 this.fireEvent("widthchange", this, col, width);
57267 * Returns the total width of all columns.
57268 * @param {Boolean} includeHidden True to include hidden column widths
57271 getTotalWidth : function(includeHidden){
57272 if(!this.totalWidth){
57273 this.totalWidth = 0;
57274 for(var i = 0, len = this.config.length; i < len; i++){
57275 if(includeHidden || !this.isHidden(i)){
57276 this.totalWidth += this.getColumnWidth(i);
57280 return this.totalWidth;
57284 * Returns the header for the specified column.
57285 * @param {Number} col The column index
57288 getColumnHeader : function(col){
57289 return this.config[col].header;
57293 * Sets the header for a column.
57294 * @param {Number} col The column index
57295 * @param {String} header The new header
57297 setColumnHeader : function(col, header){
57298 this.config[col].header = header;
57299 this.fireEvent("headerchange", this, col, header);
57303 * Returns the tooltip for the specified column.
57304 * @param {Number} col The column index
57307 getColumnTooltip : function(col){
57308 return this.config[col].tooltip;
57311 * Sets the tooltip for a column.
57312 * @param {Number} col The column index
57313 * @param {String} tooltip The new tooltip
57315 setColumnTooltip : function(col, tooltip){
57316 this.config[col].tooltip = tooltip;
57320 * Returns the dataIndex for the specified column.
57321 * @param {Number} col The column index
57324 getDataIndex : function(col){
57325 return this.config[col].dataIndex;
57329 * Sets the dataIndex for a column.
57330 * @param {Number} col The column index
57331 * @param {Number} dataIndex The new dataIndex
57333 setDataIndex : function(col, dataIndex){
57334 this.config[col].dataIndex = dataIndex;
57340 * Returns true if the cell is editable.
57341 * @param {Number} colIndex The column index
57342 * @param {Number} rowIndex The row index - this is nto actually used..?
57343 * @return {Boolean}
57345 isCellEditable : function(colIndex, rowIndex){
57346 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57350 * Returns the editor defined for the cell/column.
57351 * return false or null to disable editing.
57352 * @param {Number} colIndex The column index
57353 * @param {Number} rowIndex The row index
57356 getCellEditor : function(colIndex, rowIndex){
57357 return this.config[colIndex].editor;
57361 * Sets if a column is editable.
57362 * @param {Number} col The column index
57363 * @param {Boolean} editable True if the column is editable
57365 setEditable : function(col, editable){
57366 this.config[col].editable = editable;
57371 * Returns true if the column is hidden.
57372 * @param {Number} colIndex The column index
57373 * @return {Boolean}
57375 isHidden : function(colIndex){
57376 return this.config[colIndex].hidden;
57381 * Returns true if the column width cannot be changed
57383 isFixed : function(colIndex){
57384 return this.config[colIndex].fixed;
57388 * Returns true if the column can be resized
57389 * @return {Boolean}
57391 isResizable : function(colIndex){
57392 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57395 * Sets if a column is hidden.
57396 * @param {Number} colIndex The column index
57397 * @param {Boolean} hidden True if the column is hidden
57399 setHidden : function(colIndex, hidden){
57400 this.config[colIndex].hidden = hidden;
57401 this.totalWidth = null;
57402 this.fireEvent("hiddenchange", this, colIndex, hidden);
57406 * Sets the editor for a column.
57407 * @param {Number} col The column index
57408 * @param {Object} editor The editor object
57410 setEditor : function(col, editor){
57411 this.config[col].editor = editor;
57415 Roo.grid.ColumnModel.defaultRenderer = function(value)
57417 if(typeof value == "object") {
57420 if(typeof value == "string" && value.length < 1){
57424 return String.format("{0}", value);
57427 // Alias for backwards compatibility
57428 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57431 * Ext JS Library 1.1.1
57432 * Copyright(c) 2006-2007, Ext JS, LLC.
57434 * Originally Released Under LGPL - original licence link has changed is not relivant.
57437 * <script type="text/javascript">
57441 * @class Roo.grid.AbstractSelectionModel
57442 * @extends Roo.util.Observable
57443 * Abstract base class for grid SelectionModels. It provides the interface that should be
57444 * implemented by descendant classes. This class should not be directly instantiated.
57447 Roo.grid.AbstractSelectionModel = function(){
57448 this.locked = false;
57449 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57452 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57453 /** @ignore Called by the grid automatically. Do not call directly. */
57454 init : function(grid){
57460 * Locks the selections.
57463 this.locked = true;
57467 * Unlocks the selections.
57469 unlock : function(){
57470 this.locked = false;
57474 * Returns true if the selections are locked.
57475 * @return {Boolean}
57477 isLocked : function(){
57478 return this.locked;
57482 * Ext JS Library 1.1.1
57483 * Copyright(c) 2006-2007, Ext JS, LLC.
57485 * Originally Released Under LGPL - original licence link has changed is not relivant.
57488 * <script type="text/javascript">
57491 * @extends Roo.grid.AbstractSelectionModel
57492 * @class Roo.grid.RowSelectionModel
57493 * The default SelectionModel used by {@link Roo.grid.Grid}.
57494 * It supports multiple selections and keyboard selection/navigation.
57496 * @param {Object} config
57498 Roo.grid.RowSelectionModel = function(config){
57499 Roo.apply(this, config);
57500 this.selections = new Roo.util.MixedCollection(false, function(o){
57505 this.lastActive = false;
57509 * @event selectionchange
57510 * Fires when the selection changes
57511 * @param {SelectionModel} this
57513 "selectionchange" : true,
57515 * @event afterselectionchange
57516 * Fires after the selection changes (eg. by key press or clicking)
57517 * @param {SelectionModel} this
57519 "afterselectionchange" : true,
57521 * @event beforerowselect
57522 * Fires when a row is selected being selected, return false to cancel.
57523 * @param {SelectionModel} this
57524 * @param {Number} rowIndex The selected index
57525 * @param {Boolean} keepExisting False if other selections will be cleared
57527 "beforerowselect" : true,
57530 * Fires when a row is selected.
57531 * @param {SelectionModel} this
57532 * @param {Number} rowIndex The selected index
57533 * @param {Roo.data.Record} r The record
57535 "rowselect" : true,
57537 * @event rowdeselect
57538 * Fires when a row is deselected.
57539 * @param {SelectionModel} this
57540 * @param {Number} rowIndex The selected index
57542 "rowdeselect" : true
57544 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57545 this.locked = false;
57548 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57550 * @cfg {Boolean} singleSelect
57551 * True to allow selection of only one row at a time (defaults to false)
57553 singleSelect : false,
57556 initEvents : function(){
57558 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57559 this.grid.on("mousedown", this.handleMouseDown, this);
57560 }else{ // allow click to work like normal
57561 this.grid.on("rowclick", this.handleDragableRowClick, this);
57564 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57565 "up" : function(e){
57567 this.selectPrevious(e.shiftKey);
57568 }else if(this.last !== false && this.lastActive !== false){
57569 var last = this.last;
57570 this.selectRange(this.last, this.lastActive-1);
57571 this.grid.getView().focusRow(this.lastActive);
57572 if(last !== false){
57576 this.selectFirstRow();
57578 this.fireEvent("afterselectionchange", this);
57580 "down" : function(e){
57582 this.selectNext(e.shiftKey);
57583 }else if(this.last !== false && this.lastActive !== false){
57584 var last = this.last;
57585 this.selectRange(this.last, this.lastActive+1);
57586 this.grid.getView().focusRow(this.lastActive);
57587 if(last !== false){
57591 this.selectFirstRow();
57593 this.fireEvent("afterselectionchange", this);
57598 var view = this.grid.view;
57599 view.on("refresh", this.onRefresh, this);
57600 view.on("rowupdated", this.onRowUpdated, this);
57601 view.on("rowremoved", this.onRemove, this);
57605 onRefresh : function(){
57606 var ds = this.grid.dataSource, i, v = this.grid.view;
57607 var s = this.selections;
57608 s.each(function(r){
57609 if((i = ds.indexOfId(r.id)) != -1){
57611 s.add(ds.getAt(i)); // updating the selection relate data
57619 onRemove : function(v, index, r){
57620 this.selections.remove(r);
57624 onRowUpdated : function(v, index, r){
57625 if(this.isSelected(r)){
57626 v.onRowSelect(index);
57632 * @param {Array} records The records to select
57633 * @param {Boolean} keepExisting (optional) True to keep existing selections
57635 selectRecords : function(records, keepExisting){
57637 this.clearSelections();
57639 var ds = this.grid.dataSource;
57640 for(var i = 0, len = records.length; i < len; i++){
57641 this.selectRow(ds.indexOf(records[i]), true);
57646 * Gets the number of selected rows.
57649 getCount : function(){
57650 return this.selections.length;
57654 * Selects the first row in the grid.
57656 selectFirstRow : function(){
57661 * Select the last row.
57662 * @param {Boolean} keepExisting (optional) True to keep existing selections
57664 selectLastRow : function(keepExisting){
57665 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57669 * Selects the row immediately following the last selected row.
57670 * @param {Boolean} keepExisting (optional) True to keep existing selections
57672 selectNext : function(keepExisting){
57673 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57674 this.selectRow(this.last+1, keepExisting);
57675 this.grid.getView().focusRow(this.last);
57680 * Selects the row that precedes the last selected row.
57681 * @param {Boolean} keepExisting (optional) True to keep existing selections
57683 selectPrevious : function(keepExisting){
57685 this.selectRow(this.last-1, keepExisting);
57686 this.grid.getView().focusRow(this.last);
57691 * Returns the selected records
57692 * @return {Array} Array of selected records
57694 getSelections : function(){
57695 return [].concat(this.selections.items);
57699 * Returns the first selected record.
57702 getSelected : function(){
57703 return this.selections.itemAt(0);
57708 * Clears all selections.
57710 clearSelections : function(fast){
57715 var ds = this.grid.dataSource;
57716 var s = this.selections;
57717 s.each(function(r){
57718 this.deselectRow(ds.indexOfId(r.id));
57722 this.selections.clear();
57729 * Selects all rows.
57731 selectAll : function(){
57735 this.selections.clear();
57736 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57737 this.selectRow(i, true);
57742 * Returns True if there is a selection.
57743 * @return {Boolean}
57745 hasSelection : function(){
57746 return this.selections.length > 0;
57750 * Returns True if the specified row is selected.
57751 * @param {Number/Record} record The record or index of the record to check
57752 * @return {Boolean}
57754 isSelected : function(index){
57755 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57756 return (r && this.selections.key(r.id) ? true : false);
57760 * Returns True if the specified record id is selected.
57761 * @param {String} id The id of record to check
57762 * @return {Boolean}
57764 isIdSelected : function(id){
57765 return (this.selections.key(id) ? true : false);
57769 handleMouseDown : function(e, t){
57770 var view = this.grid.getView(), rowIndex;
57771 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57774 if(e.shiftKey && this.last !== false){
57775 var last = this.last;
57776 this.selectRange(last, rowIndex, e.ctrlKey);
57777 this.last = last; // reset the last
57778 view.focusRow(rowIndex);
57780 var isSelected = this.isSelected(rowIndex);
57781 if(e.button !== 0 && isSelected){
57782 view.focusRow(rowIndex);
57783 }else if(e.ctrlKey && isSelected){
57784 this.deselectRow(rowIndex);
57785 }else if(!isSelected){
57786 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57787 view.focusRow(rowIndex);
57790 this.fireEvent("afterselectionchange", this);
57793 handleDragableRowClick : function(grid, rowIndex, e)
57795 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57796 this.selectRow(rowIndex, false);
57797 grid.view.focusRow(rowIndex);
57798 this.fireEvent("afterselectionchange", this);
57803 * Selects multiple rows.
57804 * @param {Array} rows Array of the indexes of the row to select
57805 * @param {Boolean} keepExisting (optional) True to keep existing selections
57807 selectRows : function(rows, keepExisting){
57809 this.clearSelections();
57811 for(var i = 0, len = rows.length; i < len; i++){
57812 this.selectRow(rows[i], true);
57817 * Selects a range of rows. All rows in between startRow and endRow are also selected.
57818 * @param {Number} startRow The index of the first row in the range
57819 * @param {Number} endRow The index of the last row in the range
57820 * @param {Boolean} keepExisting (optional) True to retain existing selections
57822 selectRange : function(startRow, endRow, keepExisting){
57827 this.clearSelections();
57829 if(startRow <= endRow){
57830 for(var i = startRow; i <= endRow; i++){
57831 this.selectRow(i, true);
57834 for(var i = startRow; i >= endRow; i--){
57835 this.selectRow(i, true);
57841 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57842 * @param {Number} startRow The index of the first row in the range
57843 * @param {Number} endRow The index of the last row in the range
57845 deselectRange : function(startRow, endRow, preventViewNotify){
57849 for(var i = startRow; i <= endRow; i++){
57850 this.deselectRow(i, preventViewNotify);
57856 * @param {Number} row The index of the row to select
57857 * @param {Boolean} keepExisting (optional) True to keep existing selections
57859 selectRow : function(index, keepExisting, preventViewNotify){
57860 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
57863 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
57864 if(!keepExisting || this.singleSelect){
57865 this.clearSelections();
57867 var r = this.grid.dataSource.getAt(index);
57868 this.selections.add(r);
57869 this.last = this.lastActive = index;
57870 if(!preventViewNotify){
57871 this.grid.getView().onRowSelect(index);
57873 this.fireEvent("rowselect", this, index, r);
57874 this.fireEvent("selectionchange", this);
57880 * @param {Number} row The index of the row to deselect
57882 deselectRow : function(index, preventViewNotify){
57886 if(this.last == index){
57889 if(this.lastActive == index){
57890 this.lastActive = false;
57892 var r = this.grid.dataSource.getAt(index);
57893 this.selections.remove(r);
57894 if(!preventViewNotify){
57895 this.grid.getView().onRowDeselect(index);
57897 this.fireEvent("rowdeselect", this, index);
57898 this.fireEvent("selectionchange", this);
57902 restoreLast : function(){
57904 this.last = this._last;
57909 acceptsNav : function(row, col, cm){
57910 return !cm.isHidden(col) && cm.isCellEditable(col, row);
57914 onEditorKey : function(field, e){
57915 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
57920 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
57922 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
57924 }else if(k == e.ENTER && !e.ctrlKey){
57928 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
57930 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
57932 }else if(k == e.ESC){
57936 g.startEditing(newCell[0], newCell[1]);
57941 * Ext JS Library 1.1.1
57942 * Copyright(c) 2006-2007, Ext JS, LLC.
57944 * Originally Released Under LGPL - original licence link has changed is not relivant.
57947 * <script type="text/javascript">
57950 * @class Roo.grid.CellSelectionModel
57951 * @extends Roo.grid.AbstractSelectionModel
57952 * This class provides the basic implementation for cell selection in a grid.
57954 * @param {Object} config The object containing the configuration of this model.
57955 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
57957 Roo.grid.CellSelectionModel = function(config){
57958 Roo.apply(this, config);
57960 this.selection = null;
57964 * @event beforerowselect
57965 * Fires before a cell is selected.
57966 * @param {SelectionModel} this
57967 * @param {Number} rowIndex The selected row index
57968 * @param {Number} colIndex The selected cell index
57970 "beforecellselect" : true,
57972 * @event cellselect
57973 * Fires when a cell is selected.
57974 * @param {SelectionModel} this
57975 * @param {Number} rowIndex The selected row index
57976 * @param {Number} colIndex The selected cell index
57978 "cellselect" : true,
57980 * @event selectionchange
57981 * Fires when the active selection changes.
57982 * @param {SelectionModel} this
57983 * @param {Object} selection null for no selection or an object (o) with two properties
57985 <li>o.record: the record object for the row the selection is in</li>
57986 <li>o.cell: An array of [rowIndex, columnIndex]</li>
57989 "selectionchange" : true,
57992 * Fires when the tab (or enter) was pressed on the last editable cell
57993 * You can use this to trigger add new row.
57994 * @param {SelectionModel} this
57998 * @event beforeeditnext
57999 * Fires before the next editable sell is made active
58000 * You can use this to skip to another cell or fire the tabend
58001 * if you set cell to false
58002 * @param {Object} eventdata object : { cell : [ row, col ] }
58004 "beforeeditnext" : true
58006 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58009 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58011 enter_is_tab: false,
58014 initEvents : function(){
58015 this.grid.on("mousedown", this.handleMouseDown, this);
58016 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58017 var view = this.grid.view;
58018 view.on("refresh", this.onViewChange, this);
58019 view.on("rowupdated", this.onRowUpdated, this);
58020 view.on("beforerowremoved", this.clearSelections, this);
58021 view.on("beforerowsinserted", this.clearSelections, this);
58022 if(this.grid.isEditor){
58023 this.grid.on("beforeedit", this.beforeEdit, this);
58028 beforeEdit : function(e){
58029 this.select(e.row, e.column, false, true, e.record);
58033 onRowUpdated : function(v, index, r){
58034 if(this.selection && this.selection.record == r){
58035 v.onCellSelect(index, this.selection.cell[1]);
58040 onViewChange : function(){
58041 this.clearSelections(true);
58045 * Returns the currently selected cell,.
58046 * @return {Array} The selected cell (row, column) or null if none selected.
58048 getSelectedCell : function(){
58049 return this.selection ? this.selection.cell : null;
58053 * Clears all selections.
58054 * @param {Boolean} true to prevent the gridview from being notified about the change.
58056 clearSelections : function(preventNotify){
58057 var s = this.selection;
58059 if(preventNotify !== true){
58060 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58062 this.selection = null;
58063 this.fireEvent("selectionchange", this, null);
58068 * Returns true if there is a selection.
58069 * @return {Boolean}
58071 hasSelection : function(){
58072 return this.selection ? true : false;
58076 handleMouseDown : function(e, t){
58077 var v = this.grid.getView();
58078 if(this.isLocked()){
58081 var row = v.findRowIndex(t);
58082 var cell = v.findCellIndex(t);
58083 if(row !== false && cell !== false){
58084 this.select(row, cell);
58090 * @param {Number} rowIndex
58091 * @param {Number} collIndex
58093 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58094 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58095 this.clearSelections();
58096 r = r || this.grid.dataSource.getAt(rowIndex);
58099 cell : [rowIndex, colIndex]
58101 if(!preventViewNotify){
58102 var v = this.grid.getView();
58103 v.onCellSelect(rowIndex, colIndex);
58104 if(preventFocus !== true){
58105 v.focusCell(rowIndex, colIndex);
58108 this.fireEvent("cellselect", this, rowIndex, colIndex);
58109 this.fireEvent("selectionchange", this, this.selection);
58114 isSelectable : function(rowIndex, colIndex, cm){
58115 return !cm.isHidden(colIndex);
58119 handleKeyDown : function(e){
58120 //Roo.log('Cell Sel Model handleKeyDown');
58121 if(!e.isNavKeyPress()){
58124 var g = this.grid, s = this.selection;
58127 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58129 this.select(cell[0], cell[1]);
58134 var walk = function(row, col, step){
58135 return g.walkCells(row, col, step, sm.isSelectable, sm);
58137 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58144 // handled by onEditorKey
58145 if (g.isEditor && g.editing) {
58149 newCell = walk(r, c-1, -1);
58151 newCell = walk(r, c+1, 1);
58156 newCell = walk(r+1, c, 1);
58160 newCell = walk(r-1, c, -1);
58164 newCell = walk(r, c+1, 1);
58168 newCell = walk(r, c-1, -1);
58173 if(g.isEditor && !g.editing){
58174 g.startEditing(r, c);
58183 this.select(newCell[0], newCell[1]);
58189 acceptsNav : function(row, col, cm){
58190 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58194 * @param {Number} field (not used) - as it's normally used as a listener
58195 * @param {Number} e - event - fake it by using
58197 * var e = Roo.EventObjectImpl.prototype;
58198 * e.keyCode = e.TAB
58202 onEditorKey : function(field, e){
58204 var k = e.getKey(),
58207 ed = g.activeEditor,
58209 ///Roo.log('onEditorKey' + k);
58212 if (this.enter_is_tab && k == e.ENTER) {
58218 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58220 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58226 } else if(k == e.ENTER && !e.ctrlKey){
58229 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58231 } else if(k == e.ESC){
58236 var ecall = { cell : newCell, forward : forward };
58237 this.fireEvent('beforeeditnext', ecall );
58238 newCell = ecall.cell;
58239 forward = ecall.forward;
58243 //Roo.log('next cell after edit');
58244 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58245 } else if (forward) {
58246 // tabbed past last
58247 this.fireEvent.defer(100, this, ['tabend',this]);
58252 * Ext JS Library 1.1.1
58253 * Copyright(c) 2006-2007, Ext JS, LLC.
58255 * Originally Released Under LGPL - original licence link has changed is not relivant.
58258 * <script type="text/javascript">
58262 * @class Roo.grid.EditorGrid
58263 * @extends Roo.grid.Grid
58264 * Class for creating and editable grid.
58265 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58266 * The container MUST have some type of size defined for the grid to fill. The container will be
58267 * automatically set to position relative if it isn't already.
58268 * @param {Object} dataSource The data model to bind to
58269 * @param {Object} colModel The column model with info about this grid's columns
58271 Roo.grid.EditorGrid = function(container, config){
58272 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58273 this.getGridEl().addClass("xedit-grid");
58275 if(!this.selModel){
58276 this.selModel = new Roo.grid.CellSelectionModel();
58279 this.activeEditor = null;
58283 * @event beforeedit
58284 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58285 * <ul style="padding:5px;padding-left:16px;">
58286 * <li>grid - This grid</li>
58287 * <li>record - The record being edited</li>
58288 * <li>field - The field name being edited</li>
58289 * <li>value - The value for the field being edited.</li>
58290 * <li>row - The grid row index</li>
58291 * <li>column - The grid column index</li>
58292 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58294 * @param {Object} e An edit event (see above for description)
58296 "beforeedit" : true,
58299 * Fires after a cell is edited. <br />
58300 * <ul style="padding:5px;padding-left:16px;">
58301 * <li>grid - This grid</li>
58302 * <li>record - The record being edited</li>
58303 * <li>field - The field name being edited</li>
58304 * <li>value - The value being set</li>
58305 * <li>originalValue - The original value for the field, before the edit.</li>
58306 * <li>row - The grid row index</li>
58307 * <li>column - The grid column index</li>
58309 * @param {Object} e An edit event (see above for description)
58311 "afteredit" : true,
58313 * @event validateedit
58314 * Fires after a cell is edited, but before the value is set in the record.
58315 * You can use this to modify the value being set in the field, Return false
58316 * to cancel the change. The edit event object has the following properties <br />
58317 * <ul style="padding:5px;padding-left:16px;">
58318 * <li>editor - This editor</li>
58319 * <li>grid - This grid</li>
58320 * <li>record - The record being edited</li>
58321 * <li>field - The field name being edited</li>
58322 * <li>value - The value being set</li>
58323 * <li>originalValue - The original value for the field, before the edit.</li>
58324 * <li>row - The grid row index</li>
58325 * <li>column - The grid column index</li>
58326 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58328 * @param {Object} e An edit event (see above for description)
58330 "validateedit" : true
58332 this.on("bodyscroll", this.stopEditing, this);
58333 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58336 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58338 * @cfg {Number} clicksToEdit
58339 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58346 trackMouseOver: false, // causes very odd FF errors
58348 onCellDblClick : function(g, row, col){
58349 this.startEditing(row, col);
58352 onEditComplete : function(ed, value, startValue){
58353 this.editing = false;
58354 this.activeEditor = null;
58355 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58357 var field = this.colModel.getDataIndex(ed.col);
58362 originalValue: startValue,
58369 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58372 if(String(value) !== String(startValue)){
58374 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58375 r.set(field, e.value);
58376 // if we are dealing with a combo box..
58377 // then we also set the 'name' colum to be the displayField
58378 if (ed.field.displayField && ed.field.name) {
58379 r.set(ed.field.name, ed.field.el.dom.value);
58382 delete e.cancel; //?? why!!!
58383 this.fireEvent("afteredit", e);
58386 this.fireEvent("afteredit", e); // always fire it!
58388 this.view.focusCell(ed.row, ed.col);
58392 * Starts editing the specified for the specified row/column
58393 * @param {Number} rowIndex
58394 * @param {Number} colIndex
58396 startEditing : function(row, col){
58397 this.stopEditing();
58398 if(this.colModel.isCellEditable(col, row)){
58399 this.view.ensureVisible(row, col, true);
58401 var r = this.dataSource.getAt(row);
58402 var field = this.colModel.getDataIndex(col);
58403 var cell = Roo.get(this.view.getCell(row,col));
58408 value: r.data[field],
58413 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58414 this.editing = true;
58415 var ed = this.colModel.getCellEditor(col, row);
58421 ed.render(ed.parentEl || document.body);
58427 (function(){ // complex but required for focus issues in safari, ie and opera
58431 ed.on("complete", this.onEditComplete, this, {single: true});
58432 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58433 this.activeEditor = ed;
58434 var v = r.data[field];
58435 ed.startEdit(this.view.getCell(row, col), v);
58436 // combo's with 'displayField and name set
58437 if (ed.field.displayField && ed.field.name) {
58438 ed.field.el.dom.value = r.data[ed.field.name];
58442 }).defer(50, this);
58448 * Stops any active editing
58450 stopEditing : function(){
58451 if(this.activeEditor){
58452 this.activeEditor.completeEdit();
58454 this.activeEditor = null;
58458 * Called to get grid's drag proxy text, by default returns this.ddText.
58461 getDragDropText : function(){
58462 var count = this.selModel.getSelectedCell() ? 1 : 0;
58463 return String.format(this.ddText, count, count == 1 ? '' : 's');
58468 * Ext JS Library 1.1.1
58469 * Copyright(c) 2006-2007, Ext JS, LLC.
58471 * Originally Released Under LGPL - original licence link has changed is not relivant.
58474 * <script type="text/javascript">
58477 // private - not really -- you end up using it !
58478 // This is a support class used internally by the Grid components
58481 * @class Roo.grid.GridEditor
58482 * @extends Roo.Editor
58483 * Class for creating and editable grid elements.
58484 * @param {Object} config any settings (must include field)
58486 Roo.grid.GridEditor = function(field, config){
58487 if (!config && field.field) {
58489 field = Roo.factory(config.field, Roo.form);
58491 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58492 field.monitorTab = false;
58495 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58498 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58501 alignment: "tl-tl",
58504 cls: "x-small-editor x-grid-editor",
58509 * Ext JS Library 1.1.1
58510 * Copyright(c) 2006-2007, Ext JS, LLC.
58512 * Originally Released Under LGPL - original licence link has changed is not relivant.
58515 * <script type="text/javascript">
58520 Roo.grid.PropertyRecord = Roo.data.Record.create([
58521 {name:'name',type:'string'}, 'value'
58525 Roo.grid.PropertyStore = function(grid, source){
58527 this.store = new Roo.data.Store({
58528 recordType : Roo.grid.PropertyRecord
58530 this.store.on('update', this.onUpdate, this);
58532 this.setSource(source);
58534 Roo.grid.PropertyStore.superclass.constructor.call(this);
58539 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58540 setSource : function(o){
58542 this.store.removeAll();
58545 if(this.isEditableValue(o[k])){
58546 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58549 this.store.loadRecords({records: data}, {}, true);
58552 onUpdate : function(ds, record, type){
58553 if(type == Roo.data.Record.EDIT){
58554 var v = record.data['value'];
58555 var oldValue = record.modified['value'];
58556 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58557 this.source[record.id] = v;
58559 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58566 getProperty : function(row){
58567 return this.store.getAt(row);
58570 isEditableValue: function(val){
58571 if(val && val instanceof Date){
58573 }else if(typeof val == 'object' || typeof val == 'function'){
58579 setValue : function(prop, value){
58580 this.source[prop] = value;
58581 this.store.getById(prop).set('value', value);
58584 getSource : function(){
58585 return this.source;
58589 Roo.grid.PropertyColumnModel = function(grid, store){
58592 g.PropertyColumnModel.superclass.constructor.call(this, [
58593 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58594 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58596 this.store = store;
58597 this.bselect = Roo.DomHelper.append(document.body, {
58598 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58599 {tag: 'option', value: 'true', html: 'true'},
58600 {tag: 'option', value: 'false', html: 'false'}
58603 Roo.id(this.bselect);
58606 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58607 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58608 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58609 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58610 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58612 this.renderCellDelegate = this.renderCell.createDelegate(this);
58613 this.renderPropDelegate = this.renderProp.createDelegate(this);
58616 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58620 valueText : 'Value',
58622 dateFormat : 'm/j/Y',
58625 renderDate : function(dateVal){
58626 return dateVal.dateFormat(this.dateFormat);
58629 renderBool : function(bVal){
58630 return bVal ? 'true' : 'false';
58633 isCellEditable : function(colIndex, rowIndex){
58634 return colIndex == 1;
58637 getRenderer : function(col){
58639 this.renderCellDelegate : this.renderPropDelegate;
58642 renderProp : function(v){
58643 return this.getPropertyName(v);
58646 renderCell : function(val){
58648 if(val instanceof Date){
58649 rv = this.renderDate(val);
58650 }else if(typeof val == 'boolean'){
58651 rv = this.renderBool(val);
58653 return Roo.util.Format.htmlEncode(rv);
58656 getPropertyName : function(name){
58657 var pn = this.grid.propertyNames;
58658 return pn && pn[name] ? pn[name] : name;
58661 getCellEditor : function(colIndex, rowIndex){
58662 var p = this.store.getProperty(rowIndex);
58663 var n = p.data['name'], val = p.data['value'];
58665 if(typeof(this.grid.customEditors[n]) == 'string'){
58666 return this.editors[this.grid.customEditors[n]];
58668 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58669 return this.grid.customEditors[n];
58671 if(val instanceof Date){
58672 return this.editors['date'];
58673 }else if(typeof val == 'number'){
58674 return this.editors['number'];
58675 }else if(typeof val == 'boolean'){
58676 return this.editors['boolean'];
58678 return this.editors['string'];
58684 * @class Roo.grid.PropertyGrid
58685 * @extends Roo.grid.EditorGrid
58686 * This class represents the interface of a component based property grid control.
58687 * <br><br>Usage:<pre><code>
58688 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58696 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58697 * The container MUST have some type of size defined for the grid to fill. The container will be
58698 * automatically set to position relative if it isn't already.
58699 * @param {Object} config A config object that sets properties on this grid.
58701 Roo.grid.PropertyGrid = function(container, config){
58702 config = config || {};
58703 var store = new Roo.grid.PropertyStore(this);
58704 this.store = store;
58705 var cm = new Roo.grid.PropertyColumnModel(this, store);
58706 store.store.sort('name', 'ASC');
58707 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58710 enableColLock:false,
58711 enableColumnMove:false,
58713 trackMouseOver: false,
58716 this.getGridEl().addClass('x-props-grid');
58717 this.lastEditRow = null;
58718 this.on('columnresize', this.onColumnResize, this);
58721 * @event beforepropertychange
58722 * Fires before a property changes (return false to stop?)
58723 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58724 * @param {String} id Record Id
58725 * @param {String} newval New Value
58726 * @param {String} oldval Old Value
58728 "beforepropertychange": true,
58730 * @event propertychange
58731 * Fires after a property changes
58732 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58733 * @param {String} id Record Id
58734 * @param {String} newval New Value
58735 * @param {String} oldval Old Value
58737 "propertychange": true
58739 this.customEditors = this.customEditors || {};
58741 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58744 * @cfg {Object} customEditors map of colnames=> custom editors.
58745 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58746 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58747 * false disables editing of the field.
58751 * @cfg {Object} propertyNames map of property Names to their displayed value
58754 render : function(){
58755 Roo.grid.PropertyGrid.superclass.render.call(this);
58756 this.autoSize.defer(100, this);
58759 autoSize : function(){
58760 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58762 this.view.fitColumns();
58766 onColumnResize : function(){
58767 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58771 * Sets the data for the Grid
58772 * accepts a Key => Value object of all the elements avaiable.
58773 * @param {Object} data to appear in grid.
58775 setSource : function(source){
58776 this.store.setSource(source);
58780 * Gets all the data from the grid.
58781 * @return {Object} data data stored in grid
58783 getSource : function(){
58784 return this.store.getSource();
58793 * @class Roo.grid.Calendar
58794 * @extends Roo.util.Grid
58795 * This class extends the Grid to provide a calendar widget
58796 * <br><br>Usage:<pre><code>
58797 var grid = new Roo.grid.Calendar("my-container-id", {
58800 selModel: mySelectionModel,
58801 autoSizeColumns: true,
58802 monitorWindowResize: false,
58803 trackMouseOver: true
58804 eventstore : real data store..
58810 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58811 * The container MUST have some type of size defined for the grid to fill. The container will be
58812 * automatically set to position relative if it isn't already.
58813 * @param {Object} config A config object that sets properties on this grid.
58815 Roo.grid.Calendar = function(container, config){
58816 // initialize the container
58817 this.container = Roo.get(container);
58818 this.container.update("");
58819 this.container.setStyle("overflow", "hidden");
58820 this.container.addClass('x-grid-container');
58822 this.id = this.container.id;
58824 Roo.apply(this, config);
58825 // check and correct shorthanded configs
58829 for (var r = 0;r < 6;r++) {
58832 for (var c =0;c < 7;c++) {
58836 if (this.eventStore) {
58837 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58838 this.eventStore.on('load',this.onLoad, this);
58839 this.eventStore.on('beforeload',this.clearEvents, this);
58843 this.dataSource = new Roo.data.Store({
58844 proxy: new Roo.data.MemoryProxy(rows),
58845 reader: new Roo.data.ArrayReader({}, [
58846 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58849 this.dataSource.load();
58850 this.ds = this.dataSource;
58851 this.ds.xmodule = this.xmodule || false;
58854 var cellRender = function(v,x,r)
58856 return String.format(
58857 '<div class="fc-day fc-widget-content"><div>' +
58858 '<div class="fc-event-container"></div>' +
58859 '<div class="fc-day-number">{0}</div>'+
58861 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
58862 '</div></div>', v);
58867 this.colModel = new Roo.grid.ColumnModel( [
58869 xtype: 'ColumnModel',
58871 dataIndex : 'weekday0',
58873 renderer : cellRender
58876 xtype: 'ColumnModel',
58878 dataIndex : 'weekday1',
58880 renderer : cellRender
58883 xtype: 'ColumnModel',
58885 dataIndex : 'weekday2',
58886 header : 'Tuesday',
58887 renderer : cellRender
58890 xtype: 'ColumnModel',
58892 dataIndex : 'weekday3',
58893 header : 'Wednesday',
58894 renderer : cellRender
58897 xtype: 'ColumnModel',
58899 dataIndex : 'weekday4',
58900 header : 'Thursday',
58901 renderer : cellRender
58904 xtype: 'ColumnModel',
58906 dataIndex : 'weekday5',
58908 renderer : cellRender
58911 xtype: 'ColumnModel',
58913 dataIndex : 'weekday6',
58914 header : 'Saturday',
58915 renderer : cellRender
58918 this.cm = this.colModel;
58919 this.cm.xmodule = this.xmodule || false;
58923 //this.selModel = new Roo.grid.CellSelectionModel();
58924 //this.sm = this.selModel;
58925 //this.selModel.init(this);
58929 this.container.setWidth(this.width);
58933 this.container.setHeight(this.height);
58940 * The raw click event for the entire grid.
58941 * @param {Roo.EventObject} e
58946 * The raw dblclick event for the entire grid.
58947 * @param {Roo.EventObject} e
58951 * @event contextmenu
58952 * The raw contextmenu event for the entire grid.
58953 * @param {Roo.EventObject} e
58955 "contextmenu" : true,
58958 * The raw mousedown event for the entire grid.
58959 * @param {Roo.EventObject} e
58961 "mousedown" : true,
58964 * The raw mouseup event for the entire grid.
58965 * @param {Roo.EventObject} e
58970 * The raw mouseover event for the entire grid.
58971 * @param {Roo.EventObject} e
58973 "mouseover" : true,
58976 * The raw mouseout event for the entire grid.
58977 * @param {Roo.EventObject} e
58982 * The raw keypress event for the entire grid.
58983 * @param {Roo.EventObject} e
58988 * The raw keydown event for the entire grid.
58989 * @param {Roo.EventObject} e
58997 * Fires when a cell is clicked
58998 * @param {Grid} this
58999 * @param {Number} rowIndex
59000 * @param {Number} columnIndex
59001 * @param {Roo.EventObject} e
59003 "cellclick" : true,
59005 * @event celldblclick
59006 * Fires when a cell is double clicked
59007 * @param {Grid} this
59008 * @param {Number} rowIndex
59009 * @param {Number} columnIndex
59010 * @param {Roo.EventObject} e
59012 "celldblclick" : true,
59015 * Fires when a row is clicked
59016 * @param {Grid} this
59017 * @param {Number} rowIndex
59018 * @param {Roo.EventObject} e
59022 * @event rowdblclick
59023 * Fires when a row is double clicked
59024 * @param {Grid} this
59025 * @param {Number} rowIndex
59026 * @param {Roo.EventObject} e
59028 "rowdblclick" : true,
59030 * @event headerclick
59031 * Fires when a header is clicked
59032 * @param {Grid} this
59033 * @param {Number} columnIndex
59034 * @param {Roo.EventObject} e
59036 "headerclick" : true,
59038 * @event headerdblclick
59039 * Fires when a header cell is double clicked
59040 * @param {Grid} this
59041 * @param {Number} columnIndex
59042 * @param {Roo.EventObject} e
59044 "headerdblclick" : true,
59046 * @event rowcontextmenu
59047 * Fires when a row is right clicked
59048 * @param {Grid} this
59049 * @param {Number} rowIndex
59050 * @param {Roo.EventObject} e
59052 "rowcontextmenu" : true,
59054 * @event cellcontextmenu
59055 * Fires when a cell is right clicked
59056 * @param {Grid} this
59057 * @param {Number} rowIndex
59058 * @param {Number} cellIndex
59059 * @param {Roo.EventObject} e
59061 "cellcontextmenu" : true,
59063 * @event headercontextmenu
59064 * Fires when a header is right clicked
59065 * @param {Grid} this
59066 * @param {Number} columnIndex
59067 * @param {Roo.EventObject} e
59069 "headercontextmenu" : true,
59071 * @event bodyscroll
59072 * Fires when the body element is scrolled
59073 * @param {Number} scrollLeft
59074 * @param {Number} scrollTop
59076 "bodyscroll" : true,
59078 * @event columnresize
59079 * Fires when the user resizes a column
59080 * @param {Number} columnIndex
59081 * @param {Number} newSize
59083 "columnresize" : true,
59085 * @event columnmove
59086 * Fires when the user moves a column
59087 * @param {Number} oldIndex
59088 * @param {Number} newIndex
59090 "columnmove" : true,
59093 * Fires when row(s) start being dragged
59094 * @param {Grid} this
59095 * @param {Roo.GridDD} dd The drag drop object
59096 * @param {event} e The raw browser event
59098 "startdrag" : true,
59101 * Fires when a drag operation is complete
59102 * @param {Grid} this
59103 * @param {Roo.GridDD} dd The drag drop object
59104 * @param {event} e The raw browser event
59109 * Fires when dragged row(s) are dropped on a valid DD target
59110 * @param {Grid} this
59111 * @param {Roo.GridDD} dd The drag drop object
59112 * @param {String} targetId The target drag drop object
59113 * @param {event} e The raw browser event
59118 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59119 * @param {Grid} this
59120 * @param {Roo.GridDD} dd The drag drop object
59121 * @param {String} targetId The target drag drop object
59122 * @param {event} e The raw browser event
59127 * Fires when the dragged row(s) first cross another DD target while being dragged
59128 * @param {Grid} this
59129 * @param {Roo.GridDD} dd The drag drop object
59130 * @param {String} targetId The target drag drop object
59131 * @param {event} e The raw browser event
59133 "dragenter" : true,
59136 * Fires when the dragged row(s) leave another DD target while being dragged
59137 * @param {Grid} this
59138 * @param {Roo.GridDD} dd The drag drop object
59139 * @param {String} targetId The target drag drop object
59140 * @param {event} e The raw browser event
59145 * Fires when a row is rendered, so you can change add a style to it.
59146 * @param {GridView} gridview The grid view
59147 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59153 * Fires when the grid is rendered
59154 * @param {Grid} grid
59159 * Fires when a date is selected
59160 * @param {DatePicker} this
59161 * @param {Date} date The selected date
59165 * @event monthchange
59166 * Fires when the displayed month changes
59167 * @param {DatePicker} this
59168 * @param {Date} date The selected month
59170 'monthchange': true,
59172 * @event evententer
59173 * Fires when mouse over an event
59174 * @param {Calendar} this
59175 * @param {event} Event
59177 'evententer': true,
59179 * @event eventleave
59180 * Fires when the mouse leaves an
59181 * @param {Calendar} this
59184 'eventleave': true,
59186 * @event eventclick
59187 * Fires when the mouse click an
59188 * @param {Calendar} this
59191 'eventclick': true,
59193 * @event eventrender
59194 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59195 * @param {Calendar} this
59196 * @param {data} data to be modified
59198 'eventrender': true
59202 Roo.grid.Grid.superclass.constructor.call(this);
59203 this.on('render', function() {
59204 this.view.el.addClass('x-grid-cal');
59206 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59210 if (!Roo.grid.Calendar.style) {
59211 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59214 '.x-grid-cal .x-grid-col' : {
59215 height: 'auto !important',
59216 'vertical-align': 'top'
59218 '.x-grid-cal .fc-event-hori' : {
59229 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59231 * @cfg {Store} eventStore The store that loads events.
59236 activeDate : false,
59239 monitorWindowResize : false,
59242 resizeColumns : function() {
59243 var col = (this.view.el.getWidth() / 7) - 3;
59244 // loop through cols, and setWidth
59245 for(var i =0 ; i < 7 ; i++){
59246 this.cm.setColumnWidth(i, col);
59249 setDate :function(date) {
59251 Roo.log('setDate?');
59253 this.resizeColumns();
59254 var vd = this.activeDate;
59255 this.activeDate = date;
59256 // if(vd && this.el){
59257 // var t = date.getTime();
59258 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59259 // Roo.log('using add remove');
59261 // this.fireEvent('monthchange', this, date);
59263 // this.cells.removeClass("fc-state-highlight");
59264 // this.cells.each(function(c){
59265 // if(c.dateValue == t){
59266 // c.addClass("fc-state-highlight");
59267 // setTimeout(function(){
59268 // try{c.dom.firstChild.focus();}catch(e){}
59278 var days = date.getDaysInMonth();
59280 var firstOfMonth = date.getFirstDateOfMonth();
59281 var startingPos = firstOfMonth.getDay()-this.startDay;
59283 if(startingPos < this.startDay){
59287 var pm = date.add(Date.MONTH, -1);
59288 var prevStart = pm.getDaysInMonth()-startingPos;
59292 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59294 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59295 //this.cells.addClassOnOver('fc-state-hover');
59297 var cells = this.cells.elements;
59298 var textEls = this.textNodes;
59300 //Roo.each(cells, function(cell){
59301 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59304 days += startingPos;
59306 // convert everything to numbers so it's fast
59307 var day = 86400000;
59308 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59311 //Roo.log(prevStart);
59313 var today = new Date().clearTime().getTime();
59314 var sel = date.clearTime().getTime();
59315 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59316 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59317 var ddMatch = this.disabledDatesRE;
59318 var ddText = this.disabledDatesText;
59319 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59320 var ddaysText = this.disabledDaysText;
59321 var format = this.format;
59323 var setCellClass = function(cal, cell){
59325 //Roo.log('set Cell Class');
59327 var t = d.getTime();
59332 cell.dateValue = t;
59334 cell.className += " fc-today";
59335 cell.className += " fc-state-highlight";
59336 cell.title = cal.todayText;
59339 // disable highlight in other month..
59340 cell.className += " fc-state-highlight";
59345 //cell.className = " fc-state-disabled";
59346 cell.title = cal.minText;
59350 //cell.className = " fc-state-disabled";
59351 cell.title = cal.maxText;
59355 if(ddays.indexOf(d.getDay()) != -1){
59356 // cell.title = ddaysText;
59357 // cell.className = " fc-state-disabled";
59360 if(ddMatch && format){
59361 var fvalue = d.dateFormat(format);
59362 if(ddMatch.test(fvalue)){
59363 cell.title = ddText.replace("%0", fvalue);
59364 cell.className = " fc-state-disabled";
59368 if (!cell.initialClassName) {
59369 cell.initialClassName = cell.dom.className;
59372 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59377 for(; i < startingPos; i++) {
59378 cells[i].dayName = (++prevStart);
59379 Roo.log(textEls[i]);
59380 d.setDate(d.getDate()+1);
59382 //cells[i].className = "fc-past fc-other-month";
59383 setCellClass(this, cells[i]);
59388 for(; i < days; i++){
59389 intDay = i - startingPos + 1;
59390 cells[i].dayName = (intDay);
59391 d.setDate(d.getDate()+1);
59393 cells[i].className = ''; // "x-date-active";
59394 setCellClass(this, cells[i]);
59398 for(; i < 42; i++) {
59399 //textEls[i].innerHTML = (++extraDays);
59401 d.setDate(d.getDate()+1);
59402 cells[i].dayName = (++extraDays);
59403 cells[i].className = "fc-future fc-other-month";
59404 setCellClass(this, cells[i]);
59407 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59409 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59411 // this will cause all the cells to mis
59414 for (var r = 0;r < 6;r++) {
59415 for (var c =0;c < 7;c++) {
59416 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59420 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59421 for(i=0;i<cells.length;i++) {
59423 this.cells.elements[i].dayName = cells[i].dayName ;
59424 this.cells.elements[i].className = cells[i].className;
59425 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59426 this.cells.elements[i].title = cells[i].title ;
59427 this.cells.elements[i].dateValue = cells[i].dateValue ;
59433 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59434 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59436 ////if(totalRows != 6){
59437 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59438 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59441 this.fireEvent('monthchange', this, date);
59446 * Returns the grid's SelectionModel.
59447 * @return {SelectionModel}
59449 getSelectionModel : function(){
59450 if(!this.selModel){
59451 this.selModel = new Roo.grid.CellSelectionModel();
59453 return this.selModel;
59457 this.eventStore.load()
59463 findCell : function(dt) {
59464 dt = dt.clearTime().getTime();
59466 this.cells.each(function(c){
59467 //Roo.log("check " +c.dateValue + '?=' + dt);
59468 if(c.dateValue == dt){
59478 findCells : function(rec) {
59479 var s = rec.data.start_dt.clone().clearTime().getTime();
59481 var e= rec.data.end_dt.clone().clearTime().getTime();
59484 this.cells.each(function(c){
59485 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59487 if(c.dateValue > e){
59490 if(c.dateValue < s){
59499 findBestRow: function(cells)
59503 for (var i =0 ; i < cells.length;i++) {
59504 ret = Math.max(cells[i].rows || 0,ret);
59511 addItem : function(rec)
59513 // look for vertical location slot in
59514 var cells = this.findCells(rec);
59516 rec.row = this.findBestRow(cells);
59518 // work out the location.
59522 for(var i =0; i < cells.length; i++) {
59530 if (crow.start.getY() == cells[i].getY()) {
59532 crow.end = cells[i];
59548 for (var i = 0; i < cells.length;i++) {
59549 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59556 clearEvents: function() {
59558 if (!this.eventStore.getCount()) {
59561 // reset number of rows in cells.
59562 Roo.each(this.cells.elements, function(c){
59566 this.eventStore.each(function(e) {
59567 this.clearEvent(e);
59572 clearEvent : function(ev)
59575 Roo.each(ev.els, function(el) {
59576 el.un('mouseenter' ,this.onEventEnter, this);
59577 el.un('mouseleave' ,this.onEventLeave, this);
59585 renderEvent : function(ev,ctr) {
59587 ctr = this.view.el.select('.fc-event-container',true).first();
59591 this.clearEvent(ev);
59597 var cells = ev.cells;
59598 var rows = ev.rows;
59599 this.fireEvent('eventrender', this, ev);
59601 for(var i =0; i < rows.length; i++) {
59605 cls += ' fc-event-start';
59607 if ((i+1) == rows.length) {
59608 cls += ' fc-event-end';
59611 //Roo.log(ev.data);
59612 // how many rows should it span..
59613 var cg = this.eventTmpl.append(ctr,Roo.apply({
59616 }, ev.data) , true);
59619 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59620 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59621 cg.on('click', this.onEventClick, this, ev);
59625 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59626 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59629 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59630 cg.setWidth(ebox.right - sbox.x -2);
59634 renderEvents: function()
59636 // first make sure there is enough space..
59638 if (!this.eventTmpl) {
59639 this.eventTmpl = new Roo.Template(
59640 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59641 '<div class="fc-event-inner">' +
59642 '<span class="fc-event-time">{time}</span>' +
59643 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59645 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59653 this.cells.each(function(c) {
59654 //Roo.log(c.select('.fc-day-content div',true).first());
59655 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59658 var ctr = this.view.el.select('.fc-event-container',true).first();
59661 this.eventStore.each(function(ev){
59663 this.renderEvent(ev);
59667 this.view.layout();
59671 onEventEnter: function (e, el,event,d) {
59672 this.fireEvent('evententer', this, el, event);
59675 onEventLeave: function (e, el,event,d) {
59676 this.fireEvent('eventleave', this, el, event);
59679 onEventClick: function (e, el,event,d) {
59680 this.fireEvent('eventclick', this, el, event);
59683 onMonthChange: function () {
59687 onLoad: function () {
59689 //Roo.log('calendar onload');
59691 if(this.eventStore.getCount() > 0){
59695 this.eventStore.each(function(d){
59700 if (typeof(add.end_dt) == 'undefined') {
59701 Roo.log("Missing End time in calendar data: ");
59705 if (typeof(add.start_dt) == 'undefined') {
59706 Roo.log("Missing Start time in calendar data: ");
59710 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59711 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59712 add.id = add.id || d.id;
59713 add.title = add.title || '??';
59721 this.renderEvents();
59731 render : function ()
59735 if (!this.view.el.hasClass('course-timesheet')) {
59736 this.view.el.addClass('course-timesheet');
59738 if (this.tsStyle) {
59743 Roo.log(_this.grid.view.el.getWidth());
59746 this.tsStyle = Roo.util.CSS.createStyleSheet({
59747 '.course-timesheet .x-grid-row' : {
59750 '.x-grid-row td' : {
59751 'vertical-align' : 0
59753 '.course-edit-link' : {
59755 'text-overflow' : 'ellipsis',
59756 'overflow' : 'hidden',
59757 'white-space' : 'nowrap',
59758 'cursor' : 'pointer'
59763 '.de-act-sup-link' : {
59764 'color' : 'purple',
59765 'text-decoration' : 'line-through'
59769 'text-decoration' : 'line-through'
59771 '.course-timesheet .course-highlight' : {
59772 'border-top-style': 'dashed !important',
59773 'border-bottom-bottom': 'dashed !important'
59775 '.course-timesheet .course-item' : {
59776 'font-family' : 'tahoma, arial, helvetica',
59777 'font-size' : '11px',
59778 'overflow' : 'hidden',
59779 'padding-left' : '10px',
59780 'padding-right' : '10px',
59781 'padding-top' : '10px'
59789 monitorWindowResize : false,
59790 cellrenderer : function(v,x,r)
59795 xtype: 'CellSelectionModel',
59802 beforeload : function (_self, options)
59804 options.params = options.params || {};
59805 options.params._month = _this.monthField.getValue();
59806 options.params.limit = 9999;
59807 options.params['sort'] = 'when_dt';
59808 options.params['dir'] = 'ASC';
59809 this.proxy.loadResponse = this.loadResponse;
59811 //this.addColumns();
59813 load : function (_self, records, options)
59815 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59816 // if you click on the translation.. you can edit it...
59817 var el = Roo.get(this);
59818 var id = el.dom.getAttribute('data-id');
59819 var d = el.dom.getAttribute('data-date');
59820 var t = el.dom.getAttribute('data-time');
59821 //var id = this.child('span').dom.textContent;
59824 Pman.Dialog.CourseCalendar.show({
59828 productitem_active : id ? 1 : 0
59830 _this.grid.ds.load({});
59835 _this.panel.fireEvent('resize', [ '', '' ]);
59838 loadResponse : function(o, success, response){
59839 // this is overridden on before load..
59841 Roo.log("our code?");
59842 //Roo.log(success);
59843 //Roo.log(response)
59844 delete this.activeRequest;
59846 this.fireEvent("loadexception", this, o, response);
59847 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59852 result = o.reader.read(response);
59854 Roo.log("load exception?");
59855 this.fireEvent("loadexception", this, o, response, e);
59856 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59859 Roo.log("ready...");
59860 // loop through result.records;
59861 // and set this.tdate[date] = [] << array of records..
59863 Roo.each(result.records, function(r){
59865 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
59866 _this.tdata[r.data.when_dt.format('j')] = [];
59868 _this.tdata[r.data.when_dt.format('j')].push(r.data);
59871 //Roo.log(_this.tdata);
59873 result.records = [];
59874 result.totalRecords = 6;
59876 // let's generate some duumy records for the rows.
59877 //var st = _this.dateField.getValue();
59879 // work out monday..
59880 //st = st.add(Date.DAY, -1 * st.format('w'));
59882 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59884 var firstOfMonth = date.getFirstDayOfMonth();
59885 var days = date.getDaysInMonth();
59887 var firstAdded = false;
59888 for (var i = 0; i < result.totalRecords ; i++) {
59889 //var d= st.add(Date.DAY, i);
59892 for(var w = 0 ; w < 7 ; w++){
59893 if(!firstAdded && firstOfMonth != w){
59900 var dd = (d > 0 && d < 10) ? "0"+d : d;
59901 row['weekday'+w] = String.format(
59902 '<span style="font-size: 16px;"><b>{0}</b></span>'+
59903 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
59905 date.format('Y-m-')+dd
59908 if(typeof(_this.tdata[d]) != 'undefined'){
59909 Roo.each(_this.tdata[d], function(r){
59913 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
59914 if(r.parent_id*1>0){
59915 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
59918 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
59919 deactive = 'de-act-link';
59922 row['weekday'+w] += String.format(
59923 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
59925 r.product_id_name, //1
59926 r.when_dt.format('h:ia'), //2
59936 // only do this if something added..
59938 result.records.push(_this.grid.dataSource.reader.newRow(row));
59942 // push it twice. (second one with an hour..
59946 this.fireEvent("load", this, o, o.request.arg);
59947 o.request.callback.call(o.request.scope, result, o.request.arg, true);
59949 sortInfo : {field: 'when_dt', direction : 'ASC' },
59951 xtype: 'HttpProxy',
59954 url : baseURL + '/Roo/Shop_course.php'
59957 xtype: 'JsonReader',
59974 'name': 'parent_id',
59978 'name': 'product_id',
59982 'name': 'productitem_id',
60000 click : function (_self, e)
60002 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60003 sd.setMonth(sd.getMonth()-1);
60004 _this.monthField.setValue(sd.format('Y-m-d'));
60005 _this.grid.ds.load({});
60011 xtype: 'Separator',
60015 xtype: 'MonthField',
60018 render : function (_self)
60020 _this.monthField = _self;
60021 // _this.monthField.set today
60023 select : function (combo, date)
60025 _this.grid.ds.load({});
60028 value : (function() { return new Date(); })()
60031 xtype: 'Separator',
60037 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60047 click : function (_self, e)
60049 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60050 sd.setMonth(sd.getMonth()+1);
60051 _this.monthField.setValue(sd.format('Y-m-d'));
60052 _this.grid.ds.load({});
60065 * Ext JS Library 1.1.1
60066 * Copyright(c) 2006-2007, Ext JS, LLC.
60068 * Originally Released Under LGPL - original licence link has changed is not relivant.
60071 * <script type="text/javascript">
60075 * @class Roo.LoadMask
60076 * A simple utility class for generically masking elements while loading data. If the element being masked has
60077 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60078 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60079 * element's UpdateManager load indicator and will be destroyed after the initial load.
60081 * Create a new LoadMask
60082 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60083 * @param {Object} config The config object
60085 Roo.LoadMask = function(el, config){
60086 this.el = Roo.get(el);
60087 Roo.apply(this, config);
60089 this.store.on('beforeload', this.onBeforeLoad, this);
60090 this.store.on('load', this.onLoad, this);
60091 this.store.on('loadexception', this.onLoadException, this);
60092 this.removeMask = false;
60094 var um = this.el.getUpdateManager();
60095 um.showLoadIndicator = false; // disable the default indicator
60096 um.on('beforeupdate', this.onBeforeLoad, this);
60097 um.on('update', this.onLoad, this);
60098 um.on('failure', this.onLoad, this);
60099 this.removeMask = true;
60103 Roo.LoadMask.prototype = {
60105 * @cfg {Boolean} removeMask
60106 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60107 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60110 * @cfg {String} msg
60111 * The text to display in a centered loading message box (defaults to 'Loading...')
60113 msg : 'Loading...',
60115 * @cfg {String} msgCls
60116 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60118 msgCls : 'x-mask-loading',
60121 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60127 * Disables the mask to prevent it from being displayed
60129 disable : function(){
60130 this.disabled = true;
60134 * Enables the mask so that it can be displayed
60136 enable : function(){
60137 this.disabled = false;
60140 onLoadException : function()
60142 Roo.log(arguments);
60144 if (typeof(arguments[3]) != 'undefined') {
60145 Roo.MessageBox.alert("Error loading",arguments[3]);
60149 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60150 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60159 this.el.unmask(this.removeMask);
60162 onLoad : function()
60164 this.el.unmask(this.removeMask);
60168 onBeforeLoad : function(){
60169 if(!this.disabled){
60170 this.el.mask(this.msg, this.msgCls);
60175 destroy : function(){
60177 this.store.un('beforeload', this.onBeforeLoad, this);
60178 this.store.un('load', this.onLoad, this);
60179 this.store.un('loadexception', this.onLoadException, this);
60181 var um = this.el.getUpdateManager();
60182 um.un('beforeupdate', this.onBeforeLoad, this);
60183 um.un('update', this.onLoad, this);
60184 um.un('failure', this.onLoad, this);
60189 * Ext JS Library 1.1.1
60190 * Copyright(c) 2006-2007, Ext JS, LLC.
60192 * Originally Released Under LGPL - original licence link has changed is not relivant.
60195 * <script type="text/javascript">
60200 * @class Roo.XTemplate
60201 * @extends Roo.Template
60202 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60204 var t = new Roo.XTemplate(
60205 '<select name="{name}">',
60206 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60210 // then append, applying the master template values
60213 * Supported features:
60218 {a_variable} - output encoded.
60219 {a_variable.format:("Y-m-d")} - call a method on the variable
60220 {a_variable:raw} - unencoded output
60221 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60222 {a_variable:this.method_on_template(...)} - call a method on the template object.
60227 <tpl for="a_variable or condition.."></tpl>
60228 <tpl if="a_variable or condition"></tpl>
60229 <tpl exec="some javascript"></tpl>
60230 <tpl name="named_template"></tpl> (experimental)
60232 <tpl for="."></tpl> - just iterate the property..
60233 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60237 Roo.XTemplate = function()
60239 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60246 Roo.extend(Roo.XTemplate, Roo.Template, {
60249 * The various sub templates
60254 * basic tag replacing syntax
60257 * // you can fake an object call by doing this
60261 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60264 * compile the template
60266 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60269 compile: function()
60273 s = ['<tpl>', s, '</tpl>'].join('');
60275 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60276 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60277 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60278 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60279 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60284 while(true == !!(m = s.match(re))){
60285 var forMatch = m[0].match(nameRe),
60286 ifMatch = m[0].match(ifRe),
60287 execMatch = m[0].match(execRe),
60288 namedMatch = m[0].match(namedRe),
60293 name = forMatch && forMatch[1] ? forMatch[1] : '';
60296 // if - puts fn into test..
60297 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60299 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60304 // exec - calls a function... returns empty if true is returned.
60305 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60307 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60315 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60316 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60317 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60320 var uid = namedMatch ? namedMatch[1] : id;
60324 id: namedMatch ? namedMatch[1] : id,
60331 s = s.replace(m[0], '');
60333 s = s.replace(m[0], '{xtpl'+ id + '}');
60338 for(var i = tpls.length-1; i >= 0; --i){
60339 this.compileTpl(tpls[i]);
60340 this.tpls[tpls[i].id] = tpls[i];
60342 this.master = tpls[tpls.length-1];
60346 * same as applyTemplate, except it's done to one of the subTemplates
60347 * when using named templates, you can do:
60349 * var str = pl.applySubTemplate('your-name', values);
60352 * @param {Number} id of the template
60353 * @param {Object} values to apply to template
60354 * @param {Object} parent (normaly the instance of this object)
60356 applySubTemplate : function(id, values, parent)
60360 var t = this.tpls[id];
60364 if(t.test && !t.test.call(this, values, parent)){
60368 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60369 Roo.log(e.toString());
60375 if(t.exec && t.exec.call(this, values, parent)){
60379 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60380 Roo.log(e.toString());
60385 var vs = t.target ? t.target.call(this, values, parent) : values;
60386 parent = t.target ? values : parent;
60387 if(t.target && vs instanceof Array){
60389 for(var i = 0, len = vs.length; i < len; i++){
60390 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60392 return buf.join('');
60394 return t.compiled.call(this, vs, parent);
60396 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60397 Roo.log(e.toString());
60398 Roo.log(t.compiled);
60403 compileTpl : function(tpl)
60405 var fm = Roo.util.Format;
60406 var useF = this.disableFormats !== true;
60407 var sep = Roo.isGecko ? "+" : ",";
60408 var undef = function(str) {
60409 Roo.log("Property not found :" + str);
60413 var fn = function(m, name, format, args)
60415 //Roo.log(arguments);
60416 args = args ? args.replace(/\\'/g,"'") : args;
60417 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60418 if (typeof(format) == 'undefined') {
60419 format= 'htmlEncode';
60421 if (format == 'raw' ) {
60425 if(name.substr(0, 4) == 'xtpl'){
60426 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60429 // build an array of options to determine if value is undefined..
60431 // basically get 'xxxx.yyyy' then do
60432 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60433 // (function () { Roo.log("Property not found"); return ''; })() :
60438 Roo.each(name.split('.'), function(st) {
60439 lookfor += (lookfor.length ? '.': '') + st;
60440 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60443 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60446 if(format && useF){
60448 args = args ? ',' + args : "";
60450 if(format.substr(0, 5) != "this."){
60451 format = "fm." + format + '(';
60453 format = 'this.call("'+ format.substr(5) + '", ';
60457 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60461 // called with xxyx.yuu:(test,test)
60463 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60465 // raw.. - :raw modifier..
60466 return "'"+ sep + udef_st + name + ")"+sep+"'";
60470 // branched to use + in gecko and [].join() in others
60472 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60473 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60476 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60477 body.push(tpl.body.replace(/(\r\n|\n)/g,
60478 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60479 body.push("'].join('');};};");
60480 body = body.join('');
60483 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60485 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60491 applyTemplate : function(values){
60492 return this.master.compiled.call(this, values, {});
60493 //var s = this.subs;
60496 apply : function(){
60497 return this.applyTemplate.apply(this, arguments);
60502 Roo.XTemplate.from = function(el){
60503 el = Roo.getDom(el);
60504 return new Roo.XTemplate(el.value || el.innerHTML);