4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isGecko = !isSafari && ua.indexOf("gecko") > -1,
61 isBorderBox = isIE && !isStrict,
62 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64 isLinux = (ua.indexOf("linux") != -1),
65 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66 isIOS = /iphone|ipad/.test(ua),
67 isTouch = (function() {
69 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
70 window.addEventListener('touchstart', function __set_has_touch__ () {
72 window.removeEventListener('touchstart', __set_has_touch__);
74 return false; // no touch on chrome!?
76 document.createEvent("TouchEvent");
83 // remove css image flicker
86 document.execCommand("BackgroundImageCache", false, true);
92 * True if the browser is in strict mode
97 * True if the page is running over SSL
102 * True when the document is fully initialized and ready for action
107 * Turn on debugging output (currently only the factory uses this)
114 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117 enableGarbageCollector : true,
120 * True to automatically purge event listeners after uncaching an element (defaults to false).
121 * Note: this only happens if enableGarbageCollector is true.
124 enableListenerCollection:false,
127 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
128 * the IE insecure content warning (defaults to javascript:false).
131 SSL_SECURE_URL : "javascript:false",
134 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
135 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
140 emptyFn : function(){},
143 * Copies all the properties of config to obj if they don't already exist.
144 * @param {Object} obj The receiver of the properties
145 * @param {Object} config The source of the properties
146 * @return {Object} returns obj
148 applyIf : function(o, c){
151 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
158 * Applies event listeners to elements by selectors when the document is ready.
159 * The event name is specified with an @ suffix.
162 // add a listener for click on all anchors in element with id foo
163 '#foo a@click' : function(e, t){
167 // add the same listener to multiple selectors (separated by comma BEFORE the @)
168 '#foo a, #bar span.some-class@mouseover' : function(){
173 * @param {Object} obj The list of behaviors to apply
175 addBehaviors : function(o){
177 Roo.onReady(function(){
182 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
184 var parts = b.split('@');
185 if(parts[1]){ // for Object prototype breakers
188 cache[s] = Roo.select(s);
190 cache[s].on(parts[1], o[b]);
197 * Generates unique ids. If the element already has an id, it is unchanged
198 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
199 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
200 * @return {String} The generated Id.
202 id : function(el, prefix){
203 prefix = prefix || "roo-gen";
205 var id = prefix + (++idSeed);
206 return el ? (el.id ? el.id : (el.id = id)) : id;
211 * Extends one class with another class and optionally overrides members with the passed literal. This class
212 * also adds the function "override()" to the class that can be used to override
213 * members on an instance.
214 * @param {Object} subclass The class inheriting the functionality
215 * @param {Object} superclass The class being extended
216 * @param {Object} overrides (optional) A literal with members
221 var io = function(o){
226 return function(sb, sp, overrides){
227 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230 sb = function(){sp.apply(this, arguments);};
232 var F = function(){}, sbp, spp = sp.prototype;
234 sbp = sb.prototype = new F();
238 if(spp.constructor == Object.prototype.constructor){
243 sb.override = function(o){
247 Roo.override(sb, overrides);
253 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
255 Roo.override(MyClass, {
256 newMethod1: function(){
259 newMethod2: function(foo){
264 * @param {Object} origclass The class to override
265 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
266 * containing one or more methods.
269 override : function(origclass, overrides){
271 var p = origclass.prototype;
272 for(var method in overrides){
273 p[method] = overrides[method];
278 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
280 Roo.namespace('Company', 'Company.data');
281 Company.Widget = function() { ... }
282 Company.data.CustomStore = function(config) { ... }
284 * @param {String} namespace1
285 * @param {String} namespace2
286 * @param {String} etc
289 namespace : function(){
290 var a=arguments, o=null, i, j, d, rt;
291 for (i=0; i<a.length; ++i) {
295 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
296 for (j=1; j<d.length; ++j) {
297 o[d[j]]=o[d[j]] || {};
303 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
305 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
306 Roo.factory(conf, Roo.data);
308 * @param {String} classname
309 * @param {String} namespace (optional)
313 factory : function(c, ns)
315 // no xtype, no ns or c.xns - or forced off by c.xns
316 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
319 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
320 if (c.constructor == ns[c.xtype]) {// already created...
324 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
325 var ret = new ns[c.xtype](c);
329 c.xns = false; // prevent recursion..
333 * Logs to console if it can.
335 * @param {String|Object} string
340 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
347 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
351 urlEncode : function(o){
357 var ov = o[key], k = Roo.encodeURIComponent(key);
358 var type = typeof ov;
359 if(type == 'undefined'){
361 }else if(type != "function" && type != "object"){
362 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
363 }else if(ov instanceof Array){
365 for(var i = 0, len = ov.length; i < len; i++) {
366 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
377 * Safe version of encodeURIComponent
378 * @param {String} data
382 encodeURIComponent : function (data)
385 return encodeURIComponent(data);
386 } catch(e) {} // should be an uri encode error.
388 if (data == '' || data == null){
391 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
392 function nibble_to_hex(nibble){
393 var chars = '0123456789ABCDEF';
394 return chars.charAt(nibble);
396 data = data.toString();
398 for(var i=0; i<data.length; i++){
399 var c = data.charCodeAt(i);
400 var bs = new Array();
403 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
404 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
405 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
406 bs[3] = 0x80 | (c & 0x3F);
407 }else if (c > 0x800){
409 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
410 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
411 bs[2] = 0x80 | (c & 0x3F);
414 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
415 bs[1] = 0x80 | (c & 0x3F);
420 for(var j=0; j<bs.length; j++){
422 var hex = nibble_to_hex((b & 0xF0) >>> 4)
423 + nibble_to_hex(b &0x0F);
432 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
433 * @param {String} string
434 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
435 * @return {Object} A literal with members
437 urlDecode : function(string, overwrite){
438 if(!string || !string.length){
442 var pairs = string.split('&');
443 var pair, name, value;
444 for(var i = 0, len = pairs.length; i < len; i++){
445 pair = pairs[i].split('=');
446 name = decodeURIComponent(pair[0]);
447 value = decodeURIComponent(pair[1]);
448 if(overwrite !== true){
449 if(typeof obj[name] == "undefined"){
451 }else if(typeof obj[name] == "string"){
452 obj[name] = [obj[name]];
453 obj[name].push(value);
455 obj[name].push(value);
465 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
466 * passed array is not really an array, your function is called once with it.
467 * The supplied function is called with (Object item, Number index, Array allItems).
468 * @param {Array/NodeList/Mixed} array
469 * @param {Function} fn
470 * @param {Object} scope
472 each : function(array, fn, scope){
473 if(typeof array.length == "undefined" || typeof array == "string"){
476 for(var i = 0, len = array.length; i < len; i++){
477 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
482 combine : function(){
483 var as = arguments, l = as.length, r = [];
484 for(var i = 0; i < l; i++){
486 if(a instanceof Array){
488 }else if(a.length !== undefined && !a.substr){
489 r = r.concat(Array.prototype.slice.call(a, 0));
498 * Escapes the passed string for use in a regular expression
499 * @param {String} str
502 escapeRe : function(s) {
503 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
507 callback : function(cb, scope, args, delay){
508 if(typeof cb == "function"){
510 cb.defer(delay, scope, args || []);
512 cb.apply(scope, args || []);
518 * Return the dom node for the passed string (id), dom node, or Roo.Element
519 * @param {String/HTMLElement/Roo.Element} el
520 * @return HTMLElement
522 getDom : function(el){
526 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
530 * Shorthand for {@link Roo.ComponentMgr#get}
532 * @return Roo.Component
534 getCmp : function(id){
535 return Roo.ComponentMgr.get(id);
538 num : function(v, defaultValue){
539 if(typeof v != 'number'){
545 destroy : function(){
546 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
550 as.removeAllListeners();
554 if(typeof as.purgeListeners == 'function'){
557 if(typeof as.destroy == 'function'){
564 // inpired by a similar function in mootools library
566 * Returns the type of object that is passed in. If the object passed in is null or undefined it
567 * return false otherwise it returns one of the following values:<ul>
568 * <li><b>string</b>: If the object passed is a string</li>
569 * <li><b>number</b>: If the object passed is a number</li>
570 * <li><b>boolean</b>: If the object passed is a boolean value</li>
571 * <li><b>function</b>: If the object passed is a function reference</li>
572 * <li><b>object</b>: If the object passed is an object</li>
573 * <li><b>array</b>: If the object passed is an array</li>
574 * <li><b>regexp</b>: If the object passed is a regular expression</li>
575 * <li><b>element</b>: If the object passed is a DOM Element</li>
576 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
577 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
578 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
579 * @param {Mixed} object
583 if(o === undefined || o === null){
590 if(t == 'object' && o.nodeName) {
592 case 1: return 'element';
593 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596 if(t == 'object' || t == 'function') {
597 switch(o.constructor) {
598 case Array: return 'array';
599 case RegExp: return 'regexp';
601 if(typeof o.length == 'number' && typeof o.item == 'function') {
609 * Returns true if the passed value is null, undefined or an empty string (optional).
610 * @param {Mixed} value The value to test
611 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614 isEmpty : function(v, allowBlank){
615 return v === null || v === undefined || (!allowBlank ? v === '' : false);
623 isFirefox : isFirefox,
633 isBorderBox : isBorderBox,
635 isWindows : isWindows,
646 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
647 * you may want to set this to true.
650 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
655 * Selects a single element as a Roo Element
656 * This is about as close as you can get to jQuery's $('do crazy stuff')
657 * @param {String} selector The selector/xpath query
658 * @param {Node} root (optional) The start of the query (defaults to document).
659 * @return {Roo.Element}
661 selectNode : function(selector, root)
663 var node = Roo.DomQuery.selectNode(selector,root);
664 return node ? Roo.get(node) : new Roo.Element(false);
672 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
673 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
676 "Roo.bootstrap.dash");
679 * Ext JS Library 1.1.1
680 * Copyright(c) 2006-2007, Ext JS, LLC.
682 * Originally Released Under LGPL - original licence link has changed is not relivant.
685 * <script type="text/javascript">
689 // wrappedn so fnCleanup is not in global scope...
691 function fnCleanUp() {
692 var p = Function.prototype;
693 delete p.createSequence;
695 delete p.createDelegate;
696 delete p.createCallback;
697 delete p.createInterceptor;
699 window.detachEvent("onunload", fnCleanUp);
701 window.attachEvent("onunload", fnCleanUp);
708 * These functions are available on every Function object (any JavaScript function).
710 Roo.apply(Function.prototype, {
712 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
713 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
714 * Will create a function that is bound to those 2 args.
715 * @return {Function} The new function
717 createCallback : function(/*args...*/){
718 // make args available, in function below
719 var args = arguments;
722 return method.apply(window, args);
727 * Creates a delegate (callback) that sets the scope to obj.
728 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
729 * Will create a function that is automatically scoped to this.
730 * @param {Object} obj (optional) The object for which the scope is set
731 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
732 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
733 * if a number the args are inserted at the specified position
734 * @return {Function} The new function
736 createDelegate : function(obj, args, appendArgs){
739 var callArgs = args || arguments;
740 if(appendArgs === true){
741 callArgs = Array.prototype.slice.call(arguments, 0);
742 callArgs = callArgs.concat(args);
743 }else if(typeof appendArgs == "number"){
744 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
745 var applyArgs = [appendArgs, 0].concat(args); // create method call params
746 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
748 return method.apply(obj || window, callArgs);
753 * Calls this function after the number of millseconds specified.
754 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
755 * @param {Object} obj (optional) The object for which the scope is set
756 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
757 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
758 * if a number the args are inserted at the specified position
759 * @return {Number} The timeout id that can be used with clearTimeout
761 defer : function(millis, obj, args, appendArgs){
762 var fn = this.createDelegate(obj, args, appendArgs);
764 return setTimeout(fn, millis);
770 * Create a combined function call sequence of the original function + the passed function.
771 * The resulting function returns the results of the original function.
772 * The passed fcn is called with the parameters of the original function
773 * @param {Function} fcn The function to sequence
774 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
775 * @return {Function} The new function
777 createSequence : function(fcn, scope){
778 if(typeof fcn != "function"){
783 var retval = method.apply(this || window, arguments);
784 fcn.apply(scope || this || window, arguments);
790 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
791 * The resulting function returns the results of the original function.
792 * The passed fcn is called with the parameters of the original function.
794 * @param {Function} fcn The function to call before the original
795 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
796 * @return {Function} The new function
798 createInterceptor : function(fcn, scope){
799 if(typeof fcn != "function"){
806 if(fcn.apply(scope || this || window, arguments) === false){
809 return method.apply(this || window, arguments);
815 * Ext JS Library 1.1.1
816 * Copyright(c) 2006-2007, Ext JS, LLC.
818 * Originally Released Under LGPL - original licence link has changed is not relivant.
821 * <script type="text/javascript">
824 Roo.applyIf(String, {
829 * Escapes the passed string for ' and \
830 * @param {String} string The string to escape
831 * @return {String} The escaped string
834 escape : function(string) {
835 return string.replace(/('|\\)/g, "\\$1");
839 * Pads the left side of a string with a specified character. This is especially useful
840 * for normalizing number and date strings. Example usage:
842 var s = String.leftPad('123', 5, '0');
843 // s now contains the string: '00123'
845 * @param {String} string The original string
846 * @param {Number} size The total length of the output string
847 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
848 * @return {String} The padded string
851 leftPad : function (val, size, ch) {
852 var result = new String(val);
853 if(ch === null || ch === undefined || ch === '') {
856 while (result.length < size) {
857 result = ch + result;
863 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
864 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
866 var cls = 'my-class', text = 'Some text';
867 var s = String.format('<div class="{0}">{1}</div>', cls, text);
868 // s now contains the string: '<div class="my-class">Some text</div>'
870 * @param {String} string The tokenized string to be formatted
871 * @param {String} value1 The value to replace token {0}
872 * @param {String} value2 Etc...
873 * @return {String} The formatted string
876 format : function(format){
877 var args = Array.prototype.slice.call(arguments, 1);
878 return format.replace(/\{(\d+)\}/g, function(m, i){
879 return Roo.util.Format.htmlEncode(args[i]);
885 * Utility function that allows you to easily switch a string between two alternating values. The passed value
886 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
887 * they are already different, the first value passed in is returned. Note that this method returns the new value
888 * but does not change the current string.
890 // alternate sort directions
891 sort = sort.toggle('ASC', 'DESC');
893 // instead of conditional logic:
894 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
896 * @param {String} value The value to compare to the current string
897 * @param {String} other The new value to use if the string already equals the first value passed in
898 * @return {String} The new value
901 String.prototype.toggle = function(value, other){
902 return this == value ? other : value;
905 * Ext JS Library 1.1.1
906 * Copyright(c) 2006-2007, Ext JS, LLC.
908 * Originally Released Under LGPL - original licence link has changed is not relivant.
911 * <script type="text/javascript">
917 Roo.applyIf(Number.prototype, {
919 * Checks whether or not the current number is within a desired range. If the number is already within the
920 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
921 * exceeded. Note that this method returns the constrained value but does not change the current number.
922 * @param {Number} min The minimum number in the range
923 * @param {Number} max The maximum number in the range
924 * @return {Number} The constrained value if outside the range, otherwise the current value
926 constrain : function(min, max){
927 return Math.min(Math.max(this, min), max);
931 * Ext JS Library 1.1.1
932 * Copyright(c) 2006-2007, Ext JS, LLC.
934 * Originally Released Under LGPL - original licence link has changed is not relivant.
937 * <script type="text/javascript">
942 Roo.applyIf(Array.prototype, {
945 * Checks whether or not the specified object exists in the array.
946 * @param {Object} o The object to check for
947 * @return {Number} The index of o in the array (or -1 if it is not found)
949 indexOf : function(o){
950 for (var i = 0, len = this.length; i < len; i++){
951 if(this[i] == o) { return i; }
957 * Removes the specified object from the array. If the object is not found nothing happens.
958 * @param {Object} o The object to remove
960 remove : function(o){
961 var index = this.indexOf(o);
963 this.splice(index, 1);
967 * Map (JS 1.6 compatibility)
968 * @param {Function} function to call
972 var len = this.length >>> 0;
973 if (typeof fun != "function") {
974 throw new TypeError();
976 var res = new Array(len);
977 var thisp = arguments[1];
978 for (var i = 0; i < len; i++)
981 res[i] = fun.call(thisp, this[i], i, this);
994 * Ext JS Library 1.1.1
995 * Copyright(c) 2006-2007, Ext JS, LLC.
997 * Originally Released Under LGPL - original licence link has changed is not relivant.
1000 * <script type="text/javascript">
1006 * The date parsing and format syntax is a subset of
1007 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1008 * supported will provide results equivalent to their PHP versions.
1010 * Following is the list of all currently supported formats:
1013 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1015 Format Output Description
1016 ------ ---------- --------------------------------------------------------------
1017 d 10 Day of the month, 2 digits with leading zeros
1018 D Wed A textual representation of a day, three letters
1019 j 10 Day of the month without leading zeros
1020 l Wednesday A full textual representation of the day of the week
1021 S th English ordinal day of month suffix, 2 chars (use with j)
1022 w 3 Numeric representation of the day of the week
1023 z 9 The julian date, or day of the year (0-365)
1024 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1025 F January A full textual representation of the month
1026 m 01 Numeric representation of a month, with leading zeros
1027 M Jan Month name abbreviation, three letters
1028 n 1 Numeric representation of a month, without leading zeros
1029 t 31 Number of days in the given month
1030 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1031 Y 2007 A full numeric representation of a year, 4 digits
1032 y 07 A two digit representation of a year
1033 a pm Lowercase Ante meridiem and Post meridiem
1034 A PM Uppercase Ante meridiem and Post meridiem
1035 g 3 12-hour format of an hour without leading zeros
1036 G 15 24-hour format of an hour without leading zeros
1037 h 03 12-hour format of an hour with leading zeros
1038 H 15 24-hour format of an hour with leading zeros
1039 i 05 Minutes with leading zeros
1040 s 01 Seconds, with leading zeros
1041 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1042 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1043 T CST Timezone setting of the machine running the code
1044 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1047 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1049 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1050 document.write(dt.format('Y-m-d')); //2007-01-10
1051 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1052 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1055 * Here are some standard date/time patterns that you might find helpful. They
1056 * are not part of the source of Date.js, but to use them you can simply copy this
1057 * block of code into any script that is included after Date.js and they will also become
1058 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1061 ISO8601Long:"Y-m-d H:i:s",
1062 ISO8601Short:"Y-m-d",
1064 LongDate: "l, F d, Y",
1065 FullDateTime: "l, F d, Y g:i:s A",
1068 LongTime: "g:i:s A",
1069 SortableDateTime: "Y-m-d\\TH:i:s",
1070 UniversalSortableDateTime: "Y-m-d H:i:sO",
1077 var dt = new Date();
1078 document.write(dt.format(Date.patterns.ShortDate));
1083 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1084 * They generate precompiled functions from date formats instead of parsing and
1085 * processing the pattern every time you format a date. These functions are available
1086 * on every Date object (any javascript function).
1088 * The original article and download are here:
1089 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1096 Returns the number of milliseconds between this date and date
1097 @param {Date} date (optional) Defaults to now
1098 @return {Number} The diff in milliseconds
1099 @member Date getElapsed
1101 Date.prototype.getElapsed = function(date) {
1102 return Math.abs((date || new Date()).getTime()-this.getTime());
1104 // was in date file..
1108 Date.parseFunctions = {count:0};
1110 Date.parseRegexes = [];
1112 Date.formatFunctions = {count:0};
1115 Date.prototype.dateFormat = function(format) {
1116 if (Date.formatFunctions[format] == null) {
1117 Date.createNewFormat(format);
1119 var func = Date.formatFunctions[format];
1120 return this[func]();
1125 * Formats a date given the supplied format string
1126 * @param {String} format The format string
1127 * @return {String} The formatted date
1130 Date.prototype.format = Date.prototype.dateFormat;
1133 Date.createNewFormat = function(format) {
1134 var funcName = "format" + Date.formatFunctions.count++;
1135 Date.formatFunctions[format] = funcName;
1136 var code = "Date.prototype." + funcName + " = function(){return ";
1137 var special = false;
1139 for (var i = 0; i < format.length; ++i) {
1140 ch = format.charAt(i);
1141 if (!special && ch == "\\") {
1146 code += "'" + String.escape(ch) + "' + ";
1149 code += Date.getFormatCode(ch);
1152 /** eval:var:zzzzzzzzzzzzz */
1153 eval(code.substring(0, code.length - 3) + ";}");
1157 Date.getFormatCode = function(character) {
1158 switch (character) {
1160 return "String.leftPad(this.getDate(), 2, '0') + ";
1162 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1164 return "this.getDate() + ";
1166 return "Date.dayNames[this.getDay()] + ";
1168 return "this.getSuffix() + ";
1170 return "this.getDay() + ";
1172 return "this.getDayOfYear() + ";
1174 return "this.getWeekOfYear() + ";
1176 return "Date.monthNames[this.getMonth()] + ";
1178 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1180 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1182 return "(this.getMonth() + 1) + ";
1184 return "this.getDaysInMonth() + ";
1186 return "(this.isLeapYear() ? 1 : 0) + ";
1188 return "this.getFullYear() + ";
1190 return "('' + this.getFullYear()).substring(2, 4) + ";
1192 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1194 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1196 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1198 return "this.getHours() + ";
1200 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1202 return "String.leftPad(this.getHours(), 2, '0') + ";
1204 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1206 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1208 return "this.getGMTOffset() + ";
1210 return "this.getGMTColonOffset() + ";
1212 return "this.getTimezone() + ";
1214 return "(this.getTimezoneOffset() * -60) + ";
1216 return "'" + String.escape(character) + "' + ";
1221 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1222 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1223 * the date format that is not specified will default to the current date value for that part. Time parts can also
1224 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1225 * string or the parse operation will fail.
1228 //dt = Fri May 25 2007 (current date)
1229 var dt = new Date();
1231 //dt = Thu May 25 2006 (today's month/day in 2006)
1232 dt = Date.parseDate("2006", "Y");
1234 //dt = Sun Jan 15 2006 (all date parts specified)
1235 dt = Date.parseDate("2006-1-15", "Y-m-d");
1237 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1238 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1240 * @param {String} input The unparsed date as a string
1241 * @param {String} format The format the date is in
1242 * @return {Date} The parsed date
1245 Date.parseDate = function(input, format) {
1246 if (Date.parseFunctions[format] == null) {
1247 Date.createParser(format);
1249 var func = Date.parseFunctions[format];
1250 return Date[func](input);
1256 Date.createParser = function(format) {
1257 var funcName = "parse" + Date.parseFunctions.count++;
1258 var regexNum = Date.parseRegexes.length;
1259 var currentGroup = 1;
1260 Date.parseFunctions[format] = funcName;
1262 var code = "Date." + funcName + " = function(input){\n"
1263 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1264 + "var d = new Date();\n"
1265 + "y = d.getFullYear();\n"
1266 + "m = d.getMonth();\n"
1267 + "d = d.getDate();\n"
1268 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1269 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1270 + "if (results && results.length > 0) {";
1273 var special = false;
1275 for (var i = 0; i < format.length; ++i) {
1276 ch = format.charAt(i);
1277 if (!special && ch == "\\") {
1282 regex += String.escape(ch);
1285 var obj = Date.formatCodeToRegex(ch, currentGroup);
1286 currentGroup += obj.g;
1288 if (obj.g && obj.c) {
1294 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1295 + "{v = new Date(y, m, d, h, i, s);}\n"
1296 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1297 + "{v = new Date(y, m, d, h, i);}\n"
1298 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1299 + "{v = new Date(y, m, d, h);}\n"
1300 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1301 + "{v = new Date(y, m, d);}\n"
1302 + "else if (y >= 0 && m >= 0)\n"
1303 + "{v = new Date(y, m);}\n"
1304 + "else if (y >= 0)\n"
1305 + "{v = new Date(y);}\n"
1306 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1307 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1308 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1311 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1312 /** eval:var:zzzzzzzzzzzzz */
1317 Date.formatCodeToRegex = function(character, currentGroup) {
1318 switch (character) {
1322 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1325 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1326 s:"(\\d{1,2})"}; // day of month without leading zeroes
1329 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1330 s:"(\\d{2})"}; // day of month with leading zeroes
1334 s:"(?:" + Date.dayNames.join("|") + ")"};
1338 s:"(?:st|nd|rd|th)"};
1353 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1354 s:"(" + Date.monthNames.join("|") + ")"};
1357 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1358 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1361 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1362 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1365 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1366 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1377 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1381 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1382 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1386 c:"if (results[" + currentGroup + "] == 'am') {\n"
1387 + "if (h == 12) { h = 0; }\n"
1388 + "} else { if (h < 12) { h += 12; }}",
1392 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1393 + "if (h == 12) { h = 0; }\n"
1394 + "} else { if (h < 12) { h += 12; }}",
1399 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1400 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1404 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1405 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1408 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1412 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1417 "o = results[", currentGroup, "];\n",
1418 "var sn = o.substring(0,1);\n", // get + / - sign
1419 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1420 "var mn = o.substring(3,5) % 60;\n", // get minutes
1421 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1422 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1424 s:"([+\-]\\d{2,4})"};
1430 "o = results[", currentGroup, "];\n",
1431 "var sn = o.substring(0,1);\n",
1432 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1433 "var mn = o.substring(4,6) % 60;\n",
1434 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1435 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1441 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1444 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1445 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1446 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1450 s:String.escape(character)};
1455 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1456 * @return {String} The abbreviated timezone name (e.g. 'CST')
1458 Date.prototype.getTimezone = function() {
1459 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1463 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1464 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1466 Date.prototype.getGMTOffset = function() {
1467 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1468 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1469 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1473 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1474 * @return {String} 2-characters representing hours and 2-characters representing minutes
1475 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1477 Date.prototype.getGMTColonOffset = function() {
1478 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1479 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1481 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1485 * Get the numeric day number of the year, adjusted for leap year.
1486 * @return {Number} 0 through 364 (365 in leap years)
1488 Date.prototype.getDayOfYear = function() {
1490 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1491 for (var i = 0; i < this.getMonth(); ++i) {
1492 num += Date.daysInMonth[i];
1494 return num + this.getDate() - 1;
1498 * Get the string representation of the numeric week number of the year
1499 * (equivalent to the format specifier 'W').
1500 * @return {String} '00' through '52'
1502 Date.prototype.getWeekOfYear = function() {
1503 // Skip to Thursday of this week
1504 var now = this.getDayOfYear() + (4 - this.getDay());
1505 // Find the first Thursday of the year
1506 var jan1 = new Date(this.getFullYear(), 0, 1);
1507 var then = (7 - jan1.getDay() + 4);
1508 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1512 * Whether or not the current date is in a leap year.
1513 * @return {Boolean} True if the current date is in a leap year, else false
1515 Date.prototype.isLeapYear = function() {
1516 var year = this.getFullYear();
1517 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1521 * Get the first day of the current month, adjusted for leap year. The returned value
1522 * is the numeric day index within the week (0-6) which can be used in conjunction with
1523 * the {@link #monthNames} array to retrieve the textual day name.
1526 var dt = new Date('1/10/2007');
1527 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1529 * @return {Number} The day number (0-6)
1531 Date.prototype.getFirstDayOfMonth = function() {
1532 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1533 return (day < 0) ? (day + 7) : day;
1537 * Get the last day of the current month, adjusted for leap year. The returned value
1538 * is the numeric day index within the week (0-6) which can be used in conjunction with
1539 * the {@link #monthNames} array to retrieve the textual day name.
1542 var dt = new Date('1/10/2007');
1543 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1545 * @return {Number} The day number (0-6)
1547 Date.prototype.getLastDayOfMonth = function() {
1548 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1549 return (day < 0) ? (day + 7) : day;
1554 * Get the first date of this date's month
1557 Date.prototype.getFirstDateOfMonth = function() {
1558 return new Date(this.getFullYear(), this.getMonth(), 1);
1562 * Get the last date of this date's month
1565 Date.prototype.getLastDateOfMonth = function() {
1566 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1569 * Get the number of days in the current month, adjusted for leap year.
1570 * @return {Number} The number of days in the month
1572 Date.prototype.getDaysInMonth = function() {
1573 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1574 return Date.daysInMonth[this.getMonth()];
1578 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1579 * @return {String} 'st, 'nd', 'rd' or 'th'
1581 Date.prototype.getSuffix = function() {
1582 switch (this.getDate()) {
1599 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1602 * An array of textual month names.
1603 * Override these values for international dates, for example...
1604 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1623 * An array of textual day names.
1624 * Override these values for international dates, for example...
1625 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1641 Date.monthNumbers = {
1656 * Creates and returns a new Date instance with the exact same date value as the called instance.
1657 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1658 * variable will also be changed. When the intention is to create a new variable that will not
1659 * modify the original instance, you should create a clone.
1661 * Example of correctly cloning a date:
1664 var orig = new Date('10/1/2006');
1667 document.write(orig); //returns 'Thu Oct 05 2006'!
1670 var orig = new Date('10/1/2006');
1671 var copy = orig.clone();
1673 document.write(orig); //returns 'Thu Oct 01 2006'
1675 * @return {Date} The new Date instance
1677 Date.prototype.clone = function() {
1678 return new Date(this.getTime());
1682 * Clears any time information from this date
1683 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1684 @return {Date} this or the clone
1686 Date.prototype.clearTime = function(clone){
1688 return this.clone().clearTime();
1693 this.setMilliseconds(0);
1698 // safari setMonth is broken -- check that this is only donw once...
1699 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1700 Date.brokenSetMonth = Date.prototype.setMonth;
1701 Date.prototype.setMonth = function(num){
1703 var n = Math.ceil(-num);
1704 var back_year = Math.ceil(n/12);
1705 var month = (n % 12) ? 12 - n % 12 : 0 ;
1706 this.setFullYear(this.getFullYear() - back_year);
1707 return Date.brokenSetMonth.call(this, month);
1709 return Date.brokenSetMonth.apply(this, arguments);
1714 /** Date interval constant
1718 /** Date interval constant
1722 /** Date interval constant
1726 /** Date interval constant
1730 /** Date interval constant
1734 /** Date interval constant
1738 /** Date interval constant
1744 * Provides a convenient method of performing basic date arithmetic. This method
1745 * does not modify the Date instance being called - it creates and returns
1746 * a new Date instance containing the resulting date value.
1751 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1752 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1754 //Negative values will subtract correctly:
1755 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1756 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1758 //You can even chain several calls together in one line!
1759 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1760 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1763 * @param {String} interval A valid date interval enum value
1764 * @param {Number} value The amount to add to the current date
1765 * @return {Date} The new Date instance
1767 Date.prototype.add = function(interval, value){
1768 var d = this.clone();
1769 if (!interval || value === 0) { return d; }
1770 switch(interval.toLowerCase()){
1772 d.setMilliseconds(this.getMilliseconds() + value);
1775 d.setSeconds(this.getSeconds() + value);
1778 d.setMinutes(this.getMinutes() + value);
1781 d.setHours(this.getHours() + value);
1784 d.setDate(this.getDate() + value);
1787 var day = this.getDate();
1789 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1792 d.setMonth(this.getMonth() + value);
1795 d.setFullYear(this.getFullYear() + value);
1802 * Ext JS Library 1.1.1
1803 * Copyright(c) 2006-2007, Ext JS, LLC.
1805 * Originally Released Under LGPL - original licence link has changed is not relivant.
1808 * <script type="text/javascript">
1812 * @class Roo.lib.Dom
1815 * Dom utils (from YIU afaik)
1820 * Get the view width
1821 * @param {Boolean} full True will get the full document, otherwise it's the view width
1822 * @return {Number} The width
1825 getViewWidth : function(full) {
1826 return full ? this.getDocumentWidth() : this.getViewportWidth();
1829 * Get the view height
1830 * @param {Boolean} full True will get the full document, otherwise it's the view height
1831 * @return {Number} The height
1833 getViewHeight : function(full) {
1834 return full ? this.getDocumentHeight() : this.getViewportHeight();
1837 getDocumentHeight: function() {
1838 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1839 return Math.max(scrollHeight, this.getViewportHeight());
1842 getDocumentWidth: function() {
1843 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1844 return Math.max(scrollWidth, this.getViewportWidth());
1847 getViewportHeight: function() {
1848 var height = self.innerHeight;
1849 var mode = document.compatMode;
1851 if ((mode || Roo.isIE) && !Roo.isOpera) {
1852 height = (mode == "CSS1Compat") ?
1853 document.documentElement.clientHeight :
1854 document.body.clientHeight;
1860 getViewportWidth: function() {
1861 var width = self.innerWidth;
1862 var mode = document.compatMode;
1864 if (mode || Roo.isIE) {
1865 width = (mode == "CSS1Compat") ?
1866 document.documentElement.clientWidth :
1867 document.body.clientWidth;
1872 isAncestor : function(p, c) {
1879 if (p.contains && !Roo.isSafari) {
1880 return p.contains(c);
1881 } else if (p.compareDocumentPosition) {
1882 return !!(p.compareDocumentPosition(c) & 16);
1884 var parent = c.parentNode;
1889 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1892 parent = parent.parentNode;
1898 getRegion : function(el) {
1899 return Roo.lib.Region.getRegion(el);
1902 getY : function(el) {
1903 return this.getXY(el)[1];
1906 getX : function(el) {
1907 return this.getXY(el)[0];
1910 getXY : function(el) {
1911 var p, pe, b, scroll, bd = document.body;
1912 el = Roo.getDom(el);
1913 var fly = Roo.lib.AnimBase.fly;
1914 if (el.getBoundingClientRect) {
1915 b = el.getBoundingClientRect();
1916 scroll = fly(document).getScroll();
1917 return [b.left + scroll.left, b.top + scroll.top];
1923 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1930 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1937 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1938 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1945 if (p != el && pe.getStyle('overflow') != 'visible') {
1953 if (Roo.isSafari && hasAbsolute) {
1958 if (Roo.isGecko && !hasAbsolute) {
1960 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1961 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1965 while (p && p != bd) {
1966 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1978 setXY : function(el, xy) {
1979 el = Roo.fly(el, '_setXY');
1981 var pts = el.translatePoints(xy);
1982 if (xy[0] !== false) {
1983 el.dom.style.left = pts.left + "px";
1985 if (xy[1] !== false) {
1986 el.dom.style.top = pts.top + "px";
1990 setX : function(el, x) {
1991 this.setXY(el, [x, false]);
1994 setY : function(el, y) {
1995 this.setXY(el, [false, y]);
1999 * Portions of this file are based on pieces of Yahoo User Interface Library
2000 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2001 * YUI licensed under the BSD License:
2002 * http://developer.yahoo.net/yui/license.txt
2003 * <script type="text/javascript">
2007 Roo.lib.Event = function() {
2008 var loadComplete = false;
2010 var unloadListeners = [];
2012 var onAvailStack = [];
2014 var lastError = null;
2027 startInterval: function() {
2028 if (!this._interval) {
2030 var callback = function() {
2031 self._tryPreloadAttach();
2033 this._interval = setInterval(callback, this.POLL_INTERVAL);
2038 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2039 onAvailStack.push({ id: p_id,
2042 override: p_override,
2043 checkReady: false });
2045 retryCount = this.POLL_RETRYS;
2046 this.startInterval();
2050 addListener: function(el, eventName, fn) {
2051 el = Roo.getDom(el);
2056 if ("unload" == eventName) {
2057 unloadListeners[unloadListeners.length] =
2058 [el, eventName, fn];
2062 var wrappedFn = function(e) {
2063 return fn(Roo.lib.Event.getEvent(e));
2066 var li = [el, eventName, fn, wrappedFn];
2068 var index = listeners.length;
2069 listeners[index] = li;
2071 this.doAdd(el, eventName, wrappedFn, false);
2077 removeListener: function(el, eventName, fn) {
2080 el = Roo.getDom(el);
2083 return this.purgeElement(el, false, eventName);
2087 if ("unload" == eventName) {
2089 for (i = 0,len = unloadListeners.length; i < len; i++) {
2090 var li = unloadListeners[i];
2093 li[1] == eventName &&
2095 unloadListeners.splice(i, 1);
2103 var cacheItem = null;
2106 var index = arguments[3];
2108 if ("undefined" == typeof index) {
2109 index = this._getCacheIndex(el, eventName, fn);
2113 cacheItem = listeners[index];
2116 if (!el || !cacheItem) {
2120 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2122 delete listeners[index][this.WFN];
2123 delete listeners[index][this.FN];
2124 listeners.splice(index, 1);
2131 getTarget: function(ev, resolveTextNode) {
2132 ev = ev.browserEvent || ev;
2133 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2134 var t = ev.target || ev.srcElement;
2135 return this.resolveTextNode(t);
2139 resolveTextNode: function(node) {
2140 if (Roo.isSafari && node && 3 == node.nodeType) {
2141 return node.parentNode;
2148 getPageX: function(ev) {
2149 ev = ev.browserEvent || ev;
2150 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2152 if (!x && 0 !== x) {
2153 x = ev.clientX || 0;
2156 x += this.getScroll()[1];
2164 getPageY: function(ev) {
2165 ev = ev.browserEvent || ev;
2166 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2168 if (!y && 0 !== y) {
2169 y = ev.clientY || 0;
2172 y += this.getScroll()[0];
2181 getXY: function(ev) {
2182 ev = ev.browserEvent || ev;
2183 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2184 return [this.getPageX(ev), this.getPageY(ev)];
2188 getRelatedTarget: function(ev) {
2189 ev = ev.browserEvent || ev;
2190 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2191 var t = ev.relatedTarget;
2193 if (ev.type == "mouseout") {
2195 } else if (ev.type == "mouseover") {
2200 return this.resolveTextNode(t);
2204 getTime: function(ev) {
2205 ev = ev.browserEvent || ev;
2206 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2208 var t = new Date().getTime();
2212 this.lastError = ex;
2221 stopEvent: function(ev) {
2222 this.stopPropagation(ev);
2223 this.preventDefault(ev);
2227 stopPropagation: function(ev) {
2228 ev = ev.browserEvent || ev;
2229 if (ev.stopPropagation) {
2230 ev.stopPropagation();
2232 ev.cancelBubble = true;
2237 preventDefault: function(ev) {
2238 ev = ev.browserEvent || ev;
2239 if(ev.preventDefault) {
2240 ev.preventDefault();
2242 ev.returnValue = false;
2247 getEvent: function(e) {
2248 var ev = e || window.event;
2250 var c = this.getEvent.caller;
2252 ev = c.arguments[0];
2253 if (ev && Event == ev.constructor) {
2263 getCharCode: function(ev) {
2264 ev = ev.browserEvent || ev;
2265 return ev.charCode || ev.keyCode || 0;
2269 _getCacheIndex: function(el, eventName, fn) {
2270 for (var i = 0,len = listeners.length; i < len; ++i) {
2271 var li = listeners[i];
2273 li[this.FN] == fn &&
2274 li[this.EL] == el &&
2275 li[this.TYPE] == eventName) {
2287 getEl: function(id) {
2288 return document.getElementById(id);
2292 clearCache: function() {
2296 _load: function(e) {
2297 loadComplete = true;
2298 var EU = Roo.lib.Event;
2302 EU.doRemove(window, "load", EU._load);
2307 _tryPreloadAttach: function() {
2316 var tryAgain = !loadComplete;
2318 tryAgain = (retryCount > 0);
2323 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2324 var item = onAvailStack[i];
2326 var el = this.getEl(item.id);
2329 if (!item.checkReady ||
2332 (document && document.body)) {
2335 if (item.override) {
2336 if (item.override === true) {
2339 scope = item.override;
2342 item.fn.call(scope, item.obj);
2343 onAvailStack[i] = null;
2346 notAvail.push(item);
2351 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2355 this.startInterval();
2357 clearInterval(this._interval);
2358 this._interval = null;
2361 this.locked = false;
2368 purgeElement: function(el, recurse, eventName) {
2369 var elListeners = this.getListeners(el, eventName);
2371 for (var i = 0,len = elListeners.length; i < len; ++i) {
2372 var l = elListeners[i];
2373 this.removeListener(el, l.type, l.fn);
2377 if (recurse && el && el.childNodes) {
2378 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2379 this.purgeElement(el.childNodes[i], recurse, eventName);
2385 getListeners: function(el, eventName) {
2386 var results = [], searchLists;
2388 searchLists = [listeners, unloadListeners];
2389 } else if (eventName == "unload") {
2390 searchLists = [unloadListeners];
2392 searchLists = [listeners];
2395 for (var j = 0; j < searchLists.length; ++j) {
2396 var searchList = searchLists[j];
2397 if (searchList && searchList.length > 0) {
2398 for (var i = 0,len = searchList.length; i < len; ++i) {
2399 var l = searchList[i];
2400 if (l && l[this.EL] === el &&
2401 (!eventName || eventName === l[this.TYPE])) {
2406 adjust: l[this.ADJ_SCOPE],
2414 return (results.length) ? results : null;
2418 _unload: function(e) {
2420 var EU = Roo.lib.Event, i, j, l, len, index;
2422 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2423 l = unloadListeners[i];
2426 if (l[EU.ADJ_SCOPE]) {
2427 if (l[EU.ADJ_SCOPE] === true) {
2430 scope = l[EU.ADJ_SCOPE];
2433 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2434 unloadListeners[i] = null;
2440 unloadListeners = null;
2442 if (listeners && listeners.length > 0) {
2443 j = listeners.length;
2446 l = listeners[index];
2448 EU.removeListener(l[EU.EL], l[EU.TYPE],
2458 EU.doRemove(window, "unload", EU._unload);
2463 getScroll: function() {
2464 var dd = document.documentElement, db = document.body;
2465 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2466 return [dd.scrollTop, dd.scrollLeft];
2468 return [db.scrollTop, db.scrollLeft];
2475 doAdd: function () {
2476 if (window.addEventListener) {
2477 return function(el, eventName, fn, capture) {
2478 el.addEventListener(eventName, fn, (capture));
2480 } else if (window.attachEvent) {
2481 return function(el, eventName, fn, capture) {
2482 el.attachEvent("on" + eventName, fn);
2491 doRemove: function() {
2492 if (window.removeEventListener) {
2493 return function (el, eventName, fn, capture) {
2494 el.removeEventListener(eventName, fn, (capture));
2496 } else if (window.detachEvent) {
2497 return function (el, eventName, fn) {
2498 el.detachEvent("on" + eventName, fn);
2510 var E = Roo.lib.Event;
2511 E.on = E.addListener;
2512 E.un = E.removeListener;
2514 if (document && document.body) {
2517 E.doAdd(window, "load", E._load);
2519 E.doAdd(window, "unload", E._unload);
2520 E._tryPreloadAttach();
2524 * Portions of this file are based on pieces of Yahoo User Interface Library
2525 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2526 * YUI licensed under the BSD License:
2527 * http://developer.yahoo.net/yui/license.txt
2528 * <script type="text/javascript">
2534 * @class Roo.lib.Ajax
2541 request : function(method, uri, cb, data, options) {
2543 var hs = options.headers;
2546 if(hs.hasOwnProperty(h)){
2547 this.initHeader(h, hs[h], false);
2551 if(options.xmlData){
2552 this.initHeader('Content-Type', 'text/xml', false);
2554 data = options.xmlData;
2558 return this.asyncRequest(method, uri, cb, data);
2561 serializeForm : function(form) {
2562 if(typeof form == 'string') {
2563 form = (document.getElementById(form) || document.forms[form]);
2566 var el, name, val, disabled, data = '', hasSubmit = false;
2567 for (var i = 0; i < form.elements.length; i++) {
2568 el = form.elements[i];
2569 disabled = form.elements[i].disabled;
2570 name = form.elements[i].name;
2571 val = form.elements[i].value;
2573 if (!disabled && name){
2577 case 'select-multiple':
2578 for (var j = 0; j < el.options.length; j++) {
2579 if (el.options[j].selected) {
2581 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2584 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2592 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2605 if(hasSubmit == false) {
2606 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2611 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2616 data = data.substr(0, data.length - 1);
2624 useDefaultHeader:true,
2626 defaultPostHeader:'application/x-www-form-urlencoded',
2628 useDefaultXhrHeader:true,
2630 defaultXhrHeader:'XMLHttpRequest',
2632 hasDefaultHeaders:true,
2644 setProgId:function(id)
2646 this.activeX.unshift(id);
2649 setDefaultPostHeader:function(b)
2651 this.useDefaultHeader = b;
2654 setDefaultXhrHeader:function(b)
2656 this.useDefaultXhrHeader = b;
2659 setPollingInterval:function(i)
2661 if (typeof i == 'number' && isFinite(i)) {
2662 this.pollInterval = i;
2666 createXhrObject:function(transactionId)
2672 http = new XMLHttpRequest();
2674 obj = { conn:http, tId:transactionId };
2678 for (var i = 0; i < this.activeX.length; ++i) {
2682 http = new ActiveXObject(this.activeX[i]);
2684 obj = { conn:http, tId:transactionId };
2697 getConnectionObject:function()
2700 var tId = this.transactionId;
2704 o = this.createXhrObject(tId);
2706 this.transactionId++;
2717 asyncRequest:function(method, uri, callback, postData)
2719 var o = this.getConnectionObject();
2725 o.conn.open(method, uri, true);
2727 if (this.useDefaultXhrHeader) {
2728 if (!this.defaultHeaders['X-Requested-With']) {
2729 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2733 if(postData && this.useDefaultHeader){
2734 this.initHeader('Content-Type', this.defaultPostHeader);
2737 if (this.hasDefaultHeaders || this.hasHeaders) {
2741 this.handleReadyState(o, callback);
2742 o.conn.send(postData || null);
2748 handleReadyState:function(o, callback)
2752 if (callback && callback.timeout) {
2754 this.timeout[o.tId] = window.setTimeout(function() {
2755 oConn.abort(o, callback, true);
2756 }, callback.timeout);
2759 this.poll[o.tId] = window.setInterval(
2761 if (o.conn && o.conn.readyState == 4) {
2762 window.clearInterval(oConn.poll[o.tId]);
2763 delete oConn.poll[o.tId];
2765 if(callback && callback.timeout) {
2766 window.clearTimeout(oConn.timeout[o.tId]);
2767 delete oConn.timeout[o.tId];
2770 oConn.handleTransactionResponse(o, callback);
2773 , this.pollInterval);
2776 handleTransactionResponse:function(o, callback, isAbort)
2780 this.releaseObject(o);
2784 var httpStatus, responseObject;
2788 if (o.conn.status !== undefined && o.conn.status != 0) {
2789 httpStatus = o.conn.status;
2801 if (httpStatus >= 200 && httpStatus < 300) {
2802 responseObject = this.createResponseObject(o, callback.argument);
2803 if (callback.success) {
2804 if (!callback.scope) {
2805 callback.success(responseObject);
2810 callback.success.apply(callback.scope, [responseObject]);
2815 switch (httpStatus) {
2823 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2824 if (callback.failure) {
2825 if (!callback.scope) {
2826 callback.failure(responseObject);
2829 callback.failure.apply(callback.scope, [responseObject]);
2834 responseObject = this.createResponseObject(o, callback.argument);
2835 if (callback.failure) {
2836 if (!callback.scope) {
2837 callback.failure(responseObject);
2840 callback.failure.apply(callback.scope, [responseObject]);
2846 this.releaseObject(o);
2847 responseObject = null;
2850 createResponseObject:function(o, callbackArg)
2857 var headerStr = o.conn.getAllResponseHeaders();
2858 var header = headerStr.split('\n');
2859 for (var i = 0; i < header.length; i++) {
2860 var delimitPos = header[i].indexOf(':');
2861 if (delimitPos != -1) {
2862 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2870 obj.status = o.conn.status;
2871 obj.statusText = o.conn.statusText;
2872 obj.getResponseHeader = headerObj;
2873 obj.getAllResponseHeaders = headerStr;
2874 obj.responseText = o.conn.responseText;
2875 obj.responseXML = o.conn.responseXML;
2877 if (typeof callbackArg !== undefined) {
2878 obj.argument = callbackArg;
2884 createExceptionObject:function(tId, callbackArg, isAbort)
2887 var COMM_ERROR = 'communication failure';
2888 var ABORT_CODE = -1;
2889 var ABORT_ERROR = 'transaction aborted';
2895 obj.status = ABORT_CODE;
2896 obj.statusText = ABORT_ERROR;
2899 obj.status = COMM_CODE;
2900 obj.statusText = COMM_ERROR;
2904 obj.argument = callbackArg;
2910 initHeader:function(label, value, isDefault)
2912 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2914 if (headerObj[label] === undefined) {
2915 headerObj[label] = value;
2920 headerObj[label] = value + "," + headerObj[label];
2924 this.hasDefaultHeaders = true;
2927 this.hasHeaders = true;
2932 setHeader:function(o)
2934 if (this.hasDefaultHeaders) {
2935 for (var prop in this.defaultHeaders) {
2936 if (this.defaultHeaders.hasOwnProperty(prop)) {
2937 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2942 if (this.hasHeaders) {
2943 for (var prop in this.headers) {
2944 if (this.headers.hasOwnProperty(prop)) {
2945 o.conn.setRequestHeader(prop, this.headers[prop]);
2949 this.hasHeaders = false;
2953 resetDefaultHeaders:function() {
2954 delete this.defaultHeaders;
2955 this.defaultHeaders = {};
2956 this.hasDefaultHeaders = false;
2959 abort:function(o, callback, isTimeout)
2961 if(this.isCallInProgress(o)) {
2963 window.clearInterval(this.poll[o.tId]);
2964 delete this.poll[o.tId];
2966 delete this.timeout[o.tId];
2969 this.handleTransactionResponse(o, callback, true);
2979 isCallInProgress:function(o)
2982 return o.conn.readyState != 4 && o.conn.readyState != 0;
2991 releaseObject:function(o)
3000 'MSXML2.XMLHTTP.3.0',
3008 * Portions of this file are based on pieces of Yahoo User Interface Library
3009 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3010 * YUI licensed under the BSD License:
3011 * http://developer.yahoo.net/yui/license.txt
3012 * <script type="text/javascript">
3016 Roo.lib.Region = function(t, r, b, l) {
3026 Roo.lib.Region.prototype = {
3027 contains : function(region) {
3028 return ( region.left >= this.left &&
3029 region.right <= this.right &&
3030 region.top >= this.top &&
3031 region.bottom <= this.bottom );
3035 getArea : function() {
3036 return ( (this.bottom - this.top) * (this.right - this.left) );
3039 intersect : function(region) {
3040 var t = Math.max(this.top, region.top);
3041 var r = Math.min(this.right, region.right);
3042 var b = Math.min(this.bottom, region.bottom);
3043 var l = Math.max(this.left, region.left);
3045 if (b >= t && r >= l) {
3046 return new Roo.lib.Region(t, r, b, l);
3051 union : function(region) {
3052 var t = Math.min(this.top, region.top);
3053 var r = Math.max(this.right, region.right);
3054 var b = Math.max(this.bottom, region.bottom);
3055 var l = Math.min(this.left, region.left);
3057 return new Roo.lib.Region(t, r, b, l);
3060 adjust : function(t, l, b, r) {
3069 Roo.lib.Region.getRegion = function(el) {
3070 var p = Roo.lib.Dom.getXY(el);
3073 var r = p[0] + el.offsetWidth;
3074 var b = p[1] + el.offsetHeight;
3077 return new Roo.lib.Region(t, r, b, l);
3080 * Portions of this file are based on pieces of Yahoo User Interface Library
3081 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3082 * YUI licensed under the BSD License:
3083 * http://developer.yahoo.net/yui/license.txt
3084 * <script type="text/javascript">
3087 //@@dep Roo.lib.Region
3090 Roo.lib.Point = function(x, y) {
3091 if (x instanceof Array) {
3095 this.x = this.right = this.left = this[0] = x;
3096 this.y = this.top = this.bottom = this[1] = y;
3099 Roo.lib.Point.prototype = new Roo.lib.Region();
3101 * Portions of this file are based on pieces of Yahoo User Interface Library
3102 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3103 * YUI licensed under the BSD License:
3104 * http://developer.yahoo.net/yui/license.txt
3105 * <script type="text/javascript">
3112 scroll : function(el, args, duration, easing, cb, scope) {
3113 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3116 motion : function(el, args, duration, easing, cb, scope) {
3117 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3120 color : function(el, args, duration, easing, cb, scope) {
3121 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3124 run : function(el, args, duration, easing, cb, scope, type) {
3125 type = type || Roo.lib.AnimBase;
3126 if (typeof easing == "string") {
3127 easing = Roo.lib.Easing[easing];
3129 var anim = new type(el, args, duration, easing);
3130 anim.animateX(function() {
3131 Roo.callback(cb, scope);
3137 * Portions of this file are based on pieces of Yahoo User Interface Library
3138 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3139 * YUI licensed under the BSD License:
3140 * http://developer.yahoo.net/yui/license.txt
3141 * <script type="text/javascript">
3149 if (!libFlyweight) {
3150 libFlyweight = new Roo.Element.Flyweight();
3152 libFlyweight.dom = el;
3153 return libFlyweight;
3156 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3160 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3162 this.init(el, attributes, duration, method);
3166 Roo.lib.AnimBase.fly = fly;
3170 Roo.lib.AnimBase.prototype = {
3172 toString: function() {
3173 var el = this.getEl();
3174 var id = el.id || el.tagName;
3175 return ("Anim " + id);
3179 noNegatives: /width|height|opacity|padding/i,
3180 offsetAttribute: /^((width|height)|(top|left))$/,
3181 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3182 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3186 doMethod: function(attr, start, end) {
3187 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3191 setAttribute: function(attr, val, unit) {
3192 if (this.patterns.noNegatives.test(attr)) {
3193 val = (val > 0) ? val : 0;
3196 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3200 getAttribute: function(attr) {
3201 var el = this.getEl();
3202 var val = fly(el).getStyle(attr);
3204 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3205 return parseFloat(val);
3208 var a = this.patterns.offsetAttribute.exec(attr) || [];
3209 var pos = !!( a[3] );
3210 var box = !!( a[2] );
3213 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3214 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3223 getDefaultUnit: function(attr) {
3224 if (this.patterns.defaultUnit.test(attr)) {
3231 animateX : function(callback, scope) {
3232 var f = function() {
3233 this.onComplete.removeListener(f);
3234 if (typeof callback == "function") {
3235 callback.call(scope || this, this);
3238 this.onComplete.addListener(f, this);
3243 setRuntimeAttribute: function(attr) {
3246 var attributes = this.attributes;
3248 this.runtimeAttributes[attr] = {};
3250 var isset = function(prop) {
3251 return (typeof prop !== 'undefined');
3254 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3258 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3261 if (isset(attributes[attr]['to'])) {
3262 end = attributes[attr]['to'];
3263 } else if (isset(attributes[attr]['by'])) {
3264 if (start.constructor == Array) {
3266 for (var i = 0, len = start.length; i < len; ++i) {
3267 end[i] = start[i] + attributes[attr]['by'][i];
3270 end = start + attributes[attr]['by'];
3274 this.runtimeAttributes[attr].start = start;
3275 this.runtimeAttributes[attr].end = end;
3278 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3282 init: function(el, attributes, duration, method) {
3284 var isAnimated = false;
3287 var startTime = null;
3290 var actualFrames = 0;
3293 el = Roo.getDom(el);
3296 this.attributes = attributes || {};
3299 this.duration = duration || 1;
3302 this.method = method || Roo.lib.Easing.easeNone;
3305 this.useSeconds = true;
3308 this.currentFrame = 0;
3311 this.totalFrames = Roo.lib.AnimMgr.fps;
3314 this.getEl = function() {
3319 this.isAnimated = function() {
3324 this.getStartTime = function() {
3328 this.runtimeAttributes = {};
3331 this.animate = function() {
3332 if (this.isAnimated()) {
3336 this.currentFrame = 0;
3338 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3340 Roo.lib.AnimMgr.registerElement(this);
3344 this.stop = function(finish) {
3346 this.currentFrame = this.totalFrames;
3347 this._onTween.fire();
3349 Roo.lib.AnimMgr.stop(this);
3352 var onStart = function() {
3353 this.onStart.fire();
3355 this.runtimeAttributes = {};
3356 for (var attr in this.attributes) {
3357 this.setRuntimeAttribute(attr);
3362 startTime = new Date();
3366 var onTween = function() {
3368 duration: new Date() - this.getStartTime(),
3369 currentFrame: this.currentFrame
3372 data.toString = function() {
3374 'duration: ' + data.duration +
3375 ', currentFrame: ' + data.currentFrame
3379 this.onTween.fire(data);
3381 var runtimeAttributes = this.runtimeAttributes;
3383 for (var attr in runtimeAttributes) {
3384 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3390 var onComplete = function() {
3391 var actual_duration = (new Date() - startTime) / 1000 ;
3394 duration: actual_duration,
3395 frames: actualFrames,
3396 fps: actualFrames / actual_duration
3399 data.toString = function() {
3401 'duration: ' + data.duration +
3402 ', frames: ' + data.frames +
3403 ', fps: ' + data.fps
3409 this.onComplete.fire(data);
3413 this._onStart = new Roo.util.Event(this);
3414 this.onStart = new Roo.util.Event(this);
3415 this.onTween = new Roo.util.Event(this);
3416 this._onTween = new Roo.util.Event(this);
3417 this.onComplete = new Roo.util.Event(this);
3418 this._onComplete = new Roo.util.Event(this);
3419 this._onStart.addListener(onStart);
3420 this._onTween.addListener(onTween);
3421 this._onComplete.addListener(onComplete);
3426 * Portions of this file are based on pieces of Yahoo User Interface Library
3427 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3428 * YUI licensed under the BSD License:
3429 * http://developer.yahoo.net/yui/license.txt
3430 * <script type="text/javascript">
3434 Roo.lib.AnimMgr = new function() {
3451 this.registerElement = function(tween) {
3452 queue[queue.length] = tween;
3454 tween._onStart.fire();
3459 this.unRegister = function(tween, index) {
3460 tween._onComplete.fire();
3461 index = index || getIndex(tween);
3463 queue.splice(index, 1);
3467 if (tweenCount <= 0) {
3473 this.start = function() {
3474 if (thread === null) {
3475 thread = setInterval(this.run, this.delay);
3480 this.stop = function(tween) {
3482 clearInterval(thread);
3484 for (var i = 0, len = queue.length; i < len; ++i) {
3485 if (queue[0].isAnimated()) {
3486 this.unRegister(queue[0], 0);
3495 this.unRegister(tween);
3500 this.run = function() {
3501 for (var i = 0, len = queue.length; i < len; ++i) {
3502 var tween = queue[i];
3503 if (!tween || !tween.isAnimated()) {
3507 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3509 tween.currentFrame += 1;
3511 if (tween.useSeconds) {
3512 correctFrame(tween);
3514 tween._onTween.fire();
3517 Roo.lib.AnimMgr.stop(tween, i);
3522 var getIndex = function(anim) {
3523 for (var i = 0, len = queue.length; i < len; ++i) {
3524 if (queue[i] == anim) {
3532 var correctFrame = function(tween) {
3533 var frames = tween.totalFrames;
3534 var frame = tween.currentFrame;
3535 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3536 var elapsed = (new Date() - tween.getStartTime());
3539 if (elapsed < tween.duration * 1000) {
3540 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3542 tweak = frames - (frame + 1);
3544 if (tweak > 0 && isFinite(tweak)) {
3545 if (tween.currentFrame + tweak >= frames) {
3546 tweak = frames - (frame + 1);
3549 tween.currentFrame += tweak;
3555 * Portions of this file are based on pieces of Yahoo User Interface Library
3556 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3557 * YUI licensed under the BSD License:
3558 * http://developer.yahoo.net/yui/license.txt
3559 * <script type="text/javascript">
3562 Roo.lib.Bezier = new function() {
3564 this.getPosition = function(points, t) {
3565 var n = points.length;
3568 for (var i = 0; i < n; ++i) {
3569 tmp[i] = [points[i][0], points[i][1]];
3572 for (var j = 1; j < n; ++j) {
3573 for (i = 0; i < n - j; ++i) {
3574 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3575 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3579 return [ tmp[0][0], tmp[0][1] ];
3583 * Portions of this file are based on pieces of Yahoo User Interface Library
3584 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3585 * YUI licensed under the BSD License:
3586 * http://developer.yahoo.net/yui/license.txt
3587 * <script type="text/javascript">
3592 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3593 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3596 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3598 var fly = Roo.lib.AnimBase.fly;
3600 var superclass = Y.ColorAnim.superclass;
3601 var proto = Y.ColorAnim.prototype;
3603 proto.toString = function() {
3604 var el = this.getEl();
3605 var id = el.id || el.tagName;
3606 return ("ColorAnim " + id);
3609 proto.patterns.color = /color$/i;
3610 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3611 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3612 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3613 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3616 proto.parseColor = function(s) {
3617 if (s.length == 3) {
3621 var c = this.patterns.hex.exec(s);
3622 if (c && c.length == 4) {
3623 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3626 c = this.patterns.rgb.exec(s);
3627 if (c && c.length == 4) {
3628 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3631 c = this.patterns.hex3.exec(s);
3632 if (c && c.length == 4) {
3633 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3638 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3639 proto.getAttribute = function(attr) {
3640 var el = this.getEl();
3641 if (this.patterns.color.test(attr)) {
3642 var val = fly(el).getStyle(attr);
3644 if (this.patterns.transparent.test(val)) {
3645 var parent = el.parentNode;
3646 val = fly(parent).getStyle(attr);
3648 while (parent && this.patterns.transparent.test(val)) {
3649 parent = parent.parentNode;
3650 val = fly(parent).getStyle(attr);
3651 if (parent.tagName.toUpperCase() == 'HTML') {
3657 val = superclass.getAttribute.call(this, attr);
3662 proto.getAttribute = function(attr) {
3663 var el = this.getEl();
3664 if (this.patterns.color.test(attr)) {
3665 var val = fly(el).getStyle(attr);
3667 if (this.patterns.transparent.test(val)) {
3668 var parent = el.parentNode;
3669 val = fly(parent).getStyle(attr);
3671 while (parent && this.patterns.transparent.test(val)) {
3672 parent = parent.parentNode;
3673 val = fly(parent).getStyle(attr);
3674 if (parent.tagName.toUpperCase() == 'HTML') {
3680 val = superclass.getAttribute.call(this, attr);
3686 proto.doMethod = function(attr, start, end) {
3689 if (this.patterns.color.test(attr)) {
3691 for (var i = 0, len = start.length; i < len; ++i) {
3692 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3695 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3698 val = superclass.doMethod.call(this, attr, start, end);
3704 proto.setRuntimeAttribute = function(attr) {
3705 superclass.setRuntimeAttribute.call(this, attr);
3707 if (this.patterns.color.test(attr)) {
3708 var attributes = this.attributes;
3709 var start = this.parseColor(this.runtimeAttributes[attr].start);
3710 var end = this.parseColor(this.runtimeAttributes[attr].end);
3712 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3713 end = this.parseColor(attributes[attr].by);
3715 for (var i = 0, len = start.length; i < len; ++i) {
3716 end[i] = start[i] + end[i];
3720 this.runtimeAttributes[attr].start = start;
3721 this.runtimeAttributes[attr].end = end;
3727 * Portions of this file are based on pieces of Yahoo User Interface Library
3728 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3729 * YUI licensed under the BSD License:
3730 * http://developer.yahoo.net/yui/license.txt
3731 * <script type="text/javascript">
3737 easeNone: function (t, b, c, d) {
3738 return c * t / d + b;
3742 easeIn: function (t, b, c, d) {
3743 return c * (t /= d) * t + b;
3747 easeOut: function (t, b, c, d) {
3748 return -c * (t /= d) * (t - 2) + b;
3752 easeBoth: function (t, b, c, d) {
3753 if ((t /= d / 2) < 1) {
3754 return c / 2 * t * t + b;
3757 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3761 easeInStrong: function (t, b, c, d) {
3762 return c * (t /= d) * t * t * t + b;
3766 easeOutStrong: function (t, b, c, d) {
3767 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3771 easeBothStrong: function (t, b, c, d) {
3772 if ((t /= d / 2) < 1) {
3773 return c / 2 * t * t * t * t + b;
3776 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3781 elasticIn: function (t, b, c, d, a, p) {
3785 if ((t /= d) == 1) {
3792 if (!a || a < Math.abs(c)) {
3797 var s = p / (2 * Math.PI) * Math.asin(c / a);
3800 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3804 elasticOut: function (t, b, c, d, a, p) {
3808 if ((t /= d) == 1) {
3815 if (!a || a < Math.abs(c)) {
3820 var s = p / (2 * Math.PI) * Math.asin(c / a);
3823 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3827 elasticBoth: function (t, b, c, d, a, p) {
3832 if ((t /= d / 2) == 2) {
3840 if (!a || a < Math.abs(c)) {
3845 var s = p / (2 * Math.PI) * Math.asin(c / a);
3849 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3850 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3852 return a * Math.pow(2, -10 * (t -= 1)) *
3853 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3858 backIn: function (t, b, c, d, s) {
3859 if (typeof s == 'undefined') {
3862 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3866 backOut: function (t, b, c, d, s) {
3867 if (typeof s == 'undefined') {
3870 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3874 backBoth: function (t, b, c, d, s) {
3875 if (typeof s == 'undefined') {
3879 if ((t /= d / 2 ) < 1) {
3880 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3882 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3886 bounceIn: function (t, b, c, d) {
3887 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3891 bounceOut: function (t, b, c, d) {
3892 if ((t /= d) < (1 / 2.75)) {
3893 return c * (7.5625 * t * t) + b;
3894 } else if (t < (2 / 2.75)) {
3895 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3896 } else if (t < (2.5 / 2.75)) {
3897 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3899 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3903 bounceBoth: function (t, b, c, d) {
3905 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3907 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3910 * Portions of this file are based on pieces of Yahoo User Interface Library
3911 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3912 * YUI licensed under the BSD License:
3913 * http://developer.yahoo.net/yui/license.txt
3914 * <script type="text/javascript">
3918 Roo.lib.Motion = function(el, attributes, duration, method) {
3920 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3924 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3928 var superclass = Y.Motion.superclass;
3929 var proto = Y.Motion.prototype;
3931 proto.toString = function() {
3932 var el = this.getEl();
3933 var id = el.id || el.tagName;
3934 return ("Motion " + id);
3937 proto.patterns.points = /^points$/i;
3939 proto.setAttribute = function(attr, val, unit) {
3940 if (this.patterns.points.test(attr)) {
3941 unit = unit || 'px';
3942 superclass.setAttribute.call(this, 'left', val[0], unit);
3943 superclass.setAttribute.call(this, 'top', val[1], unit);
3945 superclass.setAttribute.call(this, attr, val, unit);
3949 proto.getAttribute = function(attr) {
3950 if (this.patterns.points.test(attr)) {
3952 superclass.getAttribute.call(this, 'left'),
3953 superclass.getAttribute.call(this, 'top')
3956 val = superclass.getAttribute.call(this, attr);
3962 proto.doMethod = function(attr, start, end) {
3965 if (this.patterns.points.test(attr)) {
3966 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3967 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3969 val = superclass.doMethod.call(this, attr, start, end);
3974 proto.setRuntimeAttribute = function(attr) {
3975 if (this.patterns.points.test(attr)) {
3976 var el = this.getEl();
3977 var attributes = this.attributes;
3979 var control = attributes['points']['control'] || [];
3983 if (control.length > 0 && !(control[0] instanceof Array)) {
3984 control = [control];
3987 for (i = 0,len = control.length; i < len; ++i) {
3988 tmp[i] = control[i];
3993 Roo.fly(el).position();
3995 if (isset(attributes['points']['from'])) {
3996 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3999 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4002 start = this.getAttribute('points');
4005 if (isset(attributes['points']['to'])) {
4006 end = translateValues.call(this, attributes['points']['to'], start);
4008 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4009 for (i = 0,len = control.length; i < len; ++i) {
4010 control[i] = translateValues.call(this, control[i], start);
4014 } else if (isset(attributes['points']['by'])) {
4015 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4017 for (i = 0,len = control.length; i < len; ++i) {
4018 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4022 this.runtimeAttributes[attr] = [start];
4024 if (control.length > 0) {
4025 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4028 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4031 superclass.setRuntimeAttribute.call(this, attr);
4035 var translateValues = function(val, start) {
4036 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4037 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4042 var isset = function(prop) {
4043 return (typeof prop !== 'undefined');
4047 * Portions of this file are based on pieces of Yahoo User Interface Library
4048 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4049 * YUI licensed under the BSD License:
4050 * http://developer.yahoo.net/yui/license.txt
4051 * <script type="text/javascript">
4055 Roo.lib.Scroll = function(el, attributes, duration, method) {
4057 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4061 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4065 var superclass = Y.Scroll.superclass;
4066 var proto = Y.Scroll.prototype;
4068 proto.toString = function() {
4069 var el = this.getEl();
4070 var id = el.id || el.tagName;
4071 return ("Scroll " + id);
4074 proto.doMethod = function(attr, start, end) {
4077 if (attr == 'scroll') {
4079 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4080 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4084 val = superclass.doMethod.call(this, attr, start, end);
4089 proto.getAttribute = function(attr) {
4091 var el = this.getEl();
4093 if (attr == 'scroll') {
4094 val = [ el.scrollLeft, el.scrollTop ];
4096 val = superclass.getAttribute.call(this, attr);
4102 proto.setAttribute = function(attr, val, unit) {
4103 var el = this.getEl();
4105 if (attr == 'scroll') {
4106 el.scrollLeft = val[0];
4107 el.scrollTop = val[1];
4109 superclass.setAttribute.call(this, attr, val, unit);
4115 * Ext JS Library 1.1.1
4116 * Copyright(c) 2006-2007, Ext JS, LLC.
4118 * Originally Released Under LGPL - original licence link has changed is not relivant.
4121 * <script type="text/javascript">
4125 // nasty IE9 hack - what a pile of crap that is..
4127 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4128 Range.prototype.createContextualFragment = function (html) {
4129 var doc = window.document;
4130 var container = doc.createElement("div");
4131 container.innerHTML = html;
4132 var frag = doc.createDocumentFragment(), n;
4133 while ((n = container.firstChild)) {
4134 frag.appendChild(n);
4141 * @class Roo.DomHelper
4142 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4143 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4146 Roo.DomHelper = function(){
4147 var tempTableEl = null;
4148 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4149 var tableRe = /^table|tbody|tr|td$/i;
4151 // build as innerHTML where available
4153 var createHtml = function(o){
4154 if(typeof o == 'string'){
4163 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4164 if(attr == "style"){
4166 if(typeof s == "function"){
4169 if(typeof s == "string"){
4170 b += ' style="' + s + '"';
4171 }else if(typeof s == "object"){
4174 if(typeof s[key] != "function"){
4175 b += key + ":" + s[key] + ";";
4182 b += ' class="' + o["cls"] + '"';
4183 }else if(attr == "htmlFor"){
4184 b += ' for="' + o["htmlFor"] + '"';
4186 b += " " + attr + '="' + o[attr] + '"';
4190 if(emptyTags.test(o.tag)){
4194 var cn = o.children || o.cn;
4196 //http://bugs.kde.org/show_bug.cgi?id=71506
4197 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4198 for(var i = 0, len = cn.length; i < len; i++) {
4199 b += createHtml(cn[i], b);
4202 b += createHtml(cn, b);
4208 b += "</" + o.tag + ">";
4215 var createDom = function(o, parentNode){
4217 // defininition craeted..
4219 if (o.ns && o.ns != 'html') {
4221 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4222 xmlns[o.ns] = o.xmlns;
4225 if (typeof(xmlns[o.ns]) == 'undefined') {
4226 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4232 if (typeof(o) == 'string') {
4233 return parentNode.appendChild(document.createTextNode(o));
4235 o.tag = o.tag || div;
4236 if (o.ns && Roo.isIE) {
4238 o.tag = o.ns + ':' + o.tag;
4241 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4242 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4245 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4246 attr == "style" || typeof o[attr] == "function") { continue; }
4248 if(attr=="cls" && Roo.isIE){
4249 el.className = o["cls"];
4251 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4257 Roo.DomHelper.applyStyles(el, o.style);
4258 var cn = o.children || o.cn;
4260 //http://bugs.kde.org/show_bug.cgi?id=71506
4261 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4262 for(var i = 0, len = cn.length; i < len; i++) {
4263 createDom(cn[i], el);
4270 el.innerHTML = o.html;
4273 parentNode.appendChild(el);
4278 var ieTable = function(depth, s, h, e){
4279 tempTableEl.innerHTML = [s, h, e].join('');
4280 var i = -1, el = tempTableEl;
4287 // kill repeat to save bytes
4291 tbe = '</tbody>'+te,
4297 * Nasty code for IE's broken table implementation
4299 var insertIntoTable = function(tag, where, el, html){
4301 tempTableEl = document.createElement('div');
4306 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4309 if(where == 'beforebegin'){
4313 before = el.nextSibling;
4316 node = ieTable(4, trs, html, tre);
4318 else if(tag == 'tr'){
4319 if(where == 'beforebegin'){
4322 node = ieTable(3, tbs, html, tbe);
4323 } else if(where == 'afterend'){
4324 before = el.nextSibling;
4326 node = ieTable(3, tbs, html, tbe);
4327 } else{ // INTO a TR
4328 if(where == 'afterbegin'){
4329 before = el.firstChild;
4331 node = ieTable(4, trs, html, tre);
4333 } else if(tag == 'tbody'){
4334 if(where == 'beforebegin'){
4337 node = ieTable(2, ts, html, te);
4338 } else if(where == 'afterend'){
4339 before = el.nextSibling;
4341 node = ieTable(2, ts, html, te);
4343 if(where == 'afterbegin'){
4344 before = el.firstChild;
4346 node = ieTable(3, tbs, html, tbe);
4349 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4352 if(where == 'afterbegin'){
4353 before = el.firstChild;
4355 node = ieTable(2, ts, html, te);
4357 el.insertBefore(node, before);
4362 /** True to force the use of DOM instead of html fragments @type Boolean */
4366 * Returns the markup for the passed Element(s) config
4367 * @param {Object} o The Dom object spec (and children)
4370 markup : function(o){
4371 return createHtml(o);
4375 * Applies a style specification to an element
4376 * @param {String/HTMLElement} el The element to apply styles to
4377 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4378 * a function which returns such a specification.
4380 applyStyles : function(el, styles){
4383 if(typeof styles == "string"){
4384 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4386 while ((matches = re.exec(styles)) != null){
4387 el.setStyle(matches[1], matches[2]);
4389 }else if (typeof styles == "object"){
4390 for (var style in styles){
4391 el.setStyle(style, styles[style]);
4393 }else if (typeof styles == "function"){
4394 Roo.DomHelper.applyStyles(el, styles.call());
4400 * Inserts an HTML fragment into the Dom
4401 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4402 * @param {HTMLElement} el The context element
4403 * @param {String} html The HTML fragmenet
4404 * @return {HTMLElement} The new node
4406 insertHtml : function(where, el, html){
4407 where = where.toLowerCase();
4408 if(el.insertAdjacentHTML){
4409 if(tableRe.test(el.tagName)){
4411 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4417 el.insertAdjacentHTML('BeforeBegin', html);
4418 return el.previousSibling;
4420 el.insertAdjacentHTML('AfterBegin', html);
4421 return el.firstChild;
4423 el.insertAdjacentHTML('BeforeEnd', html);
4424 return el.lastChild;
4426 el.insertAdjacentHTML('AfterEnd', html);
4427 return el.nextSibling;
4429 throw 'Illegal insertion point -> "' + where + '"';
4431 var range = el.ownerDocument.createRange();
4435 range.setStartBefore(el);
4436 frag = range.createContextualFragment(html);
4437 el.parentNode.insertBefore(frag, el);
4438 return el.previousSibling;
4441 range.setStartBefore(el.firstChild);
4442 frag = range.createContextualFragment(html);
4443 el.insertBefore(frag, el.firstChild);
4444 return el.firstChild;
4446 el.innerHTML = html;
4447 return el.firstChild;
4451 range.setStartAfter(el.lastChild);
4452 frag = range.createContextualFragment(html);
4453 el.appendChild(frag);
4454 return el.lastChild;
4456 el.innerHTML = html;
4457 return el.lastChild;
4460 range.setStartAfter(el);
4461 frag = range.createContextualFragment(html);
4462 el.parentNode.insertBefore(frag, el.nextSibling);
4463 return el.nextSibling;
4465 throw 'Illegal insertion point -> "' + where + '"';
4469 * Creates new Dom element(s) and inserts them before el
4470 * @param {String/HTMLElement/Element} el The context element
4471 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4472 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4473 * @return {HTMLElement/Roo.Element} The new node
4475 insertBefore : function(el, o, returnElement){
4476 return this.doInsert(el, o, returnElement, "beforeBegin");
4480 * Creates new Dom element(s) and inserts them after el
4481 * @param {String/HTMLElement/Element} el The context element
4482 * @param {Object} o The Dom object spec (and children)
4483 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4484 * @return {HTMLElement/Roo.Element} The new node
4486 insertAfter : function(el, o, returnElement){
4487 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4491 * Creates new Dom element(s) and inserts them as the first child of el
4492 * @param {String/HTMLElement/Element} el The context element
4493 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4494 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4495 * @return {HTMLElement/Roo.Element} The new node
4497 insertFirst : function(el, o, returnElement){
4498 return this.doInsert(el, o, returnElement, "afterBegin");
4502 doInsert : function(el, o, returnElement, pos, sibling){
4503 el = Roo.getDom(el);
4505 if(this.useDom || o.ns){
4506 newNode = createDom(o, null);
4507 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4509 var html = createHtml(o);
4510 newNode = this.insertHtml(pos, el, html);
4512 return returnElement ? Roo.get(newNode, true) : newNode;
4516 * Creates new Dom element(s) and appends them to el
4517 * @param {String/HTMLElement/Element} el The context element
4518 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4519 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4520 * @return {HTMLElement/Roo.Element} The new node
4522 append : function(el, o, returnElement){
4523 el = Roo.getDom(el);
4525 if(this.useDom || o.ns){
4526 newNode = createDom(o, null);
4527 el.appendChild(newNode);
4529 var html = createHtml(o);
4530 newNode = this.insertHtml("beforeEnd", el, html);
4532 return returnElement ? Roo.get(newNode, true) : newNode;
4536 * Creates new Dom element(s) and overwrites the contents of el with them
4537 * @param {String/HTMLElement/Element} el The context element
4538 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4539 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4540 * @return {HTMLElement/Roo.Element} The new node
4542 overwrite : function(el, o, returnElement){
4543 el = Roo.getDom(el);
4546 while (el.childNodes.length) {
4547 el.removeChild(el.firstChild);
4551 el.innerHTML = createHtml(o);
4554 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4558 * Creates a new Roo.DomHelper.Template from the Dom object spec
4559 * @param {Object} o The Dom object spec (and children)
4560 * @return {Roo.DomHelper.Template} The new template
4562 createTemplate : function(o){
4563 var html = createHtml(o);
4564 return new Roo.Template(html);
4570 * Ext JS Library 1.1.1
4571 * Copyright(c) 2006-2007, Ext JS, LLC.
4573 * Originally Released Under LGPL - original licence link has changed is not relivant.
4576 * <script type="text/javascript">
4580 * @class Roo.Template
4581 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4582 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4585 var t = new Roo.Template({
4586 html : '<div name="{id}">' +
4587 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4589 myformat: function (value, allValues) {
4590 return 'XX' + value;
4593 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4595 * For more information see this blog post with examples:
4596 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4597 - Create Elements using DOM, HTML fragments and Templates</a>.
4599 * @param {Object} cfg - Configuration object.
4601 Roo.Template = function(cfg){
4603 if(cfg instanceof Array){
4605 }else if(arguments.length > 1){
4606 cfg = Array.prototype.join.call(arguments, "");
4610 if (typeof(cfg) == 'object') {
4621 Roo.Template.prototype = {
4624 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4625 * it should be fixed so that template is observable...
4629 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4633 * Returns an HTML fragment of this template with the specified values applied.
4634 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4635 * @return {String} The HTML fragment
4637 applyTemplate : function(values){
4641 return this.compiled(values);
4643 var useF = this.disableFormats !== true;
4644 var fm = Roo.util.Format, tpl = this;
4645 var fn = function(m, name, format, args){
4647 if(format.substr(0, 5) == "this."){
4648 return tpl.call(format.substr(5), values[name], values);
4651 // quoted values are required for strings in compiled templates,
4652 // but for non compiled we need to strip them
4653 // quoted reversed for jsmin
4654 var re = /^\s*['"](.*)["']\s*$/;
4655 args = args.split(',');
4656 for(var i = 0, len = args.length; i < len; i++){
4657 args[i] = args[i].replace(re, "$1");
4659 args = [values[name]].concat(args);
4661 args = [values[name]];
4663 return fm[format].apply(fm, args);
4666 return values[name] !== undefined ? values[name] : "";
4669 return this.html.replace(this.re, fn);
4687 this.loading = true;
4688 this.compiled = false;
4690 var cx = new Roo.data.Connection();
4694 success : function (response) {
4696 _t.html = response.responseText;
4700 failure : function(response) {
4701 Roo.log("Template failed to load from " + _t.url);
4708 * Sets the HTML used as the template and optionally compiles it.
4709 * @param {String} html
4710 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4711 * @return {Roo.Template} this
4713 set : function(html, compile){
4715 this.compiled = null;
4723 * True to disable format functions (defaults to false)
4726 disableFormats : false,
4729 * The regular expression used to match template variables
4733 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4736 * Compiles the template into an internal function, eliminating the RegEx overhead.
4737 * @return {Roo.Template} this
4739 compile : function(){
4740 var fm = Roo.util.Format;
4741 var useF = this.disableFormats !== true;
4742 var sep = Roo.isGecko ? "+" : ",";
4743 var fn = function(m, name, format, args){
4745 args = args ? ',' + args : "";
4746 if(format.substr(0, 5) != "this."){
4747 format = "fm." + format + '(';
4749 format = 'this.call("'+ format.substr(5) + '", ';
4753 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4755 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4758 // branched to use + in gecko and [].join() in others
4760 body = "this.compiled = function(values){ return '" +
4761 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4764 body = ["this.compiled = function(values){ return ['"];
4765 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4766 body.push("'].join('');};");
4767 body = body.join('');
4777 // private function used to call members
4778 call : function(fnName, value, allValues){
4779 return this[fnName](value, allValues);
4783 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4784 * @param {String/HTMLElement/Roo.Element} el The context element
4785 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4786 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4787 * @return {HTMLElement/Roo.Element} The new node or Element
4789 insertFirst: function(el, values, returnElement){
4790 return this.doInsert('afterBegin', el, values, returnElement);
4794 * Applies the supplied values to the template and inserts the new node(s) before el.
4795 * @param {String/HTMLElement/Roo.Element} el The context element
4796 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4797 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4798 * @return {HTMLElement/Roo.Element} The new node or Element
4800 insertBefore: function(el, values, returnElement){
4801 return this.doInsert('beforeBegin', el, values, returnElement);
4805 * Applies the supplied values to the template and inserts the new node(s) after el.
4806 * @param {String/HTMLElement/Roo.Element} el The context element
4807 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4808 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4809 * @return {HTMLElement/Roo.Element} The new node or Element
4811 insertAfter : function(el, values, returnElement){
4812 return this.doInsert('afterEnd', el, values, returnElement);
4816 * Applies the supplied values to the template and appends the new node(s) to el.
4817 * @param {String/HTMLElement/Roo.Element} el The context element
4818 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4819 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4820 * @return {HTMLElement/Roo.Element} The new node or Element
4822 append : function(el, values, returnElement){
4823 return this.doInsert('beforeEnd', el, values, returnElement);
4826 doInsert : function(where, el, values, returnEl){
4827 el = Roo.getDom(el);
4828 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4829 return returnEl ? Roo.get(newNode, true) : newNode;
4833 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4834 * @param {String/HTMLElement/Roo.Element} el The context element
4835 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4836 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4837 * @return {HTMLElement/Roo.Element} The new node or Element
4839 overwrite : function(el, values, returnElement){
4840 el = Roo.getDom(el);
4841 el.innerHTML = this.applyTemplate(values);
4842 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4846 * Alias for {@link #applyTemplate}
4849 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4852 Roo.DomHelper.Template = Roo.Template;
4855 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4856 * @param {String/HTMLElement} el A DOM element or its id
4857 * @returns {Roo.Template} The created template
4860 Roo.Template.from = function(el){
4861 el = Roo.getDom(el);
4862 return new Roo.Template(el.value || el.innerHTML);
4865 * Ext JS Library 1.1.1
4866 * Copyright(c) 2006-2007, Ext JS, LLC.
4868 * Originally Released Under LGPL - original licence link has changed is not relivant.
4871 * <script type="text/javascript">
4876 * This is code is also distributed under MIT license for use
4877 * with jQuery and prototype JavaScript libraries.
4880 * @class Roo.DomQuery
4881 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4883 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4886 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4888 <h4>Element Selectors:</h4>
4890 <li> <b>*</b> any element</li>
4891 <li> <b>E</b> an element with the tag E</li>
4892 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4893 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4894 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4895 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4897 <h4>Attribute Selectors:</h4>
4898 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4900 <li> <b>E[foo]</b> has an attribute "foo"</li>
4901 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4902 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4903 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4904 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4905 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4906 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4908 <h4>Pseudo Classes:</h4>
4910 <li> <b>E:first-child</b> E is the first child of its parent</li>
4911 <li> <b>E:last-child</b> E is the last child of its parent</li>
4912 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4913 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4914 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4915 <li> <b>E:only-child</b> E is the only child of its parent</li>
4916 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4917 <li> <b>E:first</b> the first E in the resultset</li>
4918 <li> <b>E:last</b> the last E in the resultset</li>
4919 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4920 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4921 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4922 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4923 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4924 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4925 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4926 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4927 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4929 <h4>CSS Value Selectors:</h4>
4931 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4932 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4933 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4934 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4935 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4936 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4940 Roo.DomQuery = function(){
4941 var cache = {}, simpleCache = {}, valueCache = {};
4942 var nonSpace = /\S/;
4943 var trimRe = /^\s+|\s+$/g;
4944 var tplRe = /\{(\d+)\}/g;
4945 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4946 var tagTokenRe = /^(#)?([\w-\*]+)/;
4947 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4949 function child(p, index){
4951 var n = p.firstChild;
4953 if(n.nodeType == 1){
4964 while((n = n.nextSibling) && n.nodeType != 1);
4969 while((n = n.previousSibling) && n.nodeType != 1);
4973 function children(d){
4974 var n = d.firstChild, ni = -1;
4976 var nx = n.nextSibling;
4977 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4987 function byClassName(c, a, v){
4991 var r = [], ri = -1, cn;
4992 for(var i = 0, ci; ci = c[i]; i++){
4993 if((' '+ci.className+' ').indexOf(v) != -1){
5000 function attrValue(n, attr){
5001 if(!n.tagName && typeof n.length != "undefined"){
5010 if(attr == "class" || attr == "className"){
5013 return n.getAttribute(attr) || n[attr];
5017 function getNodes(ns, mode, tagName){
5018 var result = [], ri = -1, cs;
5022 tagName = tagName || "*";
5023 if(typeof ns.getElementsByTagName != "undefined"){
5027 for(var i = 0, ni; ni = ns[i]; i++){
5028 cs = ni.getElementsByTagName(tagName);
5029 for(var j = 0, ci; ci = cs[j]; j++){
5033 }else if(mode == "/" || mode == ">"){
5034 var utag = tagName.toUpperCase();
5035 for(var i = 0, ni, cn; ni = ns[i]; i++){
5036 cn = ni.children || ni.childNodes;
5037 for(var j = 0, cj; cj = cn[j]; j++){
5038 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5043 }else if(mode == "+"){
5044 var utag = tagName.toUpperCase();
5045 for(var i = 0, n; n = ns[i]; i++){
5046 while((n = n.nextSibling) && n.nodeType != 1);
5047 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5051 }else if(mode == "~"){
5052 for(var i = 0, n; n = ns[i]; i++){
5053 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5062 function concat(a, b){
5066 for(var i = 0, l = b.length; i < l; i++){
5072 function byTag(cs, tagName){
5073 if(cs.tagName || cs == document){
5079 var r = [], ri = -1;
5080 tagName = tagName.toLowerCase();
5081 for(var i = 0, ci; ci = cs[i]; i++){
5082 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5089 function byId(cs, attr, id){
5090 if(cs.tagName || cs == document){
5096 var r = [], ri = -1;
5097 for(var i = 0,ci; ci = cs[i]; i++){
5098 if(ci && ci.id == id){
5106 function byAttribute(cs, attr, value, op, custom){
5107 var r = [], ri = -1, st = custom=="{";
5108 var f = Roo.DomQuery.operators[op];
5109 for(var i = 0, ci; ci = cs[i]; i++){
5112 a = Roo.DomQuery.getStyle(ci, attr);
5114 else if(attr == "class" || attr == "className"){
5116 }else if(attr == "for"){
5118 }else if(attr == "href"){
5119 a = ci.getAttribute("href", 2);
5121 a = ci.getAttribute(attr);
5123 if((f && f(a, value)) || (!f && a)){
5130 function byPseudo(cs, name, value){
5131 return Roo.DomQuery.pseudos[name](cs, value);
5134 // This is for IE MSXML which does not support expandos.
5135 // IE runs the same speed using setAttribute, however FF slows way down
5136 // and Safari completely fails so they need to continue to use expandos.
5137 var isIE = window.ActiveXObject ? true : false;
5139 // this eval is stop the compressor from
5140 // renaming the variable to something shorter
5142 /** eval:var:batch */
5147 function nodupIEXml(cs){
5149 cs[0].setAttribute("_nodup", d);
5151 for(var i = 1, len = cs.length; i < len; i++){
5153 if(!c.getAttribute("_nodup") != d){
5154 c.setAttribute("_nodup", d);
5158 for(var i = 0, len = cs.length; i < len; i++){
5159 cs[i].removeAttribute("_nodup");
5168 var len = cs.length, c, i, r = cs, cj, ri = -1;
5169 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5172 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5173 return nodupIEXml(cs);
5177 for(i = 1; c = cs[i]; i++){
5182 for(var j = 0; j < i; j++){
5185 for(j = i+1; cj = cs[j]; j++){
5197 function quickDiffIEXml(c1, c2){
5199 for(var i = 0, len = c1.length; i < len; i++){
5200 c1[i].setAttribute("_qdiff", d);
5203 for(var i = 0, len = c2.length; i < len; i++){
5204 if(c2[i].getAttribute("_qdiff") != d){
5205 r[r.length] = c2[i];
5208 for(var i = 0, len = c1.length; i < len; i++){
5209 c1[i].removeAttribute("_qdiff");
5214 function quickDiff(c1, c2){
5215 var len1 = c1.length;
5219 if(isIE && c1[0].selectSingleNode){
5220 return quickDiffIEXml(c1, c2);
5223 for(var i = 0; i < len1; i++){
5227 for(var i = 0, len = c2.length; i < len; i++){
5228 if(c2[i]._qdiff != d){
5229 r[r.length] = c2[i];
5235 function quickId(ns, mode, root, id){
5237 var d = root.ownerDocument || root;
5238 return d.getElementById(id);
5240 ns = getNodes(ns, mode, "*");
5241 return byId(ns, null, id);
5245 getStyle : function(el, name){
5246 return Roo.fly(el).getStyle(name);
5249 * Compiles a selector/xpath query into a reusable function. The returned function
5250 * takes one parameter "root" (optional), which is the context node from where the query should start.
5251 * @param {String} selector The selector/xpath query
5252 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5253 * @return {Function}
5255 compile : function(path, type){
5256 type = type || "select";
5258 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5259 var q = path, mode, lq;
5260 var tk = Roo.DomQuery.matchers;
5261 var tklen = tk.length;
5264 // accept leading mode switch
5265 var lmode = q.match(modeRe);
5266 if(lmode && lmode[1]){
5267 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5268 q = q.replace(lmode[1], "");
5270 // strip leading slashes
5271 while(path.substr(0, 1)=="/"){
5272 path = path.substr(1);
5275 while(q && lq != q){
5277 var tm = q.match(tagTokenRe);
5278 if(type == "select"){
5281 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5283 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5285 q = q.replace(tm[0], "");
5286 }else if(q.substr(0, 1) != '@'){
5287 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5292 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5294 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5296 q = q.replace(tm[0], "");
5299 while(!(mm = q.match(modeRe))){
5300 var matched = false;
5301 for(var j = 0; j < tklen; j++){
5303 var m = q.match(t.re);
5305 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5308 q = q.replace(m[0], "");
5313 // prevent infinite loop on bad selector
5315 throw 'Error parsing selector, parsing failed at "' + q + '"';
5319 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5320 q = q.replace(mm[1], "");
5323 fn[fn.length] = "return nodup(n);\n}";
5326 * list of variables that need from compression as they are used by eval.
5336 * eval:var:byClassName
5338 * eval:var:byAttribute
5339 * eval:var:attrValue
5347 * Selects a group of elements.
5348 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5349 * @param {Node} root (optional) The start of the query (defaults to document).
5352 select : function(path, root, type){
5353 if(!root || root == document){
5356 if(typeof root == "string"){
5357 root = document.getElementById(root);
5359 var paths = path.split(",");
5361 for(var i = 0, len = paths.length; i < len; i++){
5362 var p = paths[i].replace(trimRe, "");
5364 cache[p] = Roo.DomQuery.compile(p);
5366 throw p + " is not a valid selector";
5369 var result = cache[p](root);
5370 if(result && result != document){
5371 results = results.concat(result);
5374 if(paths.length > 1){
5375 return nodup(results);
5381 * Selects a single element.
5382 * @param {String} selector The selector/xpath query
5383 * @param {Node} root (optional) The start of the query (defaults to document).
5386 selectNode : function(path, root){
5387 return Roo.DomQuery.select(path, root)[0];
5391 * Selects the value of a node, optionally replacing null with the defaultValue.
5392 * @param {String} selector The selector/xpath query
5393 * @param {Node} root (optional) The start of the query (defaults to document).
5394 * @param {String} defaultValue
5396 selectValue : function(path, root, defaultValue){
5397 path = path.replace(trimRe, "");
5398 if(!valueCache[path]){
5399 valueCache[path] = Roo.DomQuery.compile(path, "select");
5401 var n = valueCache[path](root);
5402 n = n[0] ? n[0] : n;
5403 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5404 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5408 * Selects the value of a node, parsing integers and floats.
5409 * @param {String} selector The selector/xpath query
5410 * @param {Node} root (optional) The start of the query (defaults to document).
5411 * @param {Number} defaultValue
5414 selectNumber : function(path, root, defaultValue){
5415 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5416 return parseFloat(v);
5420 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5421 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5422 * @param {String} selector The simple selector to test
5425 is : function(el, ss){
5426 if(typeof el == "string"){
5427 el = document.getElementById(el);
5429 var isArray = (el instanceof Array);
5430 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5431 return isArray ? (result.length == el.length) : (result.length > 0);
5435 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5436 * @param {Array} el An array of elements to filter
5437 * @param {String} selector The simple selector to test
5438 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5439 * the selector instead of the ones that match
5442 filter : function(els, ss, nonMatches){
5443 ss = ss.replace(trimRe, "");
5444 if(!simpleCache[ss]){
5445 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5447 var result = simpleCache[ss](els);
5448 return nonMatches ? quickDiff(result, els) : result;
5452 * Collection of matching regular expressions and code snippets.
5456 select: 'n = byClassName(n, null, " {1} ");'
5458 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5459 select: 'n = byPseudo(n, "{1}", "{2}");'
5461 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5462 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5465 select: 'n = byId(n, null, "{1}");'
5468 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5473 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5474 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5477 "=" : function(a, v){
5480 "!=" : function(a, v){
5483 "^=" : function(a, v){
5484 return a && a.substr(0, v.length) == v;
5486 "$=" : function(a, v){
5487 return a && a.substr(a.length-v.length) == v;
5489 "*=" : function(a, v){
5490 return a && a.indexOf(v) !== -1;
5492 "%=" : function(a, v){
5493 return (a % v) == 0;
5495 "|=" : function(a, v){
5496 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5498 "~=" : function(a, v){
5499 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5504 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5505 * and the argument (if any) supplied in the selector.
5508 "first-child" : function(c){
5509 var r = [], ri = -1, n;
5510 for(var i = 0, ci; ci = n = c[i]; i++){
5511 while((n = n.previousSibling) && n.nodeType != 1);
5519 "last-child" : function(c){
5520 var r = [], ri = -1, n;
5521 for(var i = 0, ci; ci = n = c[i]; i++){
5522 while((n = n.nextSibling) && n.nodeType != 1);
5530 "nth-child" : function(c, a) {
5531 var r = [], ri = -1;
5532 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5533 var f = (m[1] || 1) - 0, l = m[2] - 0;
5534 for(var i = 0, n; n = c[i]; i++){
5535 var pn = n.parentNode;
5536 if (batch != pn._batch) {
5538 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5539 if(cn.nodeType == 1){
5546 if (l == 0 || n.nodeIndex == l){
5549 } else if ((n.nodeIndex + l) % f == 0){
5557 "only-child" : function(c){
5558 var r = [], ri = -1;;
5559 for(var i = 0, ci; ci = c[i]; i++){
5560 if(!prev(ci) && !next(ci)){
5567 "empty" : function(c){
5568 var r = [], ri = -1;
5569 for(var i = 0, ci; ci = c[i]; i++){
5570 var cns = ci.childNodes, j = 0, cn, empty = true;
5573 if(cn.nodeType == 1 || cn.nodeType == 3){
5585 "contains" : function(c, v){
5586 var r = [], ri = -1;
5587 for(var i = 0, ci; ci = c[i]; i++){
5588 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5595 "nodeValue" : function(c, v){
5596 var r = [], ri = -1;
5597 for(var i = 0, ci; ci = c[i]; i++){
5598 if(ci.firstChild && ci.firstChild.nodeValue == v){
5605 "checked" : function(c){
5606 var r = [], ri = -1;
5607 for(var i = 0, ci; ci = c[i]; i++){
5608 if(ci.checked == true){
5615 "not" : function(c, ss){
5616 return Roo.DomQuery.filter(c, ss, true);
5619 "odd" : function(c){
5620 return this["nth-child"](c, "odd");
5623 "even" : function(c){
5624 return this["nth-child"](c, "even");
5627 "nth" : function(c, a){
5628 return c[a-1] || [];
5631 "first" : function(c){
5635 "last" : function(c){
5636 return c[c.length-1] || [];
5639 "has" : function(c, ss){
5640 var s = Roo.DomQuery.select;
5641 var r = [], ri = -1;
5642 for(var i = 0, ci; ci = c[i]; i++){
5643 if(s(ss, ci).length > 0){
5650 "next" : function(c, ss){
5651 var is = Roo.DomQuery.is;
5652 var r = [], ri = -1;
5653 for(var i = 0, ci; ci = c[i]; i++){
5662 "prev" : function(c, ss){
5663 var is = Roo.DomQuery.is;
5664 var r = [], ri = -1;
5665 for(var i = 0, ci; ci = c[i]; i++){
5678 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5679 * @param {String} path The selector/xpath query
5680 * @param {Node} root (optional) The start of the query (defaults to document).
5685 Roo.query = Roo.DomQuery.select;
5688 * Ext JS Library 1.1.1
5689 * Copyright(c) 2006-2007, Ext JS, LLC.
5691 * Originally Released Under LGPL - original licence link has changed is not relivant.
5694 * <script type="text/javascript">
5698 * @class Roo.util.Observable
5699 * Base class that provides a common interface for publishing events. Subclasses are expected to
5700 * to have a property "events" with all the events defined.<br>
5703 Employee = function(name){
5710 Roo.extend(Employee, Roo.util.Observable);
5712 * @param {Object} config properties to use (incuding events / listeners)
5715 Roo.util.Observable = function(cfg){
5718 this.addEvents(cfg.events || {});
5720 delete cfg.events; // make sure
5723 Roo.apply(this, cfg);
5726 this.on(this.listeners);
5727 delete this.listeners;
5730 Roo.util.Observable.prototype = {
5732 * @cfg {Object} listeners list of events and functions to call for this object,
5736 'click' : function(e) {
5746 * Fires the specified event with the passed parameters (minus the event name).
5747 * @param {String} eventName
5748 * @param {Object...} args Variable number of parameters are passed to handlers
5749 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5751 fireEvent : function(){
5752 var ce = this.events[arguments[0].toLowerCase()];
5753 if(typeof ce == "object"){
5754 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5761 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5764 * Appends an event handler to this component
5765 * @param {String} eventName The type of event to listen for
5766 * @param {Function} handler The method the event invokes
5767 * @param {Object} scope (optional) The scope in which to execute the handler
5768 * function. The handler function's "this" context.
5769 * @param {Object} options (optional) An object containing handler configuration
5770 * properties. This may contain any of the following properties:<ul>
5771 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5772 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5773 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5774 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5775 * by the specified number of milliseconds. If the event fires again within that time, the original
5776 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5779 * <b>Combining Options</b><br>
5780 * Using the options argument, it is possible to combine different types of listeners:<br>
5782 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5784 el.on('click', this.onClick, this, {
5791 * <b>Attaching multiple handlers in 1 call</b><br>
5792 * The method also allows for a single argument to be passed which is a config object containing properties
5793 * which specify multiple handlers.
5802 fn: this.onMouseOver,
5806 fn: this.onMouseOut,
5812 * Or a shorthand syntax which passes the same scope object to all handlers:
5815 'click': this.onClick,
5816 'mouseover': this.onMouseOver,
5817 'mouseout': this.onMouseOut,
5822 addListener : function(eventName, fn, scope, o){
5823 if(typeof eventName == "object"){
5826 if(this.filterOptRe.test(e)){
5829 if(typeof o[e] == "function"){
5831 this.addListener(e, o[e], o.scope, o);
5833 // individual options
5834 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5839 o = (!o || typeof o == "boolean") ? {} : o;
5840 eventName = eventName.toLowerCase();
5841 var ce = this.events[eventName] || true;
5842 if(typeof ce == "boolean"){
5843 ce = new Roo.util.Event(this, eventName);
5844 this.events[eventName] = ce;
5846 ce.addListener(fn, scope, o);
5850 * Removes a listener
5851 * @param {String} eventName The type of event to listen for
5852 * @param {Function} handler The handler to remove
5853 * @param {Object} scope (optional) The scope (this object) for the handler
5855 removeListener : function(eventName, fn, scope){
5856 var ce = this.events[eventName.toLowerCase()];
5857 if(typeof ce == "object"){
5858 ce.removeListener(fn, scope);
5863 * Removes all listeners for this object
5865 purgeListeners : function(){
5866 for(var evt in this.events){
5867 if(typeof this.events[evt] == "object"){
5868 this.events[evt].clearListeners();
5873 relayEvents : function(o, events){
5874 var createHandler = function(ename){
5876 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5879 for(var i = 0, len = events.length; i < len; i++){
5880 var ename = events[i];
5881 if(!this.events[ename]){ this.events[ename] = true; };
5882 o.on(ename, createHandler(ename), this);
5887 * Used to define events on this Observable
5888 * @param {Object} object The object with the events defined
5890 addEvents : function(o){
5894 Roo.applyIf(this.events, o);
5898 * Checks to see if this object has any listeners for a specified event
5899 * @param {String} eventName The name of the event to check for
5900 * @return {Boolean} True if the event is being listened for, else false
5902 hasListener : function(eventName){
5903 var e = this.events[eventName];
5904 return typeof e == "object" && e.listeners.length > 0;
5908 * Appends an event handler to this element (shorthand for addListener)
5909 * @param {String} eventName The type of event to listen for
5910 * @param {Function} handler The method the event invokes
5911 * @param {Object} scope (optional) The scope in which to execute the handler
5912 * function. The handler function's "this" context.
5913 * @param {Object} options (optional)
5916 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5918 * Removes a listener (shorthand for removeListener)
5919 * @param {String} eventName The type of event to listen for
5920 * @param {Function} handler The handler to remove
5921 * @param {Object} scope (optional) The scope (this object) for the handler
5924 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5927 * Starts capture on the specified Observable. All events will be passed
5928 * to the supplied function with the event name + standard signature of the event
5929 * <b>before</b> the event is fired. If the supplied function returns false,
5930 * the event will not fire.
5931 * @param {Observable} o The Observable to capture
5932 * @param {Function} fn The function to call
5933 * @param {Object} scope (optional) The scope (this object) for the fn
5936 Roo.util.Observable.capture = function(o, fn, scope){
5937 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5941 * Removes <b>all</b> added captures from the Observable.
5942 * @param {Observable} o The Observable to release
5945 Roo.util.Observable.releaseCapture = function(o){
5946 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5951 var createBuffered = function(h, o, scope){
5952 var task = new Roo.util.DelayedTask();
5954 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5958 var createSingle = function(h, e, fn, scope){
5960 e.removeListener(fn, scope);
5961 return h.apply(scope, arguments);
5965 var createDelayed = function(h, o, scope){
5967 var args = Array.prototype.slice.call(arguments, 0);
5968 setTimeout(function(){
5969 h.apply(scope, args);
5974 Roo.util.Event = function(obj, name){
5977 this.listeners = [];
5980 Roo.util.Event.prototype = {
5981 addListener : function(fn, scope, options){
5982 var o = options || {};
5983 scope = scope || this.obj;
5984 if(!this.isListening(fn, scope)){
5985 var l = {fn: fn, scope: scope, options: o};
5988 h = createDelayed(h, o, scope);
5991 h = createSingle(h, this, fn, scope);
5994 h = createBuffered(h, o, scope);
5997 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5998 this.listeners.push(l);
6000 this.listeners = this.listeners.slice(0);
6001 this.listeners.push(l);
6006 findListener : function(fn, scope){
6007 scope = scope || this.obj;
6008 var ls = this.listeners;
6009 for(var i = 0, len = ls.length; i < len; i++){
6011 if(l.fn == fn && l.scope == scope){
6018 isListening : function(fn, scope){
6019 return this.findListener(fn, scope) != -1;
6022 removeListener : function(fn, scope){
6024 if((index = this.findListener(fn, scope)) != -1){
6026 this.listeners.splice(index, 1);
6028 this.listeners = this.listeners.slice(0);
6029 this.listeners.splice(index, 1);
6036 clearListeners : function(){
6037 this.listeners = [];
6041 var ls = this.listeners, scope, len = ls.length;
6044 var args = Array.prototype.slice.call(arguments, 0);
6045 for(var i = 0; i < len; i++){
6047 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6048 this.firing = false;
6052 this.firing = false;
6059 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6066 * @class Roo.Document
6067 * @extends Roo.util.Observable
6068 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6070 * @param {Object} config the methods and properties of the 'base' class for the application.
6072 * Generic Page handler - implement this to start your app..
6075 * MyProject = new Roo.Document({
6077 'load' : true // your events..
6080 'ready' : function() {
6081 // fired on Roo.onReady()
6086 Roo.Document = function(cfg) {
6091 Roo.util.Observable.call(this,cfg);
6095 Roo.onReady(function() {
6096 _this.fireEvent('ready');
6102 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6104 * Ext JS Library 1.1.1
6105 * Copyright(c) 2006-2007, Ext JS, LLC.
6107 * Originally Released Under LGPL - original licence link has changed is not relivant.
6110 * <script type="text/javascript">
6114 * @class Roo.EventManager
6115 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6116 * several useful events directly.
6117 * See {@link Roo.EventObject} for more details on normalized event objects.
6120 Roo.EventManager = function(){
6121 var docReadyEvent, docReadyProcId, docReadyState = false;
6122 var resizeEvent, resizeTask, textEvent, textSize;
6123 var E = Roo.lib.Event;
6124 var D = Roo.lib.Dom;
6129 var fireDocReady = function(){
6131 docReadyState = true;
6134 clearInterval(docReadyProcId);
6136 if(Roo.isGecko || Roo.isOpera) {
6137 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6140 var defer = document.getElementById("ie-deferred-loader");
6142 defer.onreadystatechange = null;
6143 defer.parentNode.removeChild(defer);
6147 docReadyEvent.fire();
6148 docReadyEvent.clearListeners();
6153 var initDocReady = function(){
6154 docReadyEvent = new Roo.util.Event();
6155 if(Roo.isGecko || Roo.isOpera) {
6156 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6158 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6159 var defer = document.getElementById("ie-deferred-loader");
6160 defer.onreadystatechange = function(){
6161 if(this.readyState == "complete"){
6165 }else if(Roo.isSafari){
6166 docReadyProcId = setInterval(function(){
6167 var rs = document.readyState;
6168 if(rs == "complete") {
6173 // no matter what, make sure it fires on load
6174 E.on(window, "load", fireDocReady);
6177 var createBuffered = function(h, o){
6178 var task = new Roo.util.DelayedTask(h);
6180 // create new event object impl so new events don't wipe out properties
6181 e = new Roo.EventObjectImpl(e);
6182 task.delay(o.buffer, h, null, [e]);
6186 var createSingle = function(h, el, ename, fn){
6188 Roo.EventManager.removeListener(el, ename, fn);
6193 var createDelayed = function(h, o){
6195 // create new event object impl so new events don't wipe out properties
6196 e = new Roo.EventObjectImpl(e);
6197 setTimeout(function(){
6202 var transitionEndVal = false;
6204 var transitionEnd = function()
6206 if (transitionEndVal) {
6207 return transitionEndVal;
6209 var el = document.createElement('div');
6211 var transEndEventNames = {
6212 WebkitTransition : 'webkitTransitionEnd',
6213 MozTransition : 'transitionend',
6214 OTransition : 'oTransitionEnd otransitionend',
6215 transition : 'transitionend'
6218 for (var name in transEndEventNames) {
6219 if (el.style[name] !== undefined) {
6220 transitionEndVal = transEndEventNames[name];
6221 return transitionEndVal ;
6227 var listen = function(element, ename, opt, fn, scope){
6228 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6229 fn = fn || o.fn; scope = scope || o.scope;
6230 var el = Roo.getDom(element);
6234 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6237 if (ename == 'transitionend') {
6238 ename = transitionEnd();
6240 var h = function(e){
6241 e = Roo.EventObject.setEvent(e);
6244 t = e.getTarget(o.delegate, el);
6251 if(o.stopEvent === true){
6254 if(o.preventDefault === true){
6257 if(o.stopPropagation === true){
6258 e.stopPropagation();
6261 if(o.normalized === false){
6265 fn.call(scope || el, e, t, o);
6268 h = createDelayed(h, o);
6271 h = createSingle(h, el, ename, fn);
6274 h = createBuffered(h, o);
6276 fn._handlers = fn._handlers || [];
6279 fn._handlers.push([Roo.id(el), ename, h]);
6284 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6285 el.addEventListener("DOMMouseScroll", h, false);
6286 E.on(window, 'unload', function(){
6287 el.removeEventListener("DOMMouseScroll", h, false);
6290 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6291 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6296 var stopListening = function(el, ename, fn){
6297 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6299 for(var i = 0, len = hds.length; i < len; i++){
6301 if(h[0] == id && h[1] == ename){
6308 E.un(el, ename, hd);
6309 el = Roo.getDom(el);
6310 if(ename == "mousewheel" && el.addEventListener){
6311 el.removeEventListener("DOMMouseScroll", hd, false);
6313 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6314 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6318 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6325 * @scope Roo.EventManager
6330 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6331 * object with a Roo.EventObject
6332 * @param {Function} fn The method the event invokes
6333 * @param {Object} scope An object that becomes the scope of the handler
6334 * @param {boolean} override If true, the obj passed in becomes
6335 * the execution scope of the listener
6336 * @return {Function} The wrapped function
6339 wrap : function(fn, scope, override){
6341 Roo.EventObject.setEvent(e);
6342 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6347 * Appends an event handler to an element (shorthand for addListener)
6348 * @param {String/HTMLElement} element The html element or id to assign the
6349 * @param {String} eventName The type of event to listen for
6350 * @param {Function} handler The method the event invokes
6351 * @param {Object} scope (optional) The scope in which to execute the handler
6352 * function. The handler function's "this" context.
6353 * @param {Object} options (optional) An object containing handler configuration
6354 * properties. This may contain any of the following properties:<ul>
6355 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6356 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6357 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6358 * <li>preventDefault {Boolean} True to prevent the default action</li>
6359 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6360 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6361 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6362 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6363 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6364 * by the specified number of milliseconds. If the event fires again within that time, the original
6365 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6368 * <b>Combining Options</b><br>
6369 * Using the options argument, it is possible to combine different types of listeners:<br>
6371 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6373 el.on('click', this.onClick, this, {
6380 * <b>Attaching multiple handlers in 1 call</b><br>
6381 * The method also allows for a single argument to be passed which is a config object containing properties
6382 * which specify multiple handlers.
6392 fn: this.onMouseOver
6401 * Or a shorthand syntax:<br>
6404 'click' : this.onClick,
6405 'mouseover' : this.onMouseOver,
6406 'mouseout' : this.onMouseOut
6410 addListener : function(element, eventName, fn, scope, options){
6411 if(typeof eventName == "object"){
6417 if(typeof o[e] == "function"){
6419 listen(element, e, o, o[e], o.scope);
6421 // individual options
6422 listen(element, e, o[e]);
6427 return listen(element, eventName, options, fn, scope);
6431 * Removes an event handler
6433 * @param {String/HTMLElement} element The id or html element to remove the
6435 * @param {String} eventName The type of event
6436 * @param {Function} fn
6437 * @return {Boolean} True if a listener was actually removed
6439 removeListener : function(element, eventName, fn){
6440 return stopListening(element, eventName, fn);
6444 * Fires when the document is ready (before onload and before images are loaded). Can be
6445 * accessed shorthanded Roo.onReady().
6446 * @param {Function} fn The method the event invokes
6447 * @param {Object} scope An object that becomes the scope of the handler
6448 * @param {boolean} options
6450 onDocumentReady : function(fn, scope, options){
6451 if(docReadyState){ // if it already fired
6452 docReadyEvent.addListener(fn, scope, options);
6453 docReadyEvent.fire();
6454 docReadyEvent.clearListeners();
6460 docReadyEvent.addListener(fn, scope, options);
6464 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6465 * @param {Function} fn The method the event invokes
6466 * @param {Object} scope An object that becomes the scope of the handler
6467 * @param {boolean} options
6469 onWindowResize : function(fn, scope, options){
6471 resizeEvent = new Roo.util.Event();
6472 resizeTask = new Roo.util.DelayedTask(function(){
6473 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6475 E.on(window, "resize", function(){
6477 resizeTask.delay(50);
6479 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6483 resizeEvent.addListener(fn, scope, options);
6487 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6488 * @param {Function} fn The method the event invokes
6489 * @param {Object} scope An object that becomes the scope of the handler
6490 * @param {boolean} options
6492 onTextResize : function(fn, scope, options){
6494 textEvent = new Roo.util.Event();
6495 var textEl = new Roo.Element(document.createElement('div'));
6496 textEl.dom.className = 'x-text-resize';
6497 textEl.dom.innerHTML = 'X';
6498 textEl.appendTo(document.body);
6499 textSize = textEl.dom.offsetHeight;
6500 setInterval(function(){
6501 if(textEl.dom.offsetHeight != textSize){
6502 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6504 }, this.textResizeInterval);
6506 textEvent.addListener(fn, scope, options);
6510 * Removes the passed window resize listener.
6511 * @param {Function} fn The method the event invokes
6512 * @param {Object} scope The scope of handler
6514 removeResizeListener : function(fn, scope){
6516 resizeEvent.removeListener(fn, scope);
6521 fireResize : function(){
6523 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6527 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6531 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6533 textResizeInterval : 50
6538 * @scopeAlias pub=Roo.EventManager
6542 * Appends an event handler to an element (shorthand for addListener)
6543 * @param {String/HTMLElement} element The html element or id to assign the
6544 * @param {String} eventName The type of event to listen for
6545 * @param {Function} handler The method the event invokes
6546 * @param {Object} scope (optional) The scope in which to execute the handler
6547 * function. The handler function's "this" context.
6548 * @param {Object} options (optional) An object containing handler configuration
6549 * properties. This may contain any of the following properties:<ul>
6550 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6551 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6552 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6553 * <li>preventDefault {Boolean} True to prevent the default action</li>
6554 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6555 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6556 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6557 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6558 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6559 * by the specified number of milliseconds. If the event fires again within that time, the original
6560 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6563 * <b>Combining Options</b><br>
6564 * Using the options argument, it is possible to combine different types of listeners:<br>
6566 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6568 el.on('click', this.onClick, this, {
6575 * <b>Attaching multiple handlers in 1 call</b><br>
6576 * The method also allows for a single argument to be passed which is a config object containing properties
6577 * which specify multiple handlers.
6587 fn: this.onMouseOver
6596 * Or a shorthand syntax:<br>
6599 'click' : this.onClick,
6600 'mouseover' : this.onMouseOver,
6601 'mouseout' : this.onMouseOut
6605 pub.on = pub.addListener;
6606 pub.un = pub.removeListener;
6608 pub.stoppedMouseDownEvent = new Roo.util.Event();
6612 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6613 * @param {Function} fn The method the event invokes
6614 * @param {Object} scope An object that becomes the scope of the handler
6615 * @param {boolean} override If true, the obj passed in becomes
6616 * the execution scope of the listener
6620 Roo.onReady = Roo.EventManager.onDocumentReady;
6622 Roo.onReady(function(){
6623 var bd = Roo.get(document.body);
6628 : Roo.isGecko ? "roo-gecko"
6629 : Roo.isOpera ? "roo-opera"
6630 : Roo.isSafari ? "roo-safari" : ""];
6633 cls.push("roo-mac");
6636 cls.push("roo-linux");
6639 cls.push("roo-ios");
6642 cls.push("roo-touch");
6644 if(Roo.isBorderBox){
6645 cls.push('roo-border-box');
6647 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6648 var p = bd.dom.parentNode;
6650 p.className += ' roo-strict';
6653 bd.addClass(cls.join(' '));
6657 * @class Roo.EventObject
6658 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6659 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6662 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6664 var target = e.getTarget();
6667 var myDiv = Roo.get("myDiv");
6668 myDiv.on("click", handleClick);
6670 Roo.EventManager.on("myDiv", 'click', handleClick);
6671 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6675 Roo.EventObject = function(){
6677 var E = Roo.lib.Event;
6679 // safari keypress events for special keys return bad keycodes
6682 63235 : 39, // right
6685 63276 : 33, // page up
6686 63277 : 34, // page down
6687 63272 : 46, // delete
6692 // normalize button clicks
6693 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6694 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6696 Roo.EventObjectImpl = function(e){
6698 this.setEvent(e.browserEvent || e);
6701 Roo.EventObjectImpl.prototype = {
6703 * Used to fix doc tools.
6704 * @scope Roo.EventObject.prototype
6710 /** The normal browser event */
6711 browserEvent : null,
6712 /** The button pressed in a mouse event */
6714 /** True if the shift key was down during the event */
6716 /** True if the control key was down during the event */
6718 /** True if the alt key was down during the event */
6777 setEvent : function(e){
6778 if(e == this || (e && e.browserEvent)){ // already wrapped
6781 this.browserEvent = e;
6783 // normalize buttons
6784 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6785 if(e.type == 'click' && this.button == -1){
6789 this.shiftKey = e.shiftKey;
6790 // mac metaKey behaves like ctrlKey
6791 this.ctrlKey = e.ctrlKey || e.metaKey;
6792 this.altKey = e.altKey;
6793 // in getKey these will be normalized for the mac
6794 this.keyCode = e.keyCode;
6795 // keyup warnings on firefox.
6796 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6797 // cache the target for the delayed and or buffered events
6798 this.target = E.getTarget(e);
6800 this.xy = E.getXY(e);
6803 this.shiftKey = false;
6804 this.ctrlKey = false;
6805 this.altKey = false;
6815 * Stop the event (preventDefault and stopPropagation)
6817 stopEvent : function(){
6818 if(this.browserEvent){
6819 if(this.browserEvent.type == 'mousedown'){
6820 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6822 E.stopEvent(this.browserEvent);
6827 * Prevents the browsers default handling of the event.
6829 preventDefault : function(){
6830 if(this.browserEvent){
6831 E.preventDefault(this.browserEvent);
6836 isNavKeyPress : function(){
6837 var k = this.keyCode;
6838 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6839 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6842 isSpecialKey : function(){
6843 var k = this.keyCode;
6844 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6845 (k == 16) || (k == 17) ||
6846 (k >= 18 && k <= 20) ||
6847 (k >= 33 && k <= 35) ||
6848 (k >= 36 && k <= 39) ||
6849 (k >= 44 && k <= 45);
6852 * Cancels bubbling of the event.
6854 stopPropagation : function(){
6855 if(this.browserEvent){
6856 if(this.type == 'mousedown'){
6857 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6859 E.stopPropagation(this.browserEvent);
6864 * Gets the key code for the event.
6867 getCharCode : function(){
6868 return this.charCode || this.keyCode;
6872 * Returns a normalized keyCode for the event.
6873 * @return {Number} The key code
6875 getKey : function(){
6876 var k = this.keyCode || this.charCode;
6877 return Roo.isSafari ? (safariKeys[k] || k) : k;
6881 * Gets the x coordinate of the event.
6884 getPageX : function(){
6889 * Gets the y coordinate of the event.
6892 getPageY : function(){
6897 * Gets the time of the event.
6900 getTime : function(){
6901 if(this.browserEvent){
6902 return E.getTime(this.browserEvent);
6908 * Gets the page coordinates of the event.
6909 * @return {Array} The xy values like [x, y]
6916 * Gets the target for the event.
6917 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6918 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6919 search as a number or element (defaults to 10 || document.body)
6920 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6921 * @return {HTMLelement}
6923 getTarget : function(selector, maxDepth, returnEl){
6924 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6927 * Gets the related target.
6928 * @return {HTMLElement}
6930 getRelatedTarget : function(){
6931 if(this.browserEvent){
6932 return E.getRelatedTarget(this.browserEvent);
6938 * Normalizes mouse wheel delta across browsers
6939 * @return {Number} The delta
6941 getWheelDelta : function(){
6942 var e = this.browserEvent;
6944 if(e.wheelDelta){ /* IE/Opera. */
6945 delta = e.wheelDelta/120;
6946 }else if(e.detail){ /* Mozilla case. */
6947 delta = -e.detail/3;
6953 * Returns true if the control, meta, shift or alt key was pressed during this event.
6956 hasModifier : function(){
6957 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6961 * Returns true if the target of this event equals el or is a child of el
6962 * @param {String/HTMLElement/Element} el
6963 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6966 within : function(el, related){
6967 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6968 return t && Roo.fly(el).contains(t);
6971 getPoint : function(){
6972 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6976 return new Roo.EventObjectImpl();
6981 * Ext JS Library 1.1.1
6982 * Copyright(c) 2006-2007, Ext JS, LLC.
6984 * Originally Released Under LGPL - original licence link has changed is not relivant.
6987 * <script type="text/javascript">
6991 // was in Composite Element!??!?!
6994 var D = Roo.lib.Dom;
6995 var E = Roo.lib.Event;
6996 var A = Roo.lib.Anim;
6998 // local style camelizing for speed
7000 var camelRe = /(-[a-z])/gi;
7001 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7002 var view = document.defaultView;
7005 * @class Roo.Element
7006 * Represents an Element in the DOM.<br><br>
7009 var el = Roo.get("my-div");
7012 var el = getEl("my-div");
7014 // or with a DOM element
7015 var el = Roo.get(myDivElement);
7017 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7018 * each call instead of constructing a new one.<br><br>
7019 * <b>Animations</b><br />
7020 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7021 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7023 Option Default Description
7024 --------- -------- ---------------------------------------------
7025 duration .35 The duration of the animation in seconds
7026 easing easeOut The YUI easing method
7027 callback none A function to execute when the anim completes
7028 scope this The scope (this) of the callback function
7030 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7031 * manipulate the animation. Here's an example:
7033 var el = Roo.get("my-div");
7038 // default animation
7039 el.setWidth(100, true);
7041 // animation with some options set
7048 // using the "anim" property to get the Anim object
7054 el.setWidth(100, opt);
7056 if(opt.anim.isAnimated()){
7060 * <b> Composite (Collections of) Elements</b><br />
7061 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7062 * @constructor Create a new Element directly.
7063 * @param {String/HTMLElement} element
7064 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
7066 Roo.Element = function(element, forceNew){
7067 var dom = typeof element == "string" ?
7068 document.getElementById(element) : element;
7069 if(!dom){ // invalid id/element
7073 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7074 return Roo.Element.cache[id];
7084 * The DOM element ID
7087 this.id = id || Roo.id(dom);
7090 var El = Roo.Element;
7094 * The element's default display mode (defaults to "")
7097 originalDisplay : "",
7101 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7107 * Sets the element's visibility mode. When setVisible() is called it
7108 * will use this to determine whether to set the visibility or the display property.
7109 * @param visMode Element.VISIBILITY or Element.DISPLAY
7110 * @return {Roo.Element} this
7112 setVisibilityMode : function(visMode){
7113 this.visibilityMode = visMode;
7117 * Convenience method for setVisibilityMode(Element.DISPLAY)
7118 * @param {String} display (optional) What to set display to when visible
7119 * @return {Roo.Element} this
7121 enableDisplayMode : function(display){
7122 this.setVisibilityMode(El.DISPLAY);
7123 if(typeof display != "undefined") { this.originalDisplay = display; }
7128 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7129 * @param {String} selector The simple selector to test
7130 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7131 search as a number or element (defaults to 10 || document.body)
7132 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7133 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7135 findParent : function(simpleSelector, maxDepth, returnEl){
7136 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7137 maxDepth = maxDepth || 50;
7138 if(typeof maxDepth != "number"){
7139 stopEl = Roo.getDom(maxDepth);
7142 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7143 if(dq.is(p, simpleSelector)){
7144 return returnEl ? Roo.get(p) : p;
7154 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7155 * @param {String} selector The simple selector to test
7156 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7157 search as a number or element (defaults to 10 || document.body)
7158 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7159 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7161 findParentNode : function(simpleSelector, maxDepth, returnEl){
7162 var p = Roo.fly(this.dom.parentNode, '_internal');
7163 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7167 * Looks at the scrollable parent element
7169 findScrollableParent : function(){
7171 var overflowRegex = /(auto|scroll)/;
7173 if(this.getStyle('position') === 'fixed'){
7174 return Roo.get(document.body);
7177 var excludeStaticParent = this.getStyle('position') === "absolute";
7179 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7181 if (excludeStaticParent && parent.getStyle('position') === "static") {
7185 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7190 return Roo.get(document.body);
7194 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7195 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7196 * @param {String} selector The simple selector to test
7197 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7198 search as a number or element (defaults to 10 || document.body)
7199 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7201 up : function(simpleSelector, maxDepth){
7202 return this.findParentNode(simpleSelector, maxDepth, true);
7208 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7209 * @param {String} selector The simple selector to test
7210 * @return {Boolean} True if this element matches the selector, else false
7212 is : function(simpleSelector){
7213 return Roo.DomQuery.is(this.dom, simpleSelector);
7217 * Perform animation on this element.
7218 * @param {Object} args The YUI animation control args
7219 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7220 * @param {Function} onComplete (optional) Function to call when animation completes
7221 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7222 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7223 * @return {Roo.Element} this
7225 animate : function(args, duration, onComplete, easing, animType){
7226 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7231 * @private Internal animation call
7233 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7234 animType = animType || 'run';
7236 var anim = Roo.lib.Anim[animType](
7238 (opt.duration || defaultDur) || .35,
7239 (opt.easing || defaultEase) || 'easeOut',
7241 Roo.callback(cb, this);
7242 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7250 // private legacy anim prep
7251 preanim : function(a, i){
7252 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7256 * Removes worthless text nodes
7257 * @param {Boolean} forceReclean (optional) By default the element
7258 * keeps track if it has been cleaned already so
7259 * you can call this over and over. However, if you update the element and
7260 * need to force a reclean, you can pass true.
7262 clean : function(forceReclean){
7263 if(this.isCleaned && forceReclean !== true){
7267 var d = this.dom, n = d.firstChild, ni = -1;
7269 var nx = n.nextSibling;
7270 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7277 this.isCleaned = true;
7282 calcOffsetsTo : function(el){
7285 var restorePos = false;
7286 if(el.getStyle('position') == 'static'){
7287 el.position('relative');
7292 while(op && op != d && op.tagName != 'HTML'){
7295 op = op.offsetParent;
7298 el.position('static');
7304 * Scrolls this element into view within the passed container.
7305 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7306 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7307 * @return {Roo.Element} this
7309 scrollIntoView : function(container, hscroll){
7310 var c = Roo.getDom(container) || document.body;
7313 var o = this.calcOffsetsTo(c),
7316 b = t+el.offsetHeight,
7317 r = l+el.offsetWidth;
7319 var ch = c.clientHeight;
7320 var ct = parseInt(c.scrollTop, 10);
7321 var cl = parseInt(c.scrollLeft, 10);
7323 var cr = cl + c.clientWidth;
7331 if(hscroll !== false){
7335 c.scrollLeft = r-c.clientWidth;
7342 scrollChildIntoView : function(child, hscroll){
7343 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7347 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7348 * the new height may not be available immediately.
7349 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7350 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7351 * @param {Function} onComplete (optional) Function to call when animation completes
7352 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7353 * @return {Roo.Element} this
7355 autoHeight : function(animate, duration, onComplete, easing){
7356 var oldHeight = this.getHeight();
7358 this.setHeight(1); // force clipping
7359 setTimeout(function(){
7360 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7362 this.setHeight(height);
7364 if(typeof onComplete == "function"){
7368 this.setHeight(oldHeight); // restore original height
7369 this.setHeight(height, animate, duration, function(){
7371 if(typeof onComplete == "function") { onComplete(); }
7372 }.createDelegate(this), easing);
7374 }.createDelegate(this), 0);
7379 * Returns true if this element is an ancestor of the passed element
7380 * @param {HTMLElement/String} el The element to check
7381 * @return {Boolean} True if this element is an ancestor of el, else false
7383 contains : function(el){
7384 if(!el){return false;}
7385 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7389 * Checks whether the element is currently visible using both visibility and display properties.
7390 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7391 * @return {Boolean} True if the element is currently visible, else false
7393 isVisible : function(deep) {
7394 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7395 if(deep !== true || !vis){
7398 var p = this.dom.parentNode;
7399 while(p && p.tagName.toLowerCase() != "body"){
7400 if(!Roo.fly(p, '_isVisible').isVisible()){
7409 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7410 * @param {String} selector The CSS selector
7411 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7412 * @return {CompositeElement/CompositeElementLite} The composite element
7414 select : function(selector, unique){
7415 return El.select(selector, unique, this.dom);
7419 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7420 * @param {String} selector The CSS selector
7421 * @return {Array} An array of the matched nodes
7423 query : function(selector, unique){
7424 return Roo.DomQuery.select(selector, this.dom);
7428 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7429 * @param {String} selector The CSS selector
7430 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7431 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7433 child : function(selector, returnDom){
7434 var n = Roo.DomQuery.selectNode(selector, this.dom);
7435 return returnDom ? n : Roo.get(n);
7439 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7440 * @param {String} selector The CSS selector
7441 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7442 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7444 down : function(selector, returnDom){
7445 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7446 return returnDom ? n : Roo.get(n);
7450 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7451 * @param {String} group The group the DD object is member of
7452 * @param {Object} config The DD config object
7453 * @param {Object} overrides An object containing methods to override/implement on the DD object
7454 * @return {Roo.dd.DD} The DD object
7456 initDD : function(group, config, overrides){
7457 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7458 return Roo.apply(dd, overrides);
7462 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7463 * @param {String} group The group the DDProxy object is member of
7464 * @param {Object} config The DDProxy config object
7465 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7466 * @return {Roo.dd.DDProxy} The DDProxy object
7468 initDDProxy : function(group, config, overrides){
7469 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7470 return Roo.apply(dd, overrides);
7474 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7475 * @param {String} group The group the DDTarget object is member of
7476 * @param {Object} config The DDTarget config object
7477 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7478 * @return {Roo.dd.DDTarget} The DDTarget object
7480 initDDTarget : function(group, config, overrides){
7481 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7482 return Roo.apply(dd, overrides);
7486 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7487 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7488 * @param {Boolean} visible Whether the element is visible
7489 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7490 * @return {Roo.Element} this
7492 setVisible : function(visible, animate){
7494 if(this.visibilityMode == El.DISPLAY){
7495 this.setDisplayed(visible);
7498 this.dom.style.visibility = visible ? "visible" : "hidden";
7501 // closure for composites
7503 var visMode = this.visibilityMode;
7505 this.setOpacity(.01);
7506 this.setVisible(true);
7508 this.anim({opacity: { to: (visible?1:0) }},
7509 this.preanim(arguments, 1),
7510 null, .35, 'easeIn', function(){
7512 if(visMode == El.DISPLAY){
7513 dom.style.display = "none";
7515 dom.style.visibility = "hidden";
7517 Roo.get(dom).setOpacity(1);
7525 * Returns true if display is not "none"
7528 isDisplayed : function() {
7529 return this.getStyle("display") != "none";
7533 * Toggles the element's visibility or display, depending on visibility mode.
7534 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7535 * @return {Roo.Element} this
7537 toggle : function(animate){
7538 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7543 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7544 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7545 * @return {Roo.Element} this
7547 setDisplayed : function(value) {
7548 if(typeof value == "boolean"){
7549 value = value ? this.originalDisplay : "none";
7551 this.setStyle("display", value);
7556 * Tries to focus the element. Any exceptions are caught and ignored.
7557 * @return {Roo.Element} this
7559 focus : function() {
7567 * Tries to blur the element. Any exceptions are caught and ignored.
7568 * @return {Roo.Element} this
7578 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7579 * @param {String/Array} className The CSS class to add, or an array of classes
7580 * @return {Roo.Element} this
7582 addClass : function(className){
7583 if(className instanceof Array){
7584 for(var i = 0, len = className.length; i < len; i++) {
7585 this.addClass(className[i]);
7588 if(className && !this.hasClass(className)){
7589 this.dom.className = this.dom.className + " " + className;
7596 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7597 * @param {String/Array} className The CSS class to add, or an array of classes
7598 * @return {Roo.Element} this
7600 radioClass : function(className){
7601 var siblings = this.dom.parentNode.childNodes;
7602 for(var i = 0; i < siblings.length; i++) {
7603 var s = siblings[i];
7604 if(s.nodeType == 1){
7605 Roo.get(s).removeClass(className);
7608 this.addClass(className);
7613 * Removes one or more CSS classes from the element.
7614 * @param {String/Array} className The CSS class to remove, or an array of classes
7615 * @return {Roo.Element} this
7617 removeClass : function(className){
7618 if(!className || !this.dom.className){
7621 if(className instanceof Array){
7622 for(var i = 0, len = className.length; i < len; i++) {
7623 this.removeClass(className[i]);
7626 if(this.hasClass(className)){
7627 var re = this.classReCache[className];
7629 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7630 this.classReCache[className] = re;
7632 this.dom.className =
7633 this.dom.className.replace(re, " ");
7643 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7644 * @param {String} className The CSS class to toggle
7645 * @return {Roo.Element} this
7647 toggleClass : function(className){
7648 if(this.hasClass(className)){
7649 this.removeClass(className);
7651 this.addClass(className);
7657 * Checks if the specified CSS class exists on this element's DOM node.
7658 * @param {String} className The CSS class to check for
7659 * @return {Boolean} True if the class exists, else false
7661 hasClass : function(className){
7662 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7666 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7667 * @param {String} oldClassName The CSS class to replace
7668 * @param {String} newClassName The replacement CSS class
7669 * @return {Roo.Element} this
7671 replaceClass : function(oldClassName, newClassName){
7672 this.removeClass(oldClassName);
7673 this.addClass(newClassName);
7678 * Returns an object with properties matching the styles requested.
7679 * For example, el.getStyles('color', 'font-size', 'width') might return
7680 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7681 * @param {String} style1 A style name
7682 * @param {String} style2 A style name
7683 * @param {String} etc.
7684 * @return {Object} The style object
7686 getStyles : function(){
7687 var a = arguments, len = a.length, r = {};
7688 for(var i = 0; i < len; i++){
7689 r[a[i]] = this.getStyle(a[i]);
7695 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7696 * @param {String} property The style property whose value is returned.
7697 * @return {String} The current value of the style property for this element.
7699 getStyle : function(){
7700 return view && view.getComputedStyle ?
7702 var el = this.dom, v, cs, camel;
7703 if(prop == 'float'){
7706 if(el.style && (v = el.style[prop])){
7709 if(cs = view.getComputedStyle(el, "")){
7710 if(!(camel = propCache[prop])){
7711 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7718 var el = this.dom, v, cs, camel;
7719 if(prop == 'opacity'){
7720 if(typeof el.style.filter == 'string'){
7721 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7723 var fv = parseFloat(m[1]);
7725 return fv ? fv / 100 : 0;
7730 }else if(prop == 'float'){
7731 prop = "styleFloat";
7733 if(!(camel = propCache[prop])){
7734 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7736 if(v = el.style[camel]){
7739 if(cs = el.currentStyle){
7747 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7748 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7749 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7750 * @return {Roo.Element} this
7752 setStyle : function(prop, value){
7753 if(typeof prop == "string"){
7755 if (prop == 'float') {
7756 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7761 if(!(camel = propCache[prop])){
7762 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7765 if(camel == 'opacity') {
7766 this.setOpacity(value);
7768 this.dom.style[camel] = value;
7771 for(var style in prop){
7772 if(typeof prop[style] != "function"){
7773 this.setStyle(style, prop[style]);
7781 * More flexible version of {@link #setStyle} for setting style properties.
7782 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7783 * a function which returns such a specification.
7784 * @return {Roo.Element} this
7786 applyStyles : function(style){
7787 Roo.DomHelper.applyStyles(this.dom, style);
7792 * 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).
7793 * @return {Number} The X position of the element
7796 return D.getX(this.dom);
7800 * 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).
7801 * @return {Number} The Y position of the element
7804 return D.getY(this.dom);
7808 * 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).
7809 * @return {Array} The XY position of the element
7812 return D.getXY(this.dom);
7816 * 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).
7817 * @param {Number} The X position of the element
7818 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7819 * @return {Roo.Element} this
7821 setX : function(x, animate){
7823 D.setX(this.dom, x);
7825 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7831 * 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).
7832 * @param {Number} The Y position of the element
7833 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7834 * @return {Roo.Element} this
7836 setY : function(y, animate){
7838 D.setY(this.dom, y);
7840 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7846 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7847 * @param {String} left The left CSS property value
7848 * @return {Roo.Element} this
7850 setLeft : function(left){
7851 this.setStyle("left", this.addUnits(left));
7856 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7857 * @param {String} top The top CSS property value
7858 * @return {Roo.Element} this
7860 setTop : function(top){
7861 this.setStyle("top", this.addUnits(top));
7866 * Sets the element's CSS right style.
7867 * @param {String} right The right CSS property value
7868 * @return {Roo.Element} this
7870 setRight : function(right){
7871 this.setStyle("right", this.addUnits(right));
7876 * Sets the element's CSS bottom style.
7877 * @param {String} bottom The bottom CSS property value
7878 * @return {Roo.Element} this
7880 setBottom : function(bottom){
7881 this.setStyle("bottom", this.addUnits(bottom));
7886 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7887 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7888 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7889 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7890 * @return {Roo.Element} this
7892 setXY : function(pos, animate){
7894 D.setXY(this.dom, pos);
7896 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7902 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7903 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7904 * @param {Number} x X value for new position (coordinates are page-based)
7905 * @param {Number} y Y value for new position (coordinates are page-based)
7906 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7907 * @return {Roo.Element} this
7909 setLocation : function(x, y, animate){
7910 this.setXY([x, y], this.preanim(arguments, 2));
7915 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7916 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7917 * @param {Number} x X value for new position (coordinates are page-based)
7918 * @param {Number} y Y value for new position (coordinates are page-based)
7919 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7920 * @return {Roo.Element} this
7922 moveTo : function(x, y, animate){
7923 this.setXY([x, y], this.preanim(arguments, 2));
7928 * Returns the region of the given element.
7929 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7930 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7932 getRegion : function(){
7933 return D.getRegion(this.dom);
7937 * Returns the offset height of the element
7938 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7939 * @return {Number} The element's height
7941 getHeight : function(contentHeight){
7942 var h = this.dom.offsetHeight || 0;
7943 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7947 * Returns the offset width of the element
7948 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7949 * @return {Number} The element's width
7951 getWidth : function(contentWidth){
7952 var w = this.dom.offsetWidth || 0;
7953 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7957 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7958 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7959 * if a height has not been set using CSS.
7962 getComputedHeight : function(){
7963 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7965 h = parseInt(this.getStyle('height'), 10) || 0;
7966 if(!this.isBorderBox()){
7967 h += this.getFrameWidth('tb');
7974 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7975 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7976 * if a width has not been set using CSS.
7979 getComputedWidth : function(){
7980 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7982 w = parseInt(this.getStyle('width'), 10) || 0;
7983 if(!this.isBorderBox()){
7984 w += this.getFrameWidth('lr');
7991 * Returns the size of the element.
7992 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7993 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7995 getSize : function(contentSize){
7996 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8000 * Returns the width and height of the viewport.
8001 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8003 getViewSize : function(){
8004 var d = this.dom, doc = document, aw = 0, ah = 0;
8005 if(d == doc || d == doc.body){
8006 return {width : D.getViewWidth(), height: D.getViewHeight()};
8009 width : d.clientWidth,
8010 height: d.clientHeight
8016 * Returns the value of the "value" attribute
8017 * @param {Boolean} asNumber true to parse the value as a number
8018 * @return {String/Number}
8020 getValue : function(asNumber){
8021 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8025 adjustWidth : function(width){
8026 if(typeof width == "number"){
8027 if(this.autoBoxAdjust && !this.isBorderBox()){
8028 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8038 adjustHeight : function(height){
8039 if(typeof height == "number"){
8040 if(this.autoBoxAdjust && !this.isBorderBox()){
8041 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8051 * Set the width of the element
8052 * @param {Number} width The new width
8053 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8054 * @return {Roo.Element} this
8056 setWidth : function(width, animate){
8057 width = this.adjustWidth(width);
8059 this.dom.style.width = this.addUnits(width);
8061 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8067 * Set the height of the element
8068 * @param {Number} height The new height
8069 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8070 * @return {Roo.Element} this
8072 setHeight : function(height, animate){
8073 height = this.adjustHeight(height);
8075 this.dom.style.height = this.addUnits(height);
8077 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8083 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8084 * @param {Number} width The new width
8085 * @param {Number} height The new height
8086 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8087 * @return {Roo.Element} this
8089 setSize : function(width, height, animate){
8090 if(typeof width == "object"){ // in case of object from getSize()
8091 height = width.height; width = width.width;
8093 width = this.adjustWidth(width); height = this.adjustHeight(height);
8095 this.dom.style.width = this.addUnits(width);
8096 this.dom.style.height = this.addUnits(height);
8098 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8104 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8105 * @param {Number} x X value for new position (coordinates are page-based)
8106 * @param {Number} y Y value for new position (coordinates are page-based)
8107 * @param {Number} width The new width
8108 * @param {Number} height The new height
8109 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8110 * @return {Roo.Element} this
8112 setBounds : function(x, y, width, height, animate){
8114 this.setSize(width, height);
8115 this.setLocation(x, y);
8117 width = this.adjustWidth(width); height = this.adjustHeight(height);
8118 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8119 this.preanim(arguments, 4), 'motion');
8125 * 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.
8126 * @param {Roo.lib.Region} region The region to fill
8127 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8128 * @return {Roo.Element} this
8130 setRegion : function(region, animate){
8131 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8136 * Appends an event handler
8138 * @param {String} eventName The type of event to append
8139 * @param {Function} fn The method the event invokes
8140 * @param {Object} scope (optional) The scope (this object) of the fn
8141 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8143 addListener : function(eventName, fn, scope, options){
8145 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8150 * Removes an event handler from this element
8151 * @param {String} eventName the type of event to remove
8152 * @param {Function} fn the method the event invokes
8153 * @return {Roo.Element} this
8155 removeListener : function(eventName, fn){
8156 Roo.EventManager.removeListener(this.dom, eventName, fn);
8161 * Removes all previous added listeners from this element
8162 * @return {Roo.Element} this
8164 removeAllListeners : function(){
8165 E.purgeElement(this.dom);
8169 relayEvent : function(eventName, observable){
8170 this.on(eventName, function(e){
8171 observable.fireEvent(eventName, e);
8176 * Set the opacity of the element
8177 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8178 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8179 * @return {Roo.Element} this
8181 setOpacity : function(opacity, animate){
8183 var s = this.dom.style;
8186 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8187 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8189 s.opacity = opacity;
8192 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8198 * Gets the left X coordinate
8199 * @param {Boolean} local True to get the local css position instead of page coordinate
8202 getLeft : function(local){
8206 return parseInt(this.getStyle("left"), 10) || 0;
8211 * Gets the right X coordinate of the element (element X position + element width)
8212 * @param {Boolean} local True to get the local css position instead of page coordinate
8215 getRight : function(local){
8217 return this.getX() + this.getWidth();
8219 return (this.getLeft(true) + this.getWidth()) || 0;
8224 * Gets the top Y coordinate
8225 * @param {Boolean} local True to get the local css position instead of page coordinate
8228 getTop : function(local) {
8232 return parseInt(this.getStyle("top"), 10) || 0;
8237 * Gets the bottom Y coordinate of the element (element Y position + element height)
8238 * @param {Boolean} local True to get the local css position instead of page coordinate
8241 getBottom : function(local){
8243 return this.getY() + this.getHeight();
8245 return (this.getTop(true) + this.getHeight()) || 0;
8250 * Initializes positioning on this element. If a desired position is not passed, it will make the
8251 * the element positioned relative IF it is not already positioned.
8252 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8253 * @param {Number} zIndex (optional) The zIndex to apply
8254 * @param {Number} x (optional) Set the page X position
8255 * @param {Number} y (optional) Set the page Y position
8257 position : function(pos, zIndex, x, y){
8259 if(this.getStyle('position') == 'static'){
8260 this.setStyle('position', 'relative');
8263 this.setStyle("position", pos);
8266 this.setStyle("z-index", zIndex);
8268 if(x !== undefined && y !== undefined){
8270 }else if(x !== undefined){
8272 }else if(y !== undefined){
8278 * Clear positioning back to the default when the document was loaded
8279 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8280 * @return {Roo.Element} this
8282 clearPositioning : function(value){
8290 "position" : "static"
8296 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8297 * snapshot before performing an update and then restoring the element.
8300 getPositioning : function(){
8301 var l = this.getStyle("left");
8302 var t = this.getStyle("top");
8304 "position" : this.getStyle("position"),
8306 "right" : l ? "" : this.getStyle("right"),
8308 "bottom" : t ? "" : this.getStyle("bottom"),
8309 "z-index" : this.getStyle("z-index")
8314 * Gets the width of the border(s) for the specified side(s)
8315 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8316 * passing lr would get the border (l)eft width + the border (r)ight width.
8317 * @return {Number} The width of the sides passed added together
8319 getBorderWidth : function(side){
8320 return this.addStyles(side, El.borders);
8324 * Gets the width of the padding(s) for the specified side(s)
8325 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8326 * passing lr would get the padding (l)eft + the padding (r)ight.
8327 * @return {Number} The padding of the sides passed added together
8329 getPadding : function(side){
8330 return this.addStyles(side, El.paddings);
8334 * Set positioning with an object returned by getPositioning().
8335 * @param {Object} posCfg
8336 * @return {Roo.Element} this
8338 setPositioning : function(pc){
8339 this.applyStyles(pc);
8340 if(pc.right == "auto"){
8341 this.dom.style.right = "";
8343 if(pc.bottom == "auto"){
8344 this.dom.style.bottom = "";
8350 fixDisplay : function(){
8351 if(this.getStyle("display") == "none"){
8352 this.setStyle("visibility", "hidden");
8353 this.setStyle("display", this.originalDisplay); // first try reverting to default
8354 if(this.getStyle("display") == "none"){ // if that fails, default to block
8355 this.setStyle("display", "block");
8361 * Quick set left and top adding default units
8362 * @param {String} left The left CSS property value
8363 * @param {String} top The top CSS property value
8364 * @return {Roo.Element} this
8366 setLeftTop : function(left, top){
8367 this.dom.style.left = this.addUnits(left);
8368 this.dom.style.top = this.addUnits(top);
8373 * Move this element relative to its current position.
8374 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8375 * @param {Number} distance How far to move the element in pixels
8376 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8377 * @return {Roo.Element} this
8379 move : function(direction, distance, animate){
8380 var xy = this.getXY();
8381 direction = direction.toLowerCase();
8385 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8389 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8394 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8399 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8406 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8407 * @return {Roo.Element} this
8410 if(!this.isClipped){
8411 this.isClipped = true;
8412 this.originalClip = {
8413 "o": this.getStyle("overflow"),
8414 "x": this.getStyle("overflow-x"),
8415 "y": this.getStyle("overflow-y")
8417 this.setStyle("overflow", "hidden");
8418 this.setStyle("overflow-x", "hidden");
8419 this.setStyle("overflow-y", "hidden");
8425 * Return clipping (overflow) to original clipping before clip() was called
8426 * @return {Roo.Element} this
8428 unclip : function(){
8430 this.isClipped = false;
8431 var o = this.originalClip;
8432 if(o.o){this.setStyle("overflow", o.o);}
8433 if(o.x){this.setStyle("overflow-x", o.x);}
8434 if(o.y){this.setStyle("overflow-y", o.y);}
8441 * Gets the x,y coordinates specified by the anchor position on the element.
8442 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8443 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8444 * {width: (target width), height: (target height)} (defaults to the element's current size)
8445 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8446 * @return {Array} [x, y] An array containing the element's x and y coordinates
8448 getAnchorXY : function(anchor, local, s){
8449 //Passing a different size is useful for pre-calculating anchors,
8450 //especially for anchored animations that change the el size.
8452 var w, h, vp = false;
8455 if(d == document.body || d == document){
8457 w = D.getViewWidth(); h = D.getViewHeight();
8459 w = this.getWidth(); h = this.getHeight();
8462 w = s.width; h = s.height;
8464 var x = 0, y = 0, r = Math.round;
8465 switch((anchor || "tl").toLowerCase()){
8507 var sc = this.getScroll();
8508 return [x + sc.left, y + sc.top];
8510 //Add the element's offset xy
8511 var o = this.getXY();
8512 return [x+o[0], y+o[1]];
8516 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8517 * supported position values.
8518 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8519 * @param {String} position The position to align to.
8520 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8521 * @return {Array} [x, y]
8523 getAlignToXY : function(el, p, o){
8527 throw "Element.alignTo with an element that doesn't exist";
8529 var c = false; //constrain to viewport
8530 var p1 = "", p2 = "";
8537 }else if(p.indexOf("-") == -1){
8540 p = p.toLowerCase();
8541 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8543 throw "Element.alignTo with an invalid alignment " + p;
8545 p1 = m[1]; p2 = m[2]; c = !!m[3];
8547 //Subtract the aligned el's internal xy from the target's offset xy
8548 //plus custom offset to get the aligned el's new offset xy
8549 var a1 = this.getAnchorXY(p1, true);
8550 var a2 = el.getAnchorXY(p2, false);
8551 var x = a2[0] - a1[0] + o[0];
8552 var y = a2[1] - a1[1] + o[1];
8554 //constrain the aligned el to viewport if necessary
8555 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8556 // 5px of margin for ie
8557 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8559 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8560 //perpendicular to the vp border, allow the aligned el to slide on that border,
8561 //otherwise swap the aligned el to the opposite border of the target.
8562 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8563 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8564 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8565 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8568 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8569 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8571 if((x+w) > dw + scrollX){
8572 x = swapX ? r.left-w : dw+scrollX-w;
8575 x = swapX ? r.right : scrollX;
8577 if((y+h) > dh + scrollY){
8578 y = swapY ? r.top-h : dh+scrollY-h;
8581 y = swapY ? r.bottom : scrollY;
8588 getConstrainToXY : function(){
8589 var os = {top:0, left:0, bottom:0, right: 0};
8591 return function(el, local, offsets, proposedXY){
8593 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8595 var vw, vh, vx = 0, vy = 0;
8596 if(el.dom == document.body || el.dom == document){
8597 vw = Roo.lib.Dom.getViewWidth();
8598 vh = Roo.lib.Dom.getViewHeight();
8600 vw = el.dom.clientWidth;
8601 vh = el.dom.clientHeight;
8603 var vxy = el.getXY();
8609 var s = el.getScroll();
8611 vx += offsets.left + s.left;
8612 vy += offsets.top + s.top;
8614 vw -= offsets.right;
8615 vh -= offsets.bottom;
8620 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8621 var x = xy[0], y = xy[1];
8622 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8624 // only move it if it needs it
8627 // first validate right/bottom
8636 // then make sure top/left isn't negative
8645 return moved ? [x, y] : false;
8650 adjustForConstraints : function(xy, parent, offsets){
8651 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8655 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8656 * document it aligns it to the viewport.
8657 * The position parameter is optional, and can be specified in any one of the following formats:
8659 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8660 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8661 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8662 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8663 * <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
8664 * element's anchor point, and the second value is used as the target's anchor point.</li>
8666 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8667 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8668 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8669 * that specified in order to enforce the viewport constraints.
8670 * Following are all of the supported anchor positions:
8673 ----- -----------------------------
8674 tl The top left corner (default)
8675 t The center of the top edge
8676 tr The top right corner
8677 l The center of the left edge
8678 c In the center of the element
8679 r The center of the right edge
8680 bl The bottom left corner
8681 b The center of the bottom edge
8682 br The bottom right corner
8686 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8687 el.alignTo("other-el");
8689 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8690 el.alignTo("other-el", "tr?");
8692 // align the bottom right corner of el with the center left edge of other-el
8693 el.alignTo("other-el", "br-l?");
8695 // align the center of el with the bottom left corner of other-el and
8696 // adjust the x position by -6 pixels (and the y position by 0)
8697 el.alignTo("other-el", "c-bl", [-6, 0]);
8699 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8700 * @param {String} position The position to align to.
8701 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8702 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8703 * @return {Roo.Element} this
8705 alignTo : function(element, position, offsets, animate){
8706 var xy = this.getAlignToXY(element, position, offsets);
8707 this.setXY(xy, this.preanim(arguments, 3));
8712 * Anchors an element to another element and realigns it when the window is resized.
8713 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8714 * @param {String} position The position to align to.
8715 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8716 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8717 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8718 * is a number, it is used as the buffer delay (defaults to 50ms).
8719 * @param {Function} callback The function to call after the animation finishes
8720 * @return {Roo.Element} this
8722 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8723 var action = function(){
8724 this.alignTo(el, alignment, offsets, animate);
8725 Roo.callback(callback, this);
8727 Roo.EventManager.onWindowResize(action, this);
8728 var tm = typeof monitorScroll;
8729 if(tm != 'undefined'){
8730 Roo.EventManager.on(window, 'scroll', action, this,
8731 {buffer: tm == 'number' ? monitorScroll : 50});
8733 action.call(this); // align immediately
8737 * Clears any opacity settings from this element. Required in some cases for IE.
8738 * @return {Roo.Element} this
8740 clearOpacity : function(){
8741 if (window.ActiveXObject) {
8742 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8743 this.dom.style.filter = "";
8746 this.dom.style.opacity = "";
8747 this.dom.style["-moz-opacity"] = "";
8748 this.dom.style["-khtml-opacity"] = "";
8754 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8755 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8756 * @return {Roo.Element} this
8758 hide : function(animate){
8759 this.setVisible(false, this.preanim(arguments, 0));
8764 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8765 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8766 * @return {Roo.Element} this
8768 show : function(animate){
8769 this.setVisible(true, this.preanim(arguments, 0));
8774 * @private Test if size has a unit, otherwise appends the default
8776 addUnits : function(size){
8777 return Roo.Element.addUnits(size, this.defaultUnit);
8781 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8782 * @return {Roo.Element} this
8784 beginMeasure : function(){
8786 if(el.offsetWidth || el.offsetHeight){
8787 return this; // offsets work already
8790 var p = this.dom, b = document.body; // start with this element
8791 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8792 var pe = Roo.get(p);
8793 if(pe.getStyle('display') == 'none'){
8794 changed.push({el: p, visibility: pe.getStyle("visibility")});
8795 p.style.visibility = "hidden";
8796 p.style.display = "block";
8800 this._measureChanged = changed;
8806 * Restores displays to before beginMeasure was called
8807 * @return {Roo.Element} this
8809 endMeasure : function(){
8810 var changed = this._measureChanged;
8812 for(var i = 0, len = changed.length; i < len; i++) {
8814 r.el.style.visibility = r.visibility;
8815 r.el.style.display = "none";
8817 this._measureChanged = null;
8823 * Update the innerHTML of this element, optionally searching for and processing scripts
8824 * @param {String} html The new HTML
8825 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8826 * @param {Function} callback For async script loading you can be noticed when the update completes
8827 * @return {Roo.Element} this
8829 update : function(html, loadScripts, callback){
8830 if(typeof html == "undefined"){
8833 if(loadScripts !== true){
8834 this.dom.innerHTML = html;
8835 if(typeof callback == "function"){
8843 html += '<span id="' + id + '"></span>';
8845 E.onAvailable(id, function(){
8846 var hd = document.getElementsByTagName("head")[0];
8847 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8848 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8849 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8852 while(match = re.exec(html)){
8853 var attrs = match[1];
8854 var srcMatch = attrs ? attrs.match(srcRe) : false;
8855 if(srcMatch && srcMatch[2]){
8856 var s = document.createElement("script");
8857 s.src = srcMatch[2];
8858 var typeMatch = attrs.match(typeRe);
8859 if(typeMatch && typeMatch[2]){
8860 s.type = typeMatch[2];
8863 }else if(match[2] && match[2].length > 0){
8864 if(window.execScript) {
8865 window.execScript(match[2]);
8873 window.eval(match[2]);
8877 var el = document.getElementById(id);
8878 if(el){el.parentNode.removeChild(el);}
8879 if(typeof callback == "function"){
8883 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8888 * Direct access to the UpdateManager update() method (takes the same parameters).
8889 * @param {String/Function} url The url for this request or a function to call to get the url
8890 * @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}
8891 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8892 * @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.
8893 * @return {Roo.Element} this
8896 var um = this.getUpdateManager();
8897 um.update.apply(um, arguments);
8902 * Gets this element's UpdateManager
8903 * @return {Roo.UpdateManager} The UpdateManager
8905 getUpdateManager : function(){
8906 if(!this.updateManager){
8907 this.updateManager = new Roo.UpdateManager(this);
8909 return this.updateManager;
8913 * Disables text selection for this element (normalized across browsers)
8914 * @return {Roo.Element} this
8916 unselectable : function(){
8917 this.dom.unselectable = "on";
8918 this.swallowEvent("selectstart", true);
8919 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8920 this.addClass("x-unselectable");
8925 * Calculates the x, y to center this element on the screen
8926 * @return {Array} The x, y values [x, y]
8928 getCenterXY : function(){
8929 return this.getAlignToXY(document, 'c-c');
8933 * Centers the Element in either the viewport, or another Element.
8934 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8936 center : function(centerIn){
8937 this.alignTo(centerIn || document, 'c-c');
8942 * Tests various css rules/browsers to determine if this element uses a border box
8945 isBorderBox : function(){
8946 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8950 * Return a box {x, y, width, height} that can be used to set another elements
8951 * size/location to match this element.
8952 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8953 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8954 * @return {Object} box An object in the format {x, y, width, height}
8956 getBox : function(contentBox, local){
8961 var left = parseInt(this.getStyle("left"), 10) || 0;
8962 var top = parseInt(this.getStyle("top"), 10) || 0;
8965 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8967 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8969 var l = this.getBorderWidth("l")+this.getPadding("l");
8970 var r = this.getBorderWidth("r")+this.getPadding("r");
8971 var t = this.getBorderWidth("t")+this.getPadding("t");
8972 var b = this.getBorderWidth("b")+this.getPadding("b");
8973 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)};
8975 bx.right = bx.x + bx.width;
8976 bx.bottom = bx.y + bx.height;
8981 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8982 for more information about the sides.
8983 * @param {String} sides
8986 getFrameWidth : function(sides, onlyContentBox){
8987 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8991 * 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.
8992 * @param {Object} box The box to fill {x, y, width, height}
8993 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8994 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8995 * @return {Roo.Element} this
8997 setBox : function(box, adjust, animate){
8998 var w = box.width, h = box.height;
8999 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9000 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9001 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9003 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9008 * Forces the browser to repaint this element
9009 * @return {Roo.Element} this
9011 repaint : function(){
9013 this.addClass("x-repaint");
9014 setTimeout(function(){
9015 Roo.get(dom).removeClass("x-repaint");
9021 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9022 * then it returns the calculated width of the sides (see getPadding)
9023 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9024 * @return {Object/Number}
9026 getMargins : function(side){
9029 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9030 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9031 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9032 right: parseInt(this.getStyle("margin-right"), 10) || 0
9035 return this.addStyles(side, El.margins);
9040 addStyles : function(sides, styles){
9042 for(var i = 0, len = sides.length; i < len; i++){
9043 v = this.getStyle(styles[sides.charAt(i)]);
9045 w = parseInt(v, 10);
9053 * Creates a proxy element of this element
9054 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9055 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9056 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9057 * @return {Roo.Element} The new proxy element
9059 createProxy : function(config, renderTo, matchBox){
9061 renderTo = Roo.getDom(renderTo);
9063 renderTo = document.body;
9065 config = typeof config == "object" ?
9066 config : {tag : "div", cls: config};
9067 var proxy = Roo.DomHelper.append(renderTo, config, true);
9069 proxy.setBox(this.getBox());
9075 * Puts a mask over this element to disable user interaction. Requires core.css.
9076 * This method can only be applied to elements which accept child nodes.
9077 * @param {String} msg (optional) A message to display in the mask
9078 * @param {String} msgCls (optional) A css class to apply to the msg element
9079 * @return {Element} The mask element
9081 mask : function(msg, msgCls)
9083 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9084 this.setStyle("position", "relative");
9087 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9089 this.addClass("x-masked");
9090 this._mask.setDisplayed(true);
9095 while (dom && dom.style) {
9096 if (!isNaN(parseInt(dom.style.zIndex))) {
9097 z = Math.max(z, parseInt(dom.style.zIndex));
9099 dom = dom.parentNode;
9101 // if we are masking the body - then it hides everything..
9102 if (this.dom == document.body) {
9104 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9105 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9108 if(typeof msg == 'string'){
9110 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9112 var mm = this._maskMsg;
9113 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9114 if (mm.dom.firstChild) { // weird IE issue?
9115 mm.dom.firstChild.innerHTML = msg;
9117 mm.setDisplayed(true);
9119 mm.setStyle('z-index', z + 102);
9121 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9122 this._mask.setHeight(this.getHeight());
9124 this._mask.setStyle('z-index', z + 100);
9130 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9131 * it is cached for reuse.
9133 unmask : function(removeEl){
9135 if(removeEl === true){
9136 this._mask.remove();
9139 this._maskMsg.remove();
9140 delete this._maskMsg;
9143 this._mask.setDisplayed(false);
9145 this._maskMsg.setDisplayed(false);
9149 this.removeClass("x-masked");
9153 * Returns true if this element is masked
9156 isMasked : function(){
9157 return this._mask && this._mask.isVisible();
9161 * Creates an iframe shim for this element to keep selects and other windowed objects from
9163 * @return {Roo.Element} The new shim element
9165 createShim : function(){
9166 var el = document.createElement('iframe');
9167 el.frameBorder = 'no';
9168 el.className = 'roo-shim';
9169 if(Roo.isIE && Roo.isSecure){
9170 el.src = Roo.SSL_SECURE_URL;
9172 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9173 shim.autoBoxAdjust = false;
9178 * Removes this element from the DOM and deletes it from the cache
9180 remove : function(){
9181 if(this.dom.parentNode){
9182 this.dom.parentNode.removeChild(this.dom);
9184 delete El.cache[this.dom.id];
9188 * Sets up event handlers to add and remove a css class when the mouse is over this element
9189 * @param {String} className
9190 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9191 * mouseout events for children elements
9192 * @return {Roo.Element} this
9194 addClassOnOver : function(className, preventFlicker){
9195 this.on("mouseover", function(){
9196 Roo.fly(this, '_internal').addClass(className);
9198 var removeFn = function(e){
9199 if(preventFlicker !== true || !e.within(this, true)){
9200 Roo.fly(this, '_internal').removeClass(className);
9203 this.on("mouseout", removeFn, this.dom);
9208 * Sets up event handlers to add and remove a css class when this element has the focus
9209 * @param {String} className
9210 * @return {Roo.Element} this
9212 addClassOnFocus : function(className){
9213 this.on("focus", function(){
9214 Roo.fly(this, '_internal').addClass(className);
9216 this.on("blur", function(){
9217 Roo.fly(this, '_internal').removeClass(className);
9222 * 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)
9223 * @param {String} className
9224 * @return {Roo.Element} this
9226 addClassOnClick : function(className){
9228 this.on("mousedown", function(){
9229 Roo.fly(dom, '_internal').addClass(className);
9230 var d = Roo.get(document);
9231 var fn = function(){
9232 Roo.fly(dom, '_internal').removeClass(className);
9233 d.removeListener("mouseup", fn);
9235 d.on("mouseup", fn);
9241 * Stops the specified event from bubbling and optionally prevents the default action
9242 * @param {String} eventName
9243 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9244 * @return {Roo.Element} this
9246 swallowEvent : function(eventName, preventDefault){
9247 var fn = function(e){
9248 e.stopPropagation();
9253 if(eventName instanceof Array){
9254 for(var i = 0, len = eventName.length; i < len; i++){
9255 this.on(eventName[i], fn);
9259 this.on(eventName, fn);
9266 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9269 * Sizes this element to its parent element's dimensions performing
9270 * neccessary box adjustments.
9271 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9272 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9273 * @return {Roo.Element} this
9275 fitToParent : function(monitorResize, targetParent) {
9276 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9277 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9278 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9281 var p = Roo.get(targetParent || this.dom.parentNode);
9282 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9283 if (monitorResize === true) {
9284 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9285 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9291 * Gets the next sibling, skipping text nodes
9292 * @return {HTMLElement} The next sibling or null
9294 getNextSibling : function(){
9295 var n = this.dom.nextSibling;
9296 while(n && n.nodeType != 1){
9303 * Gets the previous sibling, skipping text nodes
9304 * @return {HTMLElement} The previous sibling or null
9306 getPrevSibling : function(){
9307 var n = this.dom.previousSibling;
9308 while(n && n.nodeType != 1){
9309 n = n.previousSibling;
9316 * Appends the passed element(s) to this element
9317 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9318 * @return {Roo.Element} this
9320 appendChild: function(el){
9327 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9328 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9329 * automatically generated with the specified attributes.
9330 * @param {HTMLElement} insertBefore (optional) a child element of this element
9331 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9332 * @return {Roo.Element} The new child element
9334 createChild: function(config, insertBefore, returnDom){
9335 config = config || {tag:'div'};
9337 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9339 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9343 * Appends this element to the passed element
9344 * @param {String/HTMLElement/Element} el The new parent element
9345 * @return {Roo.Element} this
9347 appendTo: function(el){
9348 el = Roo.getDom(el);
9349 el.appendChild(this.dom);
9354 * Inserts this element before the passed element in the DOM
9355 * @param {String/HTMLElement/Element} el The element to insert before
9356 * @return {Roo.Element} this
9358 insertBefore: function(el){
9359 el = Roo.getDom(el);
9360 el.parentNode.insertBefore(this.dom, el);
9365 * Inserts this element after the passed element in the DOM
9366 * @param {String/HTMLElement/Element} el The element to insert after
9367 * @return {Roo.Element} this
9369 insertAfter: function(el){
9370 el = Roo.getDom(el);
9371 el.parentNode.insertBefore(this.dom, el.nextSibling);
9376 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9377 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9378 * @return {Roo.Element} The new child
9380 insertFirst: function(el, returnDom){
9382 if(typeof el == 'object' && !el.nodeType){ // dh config
9383 return this.createChild(el, this.dom.firstChild, returnDom);
9385 el = Roo.getDom(el);
9386 this.dom.insertBefore(el, this.dom.firstChild);
9387 return !returnDom ? Roo.get(el) : el;
9392 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9393 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9394 * @param {String} where (optional) 'before' or 'after' defaults to before
9395 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9396 * @return {Roo.Element} the inserted Element
9398 insertSibling: function(el, where, returnDom){
9399 where = where ? where.toLowerCase() : 'before';
9401 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9403 if(typeof el == 'object' && !el.nodeType){ // dh config
9404 if(where == 'after' && !this.dom.nextSibling){
9405 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9407 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9411 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9412 where == 'before' ? this.dom : this.dom.nextSibling);
9421 * Creates and wraps this element with another element
9422 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9423 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9424 * @return {HTMLElement/Element} The newly created wrapper element
9426 wrap: function(config, returnDom){
9428 config = {tag: "div"};
9430 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9431 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9436 * Replaces the passed element with this element
9437 * @param {String/HTMLElement/Element} el The element to replace
9438 * @return {Roo.Element} this
9440 replace: function(el){
9442 this.insertBefore(el);
9448 * Inserts an html fragment into this element
9449 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9450 * @param {String} html The HTML fragment
9451 * @param {Boolean} returnEl True to return an Roo.Element
9452 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9454 insertHtml : function(where, html, returnEl){
9455 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9456 return returnEl ? Roo.get(el) : el;
9460 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9461 * @param {Object} o The object with the attributes
9462 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9463 * @return {Roo.Element} this
9465 set : function(o, useSet){
9467 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9469 if(attr == "style" || typeof o[attr] == "function") { continue; }
9471 el.className = o["cls"];
9474 el.setAttribute(attr, o[attr]);
9481 Roo.DomHelper.applyStyles(el, o.style);
9487 * Convenience method for constructing a KeyMap
9488 * @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:
9489 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9490 * @param {Function} fn The function to call
9491 * @param {Object} scope (optional) The scope of the function
9492 * @return {Roo.KeyMap} The KeyMap created
9494 addKeyListener : function(key, fn, scope){
9496 if(typeof key != "object" || key instanceof Array){
9512 return new Roo.KeyMap(this, config);
9516 * Creates a KeyMap for this element
9517 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9518 * @return {Roo.KeyMap} The KeyMap created
9520 addKeyMap : function(config){
9521 return new Roo.KeyMap(this, config);
9525 * Returns true if this element is scrollable.
9528 isScrollable : function(){
9530 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9534 * 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().
9535 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9536 * @param {Number} value The new scroll value
9537 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9538 * @return {Element} this
9541 scrollTo : function(side, value, animate){
9542 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9544 this.dom[prop] = value;
9546 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9547 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9553 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9554 * within this element's scrollable range.
9555 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9556 * @param {Number} distance How far to scroll the element in pixels
9557 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9558 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9559 * was scrolled as far as it could go.
9561 scroll : function(direction, distance, animate){
9562 if(!this.isScrollable()){
9566 var l = el.scrollLeft, t = el.scrollTop;
9567 var w = el.scrollWidth, h = el.scrollHeight;
9568 var cw = el.clientWidth, ch = el.clientHeight;
9569 direction = direction.toLowerCase();
9570 var scrolled = false;
9571 var a = this.preanim(arguments, 2);
9576 var v = Math.min(l + distance, w-cw);
9577 this.scrollTo("left", v, a);
9584 var v = Math.max(l - distance, 0);
9585 this.scrollTo("left", v, a);
9593 var v = Math.max(t - distance, 0);
9594 this.scrollTo("top", v, a);
9602 var v = Math.min(t + distance, h-ch);
9603 this.scrollTo("top", v, a);
9612 * Translates the passed page coordinates into left/top css values for this element
9613 * @param {Number/Array} x The page x or an array containing [x, y]
9614 * @param {Number} y The page y
9615 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9617 translatePoints : function(x, y){
9618 if(typeof x == 'object' || x instanceof Array){
9621 var p = this.getStyle('position');
9622 var o = this.getXY();
9624 var l = parseInt(this.getStyle('left'), 10);
9625 var t = parseInt(this.getStyle('top'), 10);
9628 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9631 t = (p == "relative") ? 0 : this.dom.offsetTop;
9634 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9638 * Returns the current scroll position of the element.
9639 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9641 getScroll : function(){
9642 var d = this.dom, doc = document;
9643 if(d == doc || d == doc.body){
9644 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9645 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9646 return {left: l, top: t};
9648 return {left: d.scrollLeft, top: d.scrollTop};
9653 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9654 * are convert to standard 6 digit hex color.
9655 * @param {String} attr The css attribute
9656 * @param {String} defaultValue The default value to use when a valid color isn't found
9657 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9660 getColor : function(attr, defaultValue, prefix){
9661 var v = this.getStyle(attr);
9662 if(!v || v == "transparent" || v == "inherit") {
9663 return defaultValue;
9665 var color = typeof prefix == "undefined" ? "#" : prefix;
9666 if(v.substr(0, 4) == "rgb("){
9667 var rvs = v.slice(4, v.length -1).split(",");
9668 for(var i = 0; i < 3; i++){
9669 var h = parseInt(rvs[i]).toString(16);
9676 if(v.substr(0, 1) == "#"){
9678 for(var i = 1; i < 4; i++){
9679 var c = v.charAt(i);
9682 }else if(v.length == 7){
9683 color += v.substr(1);
9687 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9691 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9692 * gradient background, rounded corners and a 4-way shadow.
9693 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9694 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9695 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9696 * @return {Roo.Element} this
9698 boxWrap : function(cls){
9699 cls = cls || 'x-box';
9700 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9701 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9706 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9707 * @param {String} namespace The namespace in which to look for the attribute
9708 * @param {String} name The attribute name
9709 * @return {String} The attribute value
9711 getAttributeNS : Roo.isIE ? function(ns, name){
9713 var type = typeof d[ns+":"+name];
9714 if(type != 'undefined' && type != 'unknown'){
9715 return d[ns+":"+name];
9718 } : function(ns, name){
9720 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9725 * Sets or Returns the value the dom attribute value
9726 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9727 * @param {String} value (optional) The value to set the attribute to
9728 * @return {String} The attribute value
9730 attr : function(name){
9731 if (arguments.length > 1) {
9732 this.dom.setAttribute(name, arguments[1]);
9733 return arguments[1];
9735 if (typeof(name) == 'object') {
9736 for(var i in name) {
9737 this.attr(i, name[i]);
9743 if (!this.dom.hasAttribute(name)) {
9746 return this.dom.getAttribute(name);
9753 var ep = El.prototype;
9756 * Appends an event handler (Shorthand for addListener)
9757 * @param {String} eventName The type of event to append
9758 * @param {Function} fn The method the event invokes
9759 * @param {Object} scope (optional) The scope (this object) of the fn
9760 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9763 ep.on = ep.addListener;
9765 ep.mon = ep.addListener;
9768 * Removes an event handler from this element (shorthand for removeListener)
9769 * @param {String} eventName the type of event to remove
9770 * @param {Function} fn the method the event invokes
9771 * @return {Roo.Element} this
9774 ep.un = ep.removeListener;
9777 * true to automatically adjust width and height settings for box-model issues (default to true)
9779 ep.autoBoxAdjust = true;
9782 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9785 El.addUnits = function(v, defaultUnit){
9786 if(v === "" || v == "auto"){
9789 if(v === undefined){
9792 if(typeof v == "number" || !El.unitPattern.test(v)){
9793 return v + (defaultUnit || 'px');
9798 // special markup used throughout Roo when box wrapping elements
9799 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>';
9801 * Visibility mode constant - Use visibility to hide element
9807 * Visibility mode constant - Use display to hide element
9813 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9814 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9815 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9827 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9828 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9829 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9830 * @return {Element} The Element object
9833 El.get = function(el){
9835 if(!el){ return null; }
9836 if(typeof el == "string"){ // element id
9837 if(!(elm = document.getElementById(el))){
9840 if(ex = El.cache[el]){
9843 ex = El.cache[el] = new El(elm);
9846 }else if(el.tagName){ // dom element
9850 if(ex = El.cache[id]){
9853 ex = El.cache[id] = new El(el);
9856 }else if(el instanceof El){
9858 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9859 // catch case where it hasn't been appended
9860 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9863 }else if(el.isComposite){
9865 }else if(el instanceof Array){
9866 return El.select(el);
9867 }else if(el == document){
9868 // create a bogus element object representing the document object
9870 var f = function(){};
9871 f.prototype = El.prototype;
9873 docEl.dom = document;
9881 El.uncache = function(el){
9882 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9884 delete El.cache[a[i].id || a[i]];
9890 // Garbage collection - uncache elements/purge listeners on orphaned elements
9891 // so we don't hold a reference and cause the browser to retain them
9892 El.garbageCollect = function(){
9893 if(!Roo.enableGarbageCollector){
9894 clearInterval(El.collectorThread);
9897 for(var eid in El.cache){
9898 var el = El.cache[eid], d = el.dom;
9899 // -------------------------------------------------------
9900 // Determining what is garbage:
9901 // -------------------------------------------------------
9903 // dom node is null, definitely garbage
9904 // -------------------------------------------------------
9906 // no parentNode == direct orphan, definitely garbage
9907 // -------------------------------------------------------
9908 // !d.offsetParent && !document.getElementById(eid)
9909 // display none elements have no offsetParent so we will
9910 // also try to look it up by it's id. However, check
9911 // offsetParent first so we don't do unneeded lookups.
9912 // This enables collection of elements that are not orphans
9913 // directly, but somewhere up the line they have an orphan
9915 // -------------------------------------------------------
9916 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9917 delete El.cache[eid];
9918 if(d && Roo.enableListenerCollection){
9924 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9928 El.Flyweight = function(dom){
9931 El.Flyweight.prototype = El.prototype;
9933 El._flyweights = {};
9935 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9936 * the dom node can be overwritten by other code.
9937 * @param {String/HTMLElement} el The dom node or id
9938 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9939 * prevent conflicts (e.g. internally Roo uses "_internal")
9941 * @return {Element} The shared Element object
9943 El.fly = function(el, named){
9944 named = named || '_global';
9945 el = Roo.getDom(el);
9949 if(!El._flyweights[named]){
9950 El._flyweights[named] = new El.Flyweight();
9952 El._flyweights[named].dom = el;
9953 return El._flyweights[named];
9957 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9958 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9959 * Shorthand of {@link Roo.Element#get}
9960 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9961 * @return {Element} The Element object
9967 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9968 * the dom node can be overwritten by other code.
9969 * Shorthand of {@link Roo.Element#fly}
9970 * @param {String/HTMLElement} el The dom node or id
9971 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9972 * prevent conflicts (e.g. internally Roo uses "_internal")
9974 * @return {Element} The shared Element object
9980 // speedy lookup for elements never to box adjust
9981 var noBoxAdjust = Roo.isStrict ? {
9984 input:1, select:1, textarea:1
9986 if(Roo.isIE || Roo.isGecko){
9987 noBoxAdjust['button'] = 1;
9991 Roo.EventManager.on(window, 'unload', function(){
9993 delete El._flyweights;
10001 Roo.Element.selectorFunction = Roo.DomQuery.select;
10004 Roo.Element.select = function(selector, unique, root){
10006 if(typeof selector == "string"){
10007 els = Roo.Element.selectorFunction(selector, root);
10008 }else if(selector.length !== undefined){
10011 throw "Invalid selector";
10013 if(unique === true){
10014 return new Roo.CompositeElement(els);
10016 return new Roo.CompositeElementLite(els);
10020 * Selects elements based on the passed CSS selector to enable working on them as 1.
10021 * @param {String/Array} selector The CSS selector or an array of elements
10022 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10023 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10024 * @return {CompositeElementLite/CompositeElement}
10028 Roo.select = Roo.Element.select;
10045 * Ext JS Library 1.1.1
10046 * Copyright(c) 2006-2007, Ext JS, LLC.
10048 * Originally Released Under LGPL - original licence link has changed is not relivant.
10051 * <script type="text/javascript">
10056 //Notifies Element that fx methods are available
10057 Roo.enableFx = true;
10061 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10062 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10063 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10064 * Element effects to work.</p><br/>
10066 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10067 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10068 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10069 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10070 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10071 * expected results and should be done with care.</p><br/>
10073 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10074 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10077 ----- -----------------------------
10078 tl The top left corner
10079 t The center of the top edge
10080 tr The top right corner
10081 l The center of the left edge
10082 r The center of the right edge
10083 bl The bottom left corner
10084 b The center of the bottom edge
10085 br The bottom right corner
10087 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10088 * below are common options that can be passed to any Fx method.</b>
10089 * @cfg {Function} callback A function called when the effect is finished
10090 * @cfg {Object} scope The scope of the effect function
10091 * @cfg {String} easing A valid Easing value for the effect
10092 * @cfg {String} afterCls A css class to apply after the effect
10093 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10094 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10095 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10096 * effects that end with the element being visually hidden, ignored otherwise)
10097 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10098 * a function which returns such a specification that will be applied to the Element after the effect finishes
10099 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10100 * @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
10101 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10105 * Slides the element into view. An anchor point can be optionally passed to set the point of
10106 * origin for the slide effect. This function automatically handles wrapping the element with
10107 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10110 // default: slide the element in from the top
10113 // custom: slide the element in from the right with a 2-second duration
10114 el.slideIn('r', { duration: 2 });
10116 // common config options shown with default values
10122 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10123 * @param {Object} options (optional) Object literal with any of the Fx config options
10124 * @return {Roo.Element} The Element
10126 slideIn : function(anchor, o){
10127 var el = this.getFxEl();
10130 el.queueFx(o, function(){
10132 anchor = anchor || "t";
10134 // fix display to visibility
10137 // restore values after effect
10138 var r = this.getFxRestore();
10139 var b = this.getBox();
10140 // fixed size for slide
10144 var wrap = this.fxWrap(r.pos, o, "hidden");
10146 var st = this.dom.style;
10147 st.visibility = "visible";
10148 st.position = "absolute";
10150 // clear out temp styles after slide and unwrap
10151 var after = function(){
10152 el.fxUnwrap(wrap, r.pos, o);
10153 st.width = r.width;
10154 st.height = r.height;
10157 // time to calc the positions
10158 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10160 switch(anchor.toLowerCase()){
10162 wrap.setSize(b.width, 0);
10163 st.left = st.bottom = "0";
10167 wrap.setSize(0, b.height);
10168 st.right = st.top = "0";
10172 wrap.setSize(0, b.height);
10173 wrap.setX(b.right);
10174 st.left = st.top = "0";
10175 a = {width: bw, points: pt};
10178 wrap.setSize(b.width, 0);
10179 wrap.setY(b.bottom);
10180 st.left = st.top = "0";
10181 a = {height: bh, points: pt};
10184 wrap.setSize(0, 0);
10185 st.right = st.bottom = "0";
10186 a = {width: bw, height: bh};
10189 wrap.setSize(0, 0);
10190 wrap.setY(b.y+b.height);
10191 st.right = st.top = "0";
10192 a = {width: bw, height: bh, points: pt};
10195 wrap.setSize(0, 0);
10196 wrap.setXY([b.right, b.bottom]);
10197 st.left = st.top = "0";
10198 a = {width: bw, height: bh, points: pt};
10201 wrap.setSize(0, 0);
10202 wrap.setX(b.x+b.width);
10203 st.left = st.bottom = "0";
10204 a = {width: bw, height: bh, points: pt};
10207 this.dom.style.visibility = "visible";
10210 arguments.callee.anim = wrap.fxanim(a,
10220 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10221 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10222 * 'hidden') but block elements will still take up space in the document. The element must be removed
10223 * from the DOM using the 'remove' config option if desired. This function automatically handles
10224 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10227 // default: slide the element out to the top
10230 // custom: slide the element out to the right with a 2-second duration
10231 el.slideOut('r', { duration: 2 });
10233 // common config options shown with default values
10241 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10242 * @param {Object} options (optional) Object literal with any of the Fx config options
10243 * @return {Roo.Element} The Element
10245 slideOut : function(anchor, o){
10246 var el = this.getFxEl();
10249 el.queueFx(o, function(){
10251 anchor = anchor || "t";
10253 // restore values after effect
10254 var r = this.getFxRestore();
10256 var b = this.getBox();
10257 // fixed size for slide
10261 var wrap = this.fxWrap(r.pos, o, "visible");
10263 var st = this.dom.style;
10264 st.visibility = "visible";
10265 st.position = "absolute";
10269 var after = function(){
10271 el.setDisplayed(false);
10276 el.fxUnwrap(wrap, r.pos, o);
10278 st.width = r.width;
10279 st.height = r.height;
10284 var a, zero = {to: 0};
10285 switch(anchor.toLowerCase()){
10287 st.left = st.bottom = "0";
10288 a = {height: zero};
10291 st.right = st.top = "0";
10295 st.left = st.top = "0";
10296 a = {width: zero, points: {to:[b.right, b.y]}};
10299 st.left = st.top = "0";
10300 a = {height: zero, points: {to:[b.x, b.bottom]}};
10303 st.right = st.bottom = "0";
10304 a = {width: zero, height: zero};
10307 st.right = st.top = "0";
10308 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10311 st.left = st.top = "0";
10312 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10315 st.left = st.bottom = "0";
10316 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10320 arguments.callee.anim = wrap.fxanim(a,
10330 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10331 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10332 * The element must be removed from the DOM using the 'remove' config option if desired.
10338 // common config options shown with default values
10346 * @param {Object} options (optional) Object literal with any of the Fx config options
10347 * @return {Roo.Element} The Element
10349 puff : function(o){
10350 var el = this.getFxEl();
10353 el.queueFx(o, function(){
10354 this.clearOpacity();
10357 // restore values after effect
10358 var r = this.getFxRestore();
10359 var st = this.dom.style;
10361 var after = function(){
10363 el.setDisplayed(false);
10370 el.setPositioning(r.pos);
10371 st.width = r.width;
10372 st.height = r.height;
10377 var width = this.getWidth();
10378 var height = this.getHeight();
10380 arguments.callee.anim = this.fxanim({
10381 width : {to: this.adjustWidth(width * 2)},
10382 height : {to: this.adjustHeight(height * 2)},
10383 points : {by: [-(width * .5), -(height * .5)]},
10385 fontSize: {to:200, unit: "%"}
10396 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10397 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10398 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10404 // all config options shown with default values
10412 * @param {Object} options (optional) Object literal with any of the Fx config options
10413 * @return {Roo.Element} The Element
10415 switchOff : function(o){
10416 var el = this.getFxEl();
10419 el.queueFx(o, function(){
10420 this.clearOpacity();
10423 // restore values after effect
10424 var r = this.getFxRestore();
10425 var st = this.dom.style;
10427 var after = function(){
10429 el.setDisplayed(false);
10435 el.setPositioning(r.pos);
10436 st.width = r.width;
10437 st.height = r.height;
10442 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10443 this.clearOpacity();
10447 points:{by:[0, this.getHeight() * .5]}
10448 }, o, 'motion', 0.3, 'easeIn', after);
10449 }).defer(100, this);
10456 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10457 * changed using the "attr" config option) and then fading back to the original color. If no original
10458 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10461 // default: highlight background to yellow
10464 // custom: highlight foreground text to blue for 2 seconds
10465 el.highlight("0000ff", { attr: 'color', duration: 2 });
10467 // common config options shown with default values
10468 el.highlight("ffff9c", {
10469 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10470 endColor: (current color) or "ffffff",
10475 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10476 * @param {Object} options (optional) Object literal with any of the Fx config options
10477 * @return {Roo.Element} The Element
10479 highlight : function(color, o){
10480 var el = this.getFxEl();
10483 el.queueFx(o, function(){
10484 color = color || "ffff9c";
10485 attr = o.attr || "backgroundColor";
10487 this.clearOpacity();
10490 var origColor = this.getColor(attr);
10491 var restoreColor = this.dom.style[attr];
10492 endColor = (o.endColor || origColor) || "ffffff";
10494 var after = function(){
10495 el.dom.style[attr] = restoreColor;
10500 a[attr] = {from: color, to: endColor};
10501 arguments.callee.anim = this.fxanim(a,
10511 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10514 // default: a single light blue ripple
10517 // custom: 3 red ripples lasting 3 seconds total
10518 el.frame("ff0000", 3, { duration: 3 });
10520 // common config options shown with default values
10521 el.frame("C3DAF9", 1, {
10522 duration: 1 //duration of entire animation (not each individual ripple)
10523 // Note: Easing is not configurable and will be ignored if included
10526 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10527 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10528 * @param {Object} options (optional) Object literal with any of the Fx config options
10529 * @return {Roo.Element} The Element
10531 frame : function(color, count, o){
10532 var el = this.getFxEl();
10535 el.queueFx(o, function(){
10536 color = color || "#C3DAF9";
10537 if(color.length == 6){
10538 color = "#" + color;
10540 count = count || 1;
10541 duration = o.duration || 1;
10544 var b = this.getBox();
10545 var animFn = function(){
10546 var proxy = this.createProxy({
10549 visbility:"hidden",
10550 position:"absolute",
10551 "z-index":"35000", // yee haw
10552 border:"0px solid " + color
10555 var scale = Roo.isBorderBox ? 2 : 1;
10557 top:{from:b.y, to:b.y - 20},
10558 left:{from:b.x, to:b.x - 20},
10559 borderWidth:{from:0, to:10},
10560 opacity:{from:1, to:0},
10561 height:{from:b.height, to:(b.height + (20*scale))},
10562 width:{from:b.width, to:(b.width + (20*scale))}
10563 }, duration, function(){
10567 animFn.defer((duration/2)*1000, this);
10578 * Creates a pause before any subsequent queued effects begin. If there are
10579 * no effects queued after the pause it will have no effect.
10584 * @param {Number} seconds The length of time to pause (in seconds)
10585 * @return {Roo.Element} The Element
10587 pause : function(seconds){
10588 var el = this.getFxEl();
10591 el.queueFx(o, function(){
10592 setTimeout(function(){
10594 }, seconds * 1000);
10600 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10601 * using the "endOpacity" config option.
10604 // default: fade in from opacity 0 to 100%
10607 // custom: fade in from opacity 0 to 75% over 2 seconds
10608 el.fadeIn({ endOpacity: .75, duration: 2});
10610 // common config options shown with default values
10612 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10617 * @param {Object} options (optional) Object literal with any of the Fx config options
10618 * @return {Roo.Element} The Element
10620 fadeIn : function(o){
10621 var el = this.getFxEl();
10623 el.queueFx(o, function(){
10624 this.setOpacity(0);
10626 this.dom.style.visibility = 'visible';
10627 var to = o.endOpacity || 1;
10628 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10629 o, null, .5, "easeOut", function(){
10631 this.clearOpacity();
10640 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10641 * using the "endOpacity" config option.
10644 // default: fade out from the element's current opacity to 0
10647 // custom: fade out from the element's current opacity to 25% over 2 seconds
10648 el.fadeOut({ endOpacity: .25, duration: 2});
10650 // common config options shown with default values
10652 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10659 * @param {Object} options (optional) Object literal with any of the Fx config options
10660 * @return {Roo.Element} The Element
10662 fadeOut : function(o){
10663 var el = this.getFxEl();
10665 el.queueFx(o, function(){
10666 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10667 o, null, .5, "easeOut", function(){
10668 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10669 this.dom.style.display = "none";
10671 this.dom.style.visibility = "hidden";
10673 this.clearOpacity();
10681 * Animates the transition of an element's dimensions from a starting height/width
10682 * to an ending height/width.
10685 // change height and width to 100x100 pixels
10686 el.scale(100, 100);
10688 // common config options shown with default values. The height and width will default to
10689 // the element's existing values if passed as null.
10692 [element's height], {
10697 * @param {Number} width The new width (pass undefined to keep the original width)
10698 * @param {Number} height The new height (pass undefined to keep the original height)
10699 * @param {Object} options (optional) Object literal with any of the Fx config options
10700 * @return {Roo.Element} The Element
10702 scale : function(w, h, o){
10703 this.shift(Roo.apply({}, o, {
10711 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10712 * Any of these properties not specified in the config object will not be changed. This effect
10713 * requires that at least one new dimension, position or opacity setting must be passed in on
10714 * the config object in order for the function to have any effect.
10717 // slide the element horizontally to x position 200 while changing the height and opacity
10718 el.shift({ x: 200, height: 50, opacity: .8 });
10720 // common config options shown with default values.
10722 width: [element's width],
10723 height: [element's height],
10724 x: [element's x position],
10725 y: [element's y position],
10726 opacity: [element's opacity],
10731 * @param {Object} options Object literal with any of the Fx config options
10732 * @return {Roo.Element} The Element
10734 shift : function(o){
10735 var el = this.getFxEl();
10737 el.queueFx(o, function(){
10738 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10739 if(w !== undefined){
10740 a.width = {to: this.adjustWidth(w)};
10742 if(h !== undefined){
10743 a.height = {to: this.adjustHeight(h)};
10745 if(x !== undefined || y !== undefined){
10747 x !== undefined ? x : this.getX(),
10748 y !== undefined ? y : this.getY()
10751 if(op !== undefined){
10752 a.opacity = {to: op};
10754 if(o.xy !== undefined){
10755 a.points = {to: o.xy};
10757 arguments.callee.anim = this.fxanim(a,
10758 o, 'motion', .35, "easeOut", function(){
10766 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10767 * ending point of the effect.
10770 // default: slide the element downward while fading out
10773 // custom: slide the element out to the right with a 2-second duration
10774 el.ghost('r', { duration: 2 });
10776 // common config options shown with default values
10784 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10785 * @param {Object} options (optional) Object literal with any of the Fx config options
10786 * @return {Roo.Element} The Element
10788 ghost : function(anchor, o){
10789 var el = this.getFxEl();
10792 el.queueFx(o, function(){
10793 anchor = anchor || "b";
10795 // restore values after effect
10796 var r = this.getFxRestore();
10797 var w = this.getWidth(),
10798 h = this.getHeight();
10800 var st = this.dom.style;
10802 var after = function(){
10804 el.setDisplayed(false);
10810 el.setPositioning(r.pos);
10811 st.width = r.width;
10812 st.height = r.height;
10817 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10818 switch(anchor.toLowerCase()){
10845 arguments.callee.anim = this.fxanim(a,
10855 * Ensures that all effects queued after syncFx is called on the element are
10856 * run concurrently. This is the opposite of {@link #sequenceFx}.
10857 * @return {Roo.Element} The Element
10859 syncFx : function(){
10860 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10869 * Ensures that all effects queued after sequenceFx is called on the element are
10870 * run in sequence. This is the opposite of {@link #syncFx}.
10871 * @return {Roo.Element} The Element
10873 sequenceFx : function(){
10874 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10876 concurrent : false,
10883 nextFx : function(){
10884 var ef = this.fxQueue[0];
10891 * Returns true if the element has any effects actively running or queued, else returns false.
10892 * @return {Boolean} True if element has active effects, else false
10894 hasActiveFx : function(){
10895 return this.fxQueue && this.fxQueue[0];
10899 * Stops any running effects and clears the element's internal effects queue if it contains
10900 * any additional effects that haven't started yet.
10901 * @return {Roo.Element} The Element
10903 stopFx : function(){
10904 if(this.hasActiveFx()){
10905 var cur = this.fxQueue[0];
10906 if(cur && cur.anim && cur.anim.isAnimated()){
10907 this.fxQueue = [cur]; // clear out others
10908 cur.anim.stop(true);
10915 beforeFx : function(o){
10916 if(this.hasActiveFx() && !o.concurrent){
10927 * Returns true if the element is currently blocking so that no other effect can be queued
10928 * until this effect is finished, else returns false if blocking is not set. This is commonly
10929 * used to ensure that an effect initiated by a user action runs to completion prior to the
10930 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10931 * @return {Boolean} True if blocking, else false
10933 hasFxBlock : function(){
10934 var q = this.fxQueue;
10935 return q && q[0] && q[0].block;
10939 queueFx : function(o, fn){
10943 if(!this.hasFxBlock()){
10944 Roo.applyIf(o, this.fxDefaults);
10946 var run = this.beforeFx(o);
10947 fn.block = o.block;
10948 this.fxQueue.push(fn);
10960 fxWrap : function(pos, o, vis){
10962 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10965 wrapXY = this.getXY();
10967 var div = document.createElement("div");
10968 div.style.visibility = vis;
10969 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10970 wrap.setPositioning(pos);
10971 if(wrap.getStyle("position") == "static"){
10972 wrap.position("relative");
10974 this.clearPositioning('auto');
10976 wrap.dom.appendChild(this.dom);
10978 wrap.setXY(wrapXY);
10985 fxUnwrap : function(wrap, pos, o){
10986 this.clearPositioning();
10987 this.setPositioning(pos);
10989 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10995 getFxRestore : function(){
10996 var st = this.dom.style;
10997 return {pos: this.getPositioning(), width: st.width, height : st.height};
11001 afterFx : function(o){
11003 this.applyStyles(o.afterStyle);
11006 this.addClass(o.afterCls);
11008 if(o.remove === true){
11011 Roo.callback(o.callback, o.scope, [this]);
11013 this.fxQueue.shift();
11019 getFxEl : function(){ // support for composite element fx
11020 return Roo.get(this.dom);
11024 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11025 animType = animType || 'run';
11027 var anim = Roo.lib.Anim[animType](
11029 (opt.duration || defaultDur) || .35,
11030 (opt.easing || defaultEase) || 'easeOut',
11032 Roo.callback(cb, this);
11041 // backwords compat
11042 Roo.Fx.resize = Roo.Fx.scale;
11044 //When included, Roo.Fx is automatically applied to Element so that all basic
11045 //effects are available directly via the Element API
11046 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11048 * Ext JS Library 1.1.1
11049 * Copyright(c) 2006-2007, Ext JS, LLC.
11051 * Originally Released Under LGPL - original licence link has changed is not relivant.
11054 * <script type="text/javascript">
11059 * @class Roo.CompositeElement
11060 * Standard composite class. Creates a Roo.Element for every element in the collection.
11062 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11063 * actions will be performed on all the elements in this collection.</b>
11065 * All methods return <i>this</i> and can be chained.
11067 var els = Roo.select("#some-el div.some-class", true);
11068 // or select directly from an existing element
11069 var el = Roo.get('some-el');
11070 el.select('div.some-class', true);
11072 els.setWidth(100); // all elements become 100 width
11073 els.hide(true); // all elements fade out and hide
11075 els.setWidth(100).hide(true);
11078 Roo.CompositeElement = function(els){
11079 this.elements = [];
11080 this.addElements(els);
11082 Roo.CompositeElement.prototype = {
11084 addElements : function(els){
11088 if(typeof els == "string"){
11089 els = Roo.Element.selectorFunction(els);
11091 var yels = this.elements;
11092 var index = yels.length-1;
11093 for(var i = 0, len = els.length; i < len; i++) {
11094 yels[++index] = Roo.get(els[i]);
11100 * Clears this composite and adds the elements returned by the passed selector.
11101 * @param {String/Array} els A string CSS selector, an array of elements or an element
11102 * @return {CompositeElement} this
11104 fill : function(els){
11105 this.elements = [];
11111 * Filters this composite to only elements that match the passed selector.
11112 * @param {String} selector A string CSS selector
11113 * @param {Boolean} inverse return inverse filter (not matches)
11114 * @return {CompositeElement} this
11116 filter : function(selector, inverse){
11118 inverse = inverse || false;
11119 this.each(function(el){
11120 var match = inverse ? !el.is(selector) : el.is(selector);
11122 els[els.length] = el.dom;
11129 invoke : function(fn, args){
11130 var els = this.elements;
11131 for(var i = 0, len = els.length; i < len; i++) {
11132 Roo.Element.prototype[fn].apply(els[i], args);
11137 * Adds elements to this composite.
11138 * @param {String/Array} els A string CSS selector, an array of elements or an element
11139 * @return {CompositeElement} this
11141 add : function(els){
11142 if(typeof els == "string"){
11143 this.addElements(Roo.Element.selectorFunction(els));
11144 }else if(els.length !== undefined){
11145 this.addElements(els);
11147 this.addElements([els]);
11152 * Calls the passed function passing (el, this, index) for each element in this composite.
11153 * @param {Function} fn The function to call
11154 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11155 * @return {CompositeElement} this
11157 each : function(fn, scope){
11158 var els = this.elements;
11159 for(var i = 0, len = els.length; i < len; i++){
11160 if(fn.call(scope || els[i], els[i], this, i) === false) {
11168 * Returns the Element object at the specified index
11169 * @param {Number} index
11170 * @return {Roo.Element}
11172 item : function(index){
11173 return this.elements[index] || null;
11177 * Returns the first Element
11178 * @return {Roo.Element}
11180 first : function(){
11181 return this.item(0);
11185 * Returns the last Element
11186 * @return {Roo.Element}
11189 return this.item(this.elements.length-1);
11193 * Returns the number of elements in this composite
11196 getCount : function(){
11197 return this.elements.length;
11201 * Returns true if this composite contains the passed element
11204 contains : function(el){
11205 return this.indexOf(el) !== -1;
11209 * Returns true if this composite contains the passed element
11212 indexOf : function(el){
11213 return this.elements.indexOf(Roo.get(el));
11218 * Removes the specified element(s).
11219 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11220 * or an array of any of those.
11221 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11222 * @return {CompositeElement} this
11224 removeElement : function(el, removeDom){
11225 if(el instanceof Array){
11226 for(var i = 0, len = el.length; i < len; i++){
11227 this.removeElement(el[i]);
11231 var index = typeof el == 'number' ? el : this.indexOf(el);
11234 var d = this.elements[index];
11238 d.parentNode.removeChild(d);
11241 this.elements.splice(index, 1);
11247 * Replaces the specified element with the passed element.
11248 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11250 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11251 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11252 * @return {CompositeElement} this
11254 replaceElement : function(el, replacement, domReplace){
11255 var index = typeof el == 'number' ? el : this.indexOf(el);
11258 this.elements[index].replaceWith(replacement);
11260 this.elements.splice(index, 1, Roo.get(replacement))
11267 * Removes all elements.
11269 clear : function(){
11270 this.elements = [];
11274 Roo.CompositeElement.createCall = function(proto, fnName){
11275 if(!proto[fnName]){
11276 proto[fnName] = function(){
11277 return this.invoke(fnName, arguments);
11281 for(var fnName in Roo.Element.prototype){
11282 if(typeof Roo.Element.prototype[fnName] == "function"){
11283 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11289 * Ext JS Library 1.1.1
11290 * Copyright(c) 2006-2007, Ext JS, LLC.
11292 * Originally Released Under LGPL - original licence link has changed is not relivant.
11295 * <script type="text/javascript">
11299 * @class Roo.CompositeElementLite
11300 * @extends Roo.CompositeElement
11301 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11303 var els = Roo.select("#some-el div.some-class");
11304 // or select directly from an existing element
11305 var el = Roo.get('some-el');
11306 el.select('div.some-class');
11308 els.setWidth(100); // all elements become 100 width
11309 els.hide(true); // all elements fade out and hide
11311 els.setWidth(100).hide(true);
11312 </code></pre><br><br>
11313 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11314 * actions will be performed on all the elements in this collection.</b>
11316 Roo.CompositeElementLite = function(els){
11317 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11318 this.el = new Roo.Element.Flyweight();
11320 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11321 addElements : function(els){
11323 if(els instanceof Array){
11324 this.elements = this.elements.concat(els);
11326 var yels = this.elements;
11327 var index = yels.length-1;
11328 for(var i = 0, len = els.length; i < len; i++) {
11329 yels[++index] = els[i];
11335 invoke : function(fn, args){
11336 var els = this.elements;
11338 for(var i = 0, len = els.length; i < len; i++) {
11340 Roo.Element.prototype[fn].apply(el, args);
11345 * Returns a flyweight Element of the dom element object at the specified index
11346 * @param {Number} index
11347 * @return {Roo.Element}
11349 item : function(index){
11350 if(!this.elements[index]){
11353 this.el.dom = this.elements[index];
11357 // fixes scope with flyweight
11358 addListener : function(eventName, handler, scope, opt){
11359 var els = this.elements;
11360 for(var i = 0, len = els.length; i < len; i++) {
11361 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11367 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11368 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11369 * a reference to the dom node, use el.dom.</b>
11370 * @param {Function} fn The function to call
11371 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11372 * @return {CompositeElement} this
11374 each : function(fn, scope){
11375 var els = this.elements;
11377 for(var i = 0, len = els.length; i < len; i++){
11379 if(fn.call(scope || el, el, this, i) === false){
11386 indexOf : function(el){
11387 return this.elements.indexOf(Roo.getDom(el));
11390 replaceElement : function(el, replacement, domReplace){
11391 var index = typeof el == 'number' ? el : this.indexOf(el);
11393 replacement = Roo.getDom(replacement);
11395 var d = this.elements[index];
11396 d.parentNode.insertBefore(replacement, d);
11397 d.parentNode.removeChild(d);
11399 this.elements.splice(index, 1, replacement);
11404 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11408 * Ext JS Library 1.1.1
11409 * Copyright(c) 2006-2007, Ext JS, LLC.
11411 * Originally Released Under LGPL - original licence link has changed is not relivant.
11414 * <script type="text/javascript">
11420 * @class Roo.data.Connection
11421 * @extends Roo.util.Observable
11422 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11423 * either to a configured URL, or to a URL specified at request time.<br><br>
11425 * Requests made by this class are asynchronous, and will return immediately. No data from
11426 * the server will be available to the statement immediately following the {@link #request} call.
11427 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11429 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11430 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11431 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11432 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11433 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11434 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11435 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11436 * standard DOM methods.
11438 * @param {Object} config a configuration object.
11440 Roo.data.Connection = function(config){
11441 Roo.apply(this, config);
11444 * @event beforerequest
11445 * Fires before a network request is made to retrieve a data object.
11446 * @param {Connection} conn This Connection object.
11447 * @param {Object} options The options config object passed to the {@link #request} method.
11449 "beforerequest" : true,
11451 * @event requestcomplete
11452 * Fires if the request was successfully completed.
11453 * @param {Connection} conn This Connection object.
11454 * @param {Object} response The XHR object containing the response data.
11455 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11456 * @param {Object} options The options config object passed to the {@link #request} method.
11458 "requestcomplete" : true,
11460 * @event requestexception
11461 * Fires if an error HTTP status was returned from the server.
11462 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11463 * @param {Connection} conn This Connection object.
11464 * @param {Object} response The XHR object containing the response data.
11465 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11466 * @param {Object} options The options config object passed to the {@link #request} method.
11468 "requestexception" : true
11470 Roo.data.Connection.superclass.constructor.call(this);
11473 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11475 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11478 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11479 * extra parameters to each request made by this object. (defaults to undefined)
11482 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11483 * to each request made by this object. (defaults to undefined)
11486 * @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)
11489 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11493 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11499 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11502 disableCaching: true,
11505 * Sends an HTTP request to a remote server.
11506 * @param {Object} options An object which may contain the following properties:<ul>
11507 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11508 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11509 * request, a url encoded string or a function to call to get either.</li>
11510 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11511 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11512 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11513 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11514 * <li>options {Object} The parameter to the request call.</li>
11515 * <li>success {Boolean} True if the request succeeded.</li>
11516 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11518 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11519 * The callback is passed the following parameters:<ul>
11520 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11521 * <li>options {Object} The parameter to the request call.</li>
11523 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11524 * The callback is passed the following parameters:<ul>
11525 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11526 * <li>options {Object} The parameter to the request call.</li>
11528 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11529 * for the callback function. Defaults to the browser window.</li>
11530 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11531 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11532 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11533 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11534 * params for the post data. Any params will be appended to the URL.</li>
11535 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11537 * @return {Number} transactionId
11539 request : function(o){
11540 if(this.fireEvent("beforerequest", this, o) !== false){
11543 if(typeof p == "function"){
11544 p = p.call(o.scope||window, o);
11546 if(typeof p == "object"){
11547 p = Roo.urlEncode(o.params);
11549 if(this.extraParams){
11550 var extras = Roo.urlEncode(this.extraParams);
11551 p = p ? (p + '&' + extras) : extras;
11554 var url = o.url || this.url;
11555 if(typeof url == 'function'){
11556 url = url.call(o.scope||window, o);
11560 var form = Roo.getDom(o.form);
11561 url = url || form.action;
11563 var enctype = form.getAttribute("enctype");
11564 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11565 return this.doFormUpload(o, p, url);
11567 var f = Roo.lib.Ajax.serializeForm(form);
11568 p = p ? (p + '&' + f) : f;
11571 var hs = o.headers;
11572 if(this.defaultHeaders){
11573 hs = Roo.apply(hs || {}, this.defaultHeaders);
11580 success: this.handleResponse,
11581 failure: this.handleFailure,
11583 argument: {options: o},
11584 timeout : o.timeout || this.timeout
11587 var method = o.method||this.method||(p ? "POST" : "GET");
11589 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11590 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11593 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11597 }else if(this.autoAbort !== false){
11601 if((method == 'GET' && p) || o.xmlData){
11602 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11605 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11606 return this.transId;
11608 Roo.callback(o.callback, o.scope, [o, null, null]);
11614 * Determine whether this object has a request outstanding.
11615 * @param {Number} transactionId (Optional) defaults to the last transaction
11616 * @return {Boolean} True if there is an outstanding request.
11618 isLoading : function(transId){
11620 return Roo.lib.Ajax.isCallInProgress(transId);
11622 return this.transId ? true : false;
11627 * Aborts any outstanding request.
11628 * @param {Number} transactionId (Optional) defaults to the last transaction
11630 abort : function(transId){
11631 if(transId || this.isLoading()){
11632 Roo.lib.Ajax.abort(transId || this.transId);
11637 handleResponse : function(response){
11638 this.transId = false;
11639 var options = response.argument.options;
11640 response.argument = options ? options.argument : null;
11641 this.fireEvent("requestcomplete", this, response, options);
11642 Roo.callback(options.success, options.scope, [response, options]);
11643 Roo.callback(options.callback, options.scope, [options, true, response]);
11647 handleFailure : function(response, e){
11648 this.transId = false;
11649 var options = response.argument.options;
11650 response.argument = options ? options.argument : null;
11651 this.fireEvent("requestexception", this, response, options, e);
11652 Roo.callback(options.failure, options.scope, [response, options]);
11653 Roo.callback(options.callback, options.scope, [options, false, response]);
11657 doFormUpload : function(o, ps, url){
11659 var frame = document.createElement('iframe');
11662 frame.className = 'x-hidden';
11664 frame.src = Roo.SSL_SECURE_URL;
11666 document.body.appendChild(frame);
11669 document.frames[id].name = id;
11672 var form = Roo.getDom(o.form);
11674 form.method = 'POST';
11675 form.enctype = form.encoding = 'multipart/form-data';
11681 if(ps){ // add dynamic params
11683 ps = Roo.urlDecode(ps, false);
11685 if(ps.hasOwnProperty(k)){
11686 hd = document.createElement('input');
11687 hd.type = 'hidden';
11690 form.appendChild(hd);
11697 var r = { // bogus response object
11702 r.argument = o ? o.argument : null;
11707 doc = frame.contentWindow.document;
11709 doc = (frame.contentDocument || window.frames[id].document);
11711 if(doc && doc.body){
11712 r.responseText = doc.body.innerHTML;
11714 if(doc && doc.XMLDocument){
11715 r.responseXML = doc.XMLDocument;
11717 r.responseXML = doc;
11724 Roo.EventManager.removeListener(frame, 'load', cb, this);
11726 this.fireEvent("requestcomplete", this, r, o);
11727 Roo.callback(o.success, o.scope, [r, o]);
11728 Roo.callback(o.callback, o.scope, [o, true, r]);
11730 setTimeout(function(){document.body.removeChild(frame);}, 100);
11733 Roo.EventManager.on(frame, 'load', cb, this);
11736 if(hiddens){ // remove dynamic params
11737 for(var i = 0, len = hiddens.length; i < len; i++){
11738 form.removeChild(hiddens[i]);
11745 * Ext JS Library 1.1.1
11746 * Copyright(c) 2006-2007, Ext JS, LLC.
11748 * Originally Released Under LGPL - original licence link has changed is not relivant.
11751 * <script type="text/javascript">
11755 * Global Ajax request class.
11758 * @extends Roo.data.Connection
11761 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11762 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11763 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11764 * @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)
11765 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11766 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11767 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11769 Roo.Ajax = new Roo.data.Connection({
11778 * Serialize the passed form into a url encoded string
11780 * @param {String/HTMLElement} form
11783 serializeForm : function(form){
11784 return Roo.lib.Ajax.serializeForm(form);
11788 * Ext JS Library 1.1.1
11789 * Copyright(c) 2006-2007, Ext JS, LLC.
11791 * Originally Released Under LGPL - original licence link has changed is not relivant.
11794 * <script type="text/javascript">
11799 * @class Roo.UpdateManager
11800 * @extends Roo.util.Observable
11801 * Provides AJAX-style update for Element object.<br><br>
11804 * // Get it from a Roo.Element object
11805 * var el = Roo.get("foo");
11806 * var mgr = el.getUpdateManager();
11807 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11809 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11811 * // or directly (returns the same UpdateManager instance)
11812 * var mgr = new Roo.UpdateManager("myElementId");
11813 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11814 * mgr.on("update", myFcnNeedsToKnow);
11816 // short handed call directly from the element object
11817 Roo.get("foo").load({
11821 text: "Loading Foo..."
11825 * Create new UpdateManager directly.
11826 * @param {String/HTMLElement/Roo.Element} el The element to update
11827 * @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).
11829 Roo.UpdateManager = function(el, forceNew){
11831 if(!forceNew && el.updateManager){
11832 return el.updateManager;
11835 * The Element object
11836 * @type Roo.Element
11840 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11843 this.defaultUrl = null;
11847 * @event beforeupdate
11848 * Fired before an update is made, return false from your handler and the update is cancelled.
11849 * @param {Roo.Element} el
11850 * @param {String/Object/Function} url
11851 * @param {String/Object} params
11853 "beforeupdate": true,
11856 * Fired after successful update is made.
11857 * @param {Roo.Element} el
11858 * @param {Object} oResponseObject The response Object
11863 * Fired on update failure.
11864 * @param {Roo.Element} el
11865 * @param {Object} oResponseObject The response Object
11869 var d = Roo.UpdateManager.defaults;
11871 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11874 this.sslBlankUrl = d.sslBlankUrl;
11876 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11879 this.disableCaching = d.disableCaching;
11881 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11884 this.indicatorText = d.indicatorText;
11886 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11889 this.showLoadIndicator = d.showLoadIndicator;
11891 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11894 this.timeout = d.timeout;
11897 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11900 this.loadScripts = d.loadScripts;
11903 * Transaction object of current executing transaction
11905 this.transaction = null;
11910 this.autoRefreshProcId = null;
11912 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11915 this.refreshDelegate = this.refresh.createDelegate(this);
11917 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11920 this.updateDelegate = this.update.createDelegate(this);
11922 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11925 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11929 this.successDelegate = this.processSuccess.createDelegate(this);
11933 this.failureDelegate = this.processFailure.createDelegate(this);
11935 if(!this.renderer){
11937 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11939 this.renderer = new Roo.UpdateManager.BasicRenderer();
11942 Roo.UpdateManager.superclass.constructor.call(this);
11945 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11947 * Get the Element this UpdateManager is bound to
11948 * @return {Roo.Element} The element
11950 getEl : function(){
11954 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11955 * @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:
11958 url: "your-url.php",<br/>
11959 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11960 callback: yourFunction,<br/>
11961 scope: yourObject, //(optional scope) <br/>
11962 discardUrl: false, <br/>
11963 nocache: false,<br/>
11964 text: "Loading...",<br/>
11966 scripts: false<br/>
11969 * The only required property is url. The optional properties nocache, text and scripts
11970 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11971 * @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}
11972 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11973 * @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.
11975 update : function(url, params, callback, discardUrl){
11976 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11977 var method = this.method,
11979 if(typeof url == "object"){ // must be config object
11982 params = params || cfg.params;
11983 callback = callback || cfg.callback;
11984 discardUrl = discardUrl || cfg.discardUrl;
11985 if(callback && cfg.scope){
11986 callback = callback.createDelegate(cfg.scope);
11988 if(typeof cfg.method != "undefined"){method = cfg.method;};
11989 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11990 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11991 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11992 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11994 this.showLoading();
11996 this.defaultUrl = url;
11998 if(typeof url == "function"){
11999 url = url.call(this);
12002 method = method || (params ? "POST" : "GET");
12003 if(method == "GET"){
12004 url = this.prepareUrl(url);
12007 var o = Roo.apply(cfg ||{}, {
12010 success: this.successDelegate,
12011 failure: this.failureDelegate,
12012 callback: undefined,
12013 timeout: (this.timeout*1000),
12014 argument: {"url": url, "form": null, "callback": callback, "params": params}
12016 Roo.log("updated manager called with timeout of " + o.timeout);
12017 this.transaction = Roo.Ajax.request(o);
12022 * 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.
12023 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12024 * @param {String/HTMLElement} form The form Id or form element
12025 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12026 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12027 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12029 formUpdate : function(form, url, reset, callback){
12030 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12031 if(typeof url == "function"){
12032 url = url.call(this);
12034 form = Roo.getDom(form);
12035 this.transaction = Roo.Ajax.request({
12038 success: this.successDelegate,
12039 failure: this.failureDelegate,
12040 timeout: (this.timeout*1000),
12041 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12043 this.showLoading.defer(1, this);
12048 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12049 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12051 refresh : function(callback){
12052 if(this.defaultUrl == null){
12055 this.update(this.defaultUrl, null, callback, true);
12059 * Set this element to auto refresh.
12060 * @param {Number} interval How often to update (in seconds).
12061 * @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)
12062 * @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}
12063 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12064 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12066 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12068 this.update(url || this.defaultUrl, params, callback, true);
12070 if(this.autoRefreshProcId){
12071 clearInterval(this.autoRefreshProcId);
12073 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12077 * Stop auto refresh on this element.
12079 stopAutoRefresh : function(){
12080 if(this.autoRefreshProcId){
12081 clearInterval(this.autoRefreshProcId);
12082 delete this.autoRefreshProcId;
12086 isAutoRefreshing : function(){
12087 return this.autoRefreshProcId ? true : false;
12090 * Called to update the element to "Loading" state. Override to perform custom action.
12092 showLoading : function(){
12093 if(this.showLoadIndicator){
12094 this.el.update(this.indicatorText);
12099 * Adds unique parameter to query string if disableCaching = true
12102 prepareUrl : function(url){
12103 if(this.disableCaching){
12104 var append = "_dc=" + (new Date().getTime());
12105 if(url.indexOf("?") !== -1){
12106 url += "&" + append;
12108 url += "?" + append;
12117 processSuccess : function(response){
12118 this.transaction = null;
12119 if(response.argument.form && response.argument.reset){
12120 try{ // put in try/catch since some older FF releases had problems with this
12121 response.argument.form.reset();
12124 if(this.loadScripts){
12125 this.renderer.render(this.el, response, this,
12126 this.updateComplete.createDelegate(this, [response]));
12128 this.renderer.render(this.el, response, this);
12129 this.updateComplete(response);
12133 updateComplete : function(response){
12134 this.fireEvent("update", this.el, response);
12135 if(typeof response.argument.callback == "function"){
12136 response.argument.callback(this.el, true, response);
12143 processFailure : function(response){
12144 this.transaction = null;
12145 this.fireEvent("failure", this.el, response);
12146 if(typeof response.argument.callback == "function"){
12147 response.argument.callback(this.el, false, response);
12152 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12153 * @param {Object} renderer The object implementing the render() method
12155 setRenderer : function(renderer){
12156 this.renderer = renderer;
12159 getRenderer : function(){
12160 return this.renderer;
12164 * Set the defaultUrl used for updates
12165 * @param {String/Function} defaultUrl The url or a function to call to get the url
12167 setDefaultUrl : function(defaultUrl){
12168 this.defaultUrl = defaultUrl;
12172 * Aborts the executing transaction
12174 abort : function(){
12175 if(this.transaction){
12176 Roo.Ajax.abort(this.transaction);
12181 * Returns true if an update is in progress
12182 * @return {Boolean}
12184 isUpdating : function(){
12185 if(this.transaction){
12186 return Roo.Ajax.isLoading(this.transaction);
12193 * @class Roo.UpdateManager.defaults
12194 * @static (not really - but it helps the doc tool)
12195 * The defaults collection enables customizing the default properties of UpdateManager
12197 Roo.UpdateManager.defaults = {
12199 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12205 * True to process scripts by default (Defaults to false).
12208 loadScripts : false,
12211 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12214 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12216 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12219 disableCaching : false,
12221 * Whether to show indicatorText when loading (Defaults to true).
12224 showLoadIndicator : true,
12226 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12229 indicatorText : '<div class="loading-indicator">Loading...</div>'
12233 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12235 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12236 * @param {String/HTMLElement/Roo.Element} el The element to update
12237 * @param {String} url The url
12238 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12239 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12242 * @member Roo.UpdateManager
12244 Roo.UpdateManager.updateElement = function(el, url, params, options){
12245 var um = Roo.get(el, true).getUpdateManager();
12246 Roo.apply(um, options);
12247 um.update(url, params, options ? options.callback : null);
12249 // alias for backwards compat
12250 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12252 * @class Roo.UpdateManager.BasicRenderer
12253 * Default Content renderer. Updates the elements innerHTML with the responseText.
12255 Roo.UpdateManager.BasicRenderer = function(){};
12257 Roo.UpdateManager.BasicRenderer.prototype = {
12259 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12260 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12261 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12262 * @param {Roo.Element} el The element being rendered
12263 * @param {Object} response The YUI Connect response object
12264 * @param {UpdateManager} updateManager The calling update manager
12265 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12267 render : function(el, response, updateManager, callback){
12268 el.update(response.responseText, updateManager.loadScripts, callback);
12274 * (c)) Alan Knowles
12280 * @class Roo.DomTemplate
12281 * @extends Roo.Template
12282 * An effort at a dom based template engine..
12284 * Similar to XTemplate, except it uses dom parsing to create the template..
12286 * Supported features:
12291 {a_variable} - output encoded.
12292 {a_variable.format:("Y-m-d")} - call a method on the variable
12293 {a_variable:raw} - unencoded output
12294 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12295 {a_variable:this.method_on_template(...)} - call a method on the template object.
12300 <div roo-for="a_variable or condition.."></div>
12301 <div roo-if="a_variable or condition"></div>
12302 <div roo-exec="some javascript"></div>
12303 <div roo-name="named_template"></div>
12308 Roo.DomTemplate = function()
12310 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12317 Roo.extend(Roo.DomTemplate, Roo.Template, {
12319 * id counter for sub templates.
12323 * flag to indicate if dom parser is inside a pre,
12324 * it will strip whitespace if not.
12329 * The various sub templates
12337 * basic tag replacing syntax
12340 * // you can fake an object call by doing this
12344 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12345 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12347 iterChild : function (node, method) {
12349 var oldPre = this.inPre;
12350 if (node.tagName == 'PRE') {
12353 for( var i = 0; i < node.childNodes.length; i++) {
12354 method.call(this, node.childNodes[i]);
12356 this.inPre = oldPre;
12362 * compile the template
12364 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12367 compile: function()
12371 // covert the html into DOM...
12375 doc = document.implementation.createHTMLDocument("");
12376 doc.documentElement.innerHTML = this.html ;
12377 div = doc.documentElement;
12379 // old IE... - nasty -- it causes all sorts of issues.. with
12380 // images getting pulled from server..
12381 div = document.createElement('div');
12382 div.innerHTML = this.html;
12384 //doc.documentElement.innerHTML = htmlBody
12390 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12392 var tpls = this.tpls;
12394 // create a top level template from the snippet..
12396 //Roo.log(div.innerHTML);
12403 body : div.innerHTML,
12416 Roo.each(tpls, function(tp){
12417 this.compileTpl(tp);
12418 this.tpls[tp.id] = tp;
12421 this.master = tpls[0];
12427 compileNode : function(node, istop) {
12432 // skip anything not a tag..
12433 if (node.nodeType != 1) {
12434 if (node.nodeType == 3 && !this.inPre) {
12435 // reduce white space..
12436 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12459 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12460 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12461 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12462 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12468 // just itterate children..
12469 this.iterChild(node,this.compileNode);
12472 tpl.uid = this.id++;
12473 tpl.value = node.getAttribute('roo-' + tpl.attr);
12474 node.removeAttribute('roo-'+ tpl.attr);
12475 if (tpl.attr != 'name') {
12476 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12477 node.parentNode.replaceChild(placeholder, node);
12480 var placeholder = document.createElement('span');
12481 placeholder.className = 'roo-tpl-' + tpl.value;
12482 node.parentNode.replaceChild(placeholder, node);
12485 // parent now sees '{domtplXXXX}
12486 this.iterChild(node,this.compileNode);
12488 // we should now have node body...
12489 var div = document.createElement('div');
12490 div.appendChild(node);
12492 // this has the unfortunate side effect of converting tagged attributes
12493 // eg. href="{...}" into %7C...%7D
12494 // this has been fixed by searching for those combo's although it's a bit hacky..
12497 tpl.body = div.innerHTML;
12504 switch (tpl.value) {
12505 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12506 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12507 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12512 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12516 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12520 tpl.id = tpl.value; // replace non characters???
12526 this.tpls.push(tpl);
12536 * Compile a segment of the template into a 'sub-template'
12542 compileTpl : function(tpl)
12544 var fm = Roo.util.Format;
12545 var useF = this.disableFormats !== true;
12547 var sep = Roo.isGecko ? "+\n" : ",\n";
12549 var undef = function(str) {
12550 Roo.debug && Roo.log("Property not found :" + str);
12554 //Roo.log(tpl.body);
12558 var fn = function(m, lbrace, name, format, args)
12561 //Roo.log(arguments);
12562 args = args ? args.replace(/\\'/g,"'") : args;
12563 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12564 if (typeof(format) == 'undefined') {
12565 format = 'htmlEncode';
12567 if (format == 'raw' ) {
12571 if(name.substr(0, 6) == 'domtpl'){
12572 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12575 // build an array of options to determine if value is undefined..
12577 // basically get 'xxxx.yyyy' then do
12578 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12579 // (function () { Roo.log("Property not found"); return ''; })() :
12584 Roo.each(name.split('.'), function(st) {
12585 lookfor += (lookfor.length ? '.': '') + st;
12586 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12589 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12592 if(format && useF){
12594 args = args ? ',' + args : "";
12596 if(format.substr(0, 5) != "this."){
12597 format = "fm." + format + '(';
12599 format = 'this.call("'+ format.substr(5) + '", ';
12603 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12606 if (args && args.length) {
12607 // called with xxyx.yuu:(test,test)
12609 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12611 // raw.. - :raw modifier..
12612 return "'"+ sep + udef_st + name + ")"+sep+"'";
12616 // branched to use + in gecko and [].join() in others
12618 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12619 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12622 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12623 body.push(tpl.body.replace(/(\r\n|\n)/g,
12624 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12625 body.push("'].join('');};};");
12626 body = body.join('');
12629 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12631 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12638 * same as applyTemplate, except it's done to one of the subTemplates
12639 * when using named templates, you can do:
12641 * var str = pl.applySubTemplate('your-name', values);
12644 * @param {Number} id of the template
12645 * @param {Object} values to apply to template
12646 * @param {Object} parent (normaly the instance of this object)
12648 applySubTemplate : function(id, values, parent)
12652 var t = this.tpls[id];
12656 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12657 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12661 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12668 if(t.execCall && t.execCall.call(this, values, parent)){
12672 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12678 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12679 parent = t.target ? values : parent;
12680 if(t.forCall && vs instanceof Array){
12682 for(var i = 0, len = vs.length; i < len; i++){
12684 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12686 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12688 //Roo.log(t.compiled);
12692 return buf.join('');
12695 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12700 return t.compiled.call(this, vs, parent);
12702 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12704 //Roo.log(t.compiled);
12712 applyTemplate : function(values){
12713 return this.master.compiled.call(this, values, {});
12714 //var s = this.subs;
12717 apply : function(){
12718 return this.applyTemplate.apply(this, arguments);
12723 Roo.DomTemplate.from = function(el){
12724 el = Roo.getDom(el);
12725 return new Roo.Domtemplate(el.value || el.innerHTML);
12728 * Ext JS Library 1.1.1
12729 * Copyright(c) 2006-2007, Ext JS, LLC.
12731 * Originally Released Under LGPL - original licence link has changed is not relivant.
12734 * <script type="text/javascript">
12738 * @class Roo.util.DelayedTask
12739 * Provides a convenient method of performing setTimeout where a new
12740 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12741 * You can use this class to buffer
12742 * the keypress events for a certain number of milliseconds, and perform only if they stop
12743 * for that amount of time.
12744 * @constructor The parameters to this constructor serve as defaults and are not required.
12745 * @param {Function} fn (optional) The default function to timeout
12746 * @param {Object} scope (optional) The default scope of that timeout
12747 * @param {Array} args (optional) The default Array of arguments
12749 Roo.util.DelayedTask = function(fn, scope, args){
12750 var id = null, d, t;
12752 var call = function(){
12753 var now = new Date().getTime();
12757 fn.apply(scope, args || []);
12761 * Cancels any pending timeout and queues a new one
12762 * @param {Number} delay The milliseconds to delay
12763 * @param {Function} newFn (optional) Overrides function passed to constructor
12764 * @param {Object} newScope (optional) Overrides scope passed to constructor
12765 * @param {Array} newArgs (optional) Overrides args passed to constructor
12767 this.delay = function(delay, newFn, newScope, newArgs){
12768 if(id && delay != d){
12772 t = new Date().getTime();
12774 scope = newScope || scope;
12775 args = newArgs || args;
12777 id = setInterval(call, d);
12782 * Cancel the last queued timeout
12784 this.cancel = function(){
12792 * Ext JS Library 1.1.1
12793 * Copyright(c) 2006-2007, Ext JS, LLC.
12795 * Originally Released Under LGPL - original licence link has changed is not relivant.
12798 * <script type="text/javascript">
12802 Roo.util.TaskRunner = function(interval){
12803 interval = interval || 10;
12804 var tasks = [], removeQueue = [];
12806 var running = false;
12808 var stopThread = function(){
12814 var startThread = function(){
12817 id = setInterval(runTasks, interval);
12821 var removeTask = function(task){
12822 removeQueue.push(task);
12828 var runTasks = function(){
12829 if(removeQueue.length > 0){
12830 for(var i = 0, len = removeQueue.length; i < len; i++){
12831 tasks.remove(removeQueue[i]);
12834 if(tasks.length < 1){
12839 var now = new Date().getTime();
12840 for(var i = 0, len = tasks.length; i < len; ++i){
12842 var itime = now - t.taskRunTime;
12843 if(t.interval <= itime){
12844 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12845 t.taskRunTime = now;
12846 if(rt === false || t.taskRunCount === t.repeat){
12851 if(t.duration && t.duration <= (now - t.taskStartTime)){
12858 * Queues a new task.
12859 * @param {Object} task
12861 this.start = function(task){
12863 task.taskStartTime = new Date().getTime();
12864 task.taskRunTime = 0;
12865 task.taskRunCount = 0;
12870 this.stop = function(task){
12875 this.stopAll = function(){
12877 for(var i = 0, len = tasks.length; i < len; i++){
12878 if(tasks[i].onStop){
12887 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12889 * Ext JS Library 1.1.1
12890 * Copyright(c) 2006-2007, Ext JS, LLC.
12892 * Originally Released Under LGPL - original licence link has changed is not relivant.
12895 * <script type="text/javascript">
12900 * @class Roo.util.MixedCollection
12901 * @extends Roo.util.Observable
12902 * A Collection class that maintains both numeric indexes and keys and exposes events.
12904 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12905 * collection (defaults to false)
12906 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12907 * and return the key value for that item. This is used when available to look up the key on items that
12908 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12909 * equivalent to providing an implementation for the {@link #getKey} method.
12911 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12919 * Fires when the collection is cleared.
12924 * Fires when an item is added to the collection.
12925 * @param {Number} index The index at which the item was added.
12926 * @param {Object} o The item added.
12927 * @param {String} key The key associated with the added item.
12932 * Fires when an item is replaced in the collection.
12933 * @param {String} key he key associated with the new added.
12934 * @param {Object} old The item being replaced.
12935 * @param {Object} new The new item.
12940 * Fires when an item is removed from the collection.
12941 * @param {Object} o The item being removed.
12942 * @param {String} key (optional) The key associated with the removed item.
12947 this.allowFunctions = allowFunctions === true;
12949 this.getKey = keyFn;
12951 Roo.util.MixedCollection.superclass.constructor.call(this);
12954 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12955 allowFunctions : false,
12958 * Adds an item to the collection.
12959 * @param {String} key The key to associate with the item
12960 * @param {Object} o The item to add.
12961 * @return {Object} The item added.
12963 add : function(key, o){
12964 if(arguments.length == 1){
12966 key = this.getKey(o);
12968 if(typeof key == "undefined" || key === null){
12970 this.items.push(o);
12971 this.keys.push(null);
12973 var old = this.map[key];
12975 return this.replace(key, o);
12978 this.items.push(o);
12980 this.keys.push(key);
12982 this.fireEvent("add", this.length-1, o, key);
12987 * MixedCollection has a generic way to fetch keys if you implement getKey.
12990 var mc = new Roo.util.MixedCollection();
12991 mc.add(someEl.dom.id, someEl);
12992 mc.add(otherEl.dom.id, otherEl);
12996 var mc = new Roo.util.MixedCollection();
12997 mc.getKey = function(el){
13003 // or via the constructor
13004 var mc = new Roo.util.MixedCollection(false, function(el){
13010 * @param o {Object} The item for which to find the key.
13011 * @return {Object} The key for the passed item.
13013 getKey : function(o){
13018 * Replaces an item in the collection.
13019 * @param {String} key The key associated with the item to replace, or the item to replace.
13020 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13021 * @return {Object} The new item.
13023 replace : function(key, o){
13024 if(arguments.length == 1){
13026 key = this.getKey(o);
13028 var old = this.item(key);
13029 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13030 return this.add(key, o);
13032 var index = this.indexOfKey(key);
13033 this.items[index] = o;
13035 this.fireEvent("replace", key, old, o);
13040 * Adds all elements of an Array or an Object to the collection.
13041 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13042 * an Array of values, each of which are added to the collection.
13044 addAll : function(objs){
13045 if(arguments.length > 1 || objs instanceof Array){
13046 var args = arguments.length > 1 ? arguments : objs;
13047 for(var i = 0, len = args.length; i < len; i++){
13051 for(var key in objs){
13052 if(this.allowFunctions || typeof objs[key] != "function"){
13053 this.add(key, objs[key]);
13060 * Executes the specified function once for every item in the collection, passing each
13061 * item as the first and only parameter. returning false from the function will stop the iteration.
13062 * @param {Function} fn The function to execute for each item.
13063 * @param {Object} scope (optional) The scope in which to execute the function.
13065 each : function(fn, scope){
13066 var items = [].concat(this.items); // each safe for removal
13067 for(var i = 0, len = items.length; i < len; i++){
13068 if(fn.call(scope || items[i], items[i], i, len) === false){
13075 * Executes the specified function once for every key in the collection, passing each
13076 * key, and its associated item as the first two parameters.
13077 * @param {Function} fn The function to execute for each item.
13078 * @param {Object} scope (optional) The scope in which to execute the function.
13080 eachKey : function(fn, scope){
13081 for(var i = 0, len = this.keys.length; i < len; i++){
13082 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13087 * Returns the first item in the collection which elicits a true return value from the
13088 * passed selection function.
13089 * @param {Function} fn The selection function to execute for each item.
13090 * @param {Object} scope (optional) The scope in which to execute the function.
13091 * @return {Object} The first item in the collection which returned true from the selection function.
13093 find : function(fn, scope){
13094 for(var i = 0, len = this.items.length; i < len; i++){
13095 if(fn.call(scope || window, this.items[i], this.keys[i])){
13096 return this.items[i];
13103 * Inserts an item at the specified index in the collection.
13104 * @param {Number} index The index to insert the item at.
13105 * @param {String} key The key to associate with the new item, or the item itself.
13106 * @param {Object} o (optional) If the second parameter was a key, the new item.
13107 * @return {Object} The item inserted.
13109 insert : function(index, key, o){
13110 if(arguments.length == 2){
13112 key = this.getKey(o);
13114 if(index >= this.length){
13115 return this.add(key, o);
13118 this.items.splice(index, 0, o);
13119 if(typeof key != "undefined" && key != null){
13122 this.keys.splice(index, 0, key);
13123 this.fireEvent("add", index, o, key);
13128 * Removed an item from the collection.
13129 * @param {Object} o The item to remove.
13130 * @return {Object} The item removed.
13132 remove : function(o){
13133 return this.removeAt(this.indexOf(o));
13137 * Remove an item from a specified index in the collection.
13138 * @param {Number} index The index within the collection of the item to remove.
13140 removeAt : function(index){
13141 if(index < this.length && index >= 0){
13143 var o = this.items[index];
13144 this.items.splice(index, 1);
13145 var key = this.keys[index];
13146 if(typeof key != "undefined"){
13147 delete this.map[key];
13149 this.keys.splice(index, 1);
13150 this.fireEvent("remove", o, key);
13155 * Removed an item associated with the passed key fom the collection.
13156 * @param {String} key The key of the item to remove.
13158 removeKey : function(key){
13159 return this.removeAt(this.indexOfKey(key));
13163 * Returns the number of items in the collection.
13164 * @return {Number} the number of items in the collection.
13166 getCount : function(){
13167 return this.length;
13171 * Returns index within the collection of the passed Object.
13172 * @param {Object} o The item to find the index of.
13173 * @return {Number} index of the item.
13175 indexOf : function(o){
13176 if(!this.items.indexOf){
13177 for(var i = 0, len = this.items.length; i < len; i++){
13178 if(this.items[i] == o) {
13184 return this.items.indexOf(o);
13189 * Returns index within the collection of the passed key.
13190 * @param {String} key The key to find the index of.
13191 * @return {Number} index of the key.
13193 indexOfKey : function(key){
13194 if(!this.keys.indexOf){
13195 for(var i = 0, len = this.keys.length; i < len; i++){
13196 if(this.keys[i] == key) {
13202 return this.keys.indexOf(key);
13207 * Returns the item associated with the passed key OR index. Key has priority over index.
13208 * @param {String/Number} key The key or index of the item.
13209 * @return {Object} The item associated with the passed key.
13211 item : function(key){
13212 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13213 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13217 * Returns the item at the specified index.
13218 * @param {Number} index The index of the item.
13221 itemAt : function(index){
13222 return this.items[index];
13226 * Returns the item associated with the passed key.
13227 * @param {String/Number} key The key of the item.
13228 * @return {Object} The item associated with the passed key.
13230 key : function(key){
13231 return this.map[key];
13235 * Returns true if the collection contains the passed Object as an item.
13236 * @param {Object} o The Object to look for in the collection.
13237 * @return {Boolean} True if the collection contains the Object as an item.
13239 contains : function(o){
13240 return this.indexOf(o) != -1;
13244 * Returns true if the collection contains the passed Object as a key.
13245 * @param {String} key The key to look for in the collection.
13246 * @return {Boolean} True if the collection contains the Object as a key.
13248 containsKey : function(key){
13249 return typeof this.map[key] != "undefined";
13253 * Removes all items from the collection.
13255 clear : function(){
13260 this.fireEvent("clear");
13264 * Returns the first item in the collection.
13265 * @return {Object} the first item in the collection..
13267 first : function(){
13268 return this.items[0];
13272 * Returns the last item in the collection.
13273 * @return {Object} the last item in the collection..
13276 return this.items[this.length-1];
13279 _sort : function(property, dir, fn){
13280 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13281 fn = fn || function(a, b){
13284 var c = [], k = this.keys, items = this.items;
13285 for(var i = 0, len = items.length; i < len; i++){
13286 c[c.length] = {key: k[i], value: items[i], index: i};
13288 c.sort(function(a, b){
13289 var v = fn(a[property], b[property]) * dsc;
13291 v = (a.index < b.index ? -1 : 1);
13295 for(var i = 0, len = c.length; i < len; i++){
13296 items[i] = c[i].value;
13299 this.fireEvent("sort", this);
13303 * Sorts this collection with the passed comparison function
13304 * @param {String} direction (optional) "ASC" or "DESC"
13305 * @param {Function} fn (optional) comparison function
13307 sort : function(dir, fn){
13308 this._sort("value", dir, fn);
13312 * Sorts this collection by keys
13313 * @param {String} direction (optional) "ASC" or "DESC"
13314 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13316 keySort : function(dir, fn){
13317 this._sort("key", dir, fn || function(a, b){
13318 return String(a).toUpperCase()-String(b).toUpperCase();
13323 * Returns a range of items in this collection
13324 * @param {Number} startIndex (optional) defaults to 0
13325 * @param {Number} endIndex (optional) default to the last item
13326 * @return {Array} An array of items
13328 getRange : function(start, end){
13329 var items = this.items;
13330 if(items.length < 1){
13333 start = start || 0;
13334 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13337 for(var i = start; i <= end; i++) {
13338 r[r.length] = items[i];
13341 for(var i = start; i >= end; i--) {
13342 r[r.length] = items[i];
13349 * Filter the <i>objects</i> in this collection by a specific property.
13350 * Returns a new collection that has been filtered.
13351 * @param {String} property A property on your objects
13352 * @param {String/RegExp} value Either string that the property values
13353 * should start with or a RegExp to test against the property
13354 * @return {MixedCollection} The new filtered collection
13356 filter : function(property, value){
13357 if(!value.exec){ // not a regex
13358 value = String(value);
13359 if(value.length == 0){
13360 return this.clone();
13362 value = new RegExp("^" + Roo.escapeRe(value), "i");
13364 return this.filterBy(function(o){
13365 return o && value.test(o[property]);
13370 * Filter by a function. * Returns a new collection that has been filtered.
13371 * The passed function will be called with each
13372 * object in the collection. If the function returns true, the value is included
13373 * otherwise it is filtered.
13374 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13375 * @param {Object} scope (optional) The scope of the function (defaults to this)
13376 * @return {MixedCollection} The new filtered collection
13378 filterBy : function(fn, scope){
13379 var r = new Roo.util.MixedCollection();
13380 r.getKey = this.getKey;
13381 var k = this.keys, it = this.items;
13382 for(var i = 0, len = it.length; i < len; i++){
13383 if(fn.call(scope||this, it[i], k[i])){
13384 r.add(k[i], it[i]);
13391 * Creates a duplicate of this collection
13392 * @return {MixedCollection}
13394 clone : function(){
13395 var r = new Roo.util.MixedCollection();
13396 var k = this.keys, it = this.items;
13397 for(var i = 0, len = it.length; i < len; i++){
13398 r.add(k[i], it[i]);
13400 r.getKey = this.getKey;
13405 * Returns the item associated with the passed key or index.
13407 * @param {String/Number} key The key or index of the item.
13408 * @return {Object} The item associated with the passed key.
13410 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13412 * Ext JS Library 1.1.1
13413 * Copyright(c) 2006-2007, Ext JS, LLC.
13415 * Originally Released Under LGPL - original licence link has changed is not relivant.
13418 * <script type="text/javascript">
13421 * @class Roo.util.JSON
13422 * Modified version of Douglas Crockford"s json.js that doesn"t
13423 * mess with the Object prototype
13424 * http://www.json.org/js.html
13427 Roo.util.JSON = new (function(){
13428 var useHasOwn = {}.hasOwnProperty ? true : false;
13430 // crashes Safari in some instances
13431 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13433 var pad = function(n) {
13434 return n < 10 ? "0" + n : n;
13447 var encodeString = function(s){
13448 if (/["\\\x00-\x1f]/.test(s)) {
13449 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13454 c = b.charCodeAt();
13456 Math.floor(c / 16).toString(16) +
13457 (c % 16).toString(16);
13460 return '"' + s + '"';
13463 var encodeArray = function(o){
13464 var a = ["["], b, i, l = o.length, v;
13465 for (i = 0; i < l; i += 1) {
13467 switch (typeof v) {
13476 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13484 var encodeDate = function(o){
13485 return '"' + o.getFullYear() + "-" +
13486 pad(o.getMonth() + 1) + "-" +
13487 pad(o.getDate()) + "T" +
13488 pad(o.getHours()) + ":" +
13489 pad(o.getMinutes()) + ":" +
13490 pad(o.getSeconds()) + '"';
13494 * Encodes an Object, Array or other value
13495 * @param {Mixed} o The variable to encode
13496 * @return {String} The JSON string
13498 this.encode = function(o)
13500 // should this be extended to fully wrap stringify..
13502 if(typeof o == "undefined" || o === null){
13504 }else if(o instanceof Array){
13505 return encodeArray(o);
13506 }else if(o instanceof Date){
13507 return encodeDate(o);
13508 }else if(typeof o == "string"){
13509 return encodeString(o);
13510 }else if(typeof o == "number"){
13511 return isFinite(o) ? String(o) : "null";
13512 }else if(typeof o == "boolean"){
13515 var a = ["{"], b, i, v;
13517 if(!useHasOwn || o.hasOwnProperty(i)) {
13519 switch (typeof v) {
13528 a.push(this.encode(i), ":",
13529 v === null ? "null" : this.encode(v));
13540 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13541 * @param {String} json The JSON string
13542 * @return {Object} The resulting object
13544 this.decode = function(json){
13546 return /** eval:var:json */ eval("(" + json + ')');
13550 * Shorthand for {@link Roo.util.JSON#encode}
13551 * @member Roo encode
13553 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13555 * Shorthand for {@link Roo.util.JSON#decode}
13556 * @member Roo decode
13558 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13561 * Ext JS Library 1.1.1
13562 * Copyright(c) 2006-2007, Ext JS, LLC.
13564 * Originally Released Under LGPL - original licence link has changed is not relivant.
13567 * <script type="text/javascript">
13571 * @class Roo.util.Format
13572 * Reusable data formatting functions
13575 Roo.util.Format = function(){
13576 var trimRe = /^\s+|\s+$/g;
13579 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13580 * @param {String} value The string to truncate
13581 * @param {Number} length The maximum length to allow before truncating
13582 * @return {String} The converted text
13584 ellipsis : function(value, len){
13585 if(value && value.length > len){
13586 return value.substr(0, len-3)+"...";
13592 * Checks a reference and converts it to empty string if it is undefined
13593 * @param {Mixed} value Reference to check
13594 * @return {Mixed} Empty string if converted, otherwise the original value
13596 undef : function(value){
13597 return typeof value != "undefined" ? value : "";
13601 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13602 * @param {String} value The string to encode
13603 * @return {String} The encoded text
13605 htmlEncode : function(value){
13606 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13610 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13611 * @param {String} value The string to decode
13612 * @return {String} The decoded text
13614 htmlDecode : function(value){
13615 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13619 * Trims any whitespace from either side of a string
13620 * @param {String} value The text to trim
13621 * @return {String} The trimmed text
13623 trim : function(value){
13624 return String(value).replace(trimRe, "");
13628 * Returns a substring from within an original string
13629 * @param {String} value The original text
13630 * @param {Number} start The start index of the substring
13631 * @param {Number} length The length of the substring
13632 * @return {String} The substring
13634 substr : function(value, start, length){
13635 return String(value).substr(start, length);
13639 * Converts a string to all lower case letters
13640 * @param {String} value The text to convert
13641 * @return {String} The converted text
13643 lowercase : function(value){
13644 return String(value).toLowerCase();
13648 * Converts a string to all upper case letters
13649 * @param {String} value The text to convert
13650 * @return {String} The converted text
13652 uppercase : function(value){
13653 return String(value).toUpperCase();
13657 * Converts the first character only of a string to upper case
13658 * @param {String} value The text to convert
13659 * @return {String} The converted text
13661 capitalize : function(value){
13662 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13666 call : function(value, fn){
13667 if(arguments.length > 2){
13668 var args = Array.prototype.slice.call(arguments, 2);
13669 args.unshift(value);
13671 return /** eval:var:value */ eval(fn).apply(window, args);
13673 /** eval:var:value */
13674 return /** eval:var:value */ eval(fn).call(window, value);
13680 * safer version of Math.toFixed..??/
13681 * @param {Number/String} value The numeric value to format
13682 * @param {Number/String} value Decimal places
13683 * @return {String} The formatted currency string
13685 toFixed : function(v, n)
13687 // why not use to fixed - precision is buggered???
13689 return Math.round(v-0);
13691 var fact = Math.pow(10,n+1);
13692 v = (Math.round((v-0)*fact))/fact;
13693 var z = (''+fact).substring(2);
13694 if (v == Math.floor(v)) {
13695 return Math.floor(v) + '.' + z;
13698 // now just padd decimals..
13699 var ps = String(v).split('.');
13700 var fd = (ps[1] + z);
13701 var r = fd.substring(0,n);
13702 var rm = fd.substring(n);
13704 return ps[0] + '.' + r;
13706 r*=1; // turn it into a number;
13708 if (String(r).length != n) {
13711 r = String(r).substring(1); // chop the end off.
13714 return ps[0] + '.' + r;
13719 * Format a number as US currency
13720 * @param {Number/String} value The numeric value to format
13721 * @return {String} The formatted currency string
13723 usMoney : function(v){
13724 return '$' + Roo.util.Format.number(v);
13729 * eventually this should probably emulate php's number_format
13730 * @param {Number/String} value The numeric value to format
13731 * @param {Number} decimals number of decimal places
13732 * @return {String} The formatted currency string
13734 number : function(v,decimals)
13736 // multiply and round.
13737 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13738 var mul = Math.pow(10, decimals);
13739 var zero = String(mul).substring(1);
13740 v = (Math.round((v-0)*mul))/mul;
13742 // if it's '0' number.. then
13744 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13746 var ps = v.split('.');
13750 var r = /(\d+)(\d{3})/;
13752 while (r.test(whole)) {
13753 whole = whole.replace(r, '$1' + ',' + '$2');
13759 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13760 // does not have decimals
13761 (decimals ? ('.' + zero) : '');
13764 return whole + sub ;
13768 * Parse a value into a formatted date using the specified format pattern.
13769 * @param {Mixed} value The value to format
13770 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13771 * @return {String} The formatted date string
13773 date : function(v, format){
13777 if(!(v instanceof Date)){
13778 v = new Date(Date.parse(v));
13780 return v.dateFormat(format || Roo.util.Format.defaults.date);
13784 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13785 * @param {String} format Any valid date format string
13786 * @return {Function} The date formatting function
13788 dateRenderer : function(format){
13789 return function(v){
13790 return Roo.util.Format.date(v, format);
13795 stripTagsRE : /<\/?[^>]+>/gi,
13798 * Strips all HTML tags
13799 * @param {Mixed} value The text from which to strip tags
13800 * @return {String} The stripped text
13802 stripTags : function(v){
13803 return !v ? v : String(v).replace(this.stripTagsRE, "");
13807 Roo.util.Format.defaults = {
13811 * Ext JS Library 1.1.1
13812 * Copyright(c) 2006-2007, Ext JS, LLC.
13814 * Originally Released Under LGPL - original licence link has changed is not relivant.
13817 * <script type="text/javascript">
13824 * @class Roo.MasterTemplate
13825 * @extends Roo.Template
13826 * Provides a template that can have child templates. The syntax is:
13828 var t = new Roo.MasterTemplate(
13829 '<select name="{name}">',
13830 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13833 t.add('options', {value: 'foo', text: 'bar'});
13834 // or you can add multiple child elements in one shot
13835 t.addAll('options', [
13836 {value: 'foo', text: 'bar'},
13837 {value: 'foo2', text: 'bar2'},
13838 {value: 'foo3', text: 'bar3'}
13840 // then append, applying the master template values
13841 t.append('my-form', {name: 'my-select'});
13843 * A name attribute for the child template is not required if you have only one child
13844 * template or you want to refer to them by index.
13846 Roo.MasterTemplate = function(){
13847 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13848 this.originalHtml = this.html;
13850 var m, re = this.subTemplateRe;
13853 while(m = re.exec(this.html)){
13854 var name = m[1], content = m[2];
13859 tpl : new Roo.Template(content)
13862 st[name] = st[subIndex];
13864 st[subIndex].tpl.compile();
13865 st[subIndex].tpl.call = this.call.createDelegate(this);
13868 this.subCount = subIndex;
13871 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13873 * The regular expression used to match sub templates
13877 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13880 * Applies the passed values to a child template.
13881 * @param {String/Number} name (optional) The name or index of the child template
13882 * @param {Array/Object} values The values to be applied to the template
13883 * @return {MasterTemplate} this
13885 add : function(name, values){
13886 if(arguments.length == 1){
13887 values = arguments[0];
13890 var s = this.subs[name];
13891 s.buffer[s.buffer.length] = s.tpl.apply(values);
13896 * Applies all the passed values to a child template.
13897 * @param {String/Number} name (optional) The name or index of the child template
13898 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13899 * @param {Boolean} reset (optional) True to reset the template first
13900 * @return {MasterTemplate} this
13902 fill : function(name, values, reset){
13904 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13912 for(var i = 0, len = values.length; i < len; i++){
13913 this.add(name, values[i]);
13919 * Resets the template for reuse
13920 * @return {MasterTemplate} this
13922 reset : function(){
13924 for(var i = 0; i < this.subCount; i++){
13930 applyTemplate : function(values){
13932 var replaceIndex = -1;
13933 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13934 return s[++replaceIndex].buffer.join("");
13936 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13939 apply : function(){
13940 return this.applyTemplate.apply(this, arguments);
13943 compile : function(){return this;}
13947 * Alias for fill().
13950 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13952 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13953 * var tpl = Roo.MasterTemplate.from('element-id');
13954 * @param {String/HTMLElement} el
13955 * @param {Object} config
13958 Roo.MasterTemplate.from = function(el, config){
13959 el = Roo.getDom(el);
13960 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13963 * Ext JS Library 1.1.1
13964 * Copyright(c) 2006-2007, Ext JS, LLC.
13966 * Originally Released Under LGPL - original licence link has changed is not relivant.
13969 * <script type="text/javascript">
13974 * @class Roo.util.CSS
13975 * Utility class for manipulating CSS rules
13978 Roo.util.CSS = function(){
13980 var doc = document;
13982 var camelRe = /(-[a-z])/gi;
13983 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13987 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13988 * tag and appended to the HEAD of the document.
13989 * @param {String|Object} cssText The text containing the css rules
13990 * @param {String} id An id to add to the stylesheet for later removal
13991 * @return {StyleSheet}
13993 createStyleSheet : function(cssText, id){
13995 var head = doc.getElementsByTagName("head")[0];
13996 var nrules = doc.createElement("style");
13997 nrules.setAttribute("type", "text/css");
13999 nrules.setAttribute("id", id);
14001 if (typeof(cssText) != 'string') {
14002 // support object maps..
14003 // not sure if this a good idea..
14004 // perhaps it should be merged with the general css handling
14005 // and handle js style props.
14006 var cssTextNew = [];
14007 for(var n in cssText) {
14009 for(var k in cssText[n]) {
14010 citems.push( k + ' : ' +cssText[n][k] + ';' );
14012 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14015 cssText = cssTextNew.join("\n");
14021 head.appendChild(nrules);
14022 ss = nrules.styleSheet;
14023 ss.cssText = cssText;
14026 nrules.appendChild(doc.createTextNode(cssText));
14028 nrules.cssText = cssText;
14030 head.appendChild(nrules);
14031 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14033 this.cacheStyleSheet(ss);
14038 * Removes a style or link tag by id
14039 * @param {String} id The id of the tag
14041 removeStyleSheet : function(id){
14042 var existing = doc.getElementById(id);
14044 existing.parentNode.removeChild(existing);
14049 * Dynamically swaps an existing stylesheet reference for a new one
14050 * @param {String} id The id of an existing link tag to remove
14051 * @param {String} url The href of the new stylesheet to include
14053 swapStyleSheet : function(id, url){
14054 this.removeStyleSheet(id);
14055 var ss = doc.createElement("link");
14056 ss.setAttribute("rel", "stylesheet");
14057 ss.setAttribute("type", "text/css");
14058 ss.setAttribute("id", id);
14059 ss.setAttribute("href", url);
14060 doc.getElementsByTagName("head")[0].appendChild(ss);
14064 * Refresh the rule cache if you have dynamically added stylesheets
14065 * @return {Object} An object (hash) of rules indexed by selector
14067 refreshCache : function(){
14068 return this.getRules(true);
14072 cacheStyleSheet : function(stylesheet){
14076 try{// try catch for cross domain access issue
14077 var ssRules = stylesheet.cssRules || stylesheet.rules;
14078 for(var j = ssRules.length-1; j >= 0; --j){
14079 rules[ssRules[j].selectorText] = ssRules[j];
14085 * Gets all css rules for the document
14086 * @param {Boolean} refreshCache true to refresh the internal cache
14087 * @return {Object} An object (hash) of rules indexed by selector
14089 getRules : function(refreshCache){
14090 if(rules == null || refreshCache){
14092 var ds = doc.styleSheets;
14093 for(var i =0, len = ds.length; i < len; i++){
14095 this.cacheStyleSheet(ds[i]);
14103 * Gets an an individual CSS rule by selector(s)
14104 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14105 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14106 * @return {CSSRule} The CSS rule or null if one is not found
14108 getRule : function(selector, refreshCache){
14109 var rs = this.getRules(refreshCache);
14110 if(!(selector instanceof Array)){
14111 return rs[selector];
14113 for(var i = 0; i < selector.length; i++){
14114 if(rs[selector[i]]){
14115 return rs[selector[i]];
14123 * Updates a rule property
14124 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14125 * @param {String} property The css property
14126 * @param {String} value The new value for the property
14127 * @return {Boolean} true If a rule was found and updated
14129 updateRule : function(selector, property, value){
14130 if(!(selector instanceof Array)){
14131 var rule = this.getRule(selector);
14133 rule.style[property.replace(camelRe, camelFn)] = value;
14137 for(var i = 0; i < selector.length; i++){
14138 if(this.updateRule(selector[i], property, value)){
14148 * Ext JS Library 1.1.1
14149 * Copyright(c) 2006-2007, Ext JS, LLC.
14151 * Originally Released Under LGPL - original licence link has changed is not relivant.
14154 * <script type="text/javascript">
14160 * @class Roo.util.ClickRepeater
14161 * @extends Roo.util.Observable
14163 * A wrapper class which can be applied to any element. Fires a "click" event while the
14164 * mouse is pressed. The interval between firings may be specified in the config but
14165 * defaults to 10 milliseconds.
14167 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14169 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14170 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14171 * Similar to an autorepeat key delay.
14172 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14173 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14174 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14175 * "interval" and "delay" are ignored. "immediate" is honored.
14176 * @cfg {Boolean} preventDefault True to prevent the default click event
14177 * @cfg {Boolean} stopDefault True to stop the default click event
14180 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14181 * 2007-02-02 jvs Renamed to ClickRepeater
14182 * 2007-02-03 jvs Modifications for FF Mac and Safari
14185 * @param {String/HTMLElement/Element} el The element to listen on
14186 * @param {Object} config
14188 Roo.util.ClickRepeater = function(el, config)
14190 this.el = Roo.get(el);
14191 this.el.unselectable();
14193 Roo.apply(this, config);
14198 * Fires when the mouse button is depressed.
14199 * @param {Roo.util.ClickRepeater} this
14201 "mousedown" : true,
14204 * Fires on a specified interval during the time the element is pressed.
14205 * @param {Roo.util.ClickRepeater} this
14210 * Fires when the mouse key is released.
14211 * @param {Roo.util.ClickRepeater} this
14216 this.el.on("mousedown", this.handleMouseDown, this);
14217 if(this.preventDefault || this.stopDefault){
14218 this.el.on("click", function(e){
14219 if(this.preventDefault){
14220 e.preventDefault();
14222 if(this.stopDefault){
14228 // allow inline handler
14230 this.on("click", this.handler, this.scope || this);
14233 Roo.util.ClickRepeater.superclass.constructor.call(this);
14236 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14239 preventDefault : true,
14240 stopDefault : false,
14244 handleMouseDown : function(){
14245 clearTimeout(this.timer);
14247 if(this.pressClass){
14248 this.el.addClass(this.pressClass);
14250 this.mousedownTime = new Date();
14252 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14253 this.el.on("mouseout", this.handleMouseOut, this);
14255 this.fireEvent("mousedown", this);
14256 this.fireEvent("click", this);
14258 this.timer = this.click.defer(this.delay || this.interval, this);
14262 click : function(){
14263 this.fireEvent("click", this);
14264 this.timer = this.click.defer(this.getInterval(), this);
14268 getInterval: function(){
14269 if(!this.accelerate){
14270 return this.interval;
14272 var pressTime = this.mousedownTime.getElapsed();
14273 if(pressTime < 500){
14275 }else if(pressTime < 1700){
14277 }else if(pressTime < 2600){
14279 }else if(pressTime < 3500){
14281 }else if(pressTime < 4400){
14283 }else if(pressTime < 5300){
14285 }else if(pressTime < 6200){
14293 handleMouseOut : function(){
14294 clearTimeout(this.timer);
14295 if(this.pressClass){
14296 this.el.removeClass(this.pressClass);
14298 this.el.on("mouseover", this.handleMouseReturn, this);
14302 handleMouseReturn : function(){
14303 this.el.un("mouseover", this.handleMouseReturn);
14304 if(this.pressClass){
14305 this.el.addClass(this.pressClass);
14311 handleMouseUp : function(){
14312 clearTimeout(this.timer);
14313 this.el.un("mouseover", this.handleMouseReturn);
14314 this.el.un("mouseout", this.handleMouseOut);
14315 Roo.get(document).un("mouseup", this.handleMouseUp);
14316 this.el.removeClass(this.pressClass);
14317 this.fireEvent("mouseup", this);
14321 * Ext JS Library 1.1.1
14322 * Copyright(c) 2006-2007, Ext JS, LLC.
14324 * Originally Released Under LGPL - original licence link has changed is not relivant.
14327 * <script type="text/javascript">
14332 * @class Roo.KeyNav
14333 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14334 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14335 * way to implement custom navigation schemes for any UI component.</p>
14336 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14337 * pageUp, pageDown, del, home, end. Usage:</p>
14339 var nav = new Roo.KeyNav("my-element", {
14340 "left" : function(e){
14341 this.moveLeft(e.ctrlKey);
14343 "right" : function(e){
14344 this.moveRight(e.ctrlKey);
14346 "enter" : function(e){
14353 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14354 * @param {Object} config The config
14356 Roo.KeyNav = function(el, config){
14357 this.el = Roo.get(el);
14358 Roo.apply(this, config);
14359 if(!this.disabled){
14360 this.disabled = true;
14365 Roo.KeyNav.prototype = {
14367 * @cfg {Boolean} disabled
14368 * True to disable this KeyNav instance (defaults to false)
14372 * @cfg {String} defaultEventAction
14373 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14374 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14375 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14377 defaultEventAction: "stopEvent",
14379 * @cfg {Boolean} forceKeyDown
14380 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14381 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14382 * handle keydown instead of keypress.
14384 forceKeyDown : false,
14387 prepareEvent : function(e){
14388 var k = e.getKey();
14389 var h = this.keyToHandler[k];
14390 //if(h && this[h]){
14391 // e.stopPropagation();
14393 if(Roo.isSafari && h && k >= 37 && k <= 40){
14399 relay : function(e){
14400 var k = e.getKey();
14401 var h = this.keyToHandler[k];
14403 if(this.doRelay(e, this[h], h) !== true){
14404 e[this.defaultEventAction]();
14410 doRelay : function(e, h, hname){
14411 return h.call(this.scope || this, e);
14414 // possible handlers
14428 // quick lookup hash
14445 * Enable this KeyNav
14447 enable: function(){
14449 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14450 // the EventObject will normalize Safari automatically
14451 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14452 this.el.on("keydown", this.relay, this);
14454 this.el.on("keydown", this.prepareEvent, this);
14455 this.el.on("keypress", this.relay, this);
14457 this.disabled = false;
14462 * Disable this KeyNav
14464 disable: function(){
14465 if(!this.disabled){
14466 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14467 this.el.un("keydown", this.relay);
14469 this.el.un("keydown", this.prepareEvent);
14470 this.el.un("keypress", this.relay);
14472 this.disabled = true;
14477 * Ext JS Library 1.1.1
14478 * Copyright(c) 2006-2007, Ext JS, LLC.
14480 * Originally Released Under LGPL - original licence link has changed is not relivant.
14483 * <script type="text/javascript">
14488 * @class Roo.KeyMap
14489 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14490 * The constructor accepts the same config object as defined by {@link #addBinding}.
14491 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14492 * combination it will call the function with this signature (if the match is a multi-key
14493 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14494 * A KeyMap can also handle a string representation of keys.<br />
14497 // map one key by key code
14498 var map = new Roo.KeyMap("my-element", {
14499 key: 13, // or Roo.EventObject.ENTER
14504 // map multiple keys to one action by string
14505 var map = new Roo.KeyMap("my-element", {
14511 // map multiple keys to multiple actions by strings and array of codes
14512 var map = new Roo.KeyMap("my-element", [
14515 fn: function(){ alert("Return was pressed"); }
14518 fn: function(){ alert('a, b or c was pressed'); }
14523 fn: function(){ alert('Control + shift + tab was pressed.'); }
14527 * <b>Note: A KeyMap starts enabled</b>
14529 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14530 * @param {Object} config The config (see {@link #addBinding})
14531 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14533 Roo.KeyMap = function(el, config, eventName){
14534 this.el = Roo.get(el);
14535 this.eventName = eventName || "keydown";
14536 this.bindings = [];
14538 this.addBinding(config);
14543 Roo.KeyMap.prototype = {
14545 * True to stop the event from bubbling and prevent the default browser action if the
14546 * key was handled by the KeyMap (defaults to false)
14552 * Add a new binding to this KeyMap. The following config object properties are supported:
14554 Property Type Description
14555 ---------- --------------- ----------------------------------------------------------------------
14556 key String/Array A single keycode or an array of keycodes to handle
14557 shift Boolean True to handle key only when shift is pressed (defaults to false)
14558 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14559 alt Boolean True to handle key only when alt is pressed (defaults to false)
14560 fn Function The function to call when KeyMap finds the expected key combination
14561 scope Object The scope of the callback function
14567 var map = new Roo.KeyMap(document, {
14568 key: Roo.EventObject.ENTER,
14573 //Add a new binding to the existing KeyMap later
14581 * @param {Object/Array} config A single KeyMap config or an array of configs
14583 addBinding : function(config){
14584 if(config instanceof Array){
14585 for(var i = 0, len = config.length; i < len; i++){
14586 this.addBinding(config[i]);
14590 var keyCode = config.key,
14591 shift = config.shift,
14592 ctrl = config.ctrl,
14595 scope = config.scope;
14596 if(typeof keyCode == "string"){
14598 var keyString = keyCode.toUpperCase();
14599 for(var j = 0, len = keyString.length; j < len; j++){
14600 ks.push(keyString.charCodeAt(j));
14604 var keyArray = keyCode instanceof Array;
14605 var handler = function(e){
14606 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14607 var k = e.getKey();
14609 for(var i = 0, len = keyCode.length; i < len; i++){
14610 if(keyCode[i] == k){
14611 if(this.stopEvent){
14614 fn.call(scope || window, k, e);
14620 if(this.stopEvent){
14623 fn.call(scope || window, k, e);
14628 this.bindings.push(handler);
14632 * Shorthand for adding a single key listener
14633 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14634 * following options:
14635 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14636 * @param {Function} fn The function to call
14637 * @param {Object} scope (optional) The scope of the function
14639 on : function(key, fn, scope){
14640 var keyCode, shift, ctrl, alt;
14641 if(typeof key == "object" && !(key instanceof Array)){
14660 handleKeyDown : function(e){
14661 if(this.enabled){ //just in case
14662 var b = this.bindings;
14663 for(var i = 0, len = b.length; i < len; i++){
14664 b[i].call(this, e);
14670 * Returns true if this KeyMap is enabled
14671 * @return {Boolean}
14673 isEnabled : function(){
14674 return this.enabled;
14678 * Enables this KeyMap
14680 enable: function(){
14682 this.el.on(this.eventName, this.handleKeyDown, this);
14683 this.enabled = true;
14688 * Disable this KeyMap
14690 disable: function(){
14692 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14693 this.enabled = false;
14698 * Ext JS Library 1.1.1
14699 * Copyright(c) 2006-2007, Ext JS, LLC.
14701 * Originally Released Under LGPL - original licence link has changed is not relivant.
14704 * <script type="text/javascript">
14709 * @class Roo.util.TextMetrics
14710 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14711 * wide, in pixels, a given block of text will be.
14714 Roo.util.TextMetrics = function(){
14718 * Measures the size of the specified text
14719 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14720 * that can affect the size of the rendered text
14721 * @param {String} text The text to measure
14722 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14723 * in order to accurately measure the text height
14724 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14726 measure : function(el, text, fixedWidth){
14728 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14731 shared.setFixedWidth(fixedWidth || 'auto');
14732 return shared.getSize(text);
14736 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14737 * the overhead of multiple calls to initialize the style properties on each measurement.
14738 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14739 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14740 * in order to accurately measure the text height
14741 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14743 createInstance : function(el, fixedWidth){
14744 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14751 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14752 var ml = new Roo.Element(document.createElement('div'));
14753 document.body.appendChild(ml.dom);
14754 ml.position('absolute');
14755 ml.setLeftTop(-1000, -1000);
14759 ml.setWidth(fixedWidth);
14764 * Returns the size of the specified text based on the internal element's style and width properties
14765 * @memberOf Roo.util.TextMetrics.Instance#
14766 * @param {String} text The text to measure
14767 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14769 getSize : function(text){
14771 var s = ml.getSize();
14777 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14778 * that can affect the size of the rendered text
14779 * @memberOf Roo.util.TextMetrics.Instance#
14780 * @param {String/HTMLElement} el The element, dom node or id
14782 bind : function(el){
14784 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14789 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14790 * to set a fixed width in order to accurately measure the text height.
14791 * @memberOf Roo.util.TextMetrics.Instance#
14792 * @param {Number} width The width to set on the element
14794 setFixedWidth : function(width){
14795 ml.setWidth(width);
14799 * Returns the measured width of the specified text
14800 * @memberOf Roo.util.TextMetrics.Instance#
14801 * @param {String} text The text to measure
14802 * @return {Number} width The width in pixels
14804 getWidth : function(text){
14805 ml.dom.style.width = 'auto';
14806 return this.getSize(text).width;
14810 * Returns the measured height of the specified text. For multiline text, be sure to call
14811 * {@link #setFixedWidth} if necessary.
14812 * @memberOf Roo.util.TextMetrics.Instance#
14813 * @param {String} text The text to measure
14814 * @return {Number} height The height in pixels
14816 getHeight : function(text){
14817 return this.getSize(text).height;
14821 instance.bind(bindTo);
14826 // backwards compat
14827 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14829 * Ext JS Library 1.1.1
14830 * Copyright(c) 2006-2007, Ext JS, LLC.
14832 * Originally Released Under LGPL - original licence link has changed is not relivant.
14835 * <script type="text/javascript">
14839 * @class Roo.state.Provider
14840 * Abstract base class for state provider implementations. This class provides methods
14841 * for encoding and decoding <b>typed</b> variables including dates and defines the
14842 * Provider interface.
14844 Roo.state.Provider = function(){
14846 * @event statechange
14847 * Fires when a state change occurs.
14848 * @param {Provider} this This state provider
14849 * @param {String} key The state key which was changed
14850 * @param {String} value The encoded value for the state
14853 "statechange": true
14856 Roo.state.Provider.superclass.constructor.call(this);
14858 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14860 * Returns the current value for a key
14861 * @param {String} name The key name
14862 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14863 * @return {Mixed} The state data
14865 get : function(name, defaultValue){
14866 return typeof this.state[name] == "undefined" ?
14867 defaultValue : this.state[name];
14871 * Clears a value from the state
14872 * @param {String} name The key name
14874 clear : function(name){
14875 delete this.state[name];
14876 this.fireEvent("statechange", this, name, null);
14880 * Sets the value for a key
14881 * @param {String} name The key name
14882 * @param {Mixed} value The value to set
14884 set : function(name, value){
14885 this.state[name] = value;
14886 this.fireEvent("statechange", this, name, value);
14890 * Decodes a string previously encoded with {@link #encodeValue}.
14891 * @param {String} value The value to decode
14892 * @return {Mixed} The decoded value
14894 decodeValue : function(cookie){
14895 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14896 var matches = re.exec(unescape(cookie));
14897 if(!matches || !matches[1]) {
14898 return; // non state cookie
14900 var type = matches[1];
14901 var v = matches[2];
14904 return parseFloat(v);
14906 return new Date(Date.parse(v));
14911 var values = v.split("^");
14912 for(var i = 0, len = values.length; i < len; i++){
14913 all.push(this.decodeValue(values[i]));
14918 var values = v.split("^");
14919 for(var i = 0, len = values.length; i < len; i++){
14920 var kv = values[i].split("=");
14921 all[kv[0]] = this.decodeValue(kv[1]);
14930 * Encodes a value including type information. Decode with {@link #decodeValue}.
14931 * @param {Mixed} value The value to encode
14932 * @return {String} The encoded value
14934 encodeValue : function(v){
14936 if(typeof v == "number"){
14938 }else if(typeof v == "boolean"){
14939 enc = "b:" + (v ? "1" : "0");
14940 }else if(v instanceof Date){
14941 enc = "d:" + v.toGMTString();
14942 }else if(v instanceof Array){
14944 for(var i = 0, len = v.length; i < len; i++){
14945 flat += this.encodeValue(v[i]);
14951 }else if(typeof v == "object"){
14954 if(typeof v[key] != "function"){
14955 flat += key + "=" + this.encodeValue(v[key]) + "^";
14958 enc = "o:" + flat.substring(0, flat.length-1);
14962 return escape(enc);
14968 * Ext JS Library 1.1.1
14969 * Copyright(c) 2006-2007, Ext JS, LLC.
14971 * Originally Released Under LGPL - original licence link has changed is not relivant.
14974 * <script type="text/javascript">
14977 * @class Roo.state.Manager
14978 * This is the global state manager. By default all components that are "state aware" check this class
14979 * for state information if you don't pass them a custom state provider. In order for this class
14980 * to be useful, it must be initialized with a provider when your application initializes.
14982 // in your initialization function
14984 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14986 // supposed you have a {@link Roo.BorderLayout}
14987 var layout = new Roo.BorderLayout(...);
14988 layout.restoreState();
14989 // or a {Roo.BasicDialog}
14990 var dialog = new Roo.BasicDialog(...);
14991 dialog.restoreState();
14995 Roo.state.Manager = function(){
14996 var provider = new Roo.state.Provider();
15000 * Configures the default state provider for your application
15001 * @param {Provider} stateProvider The state provider to set
15003 setProvider : function(stateProvider){
15004 provider = stateProvider;
15008 * Returns the current value for a key
15009 * @param {String} name The key name
15010 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15011 * @return {Mixed} The state data
15013 get : function(key, defaultValue){
15014 return provider.get(key, defaultValue);
15018 * Sets the value for a key
15019 * @param {String} name The key name
15020 * @param {Mixed} value The state data
15022 set : function(key, value){
15023 provider.set(key, value);
15027 * Clears a value from the state
15028 * @param {String} name The key name
15030 clear : function(key){
15031 provider.clear(key);
15035 * Gets the currently configured state provider
15036 * @return {Provider} The state provider
15038 getProvider : function(){
15045 * Ext JS Library 1.1.1
15046 * Copyright(c) 2006-2007, Ext JS, LLC.
15048 * Originally Released Under LGPL - original licence link has changed is not relivant.
15051 * <script type="text/javascript">
15054 * @class Roo.state.CookieProvider
15055 * @extends Roo.state.Provider
15056 * The default Provider implementation which saves state via cookies.
15059 var cp = new Roo.state.CookieProvider({
15061 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15062 domain: "roojs.com"
15064 Roo.state.Manager.setProvider(cp);
15066 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15067 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15068 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15069 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15070 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15071 * domain the page is running on including the 'www' like 'www.roojs.com')
15072 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15074 * Create a new CookieProvider
15075 * @param {Object} config The configuration object
15077 Roo.state.CookieProvider = function(config){
15078 Roo.state.CookieProvider.superclass.constructor.call(this);
15080 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15081 this.domain = null;
15082 this.secure = false;
15083 Roo.apply(this, config);
15084 this.state = this.readCookies();
15087 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15089 set : function(name, value){
15090 if(typeof value == "undefined" || value === null){
15094 this.setCookie(name, value);
15095 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15099 clear : function(name){
15100 this.clearCookie(name);
15101 Roo.state.CookieProvider.superclass.clear.call(this, name);
15105 readCookies : function(){
15107 var c = document.cookie + ";";
15108 var re = /\s?(.*?)=(.*?);/g;
15110 while((matches = re.exec(c)) != null){
15111 var name = matches[1];
15112 var value = matches[2];
15113 if(name && name.substring(0,3) == "ys-"){
15114 cookies[name.substr(3)] = this.decodeValue(value);
15121 setCookie : function(name, value){
15122 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15123 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15124 ((this.path == null) ? "" : ("; path=" + this.path)) +
15125 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15126 ((this.secure == true) ? "; secure" : "");
15130 clearCookie : function(name){
15131 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15132 ((this.path == null) ? "" : ("; path=" + this.path)) +
15133 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15134 ((this.secure == true) ? "; secure" : "");
15138 * Ext JS Library 1.1.1
15139 * Copyright(c) 2006-2007, Ext JS, LLC.
15141 * Originally Released Under LGPL - original licence link has changed is not relivant.
15144 * <script type="text/javascript">
15149 * @class Roo.ComponentMgr
15150 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15153 Roo.ComponentMgr = function(){
15154 var all = new Roo.util.MixedCollection();
15158 * Registers a component.
15159 * @param {Roo.Component} c The component
15161 register : function(c){
15166 * Unregisters a component.
15167 * @param {Roo.Component} c The component
15169 unregister : function(c){
15174 * Returns a component by id
15175 * @param {String} id The component id
15177 get : function(id){
15178 return all.get(id);
15182 * Registers a function that will be called when a specified component is added to ComponentMgr
15183 * @param {String} id The component id
15184 * @param {Funtction} fn The callback function
15185 * @param {Object} scope The scope of the callback
15187 onAvailable : function(id, fn, scope){
15188 all.on("add", function(index, o){
15190 fn.call(scope || o, o);
15191 all.un("add", fn, scope);
15198 * Ext JS Library 1.1.1
15199 * Copyright(c) 2006-2007, Ext JS, LLC.
15201 * Originally Released Under LGPL - original licence link has changed is not relivant.
15204 * <script type="text/javascript">
15208 * @class Roo.Component
15209 * @extends Roo.util.Observable
15210 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15211 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15212 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15213 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15214 * All visual components (widgets) that require rendering into a layout should subclass Component.
15216 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15217 * 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
15218 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15220 Roo.Component = function(config){
15221 config = config || {};
15222 if(config.tagName || config.dom || typeof config == "string"){ // element object
15223 config = {el: config, id: config.id || config};
15225 this.initialConfig = config;
15227 Roo.apply(this, config);
15231 * Fires after the component is disabled.
15232 * @param {Roo.Component} this
15237 * Fires after the component is enabled.
15238 * @param {Roo.Component} this
15242 * @event beforeshow
15243 * Fires before the component is shown. Return false to stop the show.
15244 * @param {Roo.Component} this
15249 * Fires after the component is shown.
15250 * @param {Roo.Component} this
15254 * @event beforehide
15255 * Fires before the component is hidden. Return false to stop the hide.
15256 * @param {Roo.Component} this
15261 * Fires after the component is hidden.
15262 * @param {Roo.Component} this
15266 * @event beforerender
15267 * Fires before the component is rendered. Return false to stop the render.
15268 * @param {Roo.Component} this
15270 beforerender : true,
15273 * Fires after the component is rendered.
15274 * @param {Roo.Component} this
15278 * @event beforedestroy
15279 * Fires before the component is destroyed. Return false to stop the destroy.
15280 * @param {Roo.Component} this
15282 beforedestroy : true,
15285 * Fires after the component is destroyed.
15286 * @param {Roo.Component} this
15291 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15293 Roo.ComponentMgr.register(this);
15294 Roo.Component.superclass.constructor.call(this);
15295 this.initComponent();
15296 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15297 this.render(this.renderTo);
15298 delete this.renderTo;
15303 Roo.Component.AUTO_ID = 1000;
15305 Roo.extend(Roo.Component, Roo.util.Observable, {
15307 * @scope Roo.Component.prototype
15309 * true if this component is hidden. Read-only.
15314 * true if this component is disabled. Read-only.
15319 * true if this component has been rendered. Read-only.
15323 /** @cfg {String} disableClass
15324 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15326 disabledClass : "x-item-disabled",
15327 /** @cfg {Boolean} allowDomMove
15328 * Whether the component can move the Dom node when rendering (defaults to true).
15330 allowDomMove : true,
15331 /** @cfg {String} hideMode (display|visibility)
15332 * How this component should hidden. Supported values are
15333 * "visibility" (css visibility), "offsets" (negative offset position) and
15334 * "display" (css display) - defaults to "display".
15336 hideMode: 'display',
15339 ctype : "Roo.Component",
15342 * @cfg {String} actionMode
15343 * which property holds the element that used for hide() / show() / disable() / enable()
15349 getActionEl : function(){
15350 return this[this.actionMode];
15353 initComponent : Roo.emptyFn,
15355 * If this is a lazy rendering component, render it to its container element.
15356 * @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.
15358 render : function(container, position){
15359 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15360 if(!container && this.el){
15361 this.el = Roo.get(this.el);
15362 container = this.el.dom.parentNode;
15363 this.allowDomMove = false;
15365 this.container = Roo.get(container);
15366 this.rendered = true;
15367 if(position !== undefined){
15368 if(typeof position == 'number'){
15369 position = this.container.dom.childNodes[position];
15371 position = Roo.getDom(position);
15374 this.onRender(this.container, position || null);
15376 this.el.addClass(this.cls);
15380 this.el.applyStyles(this.style);
15383 this.fireEvent("render", this);
15384 this.afterRender(this.container);
15396 // default function is not really useful
15397 onRender : function(ct, position){
15399 this.el = Roo.get(this.el);
15400 if(this.allowDomMove !== false){
15401 ct.dom.insertBefore(this.el.dom, position);
15407 getAutoCreate : function(){
15408 var cfg = typeof this.autoCreate == "object" ?
15409 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15410 if(this.id && !cfg.id){
15417 afterRender : Roo.emptyFn,
15420 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15421 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15423 destroy : function(){
15424 if(this.fireEvent("beforedestroy", this) !== false){
15425 this.purgeListeners();
15426 this.beforeDestroy();
15428 this.el.removeAllListeners();
15430 if(this.actionMode == "container"){
15431 this.container.remove();
15435 Roo.ComponentMgr.unregister(this);
15436 this.fireEvent("destroy", this);
15441 beforeDestroy : function(){
15446 onDestroy : function(){
15451 * Returns the underlying {@link Roo.Element}.
15452 * @return {Roo.Element} The element
15454 getEl : function(){
15459 * Returns the id of this component.
15462 getId : function(){
15467 * Try to focus this component.
15468 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15469 * @return {Roo.Component} this
15471 focus : function(selectText){
15474 if(selectText === true){
15475 this.el.dom.select();
15490 * Disable this component.
15491 * @return {Roo.Component} this
15493 disable : function(){
15497 this.disabled = true;
15498 this.fireEvent("disable", this);
15503 onDisable : function(){
15504 this.getActionEl().addClass(this.disabledClass);
15505 this.el.dom.disabled = true;
15509 * Enable this component.
15510 * @return {Roo.Component} this
15512 enable : function(){
15516 this.disabled = false;
15517 this.fireEvent("enable", this);
15522 onEnable : function(){
15523 this.getActionEl().removeClass(this.disabledClass);
15524 this.el.dom.disabled = false;
15528 * Convenience function for setting disabled/enabled by boolean.
15529 * @param {Boolean} disabled
15531 setDisabled : function(disabled){
15532 this[disabled ? "disable" : "enable"]();
15536 * Show this component.
15537 * @return {Roo.Component} this
15540 if(this.fireEvent("beforeshow", this) !== false){
15541 this.hidden = false;
15545 this.fireEvent("show", this);
15551 onShow : function(){
15552 var ae = this.getActionEl();
15553 if(this.hideMode == 'visibility'){
15554 ae.dom.style.visibility = "visible";
15555 }else if(this.hideMode == 'offsets'){
15556 ae.removeClass('x-hidden');
15558 ae.dom.style.display = "";
15563 * Hide this component.
15564 * @return {Roo.Component} this
15567 if(this.fireEvent("beforehide", this) !== false){
15568 this.hidden = true;
15572 this.fireEvent("hide", this);
15578 onHide : function(){
15579 var ae = this.getActionEl();
15580 if(this.hideMode == 'visibility'){
15581 ae.dom.style.visibility = "hidden";
15582 }else if(this.hideMode == 'offsets'){
15583 ae.addClass('x-hidden');
15585 ae.dom.style.display = "none";
15590 * Convenience function to hide or show this component by boolean.
15591 * @param {Boolean} visible True to show, false to hide
15592 * @return {Roo.Component} this
15594 setVisible: function(visible){
15604 * Returns true if this component is visible.
15606 isVisible : function(){
15607 return this.getActionEl().isVisible();
15610 cloneConfig : function(overrides){
15611 overrides = overrides || {};
15612 var id = overrides.id || Roo.id();
15613 var cfg = Roo.applyIf(overrides, this.initialConfig);
15614 cfg.id = id; // prevent dup id
15615 return new this.constructor(cfg);
15619 * Ext JS Library 1.1.1
15620 * Copyright(c) 2006-2007, Ext JS, LLC.
15622 * Originally Released Under LGPL - original licence link has changed is not relivant.
15625 * <script type="text/javascript">
15629 * @class Roo.BoxComponent
15630 * @extends Roo.Component
15631 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15632 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15633 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15634 * layout containers.
15636 * @param {Roo.Element/String/Object} config The configuration options.
15638 Roo.BoxComponent = function(config){
15639 Roo.Component.call(this, config);
15643 * Fires after the component is resized.
15644 * @param {Roo.Component} this
15645 * @param {Number} adjWidth The box-adjusted width that was set
15646 * @param {Number} adjHeight The box-adjusted height that was set
15647 * @param {Number} rawWidth The width that was originally specified
15648 * @param {Number} rawHeight The height that was originally specified
15653 * Fires after the component is moved.
15654 * @param {Roo.Component} this
15655 * @param {Number} x The new x position
15656 * @param {Number} y The new y position
15662 Roo.extend(Roo.BoxComponent, Roo.Component, {
15663 // private, set in afterRender to signify that the component has been rendered
15665 // private, used to defer height settings to subclasses
15666 deferHeight: false,
15667 /** @cfg {Number} width
15668 * width (optional) size of component
15670 /** @cfg {Number} height
15671 * height (optional) size of component
15675 * Sets the width and height of the component. This method fires the resize event. This method can accept
15676 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15677 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15678 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15679 * @return {Roo.BoxComponent} this
15681 setSize : function(w, h){
15682 // support for standard size objects
15683 if(typeof w == 'object'){
15688 if(!this.boxReady){
15694 // prevent recalcs when not needed
15695 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15698 this.lastSize = {width: w, height: h};
15700 var adj = this.adjustSize(w, h);
15701 var aw = adj.width, ah = adj.height;
15702 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15703 var rz = this.getResizeEl();
15704 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15705 rz.setSize(aw, ah);
15706 }else if(!this.deferHeight && ah !== undefined){
15708 }else if(aw !== undefined){
15711 this.onResize(aw, ah, w, h);
15712 this.fireEvent('resize', this, aw, ah, w, h);
15718 * Gets the current size of the component's underlying element.
15719 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15721 getSize : function(){
15722 return this.el.getSize();
15726 * Gets the current XY position of the component's underlying element.
15727 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15728 * @return {Array} The XY position of the element (e.g., [100, 200])
15730 getPosition : function(local){
15731 if(local === true){
15732 return [this.el.getLeft(true), this.el.getTop(true)];
15734 return this.xy || this.el.getXY();
15738 * Gets the current box measurements of the component's underlying element.
15739 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15740 * @returns {Object} box An object in the format {x, y, width, height}
15742 getBox : function(local){
15743 var s = this.el.getSize();
15745 s.x = this.el.getLeft(true);
15746 s.y = this.el.getTop(true);
15748 var xy = this.xy || this.el.getXY();
15756 * Sets the current box measurements of the component's underlying element.
15757 * @param {Object} box An object in the format {x, y, width, height}
15758 * @returns {Roo.BoxComponent} this
15760 updateBox : function(box){
15761 this.setSize(box.width, box.height);
15762 this.setPagePosition(box.x, box.y);
15767 getResizeEl : function(){
15768 return this.resizeEl || this.el;
15772 getPositionEl : function(){
15773 return this.positionEl || this.el;
15777 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15778 * This method fires the move event.
15779 * @param {Number} left The new left
15780 * @param {Number} top The new top
15781 * @returns {Roo.BoxComponent} this
15783 setPosition : function(x, y){
15786 if(!this.boxReady){
15789 var adj = this.adjustPosition(x, y);
15790 var ax = adj.x, ay = adj.y;
15792 var el = this.getPositionEl();
15793 if(ax !== undefined || ay !== undefined){
15794 if(ax !== undefined && ay !== undefined){
15795 el.setLeftTop(ax, ay);
15796 }else if(ax !== undefined){
15798 }else if(ay !== undefined){
15801 this.onPosition(ax, ay);
15802 this.fireEvent('move', this, ax, ay);
15808 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15809 * This method fires the move event.
15810 * @param {Number} x The new x position
15811 * @param {Number} y The new y position
15812 * @returns {Roo.BoxComponent} this
15814 setPagePosition : function(x, y){
15817 if(!this.boxReady){
15820 if(x === undefined || y === undefined){ // cannot translate undefined points
15823 var p = this.el.translatePoints(x, y);
15824 this.setPosition(p.left, p.top);
15829 onRender : function(ct, position){
15830 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15832 this.resizeEl = Roo.get(this.resizeEl);
15834 if(this.positionEl){
15835 this.positionEl = Roo.get(this.positionEl);
15840 afterRender : function(){
15841 Roo.BoxComponent.superclass.afterRender.call(this);
15842 this.boxReady = true;
15843 this.setSize(this.width, this.height);
15844 if(this.x || this.y){
15845 this.setPosition(this.x, this.y);
15847 if(this.pageX || this.pageY){
15848 this.setPagePosition(this.pageX, this.pageY);
15853 * Force the component's size to recalculate based on the underlying element's current height and width.
15854 * @returns {Roo.BoxComponent} this
15856 syncSize : function(){
15857 delete this.lastSize;
15858 this.setSize(this.el.getWidth(), this.el.getHeight());
15863 * Called after the component is resized, this method is empty by default but can be implemented by any
15864 * subclass that needs to perform custom logic after a resize occurs.
15865 * @param {Number} adjWidth The box-adjusted width that was set
15866 * @param {Number} adjHeight The box-adjusted height that was set
15867 * @param {Number} rawWidth The width that was originally specified
15868 * @param {Number} rawHeight The height that was originally specified
15870 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15875 * Called after the component is moved, this method is empty by default but can be implemented by any
15876 * subclass that needs to perform custom logic after a move occurs.
15877 * @param {Number} x The new x position
15878 * @param {Number} y The new y position
15880 onPosition : function(x, y){
15885 adjustSize : function(w, h){
15886 if(this.autoWidth){
15889 if(this.autoHeight){
15892 return {width : w, height: h};
15896 adjustPosition : function(x, y){
15897 return {x : x, y: y};
15900 * Original code for Roojs - LGPL
15901 * <script type="text/javascript">
15905 * @class Roo.XComponent
15906 * A delayed Element creator...
15907 * Or a way to group chunks of interface together.
15908 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15909 * used in conjunction with XComponent.build() it will create an instance of each element,
15910 * then call addxtype() to build the User interface.
15912 * Mypart.xyx = new Roo.XComponent({
15914 parent : 'Mypart.xyz', // empty == document.element.!!
15918 disabled : function() {}
15920 tree : function() { // return an tree of xtype declared components
15924 xtype : 'NestedLayoutPanel',
15931 * It can be used to build a big heiracy, with parent etc.
15932 * or you can just use this to render a single compoent to a dom element
15933 * MYPART.render(Roo.Element | String(id) | dom_element )
15940 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15941 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15943 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15945 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15946 * - if mulitple topModules exist, the last one is defined as the top module.
15950 * When the top level or multiple modules are to embedded into a existing HTML page,
15951 * the parent element can container '#id' of the element where the module will be drawn.
15955 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15956 * it relies more on a include mechanism, where sub modules are included into an outer page.
15957 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15959 * Bootstrap Roo Included elements
15961 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15962 * hence confusing the component builder as it thinks there are multiple top level elements.
15966 * @extends Roo.util.Observable
15968 * @param cfg {Object} configuration of component
15971 Roo.XComponent = function(cfg) {
15972 Roo.apply(this, cfg);
15976 * Fires when this the componnt is built
15977 * @param {Roo.XComponent} c the component
15982 this.region = this.region || 'center'; // default..
15983 Roo.XComponent.register(this);
15984 this.modules = false;
15985 this.el = false; // where the layout goes..
15989 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15992 * The created element (with Roo.factory())
15993 * @type {Roo.Layout}
15999 * for BC - use el in new code
16000 * @type {Roo.Layout}
16006 * for BC - use el in new code
16007 * @type {Roo.Layout}
16012 * @cfg {Function|boolean} disabled
16013 * If this module is disabled by some rule, return true from the funtion
16018 * @cfg {String} parent
16019 * Name of parent element which it get xtype added to..
16024 * @cfg {String} order
16025 * Used to set the order in which elements are created (usefull for multiple tabs)
16030 * @cfg {String} name
16031 * String to display while loading.
16035 * @cfg {String} region
16036 * Region to render component to (defaults to center)
16041 * @cfg {Array} items
16042 * A single item array - the first element is the root of the tree..
16043 * It's done this way to stay compatible with the Xtype system...
16049 * The method that retuns the tree of parts that make up this compoennt
16056 * render element to dom or tree
16057 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16060 render : function(el)
16064 var hp = this.parent ? 1 : 0;
16065 Roo.debug && Roo.log(this);
16067 var tree = this._tree ? this._tree() : this.tree();
16070 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16071 // if parent is a '#.....' string, then let's use that..
16072 var ename = this.parent.substr(1);
16073 this.parent = false;
16074 Roo.debug && Roo.log(ename);
16076 case 'bootstrap-body':
16077 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16078 // this is the BorderLayout standard?
16079 this.parent = { el : true };
16082 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16083 // need to insert stuff...
16085 el : new Roo.bootstrap.layout.Border({
16086 el : document.body,
16092 tabPosition: 'top',
16093 //resizeTabs: true,
16094 alwaysShowTabs: true,
16104 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16105 this.parent = { el : new Roo.bootstrap.Body() };
16106 Roo.debug && Roo.log("setting el to doc body");
16109 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16113 this.parent = { el : true};
16116 el = Roo.get(ename);
16117 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16118 this.parent = { el : true};
16125 if (!el && !this.parent) {
16126 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16131 Roo.debug && Roo.log("EL:");
16132 Roo.debug && Roo.log(el);
16133 Roo.debug && Roo.log("this.parent.el:");
16134 Roo.debug && Roo.log(this.parent.el);
16137 // altertive root elements ??? - we need a better way to indicate these.
16138 var is_alt = Roo.XComponent.is_alt ||
16139 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16140 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16141 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16145 if (!this.parent && is_alt) {
16146 //el = Roo.get(document.body);
16147 this.parent = { el : true };
16152 if (!this.parent) {
16154 Roo.debug && Roo.log("no parent - creating one");
16156 el = el ? Roo.get(el) : false;
16158 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16161 el : new Roo.bootstrap.layout.Border({
16162 el: el || document.body,
16168 tabPosition: 'top',
16169 //resizeTabs: true,
16170 alwaysShowTabs: false,
16173 overflow: 'visible'
16179 // it's a top level one..
16181 el : new Roo.BorderLayout(el || document.body, {
16186 tabPosition: 'top',
16187 //resizeTabs: true,
16188 alwaysShowTabs: el && hp? false : true,
16189 hideTabs: el || !hp ? true : false,
16197 if (!this.parent.el) {
16198 // probably an old style ctor, which has been disabled.
16202 // The 'tree' method is '_tree now'
16204 tree.region = tree.region || this.region;
16205 var is_body = false;
16206 if (this.parent.el === true) {
16207 // bootstrap... - body..
16211 this.parent.el = Roo.factory(tree);
16215 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16216 this.fireEvent('built', this);
16218 this.panel = this.el;
16219 this.layout = this.panel.layout;
16220 this.parentLayout = this.parent.layout || false;
16226 Roo.apply(Roo.XComponent, {
16228 * @property hideProgress
16229 * true to disable the building progress bar.. usefull on single page renders.
16232 hideProgress : false,
16234 * @property buildCompleted
16235 * True when the builder has completed building the interface.
16238 buildCompleted : false,
16241 * @property topModule
16242 * the upper most module - uses document.element as it's constructor.
16249 * @property modules
16250 * array of modules to be created by registration system.
16251 * @type {Array} of Roo.XComponent
16256 * @property elmodules
16257 * array of modules to be created by which use #ID
16258 * @type {Array} of Roo.XComponent
16265 * Is an alternative Root - normally used by bootstrap or other systems,
16266 * where the top element in the tree can wrap 'body'
16267 * @type {boolean} (default false)
16272 * @property build_from_html
16273 * Build elements from html - used by bootstrap HTML stuff
16274 * - this is cleared after build is completed
16275 * @type {boolean} (default false)
16278 build_from_html : false,
16280 * Register components to be built later.
16282 * This solves the following issues
16283 * - Building is not done on page load, but after an authentication process has occured.
16284 * - Interface elements are registered on page load
16285 * - Parent Interface elements may not be loaded before child, so this handles that..
16292 module : 'Pman.Tab.projectMgr',
16294 parent : 'Pman.layout',
16295 disabled : false, // or use a function..
16298 * * @param {Object} details about module
16300 register : function(obj) {
16302 Roo.XComponent.event.fireEvent('register', obj);
16303 switch(typeof(obj.disabled) ) {
16309 if ( obj.disabled() ) {
16315 if (obj.disabled) {
16321 this.modules.push(obj);
16325 * convert a string to an object..
16326 * eg. 'AAA.BBB' -> finds AAA.BBB
16330 toObject : function(str)
16332 if (!str || typeof(str) == 'object') {
16335 if (str.substring(0,1) == '#') {
16339 var ar = str.split('.');
16344 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16346 throw "Module not found : " + str;
16350 throw "Module not found : " + str;
16352 Roo.each(ar, function(e) {
16353 if (typeof(o[e]) == 'undefined') {
16354 throw "Module not found : " + str;
16365 * move modules into their correct place in the tree..
16368 preBuild : function ()
16371 Roo.each(this.modules , function (obj)
16373 Roo.XComponent.event.fireEvent('beforebuild', obj);
16375 var opar = obj.parent;
16377 obj.parent = this.toObject(opar);
16379 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16384 Roo.debug && Roo.log("GOT top level module");
16385 Roo.debug && Roo.log(obj);
16386 obj.modules = new Roo.util.MixedCollection(false,
16387 function(o) { return o.order + '' }
16389 this.topModule = obj;
16392 // parent is a string (usually a dom element name..)
16393 if (typeof(obj.parent) == 'string') {
16394 this.elmodules.push(obj);
16397 if (obj.parent.constructor != Roo.XComponent) {
16398 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16400 if (!obj.parent.modules) {
16401 obj.parent.modules = new Roo.util.MixedCollection(false,
16402 function(o) { return o.order + '' }
16405 if (obj.parent.disabled) {
16406 obj.disabled = true;
16408 obj.parent.modules.add(obj);
16413 * make a list of modules to build.
16414 * @return {Array} list of modules.
16417 buildOrder : function()
16420 var cmp = function(a,b) {
16421 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16423 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16424 throw "No top level modules to build";
16427 // make a flat list in order of modules to build.
16428 var mods = this.topModule ? [ this.topModule ] : [];
16431 // elmodules (is a list of DOM based modules )
16432 Roo.each(this.elmodules, function(e) {
16434 if (!this.topModule &&
16435 typeof(e.parent) == 'string' &&
16436 e.parent.substring(0,1) == '#' &&
16437 Roo.get(e.parent.substr(1))
16440 _this.topModule = e;
16446 // add modules to their parents..
16447 var addMod = function(m) {
16448 Roo.debug && Roo.log("build Order: add: " + m.name);
16451 if (m.modules && !m.disabled) {
16452 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16453 m.modules.keySort('ASC', cmp );
16454 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16456 m.modules.each(addMod);
16458 Roo.debug && Roo.log("build Order: no child modules");
16460 // not sure if this is used any more..
16462 m.finalize.name = m.name + " (clean up) ";
16463 mods.push(m.finalize);
16467 if (this.topModule && this.topModule.modules) {
16468 this.topModule.modules.keySort('ASC', cmp );
16469 this.topModule.modules.each(addMod);
16475 * Build the registered modules.
16476 * @param {Object} parent element.
16477 * @param {Function} optional method to call after module has been added.
16481 build : function(opts)
16484 if (typeof(opts) != 'undefined') {
16485 Roo.apply(this,opts);
16489 var mods = this.buildOrder();
16491 //this.allmods = mods;
16492 //Roo.debug && Roo.log(mods);
16494 if (!mods.length) { // should not happen
16495 throw "NO modules!!!";
16499 var msg = "Building Interface...";
16500 // flash it up as modal - so we store the mask!?
16501 if (!this.hideProgress && Roo.MessageBox) {
16502 Roo.MessageBox.show({ title: 'loading' });
16503 Roo.MessageBox.show({
16504 title: "Please wait...",
16513 var total = mods.length;
16516 var progressRun = function() {
16517 if (!mods.length) {
16518 Roo.debug && Roo.log('hide?');
16519 if (!this.hideProgress && Roo.MessageBox) {
16520 Roo.MessageBox.hide();
16522 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16524 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16530 var m = mods.shift();
16533 Roo.debug && Roo.log(m);
16534 // not sure if this is supported any more.. - modules that are are just function
16535 if (typeof(m) == 'function') {
16537 return progressRun.defer(10, _this);
16541 msg = "Building Interface " + (total - mods.length) +
16543 (m.name ? (' - ' + m.name) : '');
16544 Roo.debug && Roo.log(msg);
16545 if (!_this.hideProgress && Roo.MessageBox) {
16546 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16550 // is the module disabled?
16551 var disabled = (typeof(m.disabled) == 'function') ?
16552 m.disabled.call(m.module.disabled) : m.disabled;
16556 return progressRun(); // we do not update the display!
16564 // it's 10 on top level, and 1 on others??? why...
16565 return progressRun.defer(10, _this);
16568 progressRun.defer(1, _this);
16582 * wrapper for event.on - aliased later..
16583 * Typically use to register a event handler for register:
16585 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16594 Roo.XComponent.event = new Roo.util.Observable({
16598 * Fires when an Component is registered,
16599 * set the disable property on the Component to stop registration.
16600 * @param {Roo.XComponent} c the component being registerd.
16605 * @event beforebuild
16606 * Fires before each Component is built
16607 * can be used to apply permissions.
16608 * @param {Roo.XComponent} c the component being registerd.
16611 'beforebuild' : true,
16613 * @event buildcomplete
16614 * Fires on the top level element when all elements have been built
16615 * @param {Roo.XComponent} the top level component.
16617 'buildcomplete' : true
16622 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16625 * marked - a markdown parser
16626 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16627 * https://github.com/chjj/marked
16633 * Roo.Markdown - is a very crude wrapper around marked..
16637 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16639 * Note: move the sample code to the bottom of this
16640 * file before uncommenting it.
16645 Roo.Markdown.toHtml = function(text) {
16647 var c = new Roo.Markdown.marked.setOptions({
16648 renderer: new Roo.Markdown.marked.Renderer(),
16659 text = text.replace(/\\\n/g,' ');
16660 return Roo.Markdown.marked(text);
16665 // Wraps all "globals" so that the only thing
16666 // exposed is makeHtml().
16671 * Block-Level Grammar
16676 code: /^( {4}[^\n]+\n*)+/,
16678 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16679 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16681 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16682 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16683 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16684 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16685 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16687 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16691 block.bullet = /(?:[*+-]|\d+\.)/;
16692 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16693 block.item = replace(block.item, 'gm')
16694 (/bull/g, block.bullet)
16697 block.list = replace(block.list)
16698 (/bull/g, block.bullet)
16699 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16700 ('def', '\\n+(?=' + block.def.source + ')')
16703 block.blockquote = replace(block.blockquote)
16707 block._tag = '(?!(?:'
16708 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16709 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16710 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16712 block.html = replace(block.html)
16713 ('comment', /<!--[\s\S]*?-->/)
16714 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16715 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16716 (/tag/g, block._tag)
16719 block.paragraph = replace(block.paragraph)
16721 ('heading', block.heading)
16722 ('lheading', block.lheading)
16723 ('blockquote', block.blockquote)
16724 ('tag', '<' + block._tag)
16729 * Normal Block Grammar
16732 block.normal = merge({}, block);
16735 * GFM Block Grammar
16738 block.gfm = merge({}, block.normal, {
16739 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16741 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16744 block.gfm.paragraph = replace(block.paragraph)
16746 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16747 + block.list.source.replace('\\1', '\\3') + '|')
16751 * GFM + Tables Block Grammar
16754 block.tables = merge({}, block.gfm, {
16755 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16756 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16763 function Lexer(options) {
16765 this.tokens.links = {};
16766 this.options = options || marked.defaults;
16767 this.rules = block.normal;
16769 if (this.options.gfm) {
16770 if (this.options.tables) {
16771 this.rules = block.tables;
16773 this.rules = block.gfm;
16779 * Expose Block Rules
16782 Lexer.rules = block;
16785 * Static Lex Method
16788 Lexer.lex = function(src, options) {
16789 var lexer = new Lexer(options);
16790 return lexer.lex(src);
16797 Lexer.prototype.lex = function(src) {
16799 .replace(/\r\n|\r/g, '\n')
16800 .replace(/\t/g, ' ')
16801 .replace(/\u00a0/g, ' ')
16802 .replace(/\u2424/g, '\n');
16804 return this.token(src, true);
16811 Lexer.prototype.token = function(src, top, bq) {
16812 var src = src.replace(/^ +$/gm, '')
16825 if (cap = this.rules.newline.exec(src)) {
16826 src = src.substring(cap[0].length);
16827 if (cap[0].length > 1) {
16835 if (cap = this.rules.code.exec(src)) {
16836 src = src.substring(cap[0].length);
16837 cap = cap[0].replace(/^ {4}/gm, '');
16840 text: !this.options.pedantic
16841 ? cap.replace(/\n+$/, '')
16848 if (cap = this.rules.fences.exec(src)) {
16849 src = src.substring(cap[0].length);
16859 if (cap = this.rules.heading.exec(src)) {
16860 src = src.substring(cap[0].length);
16863 depth: cap[1].length,
16869 // table no leading pipe (gfm)
16870 if (top && (cap = this.rules.nptable.exec(src))) {
16871 src = src.substring(cap[0].length);
16875 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16876 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16877 cells: cap[3].replace(/\n$/, '').split('\n')
16880 for (i = 0; i < item.align.length; i++) {
16881 if (/^ *-+: *$/.test(item.align[i])) {
16882 item.align[i] = 'right';
16883 } else if (/^ *:-+: *$/.test(item.align[i])) {
16884 item.align[i] = 'center';
16885 } else if (/^ *:-+ *$/.test(item.align[i])) {
16886 item.align[i] = 'left';
16888 item.align[i] = null;
16892 for (i = 0; i < item.cells.length; i++) {
16893 item.cells[i] = item.cells[i].split(/ *\| */);
16896 this.tokens.push(item);
16902 if (cap = this.rules.lheading.exec(src)) {
16903 src = src.substring(cap[0].length);
16906 depth: cap[2] === '=' ? 1 : 2,
16913 if (cap = this.rules.hr.exec(src)) {
16914 src = src.substring(cap[0].length);
16922 if (cap = this.rules.blockquote.exec(src)) {
16923 src = src.substring(cap[0].length);
16926 type: 'blockquote_start'
16929 cap = cap[0].replace(/^ *> ?/gm, '');
16931 // Pass `top` to keep the current
16932 // "toplevel" state. This is exactly
16933 // how markdown.pl works.
16934 this.token(cap, top, true);
16937 type: 'blockquote_end'
16944 if (cap = this.rules.list.exec(src)) {
16945 src = src.substring(cap[0].length);
16949 type: 'list_start',
16950 ordered: bull.length > 1
16953 // Get each top-level item.
16954 cap = cap[0].match(this.rules.item);
16960 for (; i < l; i++) {
16963 // Remove the list item's bullet
16964 // so it is seen as the next token.
16965 space = item.length;
16966 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16968 // Outdent whatever the
16969 // list item contains. Hacky.
16970 if (~item.indexOf('\n ')) {
16971 space -= item.length;
16972 item = !this.options.pedantic
16973 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16974 : item.replace(/^ {1,4}/gm, '');
16977 // Determine whether the next list item belongs here.
16978 // Backpedal if it does not belong in this list.
16979 if (this.options.smartLists && i !== l - 1) {
16980 b = block.bullet.exec(cap[i + 1])[0];
16981 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16982 src = cap.slice(i + 1).join('\n') + src;
16987 // Determine whether item is loose or not.
16988 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16989 // for discount behavior.
16990 loose = next || /\n\n(?!\s*$)/.test(item);
16992 next = item.charAt(item.length - 1) === '\n';
16993 if (!loose) { loose = next; }
16998 ? 'loose_item_start'
16999 : 'list_item_start'
17003 this.token(item, false, bq);
17006 type: 'list_item_end'
17018 if (cap = this.rules.html.exec(src)) {
17019 src = src.substring(cap[0].length);
17021 type: this.options.sanitize
17024 pre: !this.options.sanitizer
17025 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17032 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17033 src = src.substring(cap[0].length);
17034 this.tokens.links[cap[1].toLowerCase()] = {
17042 if (top && (cap = this.rules.table.exec(src))) {
17043 src = src.substring(cap[0].length);
17047 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17048 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17049 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17052 for (i = 0; i < item.align.length; i++) {
17053 if (/^ *-+: *$/.test(item.align[i])) {
17054 item.align[i] = 'right';
17055 } else if (/^ *:-+: *$/.test(item.align[i])) {
17056 item.align[i] = 'center';
17057 } else if (/^ *:-+ *$/.test(item.align[i])) {
17058 item.align[i] = 'left';
17060 item.align[i] = null;
17064 for (i = 0; i < item.cells.length; i++) {
17065 item.cells[i] = item.cells[i]
17066 .replace(/^ *\| *| *\| *$/g, '')
17070 this.tokens.push(item);
17075 // top-level paragraph
17076 if (top && (cap = this.rules.paragraph.exec(src))) {
17077 src = src.substring(cap[0].length);
17080 text: cap[1].charAt(cap[1].length - 1) === '\n'
17081 ? cap[1].slice(0, -1)
17088 if (cap = this.rules.text.exec(src)) {
17089 // Top-level should never reach here.
17090 src = src.substring(cap[0].length);
17100 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17104 return this.tokens;
17108 * Inline-Level Grammar
17112 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17113 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17115 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17116 link: /^!?\[(inside)\]\(href\)/,
17117 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17118 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17119 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17120 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17121 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17122 br: /^ {2,}\n(?!\s*$)/,
17124 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17127 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17128 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17130 inline.link = replace(inline.link)
17131 ('inside', inline._inside)
17132 ('href', inline._href)
17135 inline.reflink = replace(inline.reflink)
17136 ('inside', inline._inside)
17140 * Normal Inline Grammar
17143 inline.normal = merge({}, inline);
17146 * Pedantic Inline Grammar
17149 inline.pedantic = merge({}, inline.normal, {
17150 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17151 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17155 * GFM Inline Grammar
17158 inline.gfm = merge({}, inline.normal, {
17159 escape: replace(inline.escape)('])', '~|])')(),
17160 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17161 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17162 text: replace(inline.text)
17164 ('|', '|https?://|')
17169 * GFM + Line Breaks Inline Grammar
17172 inline.breaks = merge({}, inline.gfm, {
17173 br: replace(inline.br)('{2,}', '*')(),
17174 text: replace(inline.gfm.text)('{2,}', '*')()
17178 * Inline Lexer & Compiler
17181 function InlineLexer(links, options) {
17182 this.options = options || marked.defaults;
17183 this.links = links;
17184 this.rules = inline.normal;
17185 this.renderer = this.options.renderer || new Renderer;
17186 this.renderer.options = this.options;
17190 Error('Tokens array requires a `links` property.');
17193 if (this.options.gfm) {
17194 if (this.options.breaks) {
17195 this.rules = inline.breaks;
17197 this.rules = inline.gfm;
17199 } else if (this.options.pedantic) {
17200 this.rules = inline.pedantic;
17205 * Expose Inline Rules
17208 InlineLexer.rules = inline;
17211 * Static Lexing/Compiling Method
17214 InlineLexer.output = function(src, links, options) {
17215 var inline = new InlineLexer(links, options);
17216 return inline.output(src);
17223 InlineLexer.prototype.output = function(src) {
17232 if (cap = this.rules.escape.exec(src)) {
17233 src = src.substring(cap[0].length);
17239 if (cap = this.rules.autolink.exec(src)) {
17240 src = src.substring(cap[0].length);
17241 if (cap[2] === '@') {
17242 text = cap[1].charAt(6) === ':'
17243 ? this.mangle(cap[1].substring(7))
17244 : this.mangle(cap[1]);
17245 href = this.mangle('mailto:') + text;
17247 text = escape(cap[1]);
17250 out += this.renderer.link(href, null, text);
17255 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17256 src = src.substring(cap[0].length);
17257 text = escape(cap[1]);
17259 out += this.renderer.link(href, null, text);
17264 if (cap = this.rules.tag.exec(src)) {
17265 if (!this.inLink && /^<a /i.test(cap[0])) {
17266 this.inLink = true;
17267 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17268 this.inLink = false;
17270 src = src.substring(cap[0].length);
17271 out += this.options.sanitize
17272 ? this.options.sanitizer
17273 ? this.options.sanitizer(cap[0])
17280 if (cap = this.rules.link.exec(src)) {
17281 src = src.substring(cap[0].length);
17282 this.inLink = true;
17283 out += this.outputLink(cap, {
17287 this.inLink = false;
17292 if ((cap = this.rules.reflink.exec(src))
17293 || (cap = this.rules.nolink.exec(src))) {
17294 src = src.substring(cap[0].length);
17295 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17296 link = this.links[link.toLowerCase()];
17297 if (!link || !link.href) {
17298 out += cap[0].charAt(0);
17299 src = cap[0].substring(1) + src;
17302 this.inLink = true;
17303 out += this.outputLink(cap, link);
17304 this.inLink = false;
17309 if (cap = this.rules.strong.exec(src)) {
17310 src = src.substring(cap[0].length);
17311 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17316 if (cap = this.rules.em.exec(src)) {
17317 src = src.substring(cap[0].length);
17318 out += this.renderer.em(this.output(cap[2] || cap[1]));
17323 if (cap = this.rules.code.exec(src)) {
17324 src = src.substring(cap[0].length);
17325 out += this.renderer.codespan(escape(cap[2], true));
17330 if (cap = this.rules.br.exec(src)) {
17331 src = src.substring(cap[0].length);
17332 out += this.renderer.br();
17337 if (cap = this.rules.del.exec(src)) {
17338 src = src.substring(cap[0].length);
17339 out += this.renderer.del(this.output(cap[1]));
17344 if (cap = this.rules.text.exec(src)) {
17345 src = src.substring(cap[0].length);
17346 out += this.renderer.text(escape(this.smartypants(cap[0])));
17352 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17363 InlineLexer.prototype.outputLink = function(cap, link) {
17364 var href = escape(link.href)
17365 , title = link.title ? escape(link.title) : null;
17367 return cap[0].charAt(0) !== '!'
17368 ? this.renderer.link(href, title, this.output(cap[1]))
17369 : this.renderer.image(href, title, escape(cap[1]));
17373 * Smartypants Transformations
17376 InlineLexer.prototype.smartypants = function(text) {
17377 if (!this.options.smartypants) { return text; }
17380 .replace(/---/g, '\u2014')
17382 .replace(/--/g, '\u2013')
17384 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17385 // closing singles & apostrophes
17386 .replace(/'/g, '\u2019')
17388 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17390 .replace(/"/g, '\u201d')
17392 .replace(/\.{3}/g, '\u2026');
17399 InlineLexer.prototype.mangle = function(text) {
17400 if (!this.options.mangle) { return text; }
17406 for (; i < l; i++) {
17407 ch = text.charCodeAt(i);
17408 if (Math.random() > 0.5) {
17409 ch = 'x' + ch.toString(16);
17411 out += '&#' + ch + ';';
17421 function Renderer(options) {
17422 this.options = options || {};
17425 Renderer.prototype.code = function(code, lang, escaped) {
17426 if (this.options.highlight) {
17427 var out = this.options.highlight(code, lang);
17428 if (out != null && out !== code) {
17433 // hack!!! - it's already escapeD?
17438 return '<pre><code>'
17439 + (escaped ? code : escape(code, true))
17440 + '\n</code></pre>';
17443 return '<pre><code class="'
17444 + this.options.langPrefix
17445 + escape(lang, true)
17447 + (escaped ? code : escape(code, true))
17448 + '\n</code></pre>\n';
17451 Renderer.prototype.blockquote = function(quote) {
17452 return '<blockquote>\n' + quote + '</blockquote>\n';
17455 Renderer.prototype.html = function(html) {
17459 Renderer.prototype.heading = function(text, level, raw) {
17463 + this.options.headerPrefix
17464 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17472 Renderer.prototype.hr = function() {
17473 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17476 Renderer.prototype.list = function(body, ordered) {
17477 var type = ordered ? 'ol' : 'ul';
17478 return '<' + type + '>\n' + body + '</' + type + '>\n';
17481 Renderer.prototype.listitem = function(text) {
17482 return '<li>' + text + '</li>\n';
17485 Renderer.prototype.paragraph = function(text) {
17486 return '<p>' + text + '</p>\n';
17489 Renderer.prototype.table = function(header, body) {
17490 return '<table class="table table-striped">\n'
17500 Renderer.prototype.tablerow = function(content) {
17501 return '<tr>\n' + content + '</tr>\n';
17504 Renderer.prototype.tablecell = function(content, flags) {
17505 var type = flags.header ? 'th' : 'td';
17506 var tag = flags.align
17507 ? '<' + type + ' style="text-align:' + flags.align + '">'
17508 : '<' + type + '>';
17509 return tag + content + '</' + type + '>\n';
17512 // span level renderer
17513 Renderer.prototype.strong = function(text) {
17514 return '<strong>' + text + '</strong>';
17517 Renderer.prototype.em = function(text) {
17518 return '<em>' + text + '</em>';
17521 Renderer.prototype.codespan = function(text) {
17522 return '<code>' + text + '</code>';
17525 Renderer.prototype.br = function() {
17526 return this.options.xhtml ? '<br/>' : '<br>';
17529 Renderer.prototype.del = function(text) {
17530 return '<del>' + text + '</del>';
17533 Renderer.prototype.link = function(href, title, text) {
17534 if (this.options.sanitize) {
17536 var prot = decodeURIComponent(unescape(href))
17537 .replace(/[^\w:]/g, '')
17542 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17546 var out = '<a href="' + href + '"';
17548 out += ' title="' + title + '"';
17550 out += '>' + text + '</a>';
17554 Renderer.prototype.image = function(href, title, text) {
17555 var out = '<img src="' + href + '" alt="' + text + '"';
17557 out += ' title="' + title + '"';
17559 out += this.options.xhtml ? '/>' : '>';
17563 Renderer.prototype.text = function(text) {
17568 * Parsing & Compiling
17571 function Parser(options) {
17574 this.options = options || marked.defaults;
17575 this.options.renderer = this.options.renderer || new Renderer;
17576 this.renderer = this.options.renderer;
17577 this.renderer.options = this.options;
17581 * Static Parse Method
17584 Parser.parse = function(src, options, renderer) {
17585 var parser = new Parser(options, renderer);
17586 return parser.parse(src);
17593 Parser.prototype.parse = function(src) {
17594 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17595 this.tokens = src.reverse();
17598 while (this.next()) {
17609 Parser.prototype.next = function() {
17610 return this.token = this.tokens.pop();
17614 * Preview Next Token
17617 Parser.prototype.peek = function() {
17618 return this.tokens[this.tokens.length - 1] || 0;
17622 * Parse Text Tokens
17625 Parser.prototype.parseText = function() {
17626 var body = this.token.text;
17628 while (this.peek().type === 'text') {
17629 body += '\n' + this.next().text;
17632 return this.inline.output(body);
17636 * Parse Current Token
17639 Parser.prototype.tok = function() {
17640 switch (this.token.type) {
17645 return this.renderer.hr();
17648 return this.renderer.heading(
17649 this.inline.output(this.token.text),
17654 return this.renderer.code(this.token.text,
17656 this.token.escaped);
17669 for (i = 0; i < this.token.header.length; i++) {
17670 flags = { header: true, align: this.token.align[i] };
17671 cell += this.renderer.tablecell(
17672 this.inline.output(this.token.header[i]),
17673 { header: true, align: this.token.align[i] }
17676 header += this.renderer.tablerow(cell);
17678 for (i = 0; i < this.token.cells.length; i++) {
17679 row = this.token.cells[i];
17682 for (j = 0; j < row.length; j++) {
17683 cell += this.renderer.tablecell(
17684 this.inline.output(row[j]),
17685 { header: false, align: this.token.align[j] }
17689 body += this.renderer.tablerow(cell);
17691 return this.renderer.table(header, body);
17693 case 'blockquote_start': {
17696 while (this.next().type !== 'blockquote_end') {
17697 body += this.tok();
17700 return this.renderer.blockquote(body);
17702 case 'list_start': {
17704 , ordered = this.token.ordered;
17706 while (this.next().type !== 'list_end') {
17707 body += this.tok();
17710 return this.renderer.list(body, ordered);
17712 case 'list_item_start': {
17715 while (this.next().type !== 'list_item_end') {
17716 body += this.token.type === 'text'
17721 return this.renderer.listitem(body);
17723 case 'loose_item_start': {
17726 while (this.next().type !== 'list_item_end') {
17727 body += this.tok();
17730 return this.renderer.listitem(body);
17733 var html = !this.token.pre && !this.options.pedantic
17734 ? this.inline.output(this.token.text)
17736 return this.renderer.html(html);
17738 case 'paragraph': {
17739 return this.renderer.paragraph(this.inline.output(this.token.text));
17742 return this.renderer.paragraph(this.parseText());
17751 function escape(html, encode) {
17753 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17754 .replace(/</g, '<')
17755 .replace(/>/g, '>')
17756 .replace(/"/g, '"')
17757 .replace(/'/g, ''');
17760 function unescape(html) {
17761 // explicitly match decimal, hex, and named HTML entities
17762 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17763 n = n.toLowerCase();
17764 if (n === 'colon') { return ':'; }
17765 if (n.charAt(0) === '#') {
17766 return n.charAt(1) === 'x'
17767 ? String.fromCharCode(parseInt(n.substring(2), 16))
17768 : String.fromCharCode(+n.substring(1));
17774 function replace(regex, opt) {
17775 regex = regex.source;
17777 return function self(name, val) {
17778 if (!name) { return new RegExp(regex, opt); }
17779 val = val.source || val;
17780 val = val.replace(/(^|[^\[])\^/g, '$1');
17781 regex = regex.replace(name, val);
17789 function merge(obj) {
17794 for (; i < arguments.length; i++) {
17795 target = arguments[i];
17796 for (key in target) {
17797 if (Object.prototype.hasOwnProperty.call(target, key)) {
17798 obj[key] = target[key];
17811 function marked(src, opt, callback) {
17812 if (callback || typeof opt === 'function') {
17818 opt = merge({}, marked.defaults, opt || {});
17820 var highlight = opt.highlight
17826 tokens = Lexer.lex(src, opt)
17828 return callback(e);
17831 pending = tokens.length;
17833 var done = function(err) {
17835 opt.highlight = highlight;
17836 return callback(err);
17842 out = Parser.parse(tokens, opt);
17847 opt.highlight = highlight;
17851 : callback(null, out);
17854 if (!highlight || highlight.length < 3) {
17858 delete opt.highlight;
17860 if (!pending) { return done(); }
17862 for (; i < tokens.length; i++) {
17864 if (token.type !== 'code') {
17865 return --pending || done();
17867 return highlight(token.text, token.lang, function(err, code) {
17868 if (err) { return done(err); }
17869 if (code == null || code === token.text) {
17870 return --pending || done();
17873 token.escaped = true;
17874 --pending || done();
17882 if (opt) { opt = merge({}, marked.defaults, opt); }
17883 return Parser.parse(Lexer.lex(src, opt), opt);
17885 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17886 if ((opt || marked.defaults).silent) {
17887 return '<p>An error occured:</p><pre>'
17888 + escape(e.message + '', true)
17900 marked.setOptions = function(opt) {
17901 merge(marked.defaults, opt);
17905 marked.defaults = {
17916 langPrefix: 'lang-',
17917 smartypants: false,
17919 renderer: new Renderer,
17927 marked.Parser = Parser;
17928 marked.parser = Parser.parse;
17930 marked.Renderer = Renderer;
17932 marked.Lexer = Lexer;
17933 marked.lexer = Lexer.lex;
17935 marked.InlineLexer = InlineLexer;
17936 marked.inlineLexer = InlineLexer.output;
17938 marked.parse = marked;
17940 Roo.Markdown.marked = marked;
17944 * Ext JS Library 1.1.1
17945 * Copyright(c) 2006-2007, Ext JS, LLC.
17947 * Originally Released Under LGPL - original licence link has changed is not relivant.
17950 * <script type="text/javascript">
17956 * These classes are derivatives of the similarly named classes in the YUI Library.
17957 * The original license:
17958 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17959 * Code licensed under the BSD License:
17960 * http://developer.yahoo.net/yui/license.txt
17965 var Event=Roo.EventManager;
17966 var Dom=Roo.lib.Dom;
17969 * @class Roo.dd.DragDrop
17970 * @extends Roo.util.Observable
17971 * Defines the interface and base operation of items that that can be
17972 * dragged or can be drop targets. It was designed to be extended, overriding
17973 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17974 * Up to three html elements can be associated with a DragDrop instance:
17976 * <li>linked element: the element that is passed into the constructor.
17977 * This is the element which defines the boundaries for interaction with
17978 * other DragDrop objects.</li>
17979 * <li>handle element(s): The drag operation only occurs if the element that
17980 * was clicked matches a handle element. By default this is the linked
17981 * element, but there are times that you will want only a portion of the
17982 * linked element to initiate the drag operation, and the setHandleElId()
17983 * method provides a way to define this.</li>
17984 * <li>drag element: this represents the element that would be moved along
17985 * with the cursor during a drag operation. By default, this is the linked
17986 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
17987 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17990 * This class should not be instantiated until the onload event to ensure that
17991 * the associated elements are available.
17992 * The following would define a DragDrop obj that would interact with any
17993 * other DragDrop obj in the "group1" group:
17995 * dd = new Roo.dd.DragDrop("div1", "group1");
17997 * Since none of the event handlers have been implemented, nothing would
17998 * actually happen if you were to run the code above. Normally you would
17999 * override this class or one of the default implementations, but you can
18000 * also override the methods you want on an instance of the class...
18002 * dd.onDragDrop = function(e, id) {
18003 * alert("dd was dropped on " + id);
18007 * @param {String} id of the element that is linked to this instance
18008 * @param {String} sGroup the group of related DragDrop objects
18009 * @param {object} config an object containing configurable attributes
18010 * Valid properties for DragDrop:
18011 * padding, isTarget, maintainOffset, primaryButtonOnly
18013 Roo.dd.DragDrop = function(id, sGroup, config) {
18015 this.init(id, sGroup, config);
18020 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18023 * The id of the element associated with this object. This is what we
18024 * refer to as the "linked element" because the size and position of
18025 * this element is used to determine when the drag and drop objects have
18033 * Configuration attributes passed into the constructor
18040 * The id of the element that will be dragged. By default this is same
18041 * as the linked element , but could be changed to another element. Ex:
18043 * @property dragElId
18050 * the id of the element that initiates the drag operation. By default
18051 * this is the linked element, but could be changed to be a child of this
18052 * element. This lets us do things like only starting the drag when the
18053 * header element within the linked html element is clicked.
18054 * @property handleElId
18061 * An associative array of HTML tags that will be ignored if clicked.
18062 * @property invalidHandleTypes
18063 * @type {string: string}
18065 invalidHandleTypes: null,
18068 * An associative array of ids for elements that will be ignored if clicked
18069 * @property invalidHandleIds
18070 * @type {string: string}
18072 invalidHandleIds: null,
18075 * An indexted array of css class names for elements that will be ignored
18077 * @property invalidHandleClasses
18080 invalidHandleClasses: null,
18083 * The linked element's absolute X position at the time the drag was
18085 * @property startPageX
18092 * The linked element's absolute X position at the time the drag was
18094 * @property startPageY
18101 * The group defines a logical collection of DragDrop objects that are
18102 * related. Instances only get events when interacting with other
18103 * DragDrop object in the same group. This lets us define multiple
18104 * groups using a single DragDrop subclass if we want.
18106 * @type {string: string}
18111 * Individual drag/drop instances can be locked. This will prevent
18112 * onmousedown start drag.
18120 * Lock this instance
18123 lock: function() { this.locked = true; },
18126 * Unlock this instace
18129 unlock: function() { this.locked = false; },
18132 * By default, all insances can be a drop target. This can be disabled by
18133 * setting isTarget to false.
18140 * The padding configured for this drag and drop object for calculating
18141 * the drop zone intersection with this object.
18148 * Cached reference to the linked element
18149 * @property _domRef
18155 * Internal typeof flag
18156 * @property __ygDragDrop
18159 __ygDragDrop: true,
18162 * Set to true when horizontal contraints are applied
18163 * @property constrainX
18170 * Set to true when vertical contraints are applied
18171 * @property constrainY
18178 * The left constraint
18186 * The right constraint
18194 * The up constraint
18203 * The down constraint
18211 * Maintain offsets when we resetconstraints. Set to true when you want
18212 * the position of the element relative to its parent to stay the same
18213 * when the page changes
18215 * @property maintainOffset
18218 maintainOffset: false,
18221 * Array of pixel locations the element will snap to if we specified a
18222 * horizontal graduation/interval. This array is generated automatically
18223 * when you define a tick interval.
18230 * Array of pixel locations the element will snap to if we specified a
18231 * vertical graduation/interval. This array is generated automatically
18232 * when you define a tick interval.
18239 * By default the drag and drop instance will only respond to the primary
18240 * button click (left button for a right-handed mouse). Set to true to
18241 * allow drag and drop to start with any mouse click that is propogated
18243 * @property primaryButtonOnly
18246 primaryButtonOnly: true,
18249 * The availabe property is false until the linked dom element is accessible.
18250 * @property available
18256 * By default, drags can only be initiated if the mousedown occurs in the
18257 * region the linked element is. This is done in part to work around a
18258 * bug in some browsers that mis-report the mousedown if the previous
18259 * mouseup happened outside of the window. This property is set to true
18260 * if outer handles are defined.
18262 * @property hasOuterHandles
18266 hasOuterHandles: false,
18269 * Code that executes immediately before the startDrag event
18270 * @method b4StartDrag
18273 b4StartDrag: function(x, y) { },
18276 * Abstract method called after a drag/drop object is clicked
18277 * and the drag or mousedown time thresholds have beeen met.
18278 * @method startDrag
18279 * @param {int} X click location
18280 * @param {int} Y click location
18282 startDrag: function(x, y) { /* override this */ },
18285 * Code that executes immediately before the onDrag event
18289 b4Drag: function(e) { },
18292 * Abstract method called during the onMouseMove event while dragging an
18295 * @param {Event} e the mousemove event
18297 onDrag: function(e) { /* override this */ },
18300 * Abstract method called when this element fist begins hovering over
18301 * another DragDrop obj
18302 * @method onDragEnter
18303 * @param {Event} e the mousemove event
18304 * @param {String|DragDrop[]} id In POINT mode, the element
18305 * id this is hovering over. In INTERSECT mode, an array of one or more
18306 * dragdrop items being hovered over.
18308 onDragEnter: function(e, id) { /* override this */ },
18311 * Code that executes immediately before the onDragOver event
18312 * @method b4DragOver
18315 b4DragOver: function(e) { },
18318 * Abstract method called when this element is hovering over another
18320 * @method onDragOver
18321 * @param {Event} e the mousemove event
18322 * @param {String|DragDrop[]} id In POINT mode, the element
18323 * id this is hovering over. In INTERSECT mode, an array of dd items
18324 * being hovered over.
18326 onDragOver: function(e, id) { /* override this */ },
18329 * Code that executes immediately before the onDragOut event
18330 * @method b4DragOut
18333 b4DragOut: function(e) { },
18336 * Abstract method called when we are no longer hovering over an element
18337 * @method onDragOut
18338 * @param {Event} e the mousemove event
18339 * @param {String|DragDrop[]} id In POINT mode, the element
18340 * id this was hovering over. In INTERSECT mode, an array of dd items
18341 * that the mouse is no longer over.
18343 onDragOut: function(e, id) { /* override this */ },
18346 * Code that executes immediately before the onDragDrop event
18347 * @method b4DragDrop
18350 b4DragDrop: function(e) { },
18353 * Abstract method called when this item is dropped on another DragDrop
18355 * @method onDragDrop
18356 * @param {Event} e the mouseup event
18357 * @param {String|DragDrop[]} id In POINT mode, the element
18358 * id this was dropped on. In INTERSECT mode, an array of dd items this
18361 onDragDrop: function(e, id) { /* override this */ },
18364 * Abstract method called when this item is dropped on an area with no
18366 * @method onInvalidDrop
18367 * @param {Event} e the mouseup event
18369 onInvalidDrop: function(e) { /* override this */ },
18372 * Code that executes immediately before the endDrag event
18373 * @method b4EndDrag
18376 b4EndDrag: function(e) { },
18379 * Fired when we are done dragging the object
18381 * @param {Event} e the mouseup event
18383 endDrag: function(e) { /* override this */ },
18386 * Code executed immediately before the onMouseDown event
18387 * @method b4MouseDown
18388 * @param {Event} e the mousedown event
18391 b4MouseDown: function(e) { },
18394 * Event handler that fires when a drag/drop obj gets a mousedown
18395 * @method onMouseDown
18396 * @param {Event} e the mousedown event
18398 onMouseDown: function(e) { /* override this */ },
18401 * Event handler that fires when a drag/drop obj gets a mouseup
18402 * @method onMouseUp
18403 * @param {Event} e the mouseup event
18405 onMouseUp: function(e) { /* override this */ },
18408 * Override the onAvailable method to do what is needed after the initial
18409 * position was determined.
18410 * @method onAvailable
18412 onAvailable: function () {
18416 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18419 defaultPadding : {left:0, right:0, top:0, bottom:0},
18422 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18426 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18427 { dragElId: "existingProxyDiv" });
18428 dd.startDrag = function(){
18429 this.constrainTo("parent-id");
18432 * Or you can initalize it using the {@link Roo.Element} object:
18434 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18435 startDrag : function(){
18436 this.constrainTo("parent-id");
18440 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18441 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18442 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18443 * an object containing the sides to pad. For example: {right:10, bottom:10}
18444 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18446 constrainTo : function(constrainTo, pad, inContent){
18447 if(typeof pad == "number"){
18448 pad = {left: pad, right:pad, top:pad, bottom:pad};
18450 pad = pad || this.defaultPadding;
18451 var b = Roo.get(this.getEl()).getBox();
18452 var ce = Roo.get(constrainTo);
18453 var s = ce.getScroll();
18454 var c, cd = ce.dom;
18455 if(cd == document.body){
18456 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18459 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18463 var topSpace = b.y - c.y;
18464 var leftSpace = b.x - c.x;
18466 this.resetConstraints();
18467 this.setXConstraint(leftSpace - (pad.left||0), // left
18468 c.width - leftSpace - b.width - (pad.right||0) //right
18470 this.setYConstraint(topSpace - (pad.top||0), //top
18471 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18476 * Returns a reference to the linked element
18478 * @return {HTMLElement} the html element
18480 getEl: function() {
18481 if (!this._domRef) {
18482 this._domRef = Roo.getDom(this.id);
18485 return this._domRef;
18489 * Returns a reference to the actual element to drag. By default this is
18490 * the same as the html element, but it can be assigned to another
18491 * element. An example of this can be found in Roo.dd.DDProxy
18492 * @method getDragEl
18493 * @return {HTMLElement} the html element
18495 getDragEl: function() {
18496 return Roo.getDom(this.dragElId);
18500 * Sets up the DragDrop object. Must be called in the constructor of any
18501 * Roo.dd.DragDrop subclass
18503 * @param id the id of the linked element
18504 * @param {String} sGroup the group of related items
18505 * @param {object} config configuration attributes
18507 init: function(id, sGroup, config) {
18508 this.initTarget(id, sGroup, config);
18509 if (!Roo.isTouch) {
18510 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18512 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18513 // Event.on(this.id, "selectstart", Event.preventDefault);
18517 * Initializes Targeting functionality only... the object does not
18518 * get a mousedown handler.
18519 * @method initTarget
18520 * @param id the id of the linked element
18521 * @param {String} sGroup the group of related items
18522 * @param {object} config configuration attributes
18524 initTarget: function(id, sGroup, config) {
18526 // configuration attributes
18527 this.config = config || {};
18529 // create a local reference to the drag and drop manager
18530 this.DDM = Roo.dd.DDM;
18531 // initialize the groups array
18534 // assume that we have an element reference instead of an id if the
18535 // parameter is not a string
18536 if (typeof id !== "string") {
18543 // add to an interaction group
18544 this.addToGroup((sGroup) ? sGroup : "default");
18546 // We don't want to register this as the handle with the manager
18547 // so we just set the id rather than calling the setter.
18548 this.handleElId = id;
18550 // the linked element is the element that gets dragged by default
18551 this.setDragElId(id);
18553 // by default, clicked anchors will not start drag operations.
18554 this.invalidHandleTypes = { A: "A" };
18555 this.invalidHandleIds = {};
18556 this.invalidHandleClasses = [];
18558 this.applyConfig();
18560 this.handleOnAvailable();
18564 * Applies the configuration parameters that were passed into the constructor.
18565 * This is supposed to happen at each level through the inheritance chain. So
18566 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18567 * DragDrop in order to get all of the parameters that are available in
18569 * @method applyConfig
18571 applyConfig: function() {
18573 // configurable properties:
18574 // padding, isTarget, maintainOffset, primaryButtonOnly
18575 this.padding = this.config.padding || [0, 0, 0, 0];
18576 this.isTarget = (this.config.isTarget !== false);
18577 this.maintainOffset = (this.config.maintainOffset);
18578 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18583 * Executed when the linked element is available
18584 * @method handleOnAvailable
18587 handleOnAvailable: function() {
18588 this.available = true;
18589 this.resetConstraints();
18590 this.onAvailable();
18594 * Configures the padding for the target zone in px. Effectively expands
18595 * (or reduces) the virtual object size for targeting calculations.
18596 * Supports css-style shorthand; if only one parameter is passed, all sides
18597 * will have that padding, and if only two are passed, the top and bottom
18598 * will have the first param, the left and right the second.
18599 * @method setPadding
18600 * @param {int} iTop Top pad
18601 * @param {int} iRight Right pad
18602 * @param {int} iBot Bot pad
18603 * @param {int} iLeft Left pad
18605 setPadding: function(iTop, iRight, iBot, iLeft) {
18606 // this.padding = [iLeft, iRight, iTop, iBot];
18607 if (!iRight && 0 !== iRight) {
18608 this.padding = [iTop, iTop, iTop, iTop];
18609 } else if (!iBot && 0 !== iBot) {
18610 this.padding = [iTop, iRight, iTop, iRight];
18612 this.padding = [iTop, iRight, iBot, iLeft];
18617 * Stores the initial placement of the linked element.
18618 * @method setInitialPosition
18619 * @param {int} diffX the X offset, default 0
18620 * @param {int} diffY the Y offset, default 0
18622 setInitPosition: function(diffX, diffY) {
18623 var el = this.getEl();
18625 if (!this.DDM.verifyEl(el)) {
18629 var dx = diffX || 0;
18630 var dy = diffY || 0;
18632 var p = Dom.getXY( el );
18634 this.initPageX = p[0] - dx;
18635 this.initPageY = p[1] - dy;
18637 this.lastPageX = p[0];
18638 this.lastPageY = p[1];
18641 this.setStartPosition(p);
18645 * Sets the start position of the element. This is set when the obj
18646 * is initialized, the reset when a drag is started.
18647 * @method setStartPosition
18648 * @param pos current position (from previous lookup)
18651 setStartPosition: function(pos) {
18652 var p = pos || Dom.getXY( this.getEl() );
18653 this.deltaSetXY = null;
18655 this.startPageX = p[0];
18656 this.startPageY = p[1];
18660 * Add this instance to a group of related drag/drop objects. All
18661 * instances belong to at least one group, and can belong to as many
18662 * groups as needed.
18663 * @method addToGroup
18664 * @param sGroup {string} the name of the group
18666 addToGroup: function(sGroup) {
18667 this.groups[sGroup] = true;
18668 this.DDM.regDragDrop(this, sGroup);
18672 * Remove's this instance from the supplied interaction group
18673 * @method removeFromGroup
18674 * @param {string} sGroup The group to drop
18676 removeFromGroup: function(sGroup) {
18677 if (this.groups[sGroup]) {
18678 delete this.groups[sGroup];
18681 this.DDM.removeDDFromGroup(this, sGroup);
18685 * Allows you to specify that an element other than the linked element
18686 * will be moved with the cursor during a drag
18687 * @method setDragElId
18688 * @param id {string} the id of the element that will be used to initiate the drag
18690 setDragElId: function(id) {
18691 this.dragElId = id;
18695 * Allows you to specify a child of the linked element that should be
18696 * used to initiate the drag operation. An example of this would be if
18697 * you have a content div with text and links. Clicking anywhere in the
18698 * content area would normally start the drag operation. Use this method
18699 * to specify that an element inside of the content div is the element
18700 * that starts the drag operation.
18701 * @method setHandleElId
18702 * @param id {string} the id of the element that will be used to
18703 * initiate the drag.
18705 setHandleElId: function(id) {
18706 if (typeof id !== "string") {
18709 this.handleElId = id;
18710 this.DDM.regHandle(this.id, id);
18714 * Allows you to set an element outside of the linked element as a drag
18716 * @method setOuterHandleElId
18717 * @param id the id of the element that will be used to initiate the drag
18719 setOuterHandleElId: function(id) {
18720 if (typeof id !== "string") {
18723 Event.on(id, "mousedown",
18724 this.handleMouseDown, this);
18725 this.setHandleElId(id);
18727 this.hasOuterHandles = true;
18731 * Remove all drag and drop hooks for this element
18734 unreg: function() {
18735 Event.un(this.id, "mousedown",
18736 this.handleMouseDown);
18737 Event.un(this.id, "touchstart",
18738 this.handleMouseDown);
18739 this._domRef = null;
18740 this.DDM._remove(this);
18743 destroy : function(){
18748 * Returns true if this instance is locked, or the drag drop mgr is locked
18749 * (meaning that all drag/drop is disabled on the page.)
18751 * @return {boolean} true if this obj or all drag/drop is locked, else
18754 isLocked: function() {
18755 return (this.DDM.isLocked() || this.locked);
18759 * Fired when this object is clicked
18760 * @method handleMouseDown
18762 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18765 handleMouseDown: function(e, oDD){
18767 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18768 //Roo.log('not touch/ button !=0');
18771 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18772 return; // double touch..
18776 if (this.isLocked()) {
18777 //Roo.log('locked');
18781 this.DDM.refreshCache(this.groups);
18782 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18783 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18784 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18785 //Roo.log('no outer handes or not over target');
18788 // Roo.log('check validator');
18789 if (this.clickValidator(e)) {
18790 // Roo.log('validate success');
18791 // set the initial element position
18792 this.setStartPosition();
18795 this.b4MouseDown(e);
18796 this.onMouseDown(e);
18798 this.DDM.handleMouseDown(e, this);
18800 this.DDM.stopEvent(e);
18808 clickValidator: function(e) {
18809 var target = e.getTarget();
18810 return ( this.isValidHandleChild(target) &&
18811 (this.id == this.handleElId ||
18812 this.DDM.handleWasClicked(target, this.id)) );
18816 * Allows you to specify a tag name that should not start a drag operation
18817 * when clicked. This is designed to facilitate embedding links within a
18818 * drag handle that do something other than start the drag.
18819 * @method addInvalidHandleType
18820 * @param {string} tagName the type of element to exclude
18822 addInvalidHandleType: function(tagName) {
18823 var type = tagName.toUpperCase();
18824 this.invalidHandleTypes[type] = type;
18828 * Lets you to specify an element id for a child of a drag handle
18829 * that should not initiate a drag
18830 * @method addInvalidHandleId
18831 * @param {string} id the element id of the element you wish to ignore
18833 addInvalidHandleId: function(id) {
18834 if (typeof id !== "string") {
18837 this.invalidHandleIds[id] = id;
18841 * Lets you specify a css class of elements that will not initiate a drag
18842 * @method addInvalidHandleClass
18843 * @param {string} cssClass the class of the elements you wish to ignore
18845 addInvalidHandleClass: function(cssClass) {
18846 this.invalidHandleClasses.push(cssClass);
18850 * Unsets an excluded tag name set by addInvalidHandleType
18851 * @method removeInvalidHandleType
18852 * @param {string} tagName the type of element to unexclude
18854 removeInvalidHandleType: function(tagName) {
18855 var type = tagName.toUpperCase();
18856 // this.invalidHandleTypes[type] = null;
18857 delete this.invalidHandleTypes[type];
18861 * Unsets an invalid handle id
18862 * @method removeInvalidHandleId
18863 * @param {string} id the id of the element to re-enable
18865 removeInvalidHandleId: function(id) {
18866 if (typeof id !== "string") {
18869 delete this.invalidHandleIds[id];
18873 * Unsets an invalid css class
18874 * @method removeInvalidHandleClass
18875 * @param {string} cssClass the class of the element(s) you wish to
18878 removeInvalidHandleClass: function(cssClass) {
18879 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18880 if (this.invalidHandleClasses[i] == cssClass) {
18881 delete this.invalidHandleClasses[i];
18887 * Checks the tag exclusion list to see if this click should be ignored
18888 * @method isValidHandleChild
18889 * @param {HTMLElement} node the HTMLElement to evaluate
18890 * @return {boolean} true if this is a valid tag type, false if not
18892 isValidHandleChild: function(node) {
18895 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18898 nodeName = node.nodeName.toUpperCase();
18900 nodeName = node.nodeName;
18902 valid = valid && !this.invalidHandleTypes[nodeName];
18903 valid = valid && !this.invalidHandleIds[node.id];
18905 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18906 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18915 * Create the array of horizontal tick marks if an interval was specified
18916 * in setXConstraint().
18917 * @method setXTicks
18920 setXTicks: function(iStartX, iTickSize) {
18922 this.xTickSize = iTickSize;
18926 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18928 this.xTicks[this.xTicks.length] = i;
18933 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18935 this.xTicks[this.xTicks.length] = i;
18940 this.xTicks.sort(this.DDM.numericSort) ;
18944 * Create the array of vertical tick marks if an interval was specified in
18945 * setYConstraint().
18946 * @method setYTicks
18949 setYTicks: function(iStartY, iTickSize) {
18951 this.yTickSize = iTickSize;
18955 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18957 this.yTicks[this.yTicks.length] = i;
18962 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18964 this.yTicks[this.yTicks.length] = i;
18969 this.yTicks.sort(this.DDM.numericSort) ;
18973 * By default, the element can be dragged any place on the screen. Use
18974 * this method to limit the horizontal travel of the element. Pass in
18975 * 0,0 for the parameters if you want to lock the drag to the y axis.
18976 * @method setXConstraint
18977 * @param {int} iLeft the number of pixels the element can move to the left
18978 * @param {int} iRight the number of pixels the element can move to the
18980 * @param {int} iTickSize optional parameter for specifying that the
18982 * should move iTickSize pixels at a time.
18984 setXConstraint: function(iLeft, iRight, iTickSize) {
18985 this.leftConstraint = iLeft;
18986 this.rightConstraint = iRight;
18988 this.minX = this.initPageX - iLeft;
18989 this.maxX = this.initPageX + iRight;
18990 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18992 this.constrainX = true;
18996 * Clears any constraints applied to this instance. Also clears ticks
18997 * since they can't exist independent of a constraint at this time.
18998 * @method clearConstraints
19000 clearConstraints: function() {
19001 this.constrainX = false;
19002 this.constrainY = false;
19007 * Clears any tick interval defined for this instance
19008 * @method clearTicks
19010 clearTicks: function() {
19011 this.xTicks = null;
19012 this.yTicks = null;
19013 this.xTickSize = 0;
19014 this.yTickSize = 0;
19018 * By default, the element can be dragged any place on the screen. Set
19019 * this to limit the vertical travel of the element. Pass in 0,0 for the
19020 * parameters if you want to lock the drag to the x axis.
19021 * @method setYConstraint
19022 * @param {int} iUp the number of pixels the element can move up
19023 * @param {int} iDown the number of pixels the element can move down
19024 * @param {int} iTickSize optional parameter for specifying that the
19025 * element should move iTickSize pixels at a time.
19027 setYConstraint: function(iUp, iDown, iTickSize) {
19028 this.topConstraint = iUp;
19029 this.bottomConstraint = iDown;
19031 this.minY = this.initPageY - iUp;
19032 this.maxY = this.initPageY + iDown;
19033 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19035 this.constrainY = true;
19040 * resetConstraints must be called if you manually reposition a dd element.
19041 * @method resetConstraints
19042 * @param {boolean} maintainOffset
19044 resetConstraints: function() {
19047 // Maintain offsets if necessary
19048 if (this.initPageX || this.initPageX === 0) {
19049 // figure out how much this thing has moved
19050 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19051 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19053 this.setInitPosition(dx, dy);
19055 // This is the first time we have detected the element's position
19057 this.setInitPosition();
19060 if (this.constrainX) {
19061 this.setXConstraint( this.leftConstraint,
19062 this.rightConstraint,
19066 if (this.constrainY) {
19067 this.setYConstraint( this.topConstraint,
19068 this.bottomConstraint,
19074 * Normally the drag element is moved pixel by pixel, but we can specify
19075 * that it move a number of pixels at a time. This method resolves the
19076 * location when we have it set up like this.
19078 * @param {int} val where we want to place the object
19079 * @param {int[]} tickArray sorted array of valid points
19080 * @return {int} the closest tick
19083 getTick: function(val, tickArray) {
19086 // If tick interval is not defined, it is effectively 1 pixel,
19087 // so we return the value passed to us.
19089 } else if (tickArray[0] >= val) {
19090 // The value is lower than the first tick, so we return the first
19092 return tickArray[0];
19094 for (var i=0, len=tickArray.length; i<len; ++i) {
19096 if (tickArray[next] && tickArray[next] >= val) {
19097 var diff1 = val - tickArray[i];
19098 var diff2 = tickArray[next] - val;
19099 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19103 // The value is larger than the last tick, so we return the last
19105 return tickArray[tickArray.length - 1];
19112 * @return {string} string representation of the dd obj
19114 toString: function() {
19115 return ("DragDrop " + this.id);
19123 * Ext JS Library 1.1.1
19124 * Copyright(c) 2006-2007, Ext JS, LLC.
19126 * Originally Released Under LGPL - original licence link has changed is not relivant.
19129 * <script type="text/javascript">
19134 * The drag and drop utility provides a framework for building drag and drop
19135 * applications. In addition to enabling drag and drop for specific elements,
19136 * the drag and drop elements are tracked by the manager class, and the
19137 * interactions between the various elements are tracked during the drag and
19138 * the implementing code is notified about these important moments.
19141 // Only load the library once. Rewriting the manager class would orphan
19142 // existing drag and drop instances.
19143 if (!Roo.dd.DragDropMgr) {
19146 * @class Roo.dd.DragDropMgr
19147 * DragDropMgr is a singleton that tracks the element interaction for
19148 * all DragDrop items in the window. Generally, you will not call
19149 * this class directly, but it does have helper methods that could
19150 * be useful in your DragDrop implementations.
19153 Roo.dd.DragDropMgr = function() {
19155 var Event = Roo.EventManager;
19160 * Two dimensional Array of registered DragDrop objects. The first
19161 * dimension is the DragDrop item group, the second the DragDrop
19164 * @type {string: string}
19171 * Array of element ids defined as drag handles. Used to determine
19172 * if the element that generated the mousedown event is actually the
19173 * handle and not the html element itself.
19174 * @property handleIds
19175 * @type {string: string}
19182 * the DragDrop object that is currently being dragged
19183 * @property dragCurrent
19191 * the DragDrop object(s) that are being hovered over
19192 * @property dragOvers
19200 * the X distance between the cursor and the object being dragged
19209 * the Y distance between the cursor and the object being dragged
19218 * Flag to determine if we should prevent the default behavior of the
19219 * events we define. By default this is true, but this can be set to
19220 * false if you need the default behavior (not recommended)
19221 * @property preventDefault
19225 preventDefault: true,
19228 * Flag to determine if we should stop the propagation of the events
19229 * we generate. This is true by default but you may want to set it to
19230 * false if the html element contains other features that require the
19232 * @property stopPropagation
19236 stopPropagation: true,
19239 * Internal flag that is set to true when drag and drop has been
19241 * @property initialized
19248 * All drag and drop can be disabled.
19256 * Called the first time an element is registered.
19262 this.initialized = true;
19266 * In point mode, drag and drop interaction is defined by the
19267 * location of the cursor during the drag/drop
19275 * In intersect mode, drag and drop interactio nis defined by the
19276 * overlap of two or more drag and drop objects.
19277 * @property INTERSECT
19284 * The current drag and drop mode. Default: POINT
19292 * Runs method on all drag and drop objects
19293 * @method _execOnAll
19297 _execOnAll: function(sMethod, args) {
19298 for (var i in this.ids) {
19299 for (var j in this.ids[i]) {
19300 var oDD = this.ids[i][j];
19301 if (! this.isTypeOfDD(oDD)) {
19304 oDD[sMethod].apply(oDD, args);
19310 * Drag and drop initialization. Sets up the global event handlers
19315 _onLoad: function() {
19319 if (!Roo.isTouch) {
19320 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19321 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19323 Event.on(document, "touchend", this.handleMouseUp, this, true);
19324 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19326 Event.on(window, "unload", this._onUnload, this, true);
19327 Event.on(window, "resize", this._onResize, this, true);
19328 // Event.on(window, "mouseout", this._test);
19333 * Reset constraints on all drag and drop objs
19334 * @method _onResize
19338 _onResize: function(e) {
19339 this._execOnAll("resetConstraints", []);
19343 * Lock all drag and drop functionality
19347 lock: function() { this.locked = true; },
19350 * Unlock all drag and drop functionality
19354 unlock: function() { this.locked = false; },
19357 * Is drag and drop locked?
19359 * @return {boolean} True if drag and drop is locked, false otherwise.
19362 isLocked: function() { return this.locked; },
19365 * Location cache that is set for all drag drop objects when a drag is
19366 * initiated, cleared when the drag is finished.
19367 * @property locationCache
19374 * Set useCache to false if you want to force object the lookup of each
19375 * drag and drop linked element constantly during a drag.
19376 * @property useCache
19383 * The number of pixels that the mouse needs to move after the
19384 * mousedown before the drag is initiated. Default=3;
19385 * @property clickPixelThresh
19389 clickPixelThresh: 3,
19392 * The number of milliseconds after the mousedown event to initiate the
19393 * drag if we don't get a mouseup event. Default=1000
19394 * @property clickTimeThresh
19398 clickTimeThresh: 350,
19401 * Flag that indicates that either the drag pixel threshold or the
19402 * mousdown time threshold has been met
19403 * @property dragThreshMet
19408 dragThreshMet: false,
19411 * Timeout used for the click time threshold
19412 * @property clickTimeout
19417 clickTimeout: null,
19420 * The X position of the mousedown event stored for later use when a
19421 * drag threshold is met.
19430 * The Y position of the mousedown event stored for later use when a
19431 * drag threshold is met.
19440 * Each DragDrop instance must be registered with the DragDropMgr.
19441 * This is executed in DragDrop.init()
19442 * @method regDragDrop
19443 * @param {DragDrop} oDD the DragDrop object to register
19444 * @param {String} sGroup the name of the group this element belongs to
19447 regDragDrop: function(oDD, sGroup) {
19448 if (!this.initialized) { this.init(); }
19450 if (!this.ids[sGroup]) {
19451 this.ids[sGroup] = {};
19453 this.ids[sGroup][oDD.id] = oDD;
19457 * Removes the supplied dd instance from the supplied group. Executed
19458 * by DragDrop.removeFromGroup, so don't call this function directly.
19459 * @method removeDDFromGroup
19463 removeDDFromGroup: function(oDD, sGroup) {
19464 if (!this.ids[sGroup]) {
19465 this.ids[sGroup] = {};
19468 var obj = this.ids[sGroup];
19469 if (obj && obj[oDD.id]) {
19470 delete obj[oDD.id];
19475 * Unregisters a drag and drop item. This is executed in
19476 * DragDrop.unreg, use that method instead of calling this directly.
19481 _remove: function(oDD) {
19482 for (var g in oDD.groups) {
19483 if (g && this.ids[g][oDD.id]) {
19484 delete this.ids[g][oDD.id];
19487 delete this.handleIds[oDD.id];
19491 * Each DragDrop handle element must be registered. This is done
19492 * automatically when executing DragDrop.setHandleElId()
19493 * @method regHandle
19494 * @param {String} sDDId the DragDrop id this element is a handle for
19495 * @param {String} sHandleId the id of the element that is the drag
19499 regHandle: function(sDDId, sHandleId) {
19500 if (!this.handleIds[sDDId]) {
19501 this.handleIds[sDDId] = {};
19503 this.handleIds[sDDId][sHandleId] = sHandleId;
19507 * Utility function to determine if a given element has been
19508 * registered as a drag drop item.
19509 * @method isDragDrop
19510 * @param {String} id the element id to check
19511 * @return {boolean} true if this element is a DragDrop item,
19515 isDragDrop: function(id) {
19516 return ( this.getDDById(id) ) ? true : false;
19520 * Returns the drag and drop instances that are in all groups the
19521 * passed in instance belongs to.
19522 * @method getRelated
19523 * @param {DragDrop} p_oDD the obj to get related data for
19524 * @param {boolean} bTargetsOnly if true, only return targetable objs
19525 * @return {DragDrop[]} the related instances
19528 getRelated: function(p_oDD, bTargetsOnly) {
19530 for (var i in p_oDD.groups) {
19531 for (j in this.ids[i]) {
19532 var dd = this.ids[i][j];
19533 if (! this.isTypeOfDD(dd)) {
19536 if (!bTargetsOnly || dd.isTarget) {
19537 oDDs[oDDs.length] = dd;
19546 * Returns true if the specified dd target is a legal target for
19547 * the specifice drag obj
19548 * @method isLegalTarget
19549 * @param {DragDrop} the drag obj
19550 * @param {DragDrop} the target
19551 * @return {boolean} true if the target is a legal target for the
19555 isLegalTarget: function (oDD, oTargetDD) {
19556 var targets = this.getRelated(oDD, true);
19557 for (var i=0, len=targets.length;i<len;++i) {
19558 if (targets[i].id == oTargetDD.id) {
19567 * My goal is to be able to transparently determine if an object is
19568 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19569 * returns "object", oDD.constructor.toString() always returns
19570 * "DragDrop" and not the name of the subclass. So for now it just
19571 * evaluates a well-known variable in DragDrop.
19572 * @method isTypeOfDD
19573 * @param {Object} the object to evaluate
19574 * @return {boolean} true if typeof oDD = DragDrop
19577 isTypeOfDD: function (oDD) {
19578 return (oDD && oDD.__ygDragDrop);
19582 * Utility function to determine if a given element has been
19583 * registered as a drag drop handle for the given Drag Drop object.
19585 * @param {String} id the element id to check
19586 * @return {boolean} true if this element is a DragDrop handle, false
19590 isHandle: function(sDDId, sHandleId) {
19591 return ( this.handleIds[sDDId] &&
19592 this.handleIds[sDDId][sHandleId] );
19596 * Returns the DragDrop instance for a given id
19597 * @method getDDById
19598 * @param {String} id the id of the DragDrop object
19599 * @return {DragDrop} the drag drop object, null if it is not found
19602 getDDById: function(id) {
19603 for (var i in this.ids) {
19604 if (this.ids[i][id]) {
19605 return this.ids[i][id];
19612 * Fired after a registered DragDrop object gets the mousedown event.
19613 * Sets up the events required to track the object being dragged
19614 * @method handleMouseDown
19615 * @param {Event} e the event
19616 * @param oDD the DragDrop object being dragged
19620 handleMouseDown: function(e, oDD) {
19622 Roo.QuickTips.disable();
19624 this.currentTarget = e.getTarget();
19626 this.dragCurrent = oDD;
19628 var el = oDD.getEl();
19630 // track start position
19631 this.startX = e.getPageX();
19632 this.startY = e.getPageY();
19634 this.deltaX = this.startX - el.offsetLeft;
19635 this.deltaY = this.startY - el.offsetTop;
19637 this.dragThreshMet = false;
19639 this.clickTimeout = setTimeout(
19641 var DDM = Roo.dd.DDM;
19642 DDM.startDrag(DDM.startX, DDM.startY);
19644 this.clickTimeThresh );
19648 * Fired when either the drag pixel threshol or the mousedown hold
19649 * time threshold has been met.
19650 * @method startDrag
19651 * @param x {int} the X position of the original mousedown
19652 * @param y {int} the Y position of the original mousedown
19655 startDrag: function(x, y) {
19656 clearTimeout(this.clickTimeout);
19657 if (this.dragCurrent) {
19658 this.dragCurrent.b4StartDrag(x, y);
19659 this.dragCurrent.startDrag(x, y);
19661 this.dragThreshMet = true;
19665 * Internal function to handle the mouseup event. Will be invoked
19666 * from the context of the document.
19667 * @method handleMouseUp
19668 * @param {Event} e the event
19672 handleMouseUp: function(e) {
19675 Roo.QuickTips.enable();
19677 if (! this.dragCurrent) {
19681 clearTimeout(this.clickTimeout);
19683 if (this.dragThreshMet) {
19684 this.fireEvents(e, true);
19694 * Utility to stop event propagation and event default, if these
19695 * features are turned on.
19696 * @method stopEvent
19697 * @param {Event} e the event as returned by this.getEvent()
19700 stopEvent: function(e){
19701 if(this.stopPropagation) {
19702 e.stopPropagation();
19705 if (this.preventDefault) {
19706 e.preventDefault();
19711 * Internal function to clean up event handlers after the drag
19712 * operation is complete
19714 * @param {Event} e the event
19718 stopDrag: function(e) {
19719 // Fire the drag end event for the item that was dragged
19720 if (this.dragCurrent) {
19721 if (this.dragThreshMet) {
19722 this.dragCurrent.b4EndDrag(e);
19723 this.dragCurrent.endDrag(e);
19726 this.dragCurrent.onMouseUp(e);
19729 this.dragCurrent = null;
19730 this.dragOvers = {};
19734 * Internal function to handle the mousemove event. Will be invoked
19735 * from the context of the html element.
19737 * @TODO figure out what we can do about mouse events lost when the
19738 * user drags objects beyond the window boundary. Currently we can
19739 * detect this in internet explorer by verifying that the mouse is
19740 * down during the mousemove event. Firefox doesn't give us the
19741 * button state on the mousemove event.
19742 * @method handleMouseMove
19743 * @param {Event} e the event
19747 handleMouseMove: function(e) {
19748 if (! this.dragCurrent) {
19752 // var button = e.which || e.button;
19754 // check for IE mouseup outside of page boundary
19755 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19757 return this.handleMouseUp(e);
19760 if (!this.dragThreshMet) {
19761 var diffX = Math.abs(this.startX - e.getPageX());
19762 var diffY = Math.abs(this.startY - e.getPageY());
19763 if (diffX > this.clickPixelThresh ||
19764 diffY > this.clickPixelThresh) {
19765 this.startDrag(this.startX, this.startY);
19769 if (this.dragThreshMet) {
19770 this.dragCurrent.b4Drag(e);
19771 this.dragCurrent.onDrag(e);
19772 if(!this.dragCurrent.moveOnly){
19773 this.fireEvents(e, false);
19783 * Iterates over all of the DragDrop elements to find ones we are
19784 * hovering over or dropping on
19785 * @method fireEvents
19786 * @param {Event} e the event
19787 * @param {boolean} isDrop is this a drop op or a mouseover op?
19791 fireEvents: function(e, isDrop) {
19792 var dc = this.dragCurrent;
19794 // If the user did the mouse up outside of the window, we could
19795 // get here even though we have ended the drag.
19796 if (!dc || dc.isLocked()) {
19800 var pt = e.getPoint();
19802 // cache the previous dragOver array
19808 var enterEvts = [];
19810 // Check to see if the object(s) we were hovering over is no longer
19811 // being hovered over so we can fire the onDragOut event
19812 for (var i in this.dragOvers) {
19814 var ddo = this.dragOvers[i];
19816 if (! this.isTypeOfDD(ddo)) {
19820 if (! this.isOverTarget(pt, ddo, this.mode)) {
19821 outEvts.push( ddo );
19824 oldOvers[i] = true;
19825 delete this.dragOvers[i];
19828 for (var sGroup in dc.groups) {
19830 if ("string" != typeof sGroup) {
19834 for (i in this.ids[sGroup]) {
19835 var oDD = this.ids[sGroup][i];
19836 if (! this.isTypeOfDD(oDD)) {
19840 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19841 if (this.isOverTarget(pt, oDD, this.mode)) {
19842 // look for drop interactions
19844 dropEvts.push( oDD );
19845 // look for drag enter and drag over interactions
19848 // initial drag over: dragEnter fires
19849 if (!oldOvers[oDD.id]) {
19850 enterEvts.push( oDD );
19851 // subsequent drag overs: dragOver fires
19853 overEvts.push( oDD );
19856 this.dragOvers[oDD.id] = oDD;
19864 if (outEvts.length) {
19865 dc.b4DragOut(e, outEvts);
19866 dc.onDragOut(e, outEvts);
19869 if (enterEvts.length) {
19870 dc.onDragEnter(e, enterEvts);
19873 if (overEvts.length) {
19874 dc.b4DragOver(e, overEvts);
19875 dc.onDragOver(e, overEvts);
19878 if (dropEvts.length) {
19879 dc.b4DragDrop(e, dropEvts);
19880 dc.onDragDrop(e, dropEvts);
19884 // fire dragout events
19886 for (i=0, len=outEvts.length; i<len; ++i) {
19887 dc.b4DragOut(e, outEvts[i].id);
19888 dc.onDragOut(e, outEvts[i].id);
19891 // fire enter events
19892 for (i=0,len=enterEvts.length; i<len; ++i) {
19893 // dc.b4DragEnter(e, oDD.id);
19894 dc.onDragEnter(e, enterEvts[i].id);
19897 // fire over events
19898 for (i=0,len=overEvts.length; i<len; ++i) {
19899 dc.b4DragOver(e, overEvts[i].id);
19900 dc.onDragOver(e, overEvts[i].id);
19903 // fire drop events
19904 for (i=0, len=dropEvts.length; i<len; ++i) {
19905 dc.b4DragDrop(e, dropEvts[i].id);
19906 dc.onDragDrop(e, dropEvts[i].id);
19911 // notify about a drop that did not find a target
19912 if (isDrop && !dropEvts.length) {
19913 dc.onInvalidDrop(e);
19919 * Helper function for getting the best match from the list of drag
19920 * and drop objects returned by the drag and drop events when we are
19921 * in INTERSECT mode. It returns either the first object that the
19922 * cursor is over, or the object that has the greatest overlap with
19923 * the dragged element.
19924 * @method getBestMatch
19925 * @param {DragDrop[]} dds The array of drag and drop objects
19927 * @return {DragDrop} The best single match
19930 getBestMatch: function(dds) {
19932 // Return null if the input is not what we expect
19933 //if (!dds || !dds.length || dds.length == 0) {
19935 // If there is only one item, it wins
19936 //} else if (dds.length == 1) {
19938 var len = dds.length;
19943 // Loop through the targeted items
19944 for (var i=0; i<len; ++i) {
19946 // If the cursor is over the object, it wins. If the
19947 // cursor is over multiple matches, the first one we come
19949 if (dd.cursorIsOver) {
19952 // Otherwise the object with the most overlap wins
19955 winner.overlap.getArea() < dd.overlap.getArea()) {
19966 * Refreshes the cache of the top-left and bottom-right points of the
19967 * drag and drop objects in the specified group(s). This is in the
19968 * format that is stored in the drag and drop instance, so typical
19971 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19975 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19977 * @TODO this really should be an indexed array. Alternatively this
19978 * method could accept both.
19979 * @method refreshCache
19980 * @param {Object} groups an associative array of groups to refresh
19983 refreshCache: function(groups) {
19984 for (var sGroup in groups) {
19985 if ("string" != typeof sGroup) {
19988 for (var i in this.ids[sGroup]) {
19989 var oDD = this.ids[sGroup][i];
19991 if (this.isTypeOfDD(oDD)) {
19992 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19993 var loc = this.getLocation(oDD);
19995 this.locationCache[oDD.id] = loc;
19997 delete this.locationCache[oDD.id];
19998 // this will unregister the drag and drop object if
19999 // the element is not in a usable state
20008 * This checks to make sure an element exists and is in the DOM. The
20009 * main purpose is to handle cases where innerHTML is used to remove
20010 * drag and drop objects from the DOM. IE provides an 'unspecified
20011 * error' when trying to access the offsetParent of such an element
20013 * @param {HTMLElement} el the element to check
20014 * @return {boolean} true if the element looks usable
20017 verifyEl: function(el) {
20022 parent = el.offsetParent;
20025 parent = el.offsetParent;
20036 * Returns a Region object containing the drag and drop element's position
20037 * and size, including the padding configured for it
20038 * @method getLocation
20039 * @param {DragDrop} oDD the drag and drop object to get the
20041 * @return {Roo.lib.Region} a Region object representing the total area
20042 * the element occupies, including any padding
20043 * the instance is configured for.
20046 getLocation: function(oDD) {
20047 if (! this.isTypeOfDD(oDD)) {
20051 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20054 pos= Roo.lib.Dom.getXY(el);
20062 x2 = x1 + el.offsetWidth;
20064 y2 = y1 + el.offsetHeight;
20066 t = y1 - oDD.padding[0];
20067 r = x2 + oDD.padding[1];
20068 b = y2 + oDD.padding[2];
20069 l = x1 - oDD.padding[3];
20071 return new Roo.lib.Region( t, r, b, l );
20075 * Checks the cursor location to see if it over the target
20076 * @method isOverTarget
20077 * @param {Roo.lib.Point} pt The point to evaluate
20078 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20079 * @return {boolean} true if the mouse is over the target
20083 isOverTarget: function(pt, oTarget, intersect) {
20084 // use cache if available
20085 var loc = this.locationCache[oTarget.id];
20086 if (!loc || !this.useCache) {
20087 loc = this.getLocation(oTarget);
20088 this.locationCache[oTarget.id] = loc;
20096 oTarget.cursorIsOver = loc.contains( pt );
20098 // DragDrop is using this as a sanity check for the initial mousedown
20099 // in this case we are done. In POINT mode, if the drag obj has no
20100 // contraints, we are also done. Otherwise we need to evaluate the
20101 // location of the target as related to the actual location of the
20102 // dragged element.
20103 var dc = this.dragCurrent;
20104 if (!dc || !dc.getTargetCoord ||
20105 (!intersect && !dc.constrainX && !dc.constrainY)) {
20106 return oTarget.cursorIsOver;
20109 oTarget.overlap = null;
20111 // Get the current location of the drag element, this is the
20112 // location of the mouse event less the delta that represents
20113 // where the original mousedown happened on the element. We
20114 // need to consider constraints and ticks as well.
20115 var pos = dc.getTargetCoord(pt.x, pt.y);
20117 var el = dc.getDragEl();
20118 var curRegion = new Roo.lib.Region( pos.y,
20119 pos.x + el.offsetWidth,
20120 pos.y + el.offsetHeight,
20123 var overlap = curRegion.intersect(loc);
20126 oTarget.overlap = overlap;
20127 return (intersect) ? true : oTarget.cursorIsOver;
20134 * unload event handler
20135 * @method _onUnload
20139 _onUnload: function(e, me) {
20140 Roo.dd.DragDropMgr.unregAll();
20144 * Cleans up the drag and drop events and objects.
20149 unregAll: function() {
20151 if (this.dragCurrent) {
20153 this.dragCurrent = null;
20156 this._execOnAll("unreg", []);
20158 for (i in this.elementCache) {
20159 delete this.elementCache[i];
20162 this.elementCache = {};
20167 * A cache of DOM elements
20168 * @property elementCache
20175 * Get the wrapper for the DOM element specified
20176 * @method getElWrapper
20177 * @param {String} id the id of the element to get
20178 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20180 * @deprecated This wrapper isn't that useful
20183 getElWrapper: function(id) {
20184 var oWrapper = this.elementCache[id];
20185 if (!oWrapper || !oWrapper.el) {
20186 oWrapper = this.elementCache[id] =
20187 new this.ElementWrapper(Roo.getDom(id));
20193 * Returns the actual DOM element
20194 * @method getElement
20195 * @param {String} id the id of the elment to get
20196 * @return {Object} The element
20197 * @deprecated use Roo.getDom instead
20200 getElement: function(id) {
20201 return Roo.getDom(id);
20205 * Returns the style property for the DOM element (i.e.,
20206 * document.getElById(id).style)
20208 * @param {String} id the id of the elment to get
20209 * @return {Object} The style property of the element
20210 * @deprecated use Roo.getDom instead
20213 getCss: function(id) {
20214 var el = Roo.getDom(id);
20215 return (el) ? el.style : null;
20219 * Inner class for cached elements
20220 * @class DragDropMgr.ElementWrapper
20225 ElementWrapper: function(el) {
20230 this.el = el || null;
20235 this.id = this.el && el.id;
20237 * A reference to the style property
20240 this.css = this.el && el.style;
20244 * Returns the X position of an html element
20246 * @param el the element for which to get the position
20247 * @return {int} the X coordinate
20249 * @deprecated use Roo.lib.Dom.getX instead
20252 getPosX: function(el) {
20253 return Roo.lib.Dom.getX(el);
20257 * Returns the Y position of an html element
20259 * @param el the element for which to get the position
20260 * @return {int} the Y coordinate
20261 * @deprecated use Roo.lib.Dom.getY instead
20264 getPosY: function(el) {
20265 return Roo.lib.Dom.getY(el);
20269 * Swap two nodes. In IE, we use the native method, for others we
20270 * emulate the IE behavior
20272 * @param n1 the first node to swap
20273 * @param n2 the other node to swap
20276 swapNode: function(n1, n2) {
20280 var p = n2.parentNode;
20281 var s = n2.nextSibling;
20284 p.insertBefore(n1, n2);
20285 } else if (n2 == n1.nextSibling) {
20286 p.insertBefore(n2, n1);
20288 n1.parentNode.replaceChild(n2, n1);
20289 p.insertBefore(n1, s);
20295 * Returns the current scroll position
20296 * @method getScroll
20300 getScroll: function () {
20301 var t, l, dde=document.documentElement, db=document.body;
20302 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20304 l = dde.scrollLeft;
20311 return { top: t, left: l };
20315 * Returns the specified element style property
20317 * @param {HTMLElement} el the element
20318 * @param {string} styleProp the style property
20319 * @return {string} The value of the style property
20320 * @deprecated use Roo.lib.Dom.getStyle
20323 getStyle: function(el, styleProp) {
20324 return Roo.fly(el).getStyle(styleProp);
20328 * Gets the scrollTop
20329 * @method getScrollTop
20330 * @return {int} the document's scrollTop
20333 getScrollTop: function () { return this.getScroll().top; },
20336 * Gets the scrollLeft
20337 * @method getScrollLeft
20338 * @return {int} the document's scrollTop
20341 getScrollLeft: function () { return this.getScroll().left; },
20344 * Sets the x/y position of an element to the location of the
20347 * @param {HTMLElement} moveEl The element to move
20348 * @param {HTMLElement} targetEl The position reference element
20351 moveToEl: function (moveEl, targetEl) {
20352 var aCoord = Roo.lib.Dom.getXY(targetEl);
20353 Roo.lib.Dom.setXY(moveEl, aCoord);
20357 * Numeric array sort function
20358 * @method numericSort
20361 numericSort: function(a, b) { return (a - b); },
20365 * @property _timeoutCount
20372 * Trying to make the load order less important. Without this we get
20373 * an error if this file is loaded before the Event Utility.
20374 * @method _addListeners
20378 _addListeners: function() {
20379 var DDM = Roo.dd.DDM;
20380 if ( Roo.lib.Event && document ) {
20383 if (DDM._timeoutCount > 2000) {
20385 setTimeout(DDM._addListeners, 10);
20386 if (document && document.body) {
20387 DDM._timeoutCount += 1;
20394 * Recursively searches the immediate parent and all child nodes for
20395 * the handle element in order to determine wheter or not it was
20397 * @method handleWasClicked
20398 * @param node the html element to inspect
20401 handleWasClicked: function(node, id) {
20402 if (this.isHandle(id, node.id)) {
20405 // check to see if this is a text node child of the one we want
20406 var p = node.parentNode;
20409 if (this.isHandle(id, p.id)) {
20424 // shorter alias, save a few bytes
20425 Roo.dd.DDM = Roo.dd.DragDropMgr;
20426 Roo.dd.DDM._addListeners();
20430 * Ext JS Library 1.1.1
20431 * Copyright(c) 2006-2007, Ext JS, LLC.
20433 * Originally Released Under LGPL - original licence link has changed is not relivant.
20436 * <script type="text/javascript">
20441 * A DragDrop implementation where the linked element follows the
20442 * mouse cursor during a drag.
20443 * @extends Roo.dd.DragDrop
20445 * @param {String} id the id of the linked element
20446 * @param {String} sGroup the group of related DragDrop items
20447 * @param {object} config an object containing configurable attributes
20448 * Valid properties for DD:
20451 Roo.dd.DD = function(id, sGroup, config) {
20453 this.init(id, sGroup, config);
20457 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20460 * When set to true, the utility automatically tries to scroll the browser
20461 * window wehn a drag and drop element is dragged near the viewport boundary.
20462 * Defaults to true.
20469 * Sets the pointer offset to the distance between the linked element's top
20470 * left corner and the location the element was clicked
20471 * @method autoOffset
20472 * @param {int} iPageX the X coordinate of the click
20473 * @param {int} iPageY the Y coordinate of the click
20475 autoOffset: function(iPageX, iPageY) {
20476 var x = iPageX - this.startPageX;
20477 var y = iPageY - this.startPageY;
20478 this.setDelta(x, y);
20482 * Sets the pointer offset. You can call this directly to force the
20483 * offset to be in a particular location (e.g., pass in 0,0 to set it
20484 * to the center of the object)
20486 * @param {int} iDeltaX the distance from the left
20487 * @param {int} iDeltaY the distance from the top
20489 setDelta: function(iDeltaX, iDeltaY) {
20490 this.deltaX = iDeltaX;
20491 this.deltaY = iDeltaY;
20495 * Sets the drag element to the location of the mousedown or click event,
20496 * maintaining the cursor location relative to the location on the element
20497 * that was clicked. Override this if you want to place the element in a
20498 * location other than where the cursor is.
20499 * @method setDragElPos
20500 * @param {int} iPageX the X coordinate of the mousedown or drag event
20501 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20503 setDragElPos: function(iPageX, iPageY) {
20504 // the first time we do this, we are going to check to make sure
20505 // the element has css positioning
20507 var el = this.getDragEl();
20508 this.alignElWithMouse(el, iPageX, iPageY);
20512 * Sets the element to the location of the mousedown or click event,
20513 * maintaining the cursor location relative to the location on the element
20514 * that was clicked. Override this if you want to place the element in a
20515 * location other than where the cursor is.
20516 * @method alignElWithMouse
20517 * @param {HTMLElement} el the element to move
20518 * @param {int} iPageX the X coordinate of the mousedown or drag event
20519 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20521 alignElWithMouse: function(el, iPageX, iPageY) {
20522 var oCoord = this.getTargetCoord(iPageX, iPageY);
20523 var fly = el.dom ? el : Roo.fly(el);
20524 if (!this.deltaSetXY) {
20525 var aCoord = [oCoord.x, oCoord.y];
20527 var newLeft = fly.getLeft(true);
20528 var newTop = fly.getTop(true);
20529 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20531 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20534 this.cachePosition(oCoord.x, oCoord.y);
20535 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20540 * Saves the most recent position so that we can reset the constraints and
20541 * tick marks on-demand. We need to know this so that we can calculate the
20542 * number of pixels the element is offset from its original position.
20543 * @method cachePosition
20544 * @param iPageX the current x position (optional, this just makes it so we
20545 * don't have to look it up again)
20546 * @param iPageY the current y position (optional, this just makes it so we
20547 * don't have to look it up again)
20549 cachePosition: function(iPageX, iPageY) {
20551 this.lastPageX = iPageX;
20552 this.lastPageY = iPageY;
20554 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20555 this.lastPageX = aCoord[0];
20556 this.lastPageY = aCoord[1];
20561 * Auto-scroll the window if the dragged object has been moved beyond the
20562 * visible window boundary.
20563 * @method autoScroll
20564 * @param {int} x the drag element's x position
20565 * @param {int} y the drag element's y position
20566 * @param {int} h the height of the drag element
20567 * @param {int} w the width of the drag element
20570 autoScroll: function(x, y, h, w) {
20573 // The client height
20574 var clientH = Roo.lib.Dom.getViewWidth();
20576 // The client width
20577 var clientW = Roo.lib.Dom.getViewHeight();
20579 // The amt scrolled down
20580 var st = this.DDM.getScrollTop();
20582 // The amt scrolled right
20583 var sl = this.DDM.getScrollLeft();
20585 // Location of the bottom of the element
20588 // Location of the right of the element
20591 // The distance from the cursor to the bottom of the visible area,
20592 // adjusted so that we don't scroll if the cursor is beyond the
20593 // element drag constraints
20594 var toBot = (clientH + st - y - this.deltaY);
20596 // The distance from the cursor to the right of the visible area
20597 var toRight = (clientW + sl - x - this.deltaX);
20600 // How close to the edge the cursor must be before we scroll
20601 // var thresh = (document.all) ? 100 : 40;
20604 // How many pixels to scroll per autoscroll op. This helps to reduce
20605 // clunky scrolling. IE is more sensitive about this ... it needs this
20606 // value to be higher.
20607 var scrAmt = (document.all) ? 80 : 30;
20609 // Scroll down if we are near the bottom of the visible page and the
20610 // obj extends below the crease
20611 if ( bot > clientH && toBot < thresh ) {
20612 window.scrollTo(sl, st + scrAmt);
20615 // Scroll up if the window is scrolled down and the top of the object
20616 // goes above the top border
20617 if ( y < st && st > 0 && y - st < thresh ) {
20618 window.scrollTo(sl, st - scrAmt);
20621 // Scroll right if the obj is beyond the right border and the cursor is
20622 // near the border.
20623 if ( right > clientW && toRight < thresh ) {
20624 window.scrollTo(sl + scrAmt, st);
20627 // Scroll left if the window has been scrolled to the right and the obj
20628 // extends past the left border
20629 if ( x < sl && sl > 0 && x - sl < thresh ) {
20630 window.scrollTo(sl - scrAmt, st);
20636 * Finds the location the element should be placed if we want to move
20637 * it to where the mouse location less the click offset would place us.
20638 * @method getTargetCoord
20639 * @param {int} iPageX the X coordinate of the click
20640 * @param {int} iPageY the Y coordinate of the click
20641 * @return an object that contains the coordinates (Object.x and Object.y)
20644 getTargetCoord: function(iPageX, iPageY) {
20647 var x = iPageX - this.deltaX;
20648 var y = iPageY - this.deltaY;
20650 if (this.constrainX) {
20651 if (x < this.minX) { x = this.minX; }
20652 if (x > this.maxX) { x = this.maxX; }
20655 if (this.constrainY) {
20656 if (y < this.minY) { y = this.minY; }
20657 if (y > this.maxY) { y = this.maxY; }
20660 x = this.getTick(x, this.xTicks);
20661 y = this.getTick(y, this.yTicks);
20668 * Sets up config options specific to this class. Overrides
20669 * Roo.dd.DragDrop, but all versions of this method through the
20670 * inheritance chain are called
20672 applyConfig: function() {
20673 Roo.dd.DD.superclass.applyConfig.call(this);
20674 this.scroll = (this.config.scroll !== false);
20678 * Event that fires prior to the onMouseDown event. Overrides
20681 b4MouseDown: function(e) {
20682 // this.resetConstraints();
20683 this.autoOffset(e.getPageX(),
20688 * Event that fires prior to the onDrag event. Overrides
20691 b4Drag: function(e) {
20692 this.setDragElPos(e.getPageX(),
20696 toString: function() {
20697 return ("DD " + this.id);
20700 //////////////////////////////////////////////////////////////////////////
20701 // Debugging ygDragDrop events that can be overridden
20702 //////////////////////////////////////////////////////////////////////////
20704 startDrag: function(x, y) {
20707 onDrag: function(e) {
20710 onDragEnter: function(e, id) {
20713 onDragOver: function(e, id) {
20716 onDragOut: function(e, id) {
20719 onDragDrop: function(e, id) {
20722 endDrag: function(e) {
20729 * Ext JS Library 1.1.1
20730 * Copyright(c) 2006-2007, Ext JS, LLC.
20732 * Originally Released Under LGPL - original licence link has changed is not relivant.
20735 * <script type="text/javascript">
20739 * @class Roo.dd.DDProxy
20740 * A DragDrop implementation that inserts an empty, bordered div into
20741 * the document that follows the cursor during drag operations. At the time of
20742 * the click, the frame div is resized to the dimensions of the linked html
20743 * element, and moved to the exact location of the linked element.
20745 * References to the "frame" element refer to the single proxy element that
20746 * was created to be dragged in place of all DDProxy elements on the
20749 * @extends Roo.dd.DD
20751 * @param {String} id the id of the linked html element
20752 * @param {String} sGroup the group of related DragDrop objects
20753 * @param {object} config an object containing configurable attributes
20754 * Valid properties for DDProxy in addition to those in DragDrop:
20755 * resizeFrame, centerFrame, dragElId
20757 Roo.dd.DDProxy = function(id, sGroup, config) {
20759 this.init(id, sGroup, config);
20765 * The default drag frame div id
20766 * @property Roo.dd.DDProxy.dragElId
20770 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20772 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20775 * By default we resize the drag frame to be the same size as the element
20776 * we want to drag (this is to get the frame effect). We can turn it off
20777 * if we want a different behavior.
20778 * @property resizeFrame
20784 * By default the frame is positioned exactly where the drag element is, so
20785 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20786 * you do not have constraints on the obj is to have the drag frame centered
20787 * around the cursor. Set centerFrame to true for this effect.
20788 * @property centerFrame
20791 centerFrame: false,
20794 * Creates the proxy element if it does not yet exist
20795 * @method createFrame
20797 createFrame: function() {
20799 var body = document.body;
20801 if (!body || !body.firstChild) {
20802 setTimeout( function() { self.createFrame(); }, 50 );
20806 var div = this.getDragEl();
20809 div = document.createElement("div");
20810 div.id = this.dragElId;
20813 s.position = "absolute";
20814 s.visibility = "hidden";
20816 s.border = "2px solid #aaa";
20819 // appendChild can blow up IE if invoked prior to the window load event
20820 // while rendering a table. It is possible there are other scenarios
20821 // that would cause this to happen as well.
20822 body.insertBefore(div, body.firstChild);
20827 * Initialization for the drag frame element. Must be called in the
20828 * constructor of all subclasses
20829 * @method initFrame
20831 initFrame: function() {
20832 this.createFrame();
20835 applyConfig: function() {
20836 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20838 this.resizeFrame = (this.config.resizeFrame !== false);
20839 this.centerFrame = (this.config.centerFrame);
20840 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20844 * Resizes the drag frame to the dimensions of the clicked object, positions
20845 * it over the object, and finally displays it
20846 * @method showFrame
20847 * @param {int} iPageX X click position
20848 * @param {int} iPageY Y click position
20851 showFrame: function(iPageX, iPageY) {
20852 var el = this.getEl();
20853 var dragEl = this.getDragEl();
20854 var s = dragEl.style;
20856 this._resizeProxy();
20858 if (this.centerFrame) {
20859 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20860 Math.round(parseInt(s.height, 10)/2) );
20863 this.setDragElPos(iPageX, iPageY);
20865 Roo.fly(dragEl).show();
20869 * The proxy is automatically resized to the dimensions of the linked
20870 * element when a drag is initiated, unless resizeFrame is set to false
20871 * @method _resizeProxy
20874 _resizeProxy: function() {
20875 if (this.resizeFrame) {
20876 var el = this.getEl();
20877 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20881 // overrides Roo.dd.DragDrop
20882 b4MouseDown: function(e) {
20883 var x = e.getPageX();
20884 var y = e.getPageY();
20885 this.autoOffset(x, y);
20886 this.setDragElPos(x, y);
20889 // overrides Roo.dd.DragDrop
20890 b4StartDrag: function(x, y) {
20891 // show the drag frame
20892 this.showFrame(x, y);
20895 // overrides Roo.dd.DragDrop
20896 b4EndDrag: function(e) {
20897 Roo.fly(this.getDragEl()).hide();
20900 // overrides Roo.dd.DragDrop
20901 // By default we try to move the element to the last location of the frame.
20902 // This is so that the default behavior mirrors that of Roo.dd.DD.
20903 endDrag: function(e) {
20905 var lel = this.getEl();
20906 var del = this.getDragEl();
20908 // Show the drag frame briefly so we can get its position
20909 del.style.visibility = "";
20912 // Hide the linked element before the move to get around a Safari
20914 lel.style.visibility = "hidden";
20915 Roo.dd.DDM.moveToEl(lel, del);
20916 del.style.visibility = "hidden";
20917 lel.style.visibility = "";
20922 beforeMove : function(){
20926 afterDrag : function(){
20930 toString: function() {
20931 return ("DDProxy " + this.id);
20937 * Ext JS Library 1.1.1
20938 * Copyright(c) 2006-2007, Ext JS, LLC.
20940 * Originally Released Under LGPL - original licence link has changed is not relivant.
20943 * <script type="text/javascript">
20947 * @class Roo.dd.DDTarget
20948 * A DragDrop implementation that does not move, but can be a drop
20949 * target. You would get the same result by simply omitting implementation
20950 * for the event callbacks, but this way we reduce the processing cost of the
20951 * event listener and the callbacks.
20952 * @extends Roo.dd.DragDrop
20954 * @param {String} id the id of the element that is a drop target
20955 * @param {String} sGroup the group of related DragDrop objects
20956 * @param {object} config an object containing configurable attributes
20957 * Valid properties for DDTarget in addition to those in
20961 Roo.dd.DDTarget = function(id, sGroup, config) {
20963 this.initTarget(id, sGroup, config);
20965 if (config.listeners || config.events) {
20966 Roo.dd.DragDrop.superclass.constructor.call(this, {
20967 listeners : config.listeners || {},
20968 events : config.events || {}
20973 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20974 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20975 toString: function() {
20976 return ("DDTarget " + this.id);
20981 * Ext JS Library 1.1.1
20982 * Copyright(c) 2006-2007, Ext JS, LLC.
20984 * Originally Released Under LGPL - original licence link has changed is not relivant.
20987 * <script type="text/javascript">
20992 * @class Roo.dd.ScrollManager
20993 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20994 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
20997 Roo.dd.ScrollManager = function(){
20998 var ddm = Roo.dd.DragDropMgr;
21005 var onStop = function(e){
21010 var triggerRefresh = function(){
21011 if(ddm.dragCurrent){
21012 ddm.refreshCache(ddm.dragCurrent.groups);
21016 var doScroll = function(){
21017 if(ddm.dragCurrent){
21018 var dds = Roo.dd.ScrollManager;
21020 if(proc.el.scroll(proc.dir, dds.increment)){
21024 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21029 var clearProc = function(){
21031 clearInterval(proc.id);
21038 var startProc = function(el, dir){
21039 Roo.log('scroll startproc');
21043 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21046 var onFire = function(e, isDrop){
21048 if(isDrop || !ddm.dragCurrent){ return; }
21049 var dds = Roo.dd.ScrollManager;
21050 if(!dragEl || dragEl != ddm.dragCurrent){
21051 dragEl = ddm.dragCurrent;
21052 // refresh regions on drag start
21053 dds.refreshCache();
21056 var xy = Roo.lib.Event.getXY(e);
21057 var pt = new Roo.lib.Point(xy[0], xy[1]);
21058 for(var id in els){
21059 var el = els[id], r = el._region;
21060 if(r && r.contains(pt) && el.isScrollable()){
21061 if(r.bottom - pt.y <= dds.thresh){
21063 startProc(el, "down");
21066 }else if(r.right - pt.x <= dds.thresh){
21068 startProc(el, "left");
21071 }else if(pt.y - r.top <= dds.thresh){
21073 startProc(el, "up");
21076 }else if(pt.x - r.left <= dds.thresh){
21078 startProc(el, "right");
21087 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21088 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21092 * Registers new overflow element(s) to auto scroll
21093 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21095 register : function(el){
21096 if(el instanceof Array){
21097 for(var i = 0, len = el.length; i < len; i++) {
21098 this.register(el[i]);
21104 Roo.dd.ScrollManager.els = els;
21108 * Unregisters overflow element(s) so they are no longer scrolled
21109 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21111 unregister : function(el){
21112 if(el instanceof Array){
21113 for(var i = 0, len = el.length; i < len; i++) {
21114 this.unregister(el[i]);
21123 * The number of pixels from the edge of a container the pointer needs to be to
21124 * trigger scrolling (defaults to 25)
21130 * The number of pixels to scroll in each scroll increment (defaults to 50)
21136 * The frequency of scrolls in milliseconds (defaults to 500)
21142 * True to animate the scroll (defaults to true)
21148 * The animation duration in seconds -
21149 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21155 * Manually trigger a cache refresh.
21157 refreshCache : function(){
21158 for(var id in els){
21159 if(typeof els[id] == 'object'){ // for people extending the object prototype
21160 els[id]._region = els[id].getRegion();
21167 * Ext JS Library 1.1.1
21168 * Copyright(c) 2006-2007, Ext JS, LLC.
21170 * Originally Released Under LGPL - original licence link has changed is not relivant.
21173 * <script type="text/javascript">
21178 * @class Roo.dd.Registry
21179 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21180 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21183 Roo.dd.Registry = function(){
21186 var autoIdSeed = 0;
21188 var getId = function(el, autogen){
21189 if(typeof el == "string"){
21193 if(!id && autogen !== false){
21194 id = "roodd-" + (++autoIdSeed);
21202 * Register a drag drop element
21203 * @param {String|HTMLElement} element The id or DOM node to register
21204 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21205 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21206 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21207 * populated in the data object (if applicable):
21209 Value Description<br />
21210 --------- ------------------------------------------<br />
21211 handles Array of DOM nodes that trigger dragging<br />
21212 for the element being registered<br />
21213 isHandle True if the element passed in triggers<br />
21214 dragging itself, else false
21217 register : function(el, data){
21219 if(typeof el == "string"){
21220 el = document.getElementById(el);
21223 elements[getId(el)] = data;
21224 if(data.isHandle !== false){
21225 handles[data.ddel.id] = data;
21228 var hs = data.handles;
21229 for(var i = 0, len = hs.length; i < len; i++){
21230 handles[getId(hs[i])] = data;
21236 * Unregister a drag drop element
21237 * @param {String|HTMLElement} element The id or DOM node to unregister
21239 unregister : function(el){
21240 var id = getId(el, false);
21241 var data = elements[id];
21243 delete elements[id];
21245 var hs = data.handles;
21246 for(var i = 0, len = hs.length; i < len; i++){
21247 delete handles[getId(hs[i], false)];
21254 * Returns the handle registered for a DOM Node by id
21255 * @param {String|HTMLElement} id The DOM node or id to look up
21256 * @return {Object} handle The custom handle data
21258 getHandle : function(id){
21259 if(typeof id != "string"){ // must be element?
21262 return handles[id];
21266 * Returns the handle that is registered for the DOM node that is the target of the event
21267 * @param {Event} e The event
21268 * @return {Object} handle The custom handle data
21270 getHandleFromEvent : function(e){
21271 var t = Roo.lib.Event.getTarget(e);
21272 return t ? handles[t.id] : null;
21276 * Returns a custom data object that is registered for a DOM node by id
21277 * @param {String|HTMLElement} id The DOM node or id to look up
21278 * @return {Object} data The custom data
21280 getTarget : function(id){
21281 if(typeof id != "string"){ // must be element?
21284 return elements[id];
21288 * Returns a custom data object that is registered for the DOM node that is the target of the event
21289 * @param {Event} e The event
21290 * @return {Object} data The custom data
21292 getTargetFromEvent : function(e){
21293 var t = Roo.lib.Event.getTarget(e);
21294 return t ? elements[t.id] || handles[t.id] : null;
21299 * Ext JS Library 1.1.1
21300 * Copyright(c) 2006-2007, Ext JS, LLC.
21302 * Originally Released Under LGPL - original licence link has changed is not relivant.
21305 * <script type="text/javascript">
21310 * @class Roo.dd.StatusProxy
21311 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21312 * default drag proxy used by all Roo.dd components.
21314 * @param {Object} config
21316 Roo.dd.StatusProxy = function(config){
21317 Roo.apply(this, config);
21318 this.id = this.id || Roo.id();
21319 this.el = new Roo.Layer({
21321 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21322 {tag: "div", cls: "x-dd-drop-icon"},
21323 {tag: "div", cls: "x-dd-drag-ghost"}
21326 shadow: !config || config.shadow !== false
21328 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21329 this.dropStatus = this.dropNotAllowed;
21332 Roo.dd.StatusProxy.prototype = {
21334 * @cfg {String} dropAllowed
21335 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21337 dropAllowed : "x-dd-drop-ok",
21339 * @cfg {String} dropNotAllowed
21340 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21342 dropNotAllowed : "x-dd-drop-nodrop",
21345 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21346 * over the current target element.
21347 * @param {String} cssClass The css class for the new drop status indicator image
21349 setStatus : function(cssClass){
21350 cssClass = cssClass || this.dropNotAllowed;
21351 if(this.dropStatus != cssClass){
21352 this.el.replaceClass(this.dropStatus, cssClass);
21353 this.dropStatus = cssClass;
21358 * Resets the status indicator to the default dropNotAllowed value
21359 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21361 reset : function(clearGhost){
21362 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21363 this.dropStatus = this.dropNotAllowed;
21365 this.ghost.update("");
21370 * Updates the contents of the ghost element
21371 * @param {String} html The html that will replace the current innerHTML of the ghost element
21373 update : function(html){
21374 if(typeof html == "string"){
21375 this.ghost.update(html);
21377 this.ghost.update("");
21378 html.style.margin = "0";
21379 this.ghost.dom.appendChild(html);
21381 // ensure float = none set?? cant remember why though.
21382 var el = this.ghost.dom.firstChild;
21384 Roo.fly(el).setStyle('float', 'none');
21389 * Returns the underlying proxy {@link Roo.Layer}
21390 * @return {Roo.Layer} el
21392 getEl : function(){
21397 * Returns the ghost element
21398 * @return {Roo.Element} el
21400 getGhost : function(){
21406 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21408 hide : function(clear){
21416 * Stops the repair animation if it's currently running
21419 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21425 * Displays this proxy
21432 * Force the Layer to sync its shadow and shim positions to the element
21439 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21440 * invalid drop operation by the item being dragged.
21441 * @param {Array} xy The XY position of the element ([x, y])
21442 * @param {Function} callback The function to call after the repair is complete
21443 * @param {Object} scope The scope in which to execute the callback
21445 repair : function(xy, callback, scope){
21446 this.callback = callback;
21447 this.scope = scope;
21448 if(xy && this.animRepair !== false){
21449 this.el.addClass("x-dd-drag-repair");
21450 this.el.hideUnders(true);
21451 this.anim = this.el.shift({
21452 duration: this.repairDuration || .5,
21456 callback: this.afterRepair,
21460 this.afterRepair();
21465 afterRepair : function(){
21467 if(typeof this.callback == "function"){
21468 this.callback.call(this.scope || this);
21470 this.callback = null;
21475 * Ext JS Library 1.1.1
21476 * Copyright(c) 2006-2007, Ext JS, LLC.
21478 * Originally Released Under LGPL - original licence link has changed is not relivant.
21481 * <script type="text/javascript">
21485 * @class Roo.dd.DragSource
21486 * @extends Roo.dd.DDProxy
21487 * A simple class that provides the basic implementation needed to make any element draggable.
21489 * @param {String/HTMLElement/Element} el The container element
21490 * @param {Object} config
21492 Roo.dd.DragSource = function(el, config){
21493 this.el = Roo.get(el);
21494 this.dragData = {};
21496 Roo.apply(this, config);
21499 this.proxy = new Roo.dd.StatusProxy();
21502 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21503 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21505 this.dragging = false;
21508 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21510 * @cfg {String} dropAllowed
21511 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21513 dropAllowed : "x-dd-drop-ok",
21515 * @cfg {String} dropNotAllowed
21516 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21518 dropNotAllowed : "x-dd-drop-nodrop",
21521 * Returns the data object associated with this drag source
21522 * @return {Object} data An object containing arbitrary data
21524 getDragData : function(e){
21525 return this.dragData;
21529 onDragEnter : function(e, id){
21530 var target = Roo.dd.DragDropMgr.getDDById(id);
21531 this.cachedTarget = target;
21532 if(this.beforeDragEnter(target, e, id) !== false){
21533 if(target.isNotifyTarget){
21534 var status = target.notifyEnter(this, e, this.dragData);
21535 this.proxy.setStatus(status);
21537 this.proxy.setStatus(this.dropAllowed);
21540 if(this.afterDragEnter){
21542 * An empty function by default, but provided so that you can perform a custom action
21543 * when the dragged item enters the drop target by providing an implementation.
21544 * @param {Roo.dd.DragDrop} target The drop target
21545 * @param {Event} e The event object
21546 * @param {String} id The id of the dragged element
21547 * @method afterDragEnter
21549 this.afterDragEnter(target, e, id);
21555 * An empty function by default, but provided so that you can perform a custom action
21556 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21557 * @param {Roo.dd.DragDrop} target The drop target
21558 * @param {Event} e The event object
21559 * @param {String} id The id of the dragged element
21560 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21562 beforeDragEnter : function(target, e, id){
21567 alignElWithMouse: function() {
21568 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21573 onDragOver : function(e, id){
21574 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21575 if(this.beforeDragOver(target, e, id) !== false){
21576 if(target.isNotifyTarget){
21577 var status = target.notifyOver(this, e, this.dragData);
21578 this.proxy.setStatus(status);
21581 if(this.afterDragOver){
21583 * An empty function by default, but provided so that you can perform a custom action
21584 * while the dragged item is over the drop target by providing an implementation.
21585 * @param {Roo.dd.DragDrop} target The drop target
21586 * @param {Event} e The event object
21587 * @param {String} id The id of the dragged element
21588 * @method afterDragOver
21590 this.afterDragOver(target, e, id);
21596 * An empty function by default, but provided so that you can perform a custom action
21597 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21598 * @param {Roo.dd.DragDrop} target The drop target
21599 * @param {Event} e The event object
21600 * @param {String} id The id of the dragged element
21601 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21603 beforeDragOver : function(target, e, id){
21608 onDragOut : function(e, id){
21609 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21610 if(this.beforeDragOut(target, e, id) !== false){
21611 if(target.isNotifyTarget){
21612 target.notifyOut(this, e, this.dragData);
21614 this.proxy.reset();
21615 if(this.afterDragOut){
21617 * An empty function by default, but provided so that you can perform a custom action
21618 * after the dragged item is dragged out of the target without dropping.
21619 * @param {Roo.dd.DragDrop} target The drop target
21620 * @param {Event} e The event object
21621 * @param {String} id The id of the dragged element
21622 * @method afterDragOut
21624 this.afterDragOut(target, e, id);
21627 this.cachedTarget = null;
21631 * An empty function by default, but provided so that you can perform a custom action before the dragged
21632 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21633 * @param {Roo.dd.DragDrop} target The drop target
21634 * @param {Event} e The event object
21635 * @param {String} id The id of the dragged element
21636 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21638 beforeDragOut : function(target, e, id){
21643 onDragDrop : function(e, id){
21644 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21645 if(this.beforeDragDrop(target, e, id) !== false){
21646 if(target.isNotifyTarget){
21647 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21648 this.onValidDrop(target, e, id);
21650 this.onInvalidDrop(target, e, id);
21653 this.onValidDrop(target, e, id);
21656 if(this.afterDragDrop){
21658 * An empty function by default, but provided so that you can perform a custom action
21659 * after a valid drag drop has occurred by providing an implementation.
21660 * @param {Roo.dd.DragDrop} target The drop target
21661 * @param {Event} e The event object
21662 * @param {String} id The id of the dropped element
21663 * @method afterDragDrop
21665 this.afterDragDrop(target, e, id);
21668 delete this.cachedTarget;
21672 * An empty function by default, but provided so that you can perform a custom action before the dragged
21673 * item is dropped onto the target and optionally cancel the onDragDrop.
21674 * @param {Roo.dd.DragDrop} target The drop target
21675 * @param {Event} e The event object
21676 * @param {String} id The id of the dragged element
21677 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21679 beforeDragDrop : function(target, e, id){
21684 onValidDrop : function(target, e, id){
21686 if(this.afterValidDrop){
21688 * An empty function by default, but provided so that you can perform a custom action
21689 * after a valid drop has occurred by providing an implementation.
21690 * @param {Object} target The target DD
21691 * @param {Event} e The event object
21692 * @param {String} id The id of the dropped element
21693 * @method afterInvalidDrop
21695 this.afterValidDrop(target, e, id);
21700 getRepairXY : function(e, data){
21701 return this.el.getXY();
21705 onInvalidDrop : function(target, e, id){
21706 this.beforeInvalidDrop(target, e, id);
21707 if(this.cachedTarget){
21708 if(this.cachedTarget.isNotifyTarget){
21709 this.cachedTarget.notifyOut(this, e, this.dragData);
21711 this.cacheTarget = null;
21713 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21715 if(this.afterInvalidDrop){
21717 * An empty function by default, but provided so that you can perform a custom action
21718 * after an invalid drop has occurred by providing an implementation.
21719 * @param {Event} e The event object
21720 * @param {String} id The id of the dropped element
21721 * @method afterInvalidDrop
21723 this.afterInvalidDrop(e, id);
21728 afterRepair : function(){
21730 this.el.highlight(this.hlColor || "c3daf9");
21732 this.dragging = false;
21736 * An empty function by default, but provided so that you can perform a custom action after an invalid
21737 * drop has occurred.
21738 * @param {Roo.dd.DragDrop} target The drop target
21739 * @param {Event} e The event object
21740 * @param {String} id The id of the dragged element
21741 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21743 beforeInvalidDrop : function(target, e, id){
21748 handleMouseDown : function(e){
21749 if(this.dragging) {
21752 var data = this.getDragData(e);
21753 if(data && this.onBeforeDrag(data, e) !== false){
21754 this.dragData = data;
21756 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21761 * An empty function by default, but provided so that you can perform a custom action before the initial
21762 * drag event begins and optionally cancel it.
21763 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21764 * @param {Event} e The event object
21765 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21767 onBeforeDrag : function(data, e){
21772 * An empty function by default, but provided so that you can perform a custom action once the initial
21773 * drag event has begun. The drag cannot be canceled from this function.
21774 * @param {Number} x The x position of the click on the dragged object
21775 * @param {Number} y The y position of the click on the dragged object
21777 onStartDrag : Roo.emptyFn,
21779 // private - YUI override
21780 startDrag : function(x, y){
21781 this.proxy.reset();
21782 this.dragging = true;
21783 this.proxy.update("");
21784 this.onInitDrag(x, y);
21789 onInitDrag : function(x, y){
21790 var clone = this.el.dom.cloneNode(true);
21791 clone.id = Roo.id(); // prevent duplicate ids
21792 this.proxy.update(clone);
21793 this.onStartDrag(x, y);
21798 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21799 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21801 getProxy : function(){
21806 * Hides the drag source's {@link Roo.dd.StatusProxy}
21808 hideProxy : function(){
21810 this.proxy.reset(true);
21811 this.dragging = false;
21815 triggerCacheRefresh : function(){
21816 Roo.dd.DDM.refreshCache(this.groups);
21819 // private - override to prevent hiding
21820 b4EndDrag: function(e) {
21823 // private - override to prevent moving
21824 endDrag : function(e){
21825 this.onEndDrag(this.dragData, e);
21829 onEndDrag : function(data, e){
21832 // private - pin to cursor
21833 autoOffset : function(x, y) {
21834 this.setDelta(-12, -20);
21838 * Ext JS Library 1.1.1
21839 * Copyright(c) 2006-2007, Ext JS, LLC.
21841 * Originally Released Under LGPL - original licence link has changed is not relivant.
21844 * <script type="text/javascript">
21849 * @class Roo.dd.DropTarget
21850 * @extends Roo.dd.DDTarget
21851 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21852 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21854 * @param {String/HTMLElement/Element} el The container element
21855 * @param {Object} config
21857 Roo.dd.DropTarget = function(el, config){
21858 this.el = Roo.get(el);
21860 var listeners = false; ;
21861 if (config && config.listeners) {
21862 listeners= config.listeners;
21863 delete config.listeners;
21865 Roo.apply(this, config);
21867 if(this.containerScroll){
21868 Roo.dd.ScrollManager.register(this.el);
21872 * @scope Roo.dd.DropTarget
21877 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21878 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21879 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21881 * IMPORTANT : it should set this.overClass and this.dropAllowed
21883 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21884 * @param {Event} e The event
21885 * @param {Object} data An object containing arbitrary data supplied by the drag source
21891 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21892 * This method will be called on every mouse movement while the drag source is over the drop target.
21893 * This default implementation simply returns the dropAllowed config value.
21895 * IMPORTANT : it should set this.dropAllowed
21897 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21898 * @param {Event} e The event
21899 * @param {Object} data An object containing arbitrary data supplied by the drag source
21905 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21906 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21907 * overClass (if any) from the drop element.
21909 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21910 * @param {Event} e The event
21911 * @param {Object} data An object containing arbitrary data supplied by the drag source
21917 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21918 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21919 * implementation that does something to process the drop event and returns true so that the drag source's
21920 * repair action does not run.
21922 * IMPORTANT : it should set this.success
21924 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21925 * @param {Event} e The event
21926 * @param {Object} data An object containing arbitrary data supplied by the drag source
21932 Roo.dd.DropTarget.superclass.constructor.call( this,
21934 this.ddGroup || this.group,
21937 listeners : listeners || {}
21945 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21947 * @cfg {String} overClass
21948 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21951 * @cfg {String} ddGroup
21952 * The drag drop group to handle drop events for
21956 * @cfg {String} dropAllowed
21957 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21959 dropAllowed : "x-dd-drop-ok",
21961 * @cfg {String} dropNotAllowed
21962 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21964 dropNotAllowed : "x-dd-drop-nodrop",
21966 * @cfg {boolean} success
21967 * set this after drop listener..
21971 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21972 * if the drop point is valid for over/enter..
21979 isNotifyTarget : true,
21984 notifyEnter : function(dd, e, data)
21987 this.fireEvent('enter', dd, e, data);
21988 if(this.overClass){
21989 this.el.addClass(this.overClass);
21991 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21992 this.valid ? this.dropAllowed : this.dropNotAllowed
21999 notifyOver : function(dd, e, data)
22002 this.fireEvent('over', dd, e, data);
22003 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22004 this.valid ? this.dropAllowed : this.dropNotAllowed
22011 notifyOut : function(dd, e, data)
22013 this.fireEvent('out', dd, e, data);
22014 if(this.overClass){
22015 this.el.removeClass(this.overClass);
22022 notifyDrop : function(dd, e, data)
22024 this.success = false;
22025 this.fireEvent('drop', dd, e, data);
22026 return this.success;
22030 * Ext JS Library 1.1.1
22031 * Copyright(c) 2006-2007, Ext JS, LLC.
22033 * Originally Released Under LGPL - original licence link has changed is not relivant.
22036 * <script type="text/javascript">
22041 * @class Roo.dd.DragZone
22042 * @extends Roo.dd.DragSource
22043 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22044 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22046 * @param {String/HTMLElement/Element} el The container element
22047 * @param {Object} config
22049 Roo.dd.DragZone = function(el, config){
22050 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22051 if(this.containerScroll){
22052 Roo.dd.ScrollManager.register(this.el);
22056 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22058 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22059 * for auto scrolling during drag operations.
22062 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22063 * method after a failed drop (defaults to "c3daf9" - light blue)
22067 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22068 * for a valid target to drag based on the mouse down. Override this method
22069 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22070 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22071 * @param {EventObject} e The mouse down event
22072 * @return {Object} The dragData
22074 getDragData : function(e){
22075 return Roo.dd.Registry.getHandleFromEvent(e);
22079 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22080 * this.dragData.ddel
22081 * @param {Number} x The x position of the click on the dragged object
22082 * @param {Number} y The y position of the click on the dragged object
22083 * @return {Boolean} true to continue the drag, false to cancel
22085 onInitDrag : function(x, y){
22086 this.proxy.update(this.dragData.ddel.cloneNode(true));
22087 this.onStartDrag(x, y);
22092 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22094 afterRepair : function(){
22096 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22098 this.dragging = false;
22102 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22103 * the XY of this.dragData.ddel
22104 * @param {EventObject} e The mouse up event
22105 * @return {Array} The xy location (e.g. [100, 200])
22107 getRepairXY : function(e){
22108 return Roo.Element.fly(this.dragData.ddel).getXY();
22112 * Ext JS Library 1.1.1
22113 * Copyright(c) 2006-2007, Ext JS, LLC.
22115 * Originally Released Under LGPL - original licence link has changed is not relivant.
22118 * <script type="text/javascript">
22121 * @class Roo.dd.DropZone
22122 * @extends Roo.dd.DropTarget
22123 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22124 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22126 * @param {String/HTMLElement/Element} el The container element
22127 * @param {Object} config
22129 Roo.dd.DropZone = function(el, config){
22130 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22133 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22135 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22136 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22137 * provide your own custom lookup.
22138 * @param {Event} e The event
22139 * @return {Object} data The custom data
22141 getTargetFromEvent : function(e){
22142 return Roo.dd.Registry.getTargetFromEvent(e);
22146 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22147 * that it has registered. This method has no default implementation and should be overridden to provide
22148 * node-specific processing if necessary.
22149 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22150 * {@link #getTargetFromEvent} for this node)
22151 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22152 * @param {Event} e The event
22153 * @param {Object} data An object containing arbitrary data supplied by the drag source
22155 onNodeEnter : function(n, dd, e, data){
22160 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22161 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22162 * overridden to provide the proper feedback.
22163 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22164 * {@link #getTargetFromEvent} for this node)
22165 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22166 * @param {Event} e The event
22167 * @param {Object} data An object containing arbitrary data supplied by the drag source
22168 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22169 * underlying {@link Roo.dd.StatusProxy} can be updated
22171 onNodeOver : function(n, dd, e, data){
22172 return this.dropAllowed;
22176 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22177 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22178 * node-specific processing if necessary.
22179 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22180 * {@link #getTargetFromEvent} for this node)
22181 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22182 * @param {Event} e The event
22183 * @param {Object} data An object containing arbitrary data supplied by the drag source
22185 onNodeOut : function(n, dd, e, data){
22190 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22191 * the drop node. The default implementation returns false, so it should be overridden to provide the
22192 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22193 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22194 * {@link #getTargetFromEvent} for this node)
22195 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22196 * @param {Event} e The event
22197 * @param {Object} data An object containing arbitrary data supplied by the drag source
22198 * @return {Boolean} True if the drop was valid, else false
22200 onNodeDrop : function(n, dd, e, data){
22205 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22206 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22207 * it should be overridden to provide the proper feedback if necessary.
22208 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22209 * @param {Event} e The event
22210 * @param {Object} data An object containing arbitrary data supplied by the drag source
22211 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22212 * underlying {@link Roo.dd.StatusProxy} can be updated
22214 onContainerOver : function(dd, e, data){
22215 return this.dropNotAllowed;
22219 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22220 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22221 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22222 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22223 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22224 * @param {Event} e The event
22225 * @param {Object} data An object containing arbitrary data supplied by the drag source
22226 * @return {Boolean} True if the drop was valid, else false
22228 onContainerDrop : function(dd, e, data){
22233 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22234 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22235 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22236 * you should override this method and provide a custom implementation.
22237 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22238 * @param {Event} e The event
22239 * @param {Object} data An object containing arbitrary data supplied by the drag source
22240 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22241 * underlying {@link Roo.dd.StatusProxy} can be updated
22243 notifyEnter : function(dd, e, data){
22244 return this.dropNotAllowed;
22248 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22249 * This method will be called on every mouse movement while the drag source is over the drop zone.
22250 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22251 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22252 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22253 * registered node, it will call {@link #onContainerOver}.
22254 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22255 * @param {Event} e The event
22256 * @param {Object} data An object containing arbitrary data supplied by the drag source
22257 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22258 * underlying {@link Roo.dd.StatusProxy} can be updated
22260 notifyOver : function(dd, e, data){
22261 var n = this.getTargetFromEvent(e);
22262 if(!n){ // not over valid drop target
22263 if(this.lastOverNode){
22264 this.onNodeOut(this.lastOverNode, dd, e, data);
22265 this.lastOverNode = null;
22267 return this.onContainerOver(dd, e, data);
22269 if(this.lastOverNode != n){
22270 if(this.lastOverNode){
22271 this.onNodeOut(this.lastOverNode, dd, e, data);
22273 this.onNodeEnter(n, dd, e, data);
22274 this.lastOverNode = n;
22276 return this.onNodeOver(n, dd, e, data);
22280 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22281 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22282 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22283 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22284 * @param {Event} e The event
22285 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22287 notifyOut : function(dd, e, data){
22288 if(this.lastOverNode){
22289 this.onNodeOut(this.lastOverNode, dd, e, data);
22290 this.lastOverNode = null;
22295 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22296 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22297 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22298 * otherwise it will call {@link #onContainerDrop}.
22299 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22300 * @param {Event} e The event
22301 * @param {Object} data An object containing arbitrary data supplied by the drag source
22302 * @return {Boolean} True if the drop was valid, else false
22304 notifyDrop : function(dd, e, data){
22305 if(this.lastOverNode){
22306 this.onNodeOut(this.lastOverNode, dd, e, data);
22307 this.lastOverNode = null;
22309 var n = this.getTargetFromEvent(e);
22311 this.onNodeDrop(n, dd, e, data) :
22312 this.onContainerDrop(dd, e, data);
22316 triggerCacheRefresh : function(){
22317 Roo.dd.DDM.refreshCache(this.groups);
22321 * Ext JS Library 1.1.1
22322 * Copyright(c) 2006-2007, Ext JS, LLC.
22324 * Originally Released Under LGPL - original licence link has changed is not relivant.
22327 * <script type="text/javascript">
22332 * @class Roo.data.SortTypes
22334 * Defines the default sorting (casting?) comparison functions used when sorting data.
22336 Roo.data.SortTypes = {
22338 * Default sort that does nothing
22339 * @param {Mixed} s The value being converted
22340 * @return {Mixed} The comparison value
22342 none : function(s){
22347 * The regular expression used to strip tags
22351 stripTagsRE : /<\/?[^>]+>/gi,
22354 * Strips all HTML tags to sort on text only
22355 * @param {Mixed} s The value being converted
22356 * @return {String} The comparison value
22358 asText : function(s){
22359 return String(s).replace(this.stripTagsRE, "");
22363 * Strips all HTML tags to sort on text only - Case insensitive
22364 * @param {Mixed} s The value being converted
22365 * @return {String} The comparison value
22367 asUCText : function(s){
22368 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22372 * Case insensitive string
22373 * @param {Mixed} s The value being converted
22374 * @return {String} The comparison value
22376 asUCString : function(s) {
22377 return String(s).toUpperCase();
22382 * @param {Mixed} s The value being converted
22383 * @return {Number} The comparison value
22385 asDate : function(s) {
22389 if(s instanceof Date){
22390 return s.getTime();
22392 return Date.parse(String(s));
22397 * @param {Mixed} s The value being converted
22398 * @return {Float} The comparison value
22400 asFloat : function(s) {
22401 var val = parseFloat(String(s).replace(/,/g, ""));
22410 * @param {Mixed} s The value being converted
22411 * @return {Number} The comparison value
22413 asInt : function(s) {
22414 var val = parseInt(String(s).replace(/,/g, ""));
22422 * Ext JS Library 1.1.1
22423 * Copyright(c) 2006-2007, Ext JS, LLC.
22425 * Originally Released Under LGPL - original licence link has changed is not relivant.
22428 * <script type="text/javascript">
22432 * @class Roo.data.Record
22433 * Instances of this class encapsulate both record <em>definition</em> information, and record
22434 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22435 * to access Records cached in an {@link Roo.data.Store} object.<br>
22437 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22438 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22441 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22443 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22444 * {@link #create}. The parameters are the same.
22445 * @param {Array} data An associative Array of data values keyed by the field name.
22446 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22447 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22448 * not specified an integer id is generated.
22450 Roo.data.Record = function(data, id){
22451 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22456 * Generate a constructor for a specific record layout.
22457 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22458 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22459 * Each field definition object may contain the following properties: <ul>
22460 * <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,
22461 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22462 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22463 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22464 * is being used, then this is a string containing the javascript expression to reference the data relative to
22465 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22466 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22467 * this may be omitted.</p></li>
22468 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22469 * <ul><li>auto (Default, implies no conversion)</li>
22474 * <li>date</li></ul></p></li>
22475 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22476 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22477 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22478 * by the Reader into an object that will be stored in the Record. It is passed the
22479 * following parameters:<ul>
22480 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22482 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22484 * <br>usage:<br><pre><code>
22485 var TopicRecord = Roo.data.Record.create(
22486 {name: 'title', mapping: 'topic_title'},
22487 {name: 'author', mapping: 'username'},
22488 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22489 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22490 {name: 'lastPoster', mapping: 'user2'},
22491 {name: 'excerpt', mapping: 'post_text'}
22494 var myNewRecord = new TopicRecord({
22495 title: 'Do my job please',
22498 lastPost: new Date(),
22499 lastPoster: 'Animal',
22500 excerpt: 'No way dude!'
22502 myStore.add(myNewRecord);
22507 Roo.data.Record.create = function(o){
22508 var f = function(){
22509 f.superclass.constructor.apply(this, arguments);
22511 Roo.extend(f, Roo.data.Record);
22512 var p = f.prototype;
22513 p.fields = new Roo.util.MixedCollection(false, function(field){
22516 for(var i = 0, len = o.length; i < len; i++){
22517 p.fields.add(new Roo.data.Field(o[i]));
22519 f.getField = function(name){
22520 return p.fields.get(name);
22525 Roo.data.Record.AUTO_ID = 1000;
22526 Roo.data.Record.EDIT = 'edit';
22527 Roo.data.Record.REJECT = 'reject';
22528 Roo.data.Record.COMMIT = 'commit';
22530 Roo.data.Record.prototype = {
22532 * Readonly flag - true if this record has been modified.
22541 join : function(store){
22542 this.store = store;
22546 * Set the named field to the specified value.
22547 * @param {String} name The name of the field to set.
22548 * @param {Object} value The value to set the field to.
22550 set : function(name, value){
22551 if(this.data[name] == value){
22555 if(!this.modified){
22556 this.modified = {};
22558 if(typeof this.modified[name] == 'undefined'){
22559 this.modified[name] = this.data[name];
22561 this.data[name] = value;
22562 if(!this.editing && this.store){
22563 this.store.afterEdit(this);
22568 * Get the value of the named field.
22569 * @param {String} name The name of the field to get the value of.
22570 * @return {Object} The value of the field.
22572 get : function(name){
22573 return this.data[name];
22577 beginEdit : function(){
22578 this.editing = true;
22579 this.modified = {};
22583 cancelEdit : function(){
22584 this.editing = false;
22585 delete this.modified;
22589 endEdit : function(){
22590 this.editing = false;
22591 if(this.dirty && this.store){
22592 this.store.afterEdit(this);
22597 * Usually called by the {@link Roo.data.Store} which owns the Record.
22598 * Rejects all changes made to the Record since either creation, or the last commit operation.
22599 * Modified fields are reverted to their original values.
22601 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22602 * of reject operations.
22604 reject : function(){
22605 var m = this.modified;
22607 if(typeof m[n] != "function"){
22608 this.data[n] = m[n];
22611 this.dirty = false;
22612 delete this.modified;
22613 this.editing = false;
22615 this.store.afterReject(this);
22620 * Usually called by the {@link Roo.data.Store} which owns the Record.
22621 * Commits all changes made to the Record since either creation, or the last commit operation.
22623 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22624 * of commit operations.
22626 commit : function(){
22627 this.dirty = false;
22628 delete this.modified;
22629 this.editing = false;
22631 this.store.afterCommit(this);
22636 hasError : function(){
22637 return this.error != null;
22641 clearError : function(){
22646 * Creates a copy of this record.
22647 * @param {String} id (optional) A new record id if you don't want to use this record's id
22650 copy : function(newId) {
22651 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22655 * Ext JS Library 1.1.1
22656 * Copyright(c) 2006-2007, Ext JS, LLC.
22658 * Originally Released Under LGPL - original licence link has changed is not relivant.
22661 * <script type="text/javascript">
22667 * @class Roo.data.Store
22668 * @extends Roo.util.Observable
22669 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22670 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22672 * 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
22673 * has no knowledge of the format of the data returned by the Proxy.<br>
22675 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22676 * instances from the data object. These records are cached and made available through accessor functions.
22678 * Creates a new Store.
22679 * @param {Object} config A config object containing the objects needed for the Store to access data,
22680 * and read the data into Records.
22682 Roo.data.Store = function(config){
22683 this.data = new Roo.util.MixedCollection(false);
22684 this.data.getKey = function(o){
22687 this.baseParams = {};
22689 this.paramNames = {
22694 "multisort" : "_multisort"
22697 if(config && config.data){
22698 this.inlineData = config.data;
22699 delete config.data;
22702 Roo.apply(this, config);
22704 if(this.reader){ // reader passed
22705 this.reader = Roo.factory(this.reader, Roo.data);
22706 this.reader.xmodule = this.xmodule || false;
22707 if(!this.recordType){
22708 this.recordType = this.reader.recordType;
22710 if(this.reader.onMetaChange){
22711 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22715 if(this.recordType){
22716 this.fields = this.recordType.prototype.fields;
22718 this.modified = [];
22722 * @event datachanged
22723 * Fires when the data cache has changed, and a widget which is using this Store
22724 * as a Record cache should refresh its view.
22725 * @param {Store} this
22727 datachanged : true,
22729 * @event metachange
22730 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22731 * @param {Store} this
22732 * @param {Object} meta The JSON metadata
22737 * Fires when Records have been added to the Store
22738 * @param {Store} this
22739 * @param {Roo.data.Record[]} records The array of Records added
22740 * @param {Number} index The index at which the record(s) were added
22745 * Fires when a Record has been removed from the Store
22746 * @param {Store} this
22747 * @param {Roo.data.Record} record The Record that was removed
22748 * @param {Number} index The index at which the record was removed
22753 * Fires when a Record has been updated
22754 * @param {Store} this
22755 * @param {Roo.data.Record} record The Record that was updated
22756 * @param {String} operation The update operation being performed. Value may be one of:
22758 Roo.data.Record.EDIT
22759 Roo.data.Record.REJECT
22760 Roo.data.Record.COMMIT
22766 * Fires when the data cache has been cleared.
22767 * @param {Store} this
22771 * @event beforeload
22772 * Fires before a request is made for a new data object. If the beforeload handler returns false
22773 * the load action will be canceled.
22774 * @param {Store} this
22775 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22779 * @event beforeloadadd
22780 * Fires after a new set of Records has been loaded.
22781 * @param {Store} this
22782 * @param {Roo.data.Record[]} records The Records that were loaded
22783 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22785 beforeloadadd : true,
22788 * Fires after a new set of Records has been loaded, before they are added to the store.
22789 * @param {Store} this
22790 * @param {Roo.data.Record[]} records The Records that were loaded
22791 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22792 * @params {Object} return from reader
22796 * @event loadexception
22797 * Fires if an exception occurs in the Proxy during loading.
22798 * Called with the signature of the Proxy's "loadexception" event.
22799 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22802 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22803 * @param {Object} load options
22804 * @param {Object} jsonData from your request (normally this contains the Exception)
22806 loadexception : true
22810 this.proxy = Roo.factory(this.proxy, Roo.data);
22811 this.proxy.xmodule = this.xmodule || false;
22812 this.relayEvents(this.proxy, ["loadexception"]);
22814 this.sortToggle = {};
22815 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22817 Roo.data.Store.superclass.constructor.call(this);
22819 if(this.inlineData){
22820 this.loadData(this.inlineData);
22821 delete this.inlineData;
22825 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22827 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22828 * without a remote query - used by combo/forms at present.
22832 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22835 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22838 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22839 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22842 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22843 * on any HTTP request
22846 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22849 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22853 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22854 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22856 remoteSort : false,
22859 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22860 * loaded or when a record is removed. (defaults to false).
22862 pruneModifiedRecords : false,
22865 lastOptions : null,
22868 * Add Records to the Store and fires the add event.
22869 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22871 add : function(records){
22872 records = [].concat(records);
22873 for(var i = 0, len = records.length; i < len; i++){
22874 records[i].join(this);
22876 var index = this.data.length;
22877 this.data.addAll(records);
22878 this.fireEvent("add", this, records, index);
22882 * Remove a Record from the Store and fires the remove event.
22883 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
22885 remove : function(record){
22886 var index = this.data.indexOf(record);
22887 this.data.removeAt(index);
22888 if(this.pruneModifiedRecords){
22889 this.modified.remove(record);
22891 this.fireEvent("remove", this, record, index);
22895 * Remove all Records from the Store and fires the clear event.
22897 removeAll : function(){
22899 if(this.pruneModifiedRecords){
22900 this.modified = [];
22902 this.fireEvent("clear", this);
22906 * Inserts Records to the Store at the given index and fires the add event.
22907 * @param {Number} index The start index at which to insert the passed Records.
22908 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22910 insert : function(index, records){
22911 records = [].concat(records);
22912 for(var i = 0, len = records.length; i < len; i++){
22913 this.data.insert(index, records[i]);
22914 records[i].join(this);
22916 this.fireEvent("add", this, records, index);
22920 * Get the index within the cache of the passed Record.
22921 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
22922 * @return {Number} The index of the passed Record. Returns -1 if not found.
22924 indexOf : function(record){
22925 return this.data.indexOf(record);
22929 * Get the index within the cache of the Record with the passed id.
22930 * @param {String} id The id of the Record to find.
22931 * @return {Number} The index of the Record. Returns -1 if not found.
22933 indexOfId : function(id){
22934 return this.data.indexOfKey(id);
22938 * Get the Record with the specified id.
22939 * @param {String} id The id of the Record to find.
22940 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
22942 getById : function(id){
22943 return this.data.key(id);
22947 * Get the Record at the specified index.
22948 * @param {Number} index The index of the Record to find.
22949 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
22951 getAt : function(index){
22952 return this.data.itemAt(index);
22956 * Returns a range of Records between specified indices.
22957 * @param {Number} startIndex (optional) The starting index (defaults to 0)
22958 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
22959 * @return {Roo.data.Record[]} An array of Records
22961 getRange : function(start, end){
22962 return this.data.getRange(start, end);
22966 storeOptions : function(o){
22967 o = Roo.apply({}, o);
22970 this.lastOptions = o;
22974 * Loads the Record cache from the configured Proxy using the configured Reader.
22976 * If using remote paging, then the first load call must specify the <em>start</em>
22977 * and <em>limit</em> properties in the options.params property to establish the initial
22978 * position within the dataset, and the number of Records to cache on each read from the Proxy.
22980 * <strong>It is important to note that for remote data sources, loading is asynchronous,
22981 * and this call will return before the new data has been loaded. Perform any post-processing
22982 * in a callback function, or in a "load" event handler.</strong>
22984 * @param {Object} options An object containing properties which control loading options:<ul>
22985 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
22986 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
22987 * passed the following arguments:<ul>
22988 * <li>r : Roo.data.Record[]</li>
22989 * <li>options: Options object from the load call</li>
22990 * <li>success: Boolean success indicator</li></ul></li>
22991 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
22992 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
22995 load : function(options){
22996 options = options || {};
22997 if(this.fireEvent("beforeload", this, options) !== false){
22998 this.storeOptions(options);
22999 var p = Roo.apply(options.params || {}, this.baseParams);
23000 // if meta was not loaded from remote source.. try requesting it.
23001 if (!this.reader.metaFromRemote) {
23002 p._requestMeta = 1;
23004 if(this.sortInfo && this.remoteSort){
23005 var pn = this.paramNames;
23006 p[pn["sort"]] = this.sortInfo.field;
23007 p[pn["dir"]] = this.sortInfo.direction;
23009 if (this.multiSort) {
23010 var pn = this.paramNames;
23011 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23014 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23019 * Reloads the Record cache from the configured Proxy using the configured Reader and
23020 * the options from the last load operation performed.
23021 * @param {Object} options (optional) An object containing properties which may override the options
23022 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23023 * the most recently used options are reused).
23025 reload : function(options){
23026 this.load(Roo.applyIf(options||{}, this.lastOptions));
23030 // Called as a callback by the Reader during a load operation.
23031 loadRecords : function(o, options, success){
23032 if(!o || success === false){
23033 if(success !== false){
23034 this.fireEvent("load", this, [], options, o);
23036 if(options.callback){
23037 options.callback.call(options.scope || this, [], options, false);
23041 // if data returned failure - throw an exception.
23042 if (o.success === false) {
23043 // show a message if no listener is registered.
23044 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23045 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23047 // loadmask wil be hooked into this..
23048 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23051 var r = o.records, t = o.totalRecords || r.length;
23053 this.fireEvent("beforeloadadd", this, r, options, o);
23055 if(!options || options.add !== true){
23056 if(this.pruneModifiedRecords){
23057 this.modified = [];
23059 for(var i = 0, len = r.length; i < len; i++){
23063 this.data = this.snapshot;
23064 delete this.snapshot;
23067 this.data.addAll(r);
23068 this.totalLength = t;
23070 this.fireEvent("datachanged", this);
23072 this.totalLength = Math.max(t, this.data.length+r.length);
23075 this.fireEvent("load", this, r, options, o);
23076 if(options.callback){
23077 options.callback.call(options.scope || this, r, options, true);
23083 * Loads data from a passed data block. A Reader which understands the format of the data
23084 * must have been configured in the constructor.
23085 * @param {Object} data The data block from which to read the Records. The format of the data expected
23086 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23087 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23089 loadData : function(o, append){
23090 var r = this.reader.readRecords(o);
23091 this.loadRecords(r, {add: append}, true);
23095 * Gets the number of cached records.
23097 * <em>If using paging, this may not be the total size of the dataset. If the data object
23098 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23099 * the data set size</em>
23101 getCount : function(){
23102 return this.data.length || 0;
23106 * Gets the total number of records in the dataset as returned by the server.
23108 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23109 * the dataset size</em>
23111 getTotalCount : function(){
23112 return this.totalLength || 0;
23116 * Returns the sort state of the Store as an object with two properties:
23118 field {String} The name of the field by which the Records are sorted
23119 direction {String} The sort order, "ASC" or "DESC"
23122 getSortState : function(){
23123 return this.sortInfo;
23127 applySort : function(){
23128 if(this.sortInfo && !this.remoteSort){
23129 var s = this.sortInfo, f = s.field;
23130 var st = this.fields.get(f).sortType;
23131 var fn = function(r1, r2){
23132 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23133 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23135 this.data.sort(s.direction, fn);
23136 if(this.snapshot && this.snapshot != this.data){
23137 this.snapshot.sort(s.direction, fn);
23143 * Sets the default sort column and order to be used by the next load operation.
23144 * @param {String} fieldName The name of the field to sort by.
23145 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23147 setDefaultSort : function(field, dir){
23148 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23152 * Sort the Records.
23153 * If remote sorting is used, the sort is performed on the server, and the cache is
23154 * reloaded. If local sorting is used, the cache is sorted internally.
23155 * @param {String} fieldName The name of the field to sort by.
23156 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23158 sort : function(fieldName, dir){
23159 var f = this.fields.get(fieldName);
23161 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23163 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23164 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23169 this.sortToggle[f.name] = dir;
23170 this.sortInfo = {field: f.name, direction: dir};
23171 if(!this.remoteSort){
23173 this.fireEvent("datachanged", this);
23175 this.load(this.lastOptions);
23180 * Calls the specified function for each of the Records in the cache.
23181 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23182 * Returning <em>false</em> aborts and exits the iteration.
23183 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23185 each : function(fn, scope){
23186 this.data.each(fn, scope);
23190 * Gets all records modified since the last commit. Modified records are persisted across load operations
23191 * (e.g., during paging).
23192 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23194 getModifiedRecords : function(){
23195 return this.modified;
23199 createFilterFn : function(property, value, anyMatch){
23200 if(!value.exec){ // not a regex
23201 value = String(value);
23202 if(value.length == 0){
23205 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23207 return function(r){
23208 return value.test(r.data[property]);
23213 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23214 * @param {String} property A field on your records
23215 * @param {Number} start The record index to start at (defaults to 0)
23216 * @param {Number} end The last record index to include (defaults to length - 1)
23217 * @return {Number} The sum
23219 sum : function(property, start, end){
23220 var rs = this.data.items, v = 0;
23221 start = start || 0;
23222 end = (end || end === 0) ? end : rs.length-1;
23224 for(var i = start; i <= end; i++){
23225 v += (rs[i].data[property] || 0);
23231 * Filter the records by a specified property.
23232 * @param {String} field A field on your records
23233 * @param {String/RegExp} value Either a string that the field
23234 * should start with or a RegExp to test against the field
23235 * @param {Boolean} anyMatch True to match any part not just the beginning
23237 filter : function(property, value, anyMatch){
23238 var fn = this.createFilterFn(property, value, anyMatch);
23239 return fn ? this.filterBy(fn) : this.clearFilter();
23243 * Filter by a function. The specified function will be called with each
23244 * record in this data source. If the function returns true the record is included,
23245 * otherwise it is filtered.
23246 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23247 * @param {Object} scope (optional) The scope of the function (defaults to this)
23249 filterBy : function(fn, scope){
23250 this.snapshot = this.snapshot || this.data;
23251 this.data = this.queryBy(fn, scope||this);
23252 this.fireEvent("datachanged", this);
23256 * Query the records by a specified property.
23257 * @param {String} field A field on your records
23258 * @param {String/RegExp} value Either a string that the field
23259 * should start with or a RegExp to test against the field
23260 * @param {Boolean} anyMatch True to match any part not just the beginning
23261 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23263 query : function(property, value, anyMatch){
23264 var fn = this.createFilterFn(property, value, anyMatch);
23265 return fn ? this.queryBy(fn) : this.data.clone();
23269 * Query by a function. The specified function will be called with each
23270 * record in this data source. If the function returns true the record is included
23272 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23273 * @param {Object} scope (optional) The scope of the function (defaults to this)
23274 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23276 queryBy : function(fn, scope){
23277 var data = this.snapshot || this.data;
23278 return data.filterBy(fn, scope||this);
23282 * Collects unique values for a particular dataIndex from this store.
23283 * @param {String} dataIndex The property to collect
23284 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23285 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23286 * @return {Array} An array of the unique values
23288 collect : function(dataIndex, allowNull, bypassFilter){
23289 var d = (bypassFilter === true && this.snapshot) ?
23290 this.snapshot.items : this.data.items;
23291 var v, sv, r = [], l = {};
23292 for(var i = 0, len = d.length; i < len; i++){
23293 v = d[i].data[dataIndex];
23295 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23304 * Revert to a view of the Record cache with no filtering applied.
23305 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23307 clearFilter : function(suppressEvent){
23308 if(this.snapshot && this.snapshot != this.data){
23309 this.data = this.snapshot;
23310 delete this.snapshot;
23311 if(suppressEvent !== true){
23312 this.fireEvent("datachanged", this);
23318 afterEdit : function(record){
23319 if(this.modified.indexOf(record) == -1){
23320 this.modified.push(record);
23322 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23326 afterReject : function(record){
23327 this.modified.remove(record);
23328 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23332 afterCommit : function(record){
23333 this.modified.remove(record);
23334 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23338 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23339 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23341 commitChanges : function(){
23342 var m = this.modified.slice(0);
23343 this.modified = [];
23344 for(var i = 0, len = m.length; i < len; i++){
23350 * Cancel outstanding changes on all changed records.
23352 rejectChanges : function(){
23353 var m = this.modified.slice(0);
23354 this.modified = [];
23355 for(var i = 0, len = m.length; i < len; i++){
23360 onMetaChange : function(meta, rtype, o){
23361 this.recordType = rtype;
23362 this.fields = rtype.prototype.fields;
23363 delete this.snapshot;
23364 this.sortInfo = meta.sortInfo || this.sortInfo;
23365 this.modified = [];
23366 this.fireEvent('metachange', this, this.reader.meta);
23369 moveIndex : function(data, type)
23371 var index = this.indexOf(data);
23373 var newIndex = index + type;
23377 this.insert(newIndex, data);
23382 * Ext JS Library 1.1.1
23383 * Copyright(c) 2006-2007, Ext JS, LLC.
23385 * Originally Released Under LGPL - original licence link has changed is not relivant.
23388 * <script type="text/javascript">
23392 * @class Roo.data.SimpleStore
23393 * @extends Roo.data.Store
23394 * Small helper class to make creating Stores from Array data easier.
23395 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23396 * @cfg {Array} fields An array of field definition objects, or field name strings.
23397 * @cfg {Array} data The multi-dimensional array of data
23399 * @param {Object} config
23401 Roo.data.SimpleStore = function(config){
23402 Roo.data.SimpleStore.superclass.constructor.call(this, {
23404 reader: new Roo.data.ArrayReader({
23407 Roo.data.Record.create(config.fields)
23409 proxy : new Roo.data.MemoryProxy(config.data)
23413 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23415 * Ext JS Library 1.1.1
23416 * Copyright(c) 2006-2007, Ext JS, LLC.
23418 * Originally Released Under LGPL - original licence link has changed is not relivant.
23421 * <script type="text/javascript">
23426 * @extends Roo.data.Store
23427 * @class Roo.data.JsonStore
23428 * Small helper class to make creating Stores for JSON data easier. <br/>
23430 var store = new Roo.data.JsonStore({
23431 url: 'get-images.php',
23433 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23436 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23437 * JsonReader and HttpProxy (unless inline data is provided).</b>
23438 * @cfg {Array} fields An array of field definition objects, or field name strings.
23440 * @param {Object} config
23442 Roo.data.JsonStore = function(c){
23443 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23444 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23445 reader: new Roo.data.JsonReader(c, c.fields)
23448 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23450 * Ext JS Library 1.1.1
23451 * Copyright(c) 2006-2007, Ext JS, LLC.
23453 * Originally Released Under LGPL - original licence link has changed is not relivant.
23456 * <script type="text/javascript">
23460 Roo.data.Field = function(config){
23461 if(typeof config == "string"){
23462 config = {name: config};
23464 Roo.apply(this, config);
23467 this.type = "auto";
23470 var st = Roo.data.SortTypes;
23471 // named sortTypes are supported, here we look them up
23472 if(typeof this.sortType == "string"){
23473 this.sortType = st[this.sortType];
23476 // set default sortType for strings and dates
23477 if(!this.sortType){
23480 this.sortType = st.asUCString;
23483 this.sortType = st.asDate;
23486 this.sortType = st.none;
23491 var stripRe = /[\$,%]/g;
23493 // prebuilt conversion function for this field, instead of
23494 // switching every time we're reading a value
23496 var cv, dateFormat = this.dateFormat;
23501 cv = function(v){ return v; };
23504 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23508 return v !== undefined && v !== null && v !== '' ?
23509 parseInt(String(v).replace(stripRe, ""), 10) : '';
23514 return v !== undefined && v !== null && v !== '' ?
23515 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23520 cv = function(v){ return v === true || v === "true" || v == 1; };
23527 if(v instanceof Date){
23531 if(dateFormat == "timestamp"){
23532 return new Date(v*1000);
23534 return Date.parseDate(v, dateFormat);
23536 var parsed = Date.parse(v);
23537 return parsed ? new Date(parsed) : null;
23546 Roo.data.Field.prototype = {
23554 * Ext JS Library 1.1.1
23555 * Copyright(c) 2006-2007, Ext JS, LLC.
23557 * Originally Released Under LGPL - original licence link has changed is not relivant.
23560 * <script type="text/javascript">
23563 // Base class for reading structured data from a data source. This class is intended to be
23564 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23567 * @class Roo.data.DataReader
23568 * Base class for reading structured data from a data source. This class is intended to be
23569 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23572 Roo.data.DataReader = function(meta, recordType){
23576 this.recordType = recordType instanceof Array ?
23577 Roo.data.Record.create(recordType) : recordType;
23580 Roo.data.DataReader.prototype = {
23582 * Create an empty record
23583 * @param {Object} data (optional) - overlay some values
23584 * @return {Roo.data.Record} record created.
23586 newRow : function(d) {
23588 this.recordType.prototype.fields.each(function(c) {
23590 case 'int' : da[c.name] = 0; break;
23591 case 'date' : da[c.name] = new Date(); break;
23592 case 'float' : da[c.name] = 0.0; break;
23593 case 'boolean' : da[c.name] = false; break;
23594 default : da[c.name] = ""; break;
23598 return new this.recordType(Roo.apply(da, d));
23603 * Ext JS Library 1.1.1
23604 * Copyright(c) 2006-2007, Ext JS, LLC.
23606 * Originally Released Under LGPL - original licence link has changed is not relivant.
23609 * <script type="text/javascript">
23613 * @class Roo.data.DataProxy
23614 * @extends Roo.data.Observable
23615 * This class is an abstract base class for implementations which provide retrieval of
23616 * unformatted data objects.<br>
23618 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23619 * (of the appropriate type which knows how to parse the data object) to provide a block of
23620 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23622 * Custom implementations must implement the load method as described in
23623 * {@link Roo.data.HttpProxy#load}.
23625 Roo.data.DataProxy = function(){
23628 * @event beforeload
23629 * Fires before a network request is made to retrieve a data object.
23630 * @param {Object} This DataProxy object.
23631 * @param {Object} params The params parameter to the load function.
23636 * Fires before the load method's callback is called.
23637 * @param {Object} This DataProxy object.
23638 * @param {Object} o The data object.
23639 * @param {Object} arg The callback argument object passed to the load function.
23643 * @event loadexception
23644 * Fires if an Exception occurs during data retrieval.
23645 * @param {Object} This DataProxy object.
23646 * @param {Object} o The data object.
23647 * @param {Object} arg The callback argument object passed to the load function.
23648 * @param {Object} e The Exception.
23650 loadexception : true
23652 Roo.data.DataProxy.superclass.constructor.call(this);
23655 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23658 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23662 * Ext JS Library 1.1.1
23663 * Copyright(c) 2006-2007, Ext JS, LLC.
23665 * Originally Released Under LGPL - original licence link has changed is not relivant.
23668 * <script type="text/javascript">
23671 * @class Roo.data.MemoryProxy
23672 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23673 * to the Reader when its load method is called.
23675 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23677 Roo.data.MemoryProxy = function(data){
23681 Roo.data.MemoryProxy.superclass.constructor.call(this);
23685 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23688 * Load data from the requested source (in this case an in-memory
23689 * data object passed to the constructor), read the data object into
23690 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23691 * process that block using the passed callback.
23692 * @param {Object} params This parameter is not used by the MemoryProxy class.
23693 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23694 * object into a block of Roo.data.Records.
23695 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23696 * The function must be passed <ul>
23697 * <li>The Record block object</li>
23698 * <li>The "arg" argument from the load function</li>
23699 * <li>A boolean success indicator</li>
23701 * @param {Object} scope The scope in which to call the callback
23702 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23704 load : function(params, reader, callback, scope, arg){
23705 params = params || {};
23708 result = reader.readRecords(this.data);
23710 this.fireEvent("loadexception", this, arg, null, e);
23711 callback.call(scope, null, arg, false);
23714 callback.call(scope, result, arg, true);
23718 update : function(params, records){
23723 * Ext JS Library 1.1.1
23724 * Copyright(c) 2006-2007, Ext JS, LLC.
23726 * Originally Released Under LGPL - original licence link has changed is not relivant.
23729 * <script type="text/javascript">
23732 * @class Roo.data.HttpProxy
23733 * @extends Roo.data.DataProxy
23734 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23735 * configured to reference a certain URL.<br><br>
23737 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23738 * from which the running page was served.<br><br>
23740 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23742 * Be aware that to enable the browser to parse an XML document, the server must set
23743 * the Content-Type header in the HTTP response to "text/xml".
23745 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23746 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23747 * will be used to make the request.
23749 Roo.data.HttpProxy = function(conn){
23750 Roo.data.HttpProxy.superclass.constructor.call(this);
23751 // is conn a conn config or a real conn?
23753 this.useAjax = !conn || !conn.events;
23757 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23758 // thse are take from connection...
23761 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23764 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23765 * extra parameters to each request made by this object. (defaults to undefined)
23768 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23769 * to each request made by this object. (defaults to undefined)
23772 * @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)
23775 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23778 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23784 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23788 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23789 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23790 * a finer-grained basis than the DataProxy events.
23792 getConnection : function(){
23793 return this.useAjax ? Roo.Ajax : this.conn;
23797 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23798 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23799 * process that block using the passed callback.
23800 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23801 * for the request to the remote server.
23802 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23803 * object into a block of Roo.data.Records.
23804 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23805 * The function must be passed <ul>
23806 * <li>The Record block object</li>
23807 * <li>The "arg" argument from the load function</li>
23808 * <li>A boolean success indicator</li>
23810 * @param {Object} scope The scope in which to call the callback
23811 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23813 load : function(params, reader, callback, scope, arg){
23814 if(this.fireEvent("beforeload", this, params) !== false){
23816 params : params || {},
23818 callback : callback,
23823 callback : this.loadResponse,
23827 Roo.applyIf(o, this.conn);
23828 if(this.activeRequest){
23829 Roo.Ajax.abort(this.activeRequest);
23831 this.activeRequest = Roo.Ajax.request(o);
23833 this.conn.request(o);
23836 callback.call(scope||this, null, arg, false);
23841 loadResponse : function(o, success, response){
23842 delete this.activeRequest;
23844 this.fireEvent("loadexception", this, o, response);
23845 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23850 result = o.reader.read(response);
23852 this.fireEvent("loadexception", this, o, response, e);
23853 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23857 this.fireEvent("load", this, o, o.request.arg);
23858 o.request.callback.call(o.request.scope, result, o.request.arg, true);
23862 update : function(dataSet){
23867 updateResponse : function(dataSet){
23872 * Ext JS Library 1.1.1
23873 * Copyright(c) 2006-2007, Ext JS, LLC.
23875 * Originally Released Under LGPL - original licence link has changed is not relivant.
23878 * <script type="text/javascript">
23882 * @class Roo.data.ScriptTagProxy
23883 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
23884 * other than the originating domain of the running page.<br><br>
23886 * <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
23887 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
23889 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
23890 * source code that is used as the source inside a <script> tag.<br><br>
23892 * In order for the browser to process the returned data, the server must wrap the data object
23893 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
23894 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
23895 * depending on whether the callback name was passed:
23898 boolean scriptTag = false;
23899 String cb = request.getParameter("callback");
23902 response.setContentType("text/javascript");
23904 response.setContentType("application/x-json");
23906 Writer out = response.getWriter();
23908 out.write(cb + "(");
23910 out.print(dataBlock.toJsonString());
23917 * @param {Object} config A configuration object.
23919 Roo.data.ScriptTagProxy = function(config){
23920 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
23921 Roo.apply(this, config);
23922 this.head = document.getElementsByTagName("head")[0];
23925 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
23927 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
23929 * @cfg {String} url The URL from which to request the data object.
23932 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
23936 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
23937 * the server the name of the callback function set up by the load call to process the returned data object.
23938 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
23939 * javascript output which calls this named function passing the data object as its only parameter.
23941 callbackParam : "callback",
23943 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
23944 * name to the request.
23949 * Load data from the configured URL, read the data object into
23950 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23951 * process that block using the passed callback.
23952 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23953 * for the request to the remote server.
23954 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23955 * object into a block of Roo.data.Records.
23956 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23957 * The function must be passed <ul>
23958 * <li>The Record block object</li>
23959 * <li>The "arg" argument from the load function</li>
23960 * <li>A boolean success indicator</li>
23962 * @param {Object} scope The scope in which to call the callback
23963 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23965 load : function(params, reader, callback, scope, arg){
23966 if(this.fireEvent("beforeload", this, params) !== false){
23968 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
23970 var url = this.url;
23971 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
23973 url += "&_dc=" + (new Date().getTime());
23975 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
23978 cb : "stcCallback"+transId,
23979 scriptId : "stcScript"+transId,
23983 callback : callback,
23989 window[trans.cb] = function(o){
23990 conn.handleResponse(o, trans);
23993 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
23995 if(this.autoAbort !== false){
23999 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24001 var script = document.createElement("script");
24002 script.setAttribute("src", url);
24003 script.setAttribute("type", "text/javascript");
24004 script.setAttribute("id", trans.scriptId);
24005 this.head.appendChild(script);
24007 this.trans = trans;
24009 callback.call(scope||this, null, arg, false);
24014 isLoading : function(){
24015 return this.trans ? true : false;
24019 * Abort the current server request.
24021 abort : function(){
24022 if(this.isLoading()){
24023 this.destroyTrans(this.trans);
24028 destroyTrans : function(trans, isLoaded){
24029 this.head.removeChild(document.getElementById(trans.scriptId));
24030 clearTimeout(trans.timeoutId);
24032 window[trans.cb] = undefined;
24034 delete window[trans.cb];
24037 // if hasn't been loaded, wait for load to remove it to prevent script error
24038 window[trans.cb] = function(){
24039 window[trans.cb] = undefined;
24041 delete window[trans.cb];
24048 handleResponse : function(o, trans){
24049 this.trans = false;
24050 this.destroyTrans(trans, true);
24053 result = trans.reader.readRecords(o);
24055 this.fireEvent("loadexception", this, o, trans.arg, e);
24056 trans.callback.call(trans.scope||window, null, trans.arg, false);
24059 this.fireEvent("load", this, o, trans.arg);
24060 trans.callback.call(trans.scope||window, result, trans.arg, true);
24064 handleFailure : function(trans){
24065 this.trans = false;
24066 this.destroyTrans(trans, false);
24067 this.fireEvent("loadexception", this, null, trans.arg);
24068 trans.callback.call(trans.scope||window, null, trans.arg, false);
24072 * Ext JS Library 1.1.1
24073 * Copyright(c) 2006-2007, Ext JS, LLC.
24075 * Originally Released Under LGPL - original licence link has changed is not relivant.
24078 * <script type="text/javascript">
24082 * @class Roo.data.JsonReader
24083 * @extends Roo.data.DataReader
24084 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24085 * based on mappings in a provided Roo.data.Record constructor.
24087 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24088 * in the reply previously.
24093 var RecordDef = Roo.data.Record.create([
24094 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24095 {name: 'occupation'} // This field will use "occupation" as the mapping.
24097 var myReader = new Roo.data.JsonReader({
24098 totalProperty: "results", // The property which contains the total dataset size (optional)
24099 root: "rows", // The property which contains an Array of row objects
24100 id: "id" // The property within each row object that provides an ID for the record (optional)
24104 * This would consume a JSON file like this:
24106 { 'results': 2, 'rows': [
24107 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24108 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24111 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24112 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24113 * paged from the remote server.
24114 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24115 * @cfg {String} root name of the property which contains the Array of row objects.
24116 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24117 * @cfg {Array} fields Array of field definition objects
24119 * Create a new JsonReader
24120 * @param {Object} meta Metadata configuration options
24121 * @param {Object} recordType Either an Array of field definition objects,
24122 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24124 Roo.data.JsonReader = function(meta, recordType){
24127 // set some defaults:
24128 Roo.applyIf(meta, {
24129 totalProperty: 'total',
24130 successProperty : 'success',
24135 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24137 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24140 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24141 * Used by Store query builder to append _requestMeta to params.
24144 metaFromRemote : false,
24146 * This method is only used by a DataProxy which has retrieved data from a remote server.
24147 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24148 * @return {Object} data A data block which is used by an Roo.data.Store object as
24149 * a cache of Roo.data.Records.
24151 read : function(response){
24152 var json = response.responseText;
24154 var o = /* eval:var:o */ eval("("+json+")");
24156 throw {message: "JsonReader.read: Json object not found"};
24162 this.metaFromRemote = true;
24163 this.meta = o.metaData;
24164 this.recordType = Roo.data.Record.create(o.metaData.fields);
24165 this.onMetaChange(this.meta, this.recordType, o);
24167 return this.readRecords(o);
24170 // private function a store will implement
24171 onMetaChange : function(meta, recordType, o){
24178 simpleAccess: function(obj, subsc) {
24185 getJsonAccessor: function(){
24187 return function(expr) {
24189 return(re.test(expr))
24190 ? new Function("obj", "return obj." + expr)
24195 return Roo.emptyFn;
24200 * Create a data block containing Roo.data.Records from an XML document.
24201 * @param {Object} o An object which contains an Array of row objects in the property specified
24202 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24203 * which contains the total size of the dataset.
24204 * @return {Object} data A data block which is used by an Roo.data.Store object as
24205 * a cache of Roo.data.Records.
24207 readRecords : function(o){
24209 * After any data loads, the raw JSON data is available for further custom processing.
24213 var s = this.meta, Record = this.recordType,
24214 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24216 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24218 if(s.totalProperty) {
24219 this.getTotal = this.getJsonAccessor(s.totalProperty);
24221 if(s.successProperty) {
24222 this.getSuccess = this.getJsonAccessor(s.successProperty);
24224 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24226 var g = this.getJsonAccessor(s.id);
24227 this.getId = function(rec) {
24229 return (r === undefined || r === "") ? null : r;
24232 this.getId = function(){return null;};
24235 for(var jj = 0; jj < fl; jj++){
24237 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24238 this.ef[jj] = this.getJsonAccessor(map);
24242 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24243 if(s.totalProperty){
24244 var vt = parseInt(this.getTotal(o), 10);
24249 if(s.successProperty){
24250 var vs = this.getSuccess(o);
24251 if(vs === false || vs === 'false'){
24256 for(var i = 0; i < c; i++){
24259 var id = this.getId(n);
24260 for(var j = 0; j < fl; j++){
24262 var v = this.ef[j](n);
24264 Roo.log('missing convert for ' + f.name);
24268 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24270 var record = new Record(values, id);
24272 records[i] = record;
24278 totalRecords : totalRecords
24283 * Ext JS Library 1.1.1
24284 * Copyright(c) 2006-2007, Ext JS, LLC.
24286 * Originally Released Under LGPL - original licence link has changed is not relivant.
24289 * <script type="text/javascript">
24293 * @class Roo.data.XmlReader
24294 * @extends Roo.data.DataReader
24295 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24296 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24298 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24299 * header in the HTTP response must be set to "text/xml".</em>
24303 var RecordDef = Roo.data.Record.create([
24304 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24305 {name: 'occupation'} // This field will use "occupation" as the mapping.
24307 var myReader = new Roo.data.XmlReader({
24308 totalRecords: "results", // The element which contains the total dataset size (optional)
24309 record: "row", // The repeated element which contains row information
24310 id: "id" // The element within the row that provides an ID for the record (optional)
24314 * This would consume an XML file like this:
24318 <results>2</results>
24321 <name>Bill</name>
24322 <occupation>Gardener</occupation>
24326 <name>Ben</name>
24327 <occupation>Horticulturalist</occupation>
24331 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24332 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24333 * paged from the remote server.
24334 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24335 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24336 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24337 * a record identifier value.
24339 * Create a new XmlReader
24340 * @param {Object} meta Metadata configuration options
24341 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24342 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24343 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24345 Roo.data.XmlReader = function(meta, recordType){
24347 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24349 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24351 * This method is only used by a DataProxy which has retrieved data from a remote server.
24352 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24353 * to contain a method called 'responseXML' that returns an XML document object.
24354 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24355 * a cache of Roo.data.Records.
24357 read : function(response){
24358 var doc = response.responseXML;
24360 throw {message: "XmlReader.read: XML Document not available"};
24362 return this.readRecords(doc);
24366 * Create a data block containing Roo.data.Records from an XML document.
24367 * @param {Object} doc A parsed XML document.
24368 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24369 * a cache of Roo.data.Records.
24371 readRecords : function(doc){
24373 * After any data loads/reads, the raw XML Document is available for further custom processing.
24374 * @type XMLDocument
24376 this.xmlData = doc;
24377 var root = doc.documentElement || doc;
24378 var q = Roo.DomQuery;
24379 var recordType = this.recordType, fields = recordType.prototype.fields;
24380 var sid = this.meta.id;
24381 var totalRecords = 0, success = true;
24382 if(this.meta.totalRecords){
24383 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24386 if(this.meta.success){
24387 var sv = q.selectValue(this.meta.success, root, true);
24388 success = sv !== false && sv !== 'false';
24391 var ns = q.select(this.meta.record, root);
24392 for(var i = 0, len = ns.length; i < len; i++) {
24395 var id = sid ? q.selectValue(sid, n) : undefined;
24396 for(var j = 0, jlen = fields.length; j < jlen; j++){
24397 var f = fields.items[j];
24398 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24400 values[f.name] = v;
24402 var record = new recordType(values, id);
24404 records[records.length] = record;
24410 totalRecords : totalRecords || records.length
24415 * Ext JS Library 1.1.1
24416 * Copyright(c) 2006-2007, Ext JS, LLC.
24418 * Originally Released Under LGPL - original licence link has changed is not relivant.
24421 * <script type="text/javascript">
24425 * @class Roo.data.ArrayReader
24426 * @extends Roo.data.DataReader
24427 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24428 * Each element of that Array represents a row of data fields. The
24429 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24430 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24434 var RecordDef = Roo.data.Record.create([
24435 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24436 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24438 var myReader = new Roo.data.ArrayReader({
24439 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24443 * This would consume an Array like this:
24445 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24447 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24449 * Create a new JsonReader
24450 * @param {Object} meta Metadata configuration options.
24451 * @param {Object} recordType Either an Array of field definition objects
24452 * as specified to {@link Roo.data.Record#create},
24453 * or an {@link Roo.data.Record} object
24454 * created using {@link Roo.data.Record#create}.
24456 Roo.data.ArrayReader = function(meta, recordType){
24457 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24460 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24462 * Create a data block containing Roo.data.Records from an XML document.
24463 * @param {Object} o An Array of row objects which represents the dataset.
24464 * @return {Object} data A data block which is used by an Roo.data.Store object as
24465 * a cache of Roo.data.Records.
24467 readRecords : function(o){
24468 var sid = this.meta ? this.meta.id : null;
24469 var recordType = this.recordType, fields = recordType.prototype.fields;
24472 for(var i = 0; i < root.length; i++){
24475 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24476 for(var j = 0, jlen = fields.length; j < jlen; j++){
24477 var f = fields.items[j];
24478 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24479 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24481 values[f.name] = v;
24483 var record = new recordType(values, id);
24485 records[records.length] = record;
24489 totalRecords : records.length
24494 * Ext JS Library 1.1.1
24495 * Copyright(c) 2006-2007, Ext JS, LLC.
24497 * Originally Released Under LGPL - original licence link has changed is not relivant.
24500 * <script type="text/javascript">
24505 * @class Roo.data.Tree
24506 * @extends Roo.util.Observable
24507 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24508 * in the tree have most standard DOM functionality.
24510 * @param {Node} root (optional) The root node
24512 Roo.data.Tree = function(root){
24513 this.nodeHash = {};
24515 * The root node for this tree
24520 this.setRootNode(root);
24525 * Fires when a new child node is appended to a node in this tree.
24526 * @param {Tree} tree The owner tree
24527 * @param {Node} parent The parent node
24528 * @param {Node} node The newly appended node
24529 * @param {Number} index The index of the newly appended node
24534 * Fires when a child node is removed from a node in this tree.
24535 * @param {Tree} tree The owner tree
24536 * @param {Node} parent The parent node
24537 * @param {Node} node The child node removed
24542 * Fires when a node is moved to a new location in the tree
24543 * @param {Tree} tree The owner tree
24544 * @param {Node} node The node moved
24545 * @param {Node} oldParent The old parent of this node
24546 * @param {Node} newParent The new parent of this node
24547 * @param {Number} index The index it was moved to
24552 * Fires when a new child node is inserted in a node in this tree.
24553 * @param {Tree} tree The owner tree
24554 * @param {Node} parent The parent node
24555 * @param {Node} node The child node inserted
24556 * @param {Node} refNode The child node the node was inserted before
24560 * @event beforeappend
24561 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24562 * @param {Tree} tree The owner tree
24563 * @param {Node} parent The parent node
24564 * @param {Node} node The child node to be appended
24566 "beforeappend" : true,
24568 * @event beforeremove
24569 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24570 * @param {Tree} tree The owner tree
24571 * @param {Node} parent The parent node
24572 * @param {Node} node The child node to be removed
24574 "beforeremove" : true,
24576 * @event beforemove
24577 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24578 * @param {Tree} tree The owner tree
24579 * @param {Node} node The node being moved
24580 * @param {Node} oldParent The parent of the node
24581 * @param {Node} newParent The new parent the node is moving to
24582 * @param {Number} index The index it is being moved to
24584 "beforemove" : true,
24586 * @event beforeinsert
24587 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24588 * @param {Tree} tree The owner tree
24589 * @param {Node} parent The parent node
24590 * @param {Node} node The child node to be inserted
24591 * @param {Node} refNode The child node the node is being inserted before
24593 "beforeinsert" : true
24596 Roo.data.Tree.superclass.constructor.call(this);
24599 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24600 pathSeparator: "/",
24602 proxyNodeEvent : function(){
24603 return this.fireEvent.apply(this, arguments);
24607 * Returns the root node for this tree.
24610 getRootNode : function(){
24615 * Sets the root node for this tree.
24616 * @param {Node} node
24619 setRootNode : function(node){
24621 node.ownerTree = this;
24622 node.isRoot = true;
24623 this.registerNode(node);
24628 * Gets a node in this tree by its id.
24629 * @param {String} id
24632 getNodeById : function(id){
24633 return this.nodeHash[id];
24636 registerNode : function(node){
24637 this.nodeHash[node.id] = node;
24640 unregisterNode : function(node){
24641 delete this.nodeHash[node.id];
24644 toString : function(){
24645 return "[Tree"+(this.id?" "+this.id:"")+"]";
24650 * @class Roo.data.Node
24651 * @extends Roo.util.Observable
24652 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24653 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24655 * @param {Object} attributes The attributes/config for the node
24657 Roo.data.Node = function(attributes){
24659 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24662 this.attributes = attributes || {};
24663 this.leaf = this.attributes.leaf;
24665 * The node id. @type String
24667 this.id = this.attributes.id;
24669 this.id = Roo.id(null, "ynode-");
24670 this.attributes.id = this.id;
24675 * All child nodes of this node. @type Array
24677 this.childNodes = [];
24678 if(!this.childNodes.indexOf){ // indexOf is a must
24679 this.childNodes.indexOf = function(o){
24680 for(var i = 0, len = this.length; i < len; i++){
24689 * The parent node for this node. @type Node
24691 this.parentNode = null;
24693 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24695 this.firstChild = null;
24697 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24699 this.lastChild = null;
24701 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24703 this.previousSibling = null;
24705 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24707 this.nextSibling = null;
24712 * Fires when a new child node is appended
24713 * @param {Tree} tree The owner tree
24714 * @param {Node} this This node
24715 * @param {Node} node The newly appended node
24716 * @param {Number} index The index of the newly appended node
24721 * Fires when a child node is removed
24722 * @param {Tree} tree The owner tree
24723 * @param {Node} this This node
24724 * @param {Node} node The removed node
24729 * Fires when this node is moved to a new location in the tree
24730 * @param {Tree} tree The owner tree
24731 * @param {Node} this This node
24732 * @param {Node} oldParent The old parent of this node
24733 * @param {Node} newParent The new parent of this node
24734 * @param {Number} index The index it was moved to
24739 * Fires when a new child node is inserted.
24740 * @param {Tree} tree The owner tree
24741 * @param {Node} this This node
24742 * @param {Node} node The child node inserted
24743 * @param {Node} refNode The child node the node was inserted before
24747 * @event beforeappend
24748 * Fires before a new child is appended, return false to cancel the append.
24749 * @param {Tree} tree The owner tree
24750 * @param {Node} this This node
24751 * @param {Node} node The child node to be appended
24753 "beforeappend" : true,
24755 * @event beforeremove
24756 * Fires before a child is removed, return false to cancel the remove.
24757 * @param {Tree} tree The owner tree
24758 * @param {Node} this This node
24759 * @param {Node} node The child node to be removed
24761 "beforeremove" : true,
24763 * @event beforemove
24764 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24765 * @param {Tree} tree The owner tree
24766 * @param {Node} this This node
24767 * @param {Node} oldParent The parent of this node
24768 * @param {Node} newParent The new parent this node is moving to
24769 * @param {Number} index The index it is being moved to
24771 "beforemove" : true,
24773 * @event beforeinsert
24774 * Fires before a new child is inserted, return false to cancel the insert.
24775 * @param {Tree} tree The owner tree
24776 * @param {Node} this This node
24777 * @param {Node} node The child node to be inserted
24778 * @param {Node} refNode The child node the node is being inserted before
24780 "beforeinsert" : true
24782 this.listeners = this.attributes.listeners;
24783 Roo.data.Node.superclass.constructor.call(this);
24786 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24787 fireEvent : function(evtName){
24788 // first do standard event for this node
24789 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24792 // then bubble it up to the tree if the event wasn't cancelled
24793 var ot = this.getOwnerTree();
24795 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24803 * Returns true if this node is a leaf
24804 * @return {Boolean}
24806 isLeaf : function(){
24807 return this.leaf === true;
24811 setFirstChild : function(node){
24812 this.firstChild = node;
24816 setLastChild : function(node){
24817 this.lastChild = node;
24822 * Returns true if this node is the last child of its parent
24823 * @return {Boolean}
24825 isLast : function(){
24826 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24830 * Returns true if this node is the first child of its parent
24831 * @return {Boolean}
24833 isFirst : function(){
24834 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24837 hasChildNodes : function(){
24838 return !this.isLeaf() && this.childNodes.length > 0;
24842 * Insert node(s) as the last child node of this node.
24843 * @param {Node/Array} node The node or Array of nodes to append
24844 * @return {Node} The appended node if single append, or null if an array was passed
24846 appendChild : function(node){
24848 if(node instanceof Array){
24850 }else if(arguments.length > 1){
24853 // if passed an array or multiple args do them one by one
24855 for(var i = 0, len = multi.length; i < len; i++) {
24856 this.appendChild(multi[i]);
24859 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
24862 var index = this.childNodes.length;
24863 var oldParent = node.parentNode;
24864 // it's a move, make sure we move it cleanly
24866 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
24869 oldParent.removeChild(node);
24871 index = this.childNodes.length;
24873 this.setFirstChild(node);
24875 this.childNodes.push(node);
24876 node.parentNode = this;
24877 var ps = this.childNodes[index-1];
24879 node.previousSibling = ps;
24880 ps.nextSibling = node;
24882 node.previousSibling = null;
24884 node.nextSibling = null;
24885 this.setLastChild(node);
24886 node.setOwnerTree(this.getOwnerTree());
24887 this.fireEvent("append", this.ownerTree, this, node, index);
24889 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
24896 * Removes a child node from this node.
24897 * @param {Node} node The node to remove
24898 * @return {Node} The removed node
24900 removeChild : function(node){
24901 var index = this.childNodes.indexOf(node);
24905 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
24909 // remove it from childNodes collection
24910 this.childNodes.splice(index, 1);
24913 if(node.previousSibling){
24914 node.previousSibling.nextSibling = node.nextSibling;
24916 if(node.nextSibling){
24917 node.nextSibling.previousSibling = node.previousSibling;
24920 // update child refs
24921 if(this.firstChild == node){
24922 this.setFirstChild(node.nextSibling);
24924 if(this.lastChild == node){
24925 this.setLastChild(node.previousSibling);
24928 node.setOwnerTree(null);
24929 // clear any references from the node
24930 node.parentNode = null;
24931 node.previousSibling = null;
24932 node.nextSibling = null;
24933 this.fireEvent("remove", this.ownerTree, this, node);
24938 * Inserts the first node before the second node in this nodes childNodes collection.
24939 * @param {Node} node The node to insert
24940 * @param {Node} refNode The node to insert before (if null the node is appended)
24941 * @return {Node} The inserted node
24943 insertBefore : function(node, refNode){
24944 if(!refNode){ // like standard Dom, refNode can be null for append
24945 return this.appendChild(node);
24948 if(node == refNode){
24952 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
24955 var index = this.childNodes.indexOf(refNode);
24956 var oldParent = node.parentNode;
24957 var refIndex = index;
24959 // when moving internally, indexes will change after remove
24960 if(oldParent == this && this.childNodes.indexOf(node) < index){
24964 // it's a move, make sure we move it cleanly
24966 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
24969 oldParent.removeChild(node);
24972 this.setFirstChild(node);
24974 this.childNodes.splice(refIndex, 0, node);
24975 node.parentNode = this;
24976 var ps = this.childNodes[refIndex-1];
24978 node.previousSibling = ps;
24979 ps.nextSibling = node;
24981 node.previousSibling = null;
24983 node.nextSibling = refNode;
24984 refNode.previousSibling = node;
24985 node.setOwnerTree(this.getOwnerTree());
24986 this.fireEvent("insert", this.ownerTree, this, node, refNode);
24988 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
24994 * Returns the child node at the specified index.
24995 * @param {Number} index
24998 item : function(index){
24999 return this.childNodes[index];
25003 * Replaces one child node in this node with another.
25004 * @param {Node} newChild The replacement node
25005 * @param {Node} oldChild The node to replace
25006 * @return {Node} The replaced node
25008 replaceChild : function(newChild, oldChild){
25009 this.insertBefore(newChild, oldChild);
25010 this.removeChild(oldChild);
25015 * Returns the index of a child node
25016 * @param {Node} node
25017 * @return {Number} The index of the node or -1 if it was not found
25019 indexOf : function(child){
25020 return this.childNodes.indexOf(child);
25024 * Returns the tree this node is in.
25027 getOwnerTree : function(){
25028 // if it doesn't have one, look for one
25029 if(!this.ownerTree){
25033 this.ownerTree = p.ownerTree;
25039 return this.ownerTree;
25043 * Returns depth of this node (the root node has a depth of 0)
25046 getDepth : function(){
25049 while(p.parentNode){
25057 setOwnerTree : function(tree){
25058 // if it's move, we need to update everyone
25059 if(tree != this.ownerTree){
25060 if(this.ownerTree){
25061 this.ownerTree.unregisterNode(this);
25063 this.ownerTree = tree;
25064 var cs = this.childNodes;
25065 for(var i = 0, len = cs.length; i < len; i++) {
25066 cs[i].setOwnerTree(tree);
25069 tree.registerNode(this);
25075 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25076 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25077 * @return {String} The path
25079 getPath : function(attr){
25080 attr = attr || "id";
25081 var p = this.parentNode;
25082 var b = [this.attributes[attr]];
25084 b.unshift(p.attributes[attr]);
25087 var sep = this.getOwnerTree().pathSeparator;
25088 return sep + b.join(sep);
25092 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25093 * function call will be the scope provided or the current node. The arguments to the function
25094 * will be the args provided or the current node. If the function returns false at any point,
25095 * the bubble is stopped.
25096 * @param {Function} fn The function to call
25097 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25098 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25100 bubble : function(fn, scope, args){
25103 if(fn.call(scope || p, args || p) === false){
25111 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25112 * function call will be the scope provided or the current node. The arguments to the function
25113 * will be the args provided or the current node. If the function returns false at any point,
25114 * the cascade is stopped on that branch.
25115 * @param {Function} fn The function to call
25116 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25117 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25119 cascade : function(fn, scope, args){
25120 if(fn.call(scope || this, args || this) !== false){
25121 var cs = this.childNodes;
25122 for(var i = 0, len = cs.length; i < len; i++) {
25123 cs[i].cascade(fn, scope, args);
25129 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25130 * function call will be the scope provided or the current node. The arguments to the function
25131 * will be the args provided or the current node. If the function returns false at any point,
25132 * the iteration stops.
25133 * @param {Function} fn The function to call
25134 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25135 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25137 eachChild : function(fn, scope, args){
25138 var cs = this.childNodes;
25139 for(var i = 0, len = cs.length; i < len; i++) {
25140 if(fn.call(scope || this, args || cs[i]) === false){
25147 * Finds the first child that has the attribute with the specified value.
25148 * @param {String} attribute The attribute name
25149 * @param {Mixed} value The value to search for
25150 * @return {Node} The found child or null if none was found
25152 findChild : function(attribute, value){
25153 var cs = this.childNodes;
25154 for(var i = 0, len = cs.length; i < len; i++) {
25155 if(cs[i].attributes[attribute] == value){
25163 * Finds the first child by a custom function. The child matches if the function passed
25165 * @param {Function} fn
25166 * @param {Object} scope (optional)
25167 * @return {Node} The found child or null if none was found
25169 findChildBy : function(fn, scope){
25170 var cs = this.childNodes;
25171 for(var i = 0, len = cs.length; i < len; i++) {
25172 if(fn.call(scope||cs[i], cs[i]) === true){
25180 * Sorts this nodes children using the supplied sort function
25181 * @param {Function} fn
25182 * @param {Object} scope (optional)
25184 sort : function(fn, scope){
25185 var cs = this.childNodes;
25186 var len = cs.length;
25188 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25190 for(var i = 0; i < len; i++){
25192 n.previousSibling = cs[i-1];
25193 n.nextSibling = cs[i+1];
25195 this.setFirstChild(n);
25198 this.setLastChild(n);
25205 * Returns true if this node is an ancestor (at any point) of the passed node.
25206 * @param {Node} node
25207 * @return {Boolean}
25209 contains : function(node){
25210 return node.isAncestor(this);
25214 * Returns true if the passed node is an ancestor (at any point) of this node.
25215 * @param {Node} node
25216 * @return {Boolean}
25218 isAncestor : function(node){
25219 var p = this.parentNode;
25229 toString : function(){
25230 return "[Node"+(this.id?" "+this.id:"")+"]";
25234 * Ext JS Library 1.1.1
25235 * Copyright(c) 2006-2007, Ext JS, LLC.
25237 * Originally Released Under LGPL - original licence link has changed is not relivant.
25240 * <script type="text/javascript">
25245 * @extends Roo.Element
25246 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25247 * automatic maintaining of shadow/shim positions.
25248 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25249 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25250 * you can pass a string with a CSS class name. False turns off the shadow.
25251 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25252 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25253 * @cfg {String} cls CSS class to add to the element
25254 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25255 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25257 * @param {Object} config An object with config options.
25258 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25261 Roo.Layer = function(config, existingEl){
25262 config = config || {};
25263 var dh = Roo.DomHelper;
25264 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25266 this.dom = Roo.getDom(existingEl);
25269 var o = config.dh || {tag: "div", cls: "x-layer"};
25270 this.dom = dh.append(pel, o);
25273 this.addClass(config.cls);
25275 this.constrain = config.constrain !== false;
25276 this.visibilityMode = Roo.Element.VISIBILITY;
25278 this.id = this.dom.id = config.id;
25280 this.id = Roo.id(this.dom);
25282 this.zindex = config.zindex || this.getZIndex();
25283 this.position("absolute", this.zindex);
25285 this.shadowOffset = config.shadowOffset || 4;
25286 this.shadow = new Roo.Shadow({
25287 offset : this.shadowOffset,
25288 mode : config.shadow
25291 this.shadowOffset = 0;
25293 this.useShim = config.shim !== false && Roo.useShims;
25294 this.useDisplay = config.useDisplay;
25298 var supr = Roo.Element.prototype;
25300 // shims are shared among layer to keep from having 100 iframes
25303 Roo.extend(Roo.Layer, Roo.Element, {
25305 getZIndex : function(){
25306 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25309 getShim : function(){
25316 var shim = shims.shift();
25318 shim = this.createShim();
25319 shim.enableDisplayMode('block');
25320 shim.dom.style.display = 'none';
25321 shim.dom.style.visibility = 'visible';
25323 var pn = this.dom.parentNode;
25324 if(shim.dom.parentNode != pn){
25325 pn.insertBefore(shim.dom, this.dom);
25327 shim.setStyle('z-index', this.getZIndex()-2);
25332 hideShim : function(){
25334 this.shim.setDisplayed(false);
25335 shims.push(this.shim);
25340 disableShadow : function(){
25342 this.shadowDisabled = true;
25343 this.shadow.hide();
25344 this.lastShadowOffset = this.shadowOffset;
25345 this.shadowOffset = 0;
25349 enableShadow : function(show){
25351 this.shadowDisabled = false;
25352 this.shadowOffset = this.lastShadowOffset;
25353 delete this.lastShadowOffset;
25361 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25362 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25363 sync : function(doShow){
25364 var sw = this.shadow;
25365 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25366 var sh = this.getShim();
25368 var w = this.getWidth(),
25369 h = this.getHeight();
25371 var l = this.getLeft(true),
25372 t = this.getTop(true);
25374 if(sw && !this.shadowDisabled){
25375 if(doShow && !sw.isVisible()){
25378 sw.realign(l, t, w, h);
25384 // fit the shim behind the shadow, so it is shimmed too
25385 var a = sw.adjusts, s = sh.dom.style;
25386 s.left = (Math.min(l, l+a.l))+"px";
25387 s.top = (Math.min(t, t+a.t))+"px";
25388 s.width = (w+a.w)+"px";
25389 s.height = (h+a.h)+"px";
25396 sh.setLeftTop(l, t);
25403 destroy : function(){
25406 this.shadow.hide();
25408 this.removeAllListeners();
25409 var pn = this.dom.parentNode;
25411 pn.removeChild(this.dom);
25413 Roo.Element.uncache(this.id);
25416 remove : function(){
25421 beginUpdate : function(){
25422 this.updating = true;
25426 endUpdate : function(){
25427 this.updating = false;
25432 hideUnders : function(negOffset){
25434 this.shadow.hide();
25440 constrainXY : function(){
25441 if(this.constrain){
25442 var vw = Roo.lib.Dom.getViewWidth(),
25443 vh = Roo.lib.Dom.getViewHeight();
25444 var s = Roo.get(document).getScroll();
25446 var xy = this.getXY();
25447 var x = xy[0], y = xy[1];
25448 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25449 // only move it if it needs it
25451 // first validate right/bottom
25452 if((x + w) > vw+s.left){
25453 x = vw - w - this.shadowOffset;
25456 if((y + h) > vh+s.top){
25457 y = vh - h - this.shadowOffset;
25460 // then make sure top/left isn't negative
25471 var ay = this.avoidY;
25472 if(y <= ay && (y+h) >= ay){
25478 supr.setXY.call(this, xy);
25484 isVisible : function(){
25485 return this.visible;
25489 showAction : function(){
25490 this.visible = true; // track visibility to prevent getStyle calls
25491 if(this.useDisplay === true){
25492 this.setDisplayed("");
25493 }else if(this.lastXY){
25494 supr.setXY.call(this, this.lastXY);
25495 }else if(this.lastLT){
25496 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25501 hideAction : function(){
25502 this.visible = false;
25503 if(this.useDisplay === true){
25504 this.setDisplayed(false);
25506 this.setLeftTop(-10000,-10000);
25510 // overridden Element method
25511 setVisible : function(v, a, d, c, e){
25516 var cb = function(){
25521 }.createDelegate(this);
25522 supr.setVisible.call(this, true, true, d, cb, e);
25525 this.hideUnders(true);
25534 }.createDelegate(this);
25536 supr.setVisible.call(this, v, a, d, cb, e);
25545 storeXY : function(xy){
25546 delete this.lastLT;
25550 storeLeftTop : function(left, top){
25551 delete this.lastXY;
25552 this.lastLT = [left, top];
25556 beforeFx : function(){
25557 this.beforeAction();
25558 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25562 afterFx : function(){
25563 Roo.Layer.superclass.afterFx.apply(this, arguments);
25564 this.sync(this.isVisible());
25568 beforeAction : function(){
25569 if(!this.updating && this.shadow){
25570 this.shadow.hide();
25574 // overridden Element method
25575 setLeft : function(left){
25576 this.storeLeftTop(left, this.getTop(true));
25577 supr.setLeft.apply(this, arguments);
25581 setTop : function(top){
25582 this.storeLeftTop(this.getLeft(true), top);
25583 supr.setTop.apply(this, arguments);
25587 setLeftTop : function(left, top){
25588 this.storeLeftTop(left, top);
25589 supr.setLeftTop.apply(this, arguments);
25593 setXY : function(xy, a, d, c, e){
25595 this.beforeAction();
25597 var cb = this.createCB(c);
25598 supr.setXY.call(this, xy, a, d, cb, e);
25605 createCB : function(c){
25616 // overridden Element method
25617 setX : function(x, a, d, c, e){
25618 this.setXY([x, this.getY()], a, d, c, e);
25621 // overridden Element method
25622 setY : function(y, a, d, c, e){
25623 this.setXY([this.getX(), y], a, d, c, e);
25626 // overridden Element method
25627 setSize : function(w, h, a, d, c, e){
25628 this.beforeAction();
25629 var cb = this.createCB(c);
25630 supr.setSize.call(this, w, h, a, d, cb, e);
25636 // overridden Element method
25637 setWidth : function(w, a, d, c, e){
25638 this.beforeAction();
25639 var cb = this.createCB(c);
25640 supr.setWidth.call(this, w, a, d, cb, e);
25646 // overridden Element method
25647 setHeight : function(h, a, d, c, e){
25648 this.beforeAction();
25649 var cb = this.createCB(c);
25650 supr.setHeight.call(this, h, a, d, cb, e);
25656 // overridden Element method
25657 setBounds : function(x, y, w, h, a, d, c, e){
25658 this.beforeAction();
25659 var cb = this.createCB(c);
25661 this.storeXY([x, y]);
25662 supr.setXY.call(this, [x, y]);
25663 supr.setSize.call(this, w, h, a, d, cb, e);
25666 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25672 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25673 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25674 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25675 * @param {Number} zindex The new z-index to set
25676 * @return {this} The Layer
25678 setZIndex : function(zindex){
25679 this.zindex = zindex;
25680 this.setStyle("z-index", zindex + 2);
25682 this.shadow.setZIndex(zindex + 1);
25685 this.shim.setStyle("z-index", zindex);
25691 * Ext JS Library 1.1.1
25692 * Copyright(c) 2006-2007, Ext JS, LLC.
25694 * Originally Released Under LGPL - original licence link has changed is not relivant.
25697 * <script type="text/javascript">
25702 * @class Roo.Shadow
25703 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25704 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25705 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25707 * Create a new Shadow
25708 * @param {Object} config The config object
25710 Roo.Shadow = function(config){
25711 Roo.apply(this, config);
25712 if(typeof this.mode != "string"){
25713 this.mode = this.defaultMode;
25715 var o = this.offset, a = {h: 0};
25716 var rad = Math.floor(this.offset/2);
25717 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25723 a.l -= this.offset + rad;
25724 a.t -= this.offset + rad;
25735 a.l -= (this.offset - rad);
25736 a.t -= this.offset + rad;
25738 a.w -= (this.offset - rad)*2;
25749 a.l -= (this.offset - rad);
25750 a.t -= (this.offset - rad);
25752 a.w -= (this.offset + rad + 1);
25753 a.h -= (this.offset + rad);
25762 Roo.Shadow.prototype = {
25764 * @cfg {String} mode
25765 * The shadow display mode. Supports the following options:<br />
25766 * sides: Shadow displays on both sides and bottom only<br />
25767 * frame: Shadow displays equally on all four sides<br />
25768 * drop: Traditional bottom-right drop shadow (default)
25771 * @cfg {String} offset
25772 * The number of pixels to offset the shadow from the element (defaults to 4)
25777 defaultMode: "drop",
25780 * Displays the shadow under the target element
25781 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25783 show : function(target){
25784 target = Roo.get(target);
25786 this.el = Roo.Shadow.Pool.pull();
25787 if(this.el.dom.nextSibling != target.dom){
25788 this.el.insertBefore(target);
25791 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25793 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25796 target.getLeft(true),
25797 target.getTop(true),
25801 this.el.dom.style.display = "block";
25805 * Returns true if the shadow is visible, else false
25807 isVisible : function(){
25808 return this.el ? true : false;
25812 * Direct alignment when values are already available. Show must be called at least once before
25813 * calling this method to ensure it is initialized.
25814 * @param {Number} left The target element left position
25815 * @param {Number} top The target element top position
25816 * @param {Number} width The target element width
25817 * @param {Number} height The target element height
25819 realign : function(l, t, w, h){
25823 var a = this.adjusts, d = this.el.dom, s = d.style;
25825 s.left = (l+a.l)+"px";
25826 s.top = (t+a.t)+"px";
25827 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25829 if(s.width != sws || s.height != shs){
25833 var cn = d.childNodes;
25834 var sww = Math.max(0, (sw-12))+"px";
25835 cn[0].childNodes[1].style.width = sww;
25836 cn[1].childNodes[1].style.width = sww;
25837 cn[2].childNodes[1].style.width = sww;
25838 cn[1].style.height = Math.max(0, (sh-12))+"px";
25844 * Hides this shadow
25848 this.el.dom.style.display = "none";
25849 Roo.Shadow.Pool.push(this.el);
25855 * Adjust the z-index of this shadow
25856 * @param {Number} zindex The new z-index
25858 setZIndex : function(z){
25861 this.el.setStyle("z-index", z);
25866 // Private utility class that manages the internal Shadow cache
25867 Roo.Shadow.Pool = function(){
25869 var markup = Roo.isIE ?
25870 '<div class="x-ie-shadow"></div>' :
25871 '<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>';
25874 var sh = p.shift();
25876 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
25877 sh.autoBoxAdjust = false;
25882 push : function(sh){
25888 * Ext JS Library 1.1.1
25889 * Copyright(c) 2006-2007, Ext JS, LLC.
25891 * Originally Released Under LGPL - original licence link has changed is not relivant.
25894 * <script type="text/javascript">
25899 * @class Roo.SplitBar
25900 * @extends Roo.util.Observable
25901 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
25905 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
25906 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
25907 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
25908 split.minSize = 100;
25909 split.maxSize = 600;
25910 split.animate = true;
25911 split.on('moved', splitterMoved);
25914 * Create a new SplitBar
25915 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
25916 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
25917 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25918 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
25919 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
25920 position of the SplitBar).
25922 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
25925 this.el = Roo.get(dragElement, true);
25926 this.el.dom.unselectable = "on";
25928 this.resizingEl = Roo.get(resizingElement, true);
25932 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25933 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
25936 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
25939 * The minimum size of the resizing element. (Defaults to 0)
25945 * The maximum size of the resizing element. (Defaults to 2000)
25948 this.maxSize = 2000;
25951 * Whether to animate the transition to the new size
25954 this.animate = false;
25957 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
25960 this.useShim = false;
25965 if(!existingProxy){
25967 this.proxy = Roo.SplitBar.createProxy(this.orientation);
25969 this.proxy = Roo.get(existingProxy).dom;
25972 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
25975 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
25978 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
25981 this.dragSpecs = {};
25984 * @private The adapter to use to positon and resize elements
25986 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
25987 this.adapter.init(this);
25989 if(this.orientation == Roo.SplitBar.HORIZONTAL){
25991 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
25992 this.el.addClass("x-splitbar-h");
25995 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
25996 this.el.addClass("x-splitbar-v");
26002 * Fires when the splitter is moved (alias for {@link #event-moved})
26003 * @param {Roo.SplitBar} this
26004 * @param {Number} newSize the new width or height
26009 * Fires when the splitter is moved
26010 * @param {Roo.SplitBar} this
26011 * @param {Number} newSize the new width or height
26015 * @event beforeresize
26016 * Fires before the splitter is dragged
26017 * @param {Roo.SplitBar} this
26019 "beforeresize" : true,
26021 "beforeapply" : true
26024 Roo.util.Observable.call(this);
26027 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26028 onStartProxyDrag : function(x, y){
26029 this.fireEvent("beforeresize", this);
26031 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26033 o.enableDisplayMode("block");
26034 // all splitbars share the same overlay
26035 Roo.SplitBar.prototype.overlay = o;
26037 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26038 this.overlay.show();
26039 Roo.get(this.proxy).setDisplayed("block");
26040 var size = this.adapter.getElementSize(this);
26041 this.activeMinSize = this.getMinimumSize();;
26042 this.activeMaxSize = this.getMaximumSize();;
26043 var c1 = size - this.activeMinSize;
26044 var c2 = Math.max(this.activeMaxSize - size, 0);
26045 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26046 this.dd.resetConstraints();
26047 this.dd.setXConstraint(
26048 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26049 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26051 this.dd.setYConstraint(0, 0);
26053 this.dd.resetConstraints();
26054 this.dd.setXConstraint(0, 0);
26055 this.dd.setYConstraint(
26056 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26057 this.placement == Roo.SplitBar.TOP ? c2 : c1
26060 this.dragSpecs.startSize = size;
26061 this.dragSpecs.startPoint = [x, y];
26062 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26066 * @private Called after the drag operation by the DDProxy
26068 onEndProxyDrag : function(e){
26069 Roo.get(this.proxy).setDisplayed(false);
26070 var endPoint = Roo.lib.Event.getXY(e);
26072 this.overlay.hide();
26075 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26076 newSize = this.dragSpecs.startSize +
26077 (this.placement == Roo.SplitBar.LEFT ?
26078 endPoint[0] - this.dragSpecs.startPoint[0] :
26079 this.dragSpecs.startPoint[0] - endPoint[0]
26082 newSize = this.dragSpecs.startSize +
26083 (this.placement == Roo.SplitBar.TOP ?
26084 endPoint[1] - this.dragSpecs.startPoint[1] :
26085 this.dragSpecs.startPoint[1] - endPoint[1]
26088 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26089 if(newSize != this.dragSpecs.startSize){
26090 if(this.fireEvent('beforeapply', this, newSize) !== false){
26091 this.adapter.setElementSize(this, newSize);
26092 this.fireEvent("moved", this, newSize);
26093 this.fireEvent("resize", this, newSize);
26099 * Get the adapter this SplitBar uses
26100 * @return The adapter object
26102 getAdapter : function(){
26103 return this.adapter;
26107 * Set the adapter this SplitBar uses
26108 * @param {Object} adapter A SplitBar adapter object
26110 setAdapter : function(adapter){
26111 this.adapter = adapter;
26112 this.adapter.init(this);
26116 * Gets the minimum size for the resizing element
26117 * @return {Number} The minimum size
26119 getMinimumSize : function(){
26120 return this.minSize;
26124 * Sets the minimum size for the resizing element
26125 * @param {Number} minSize The minimum size
26127 setMinimumSize : function(minSize){
26128 this.minSize = minSize;
26132 * Gets the maximum size for the resizing element
26133 * @return {Number} The maximum size
26135 getMaximumSize : function(){
26136 return this.maxSize;
26140 * Sets the maximum size for the resizing element
26141 * @param {Number} maxSize The maximum size
26143 setMaximumSize : function(maxSize){
26144 this.maxSize = maxSize;
26148 * Sets the initialize size for the resizing element
26149 * @param {Number} size The initial size
26151 setCurrentSize : function(size){
26152 var oldAnimate = this.animate;
26153 this.animate = false;
26154 this.adapter.setElementSize(this, size);
26155 this.animate = oldAnimate;
26159 * Destroy this splitbar.
26160 * @param {Boolean} removeEl True to remove the element
26162 destroy : function(removeEl){
26164 this.shim.remove();
26167 this.proxy.parentNode.removeChild(this.proxy);
26175 * @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.
26177 Roo.SplitBar.createProxy = function(dir){
26178 var proxy = new Roo.Element(document.createElement("div"));
26179 proxy.unselectable();
26180 var cls = 'x-splitbar-proxy';
26181 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26182 document.body.appendChild(proxy.dom);
26187 * @class Roo.SplitBar.BasicLayoutAdapter
26188 * Default Adapter. It assumes the splitter and resizing element are not positioned
26189 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26191 Roo.SplitBar.BasicLayoutAdapter = function(){
26194 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26195 // do nothing for now
26196 init : function(s){
26200 * Called before drag operations to get the current size of the resizing element.
26201 * @param {Roo.SplitBar} s The SplitBar using this adapter
26203 getElementSize : function(s){
26204 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26205 return s.resizingEl.getWidth();
26207 return s.resizingEl.getHeight();
26212 * Called after drag operations to set the size of the resizing element.
26213 * @param {Roo.SplitBar} s The SplitBar using this adapter
26214 * @param {Number} newSize The new size to set
26215 * @param {Function} onComplete A function to be invoked when resizing is complete
26217 setElementSize : function(s, newSize, onComplete){
26218 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26220 s.resizingEl.setWidth(newSize);
26222 onComplete(s, newSize);
26225 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26230 s.resizingEl.setHeight(newSize);
26232 onComplete(s, newSize);
26235 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26242 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26243 * @extends Roo.SplitBar.BasicLayoutAdapter
26244 * Adapter that moves the splitter element to align with the resized sizing element.
26245 * Used with an absolute positioned SplitBar.
26246 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26247 * document.body, make sure you assign an id to the body element.
26249 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26250 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26251 this.container = Roo.get(container);
26254 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26255 init : function(s){
26256 this.basic.init(s);
26259 getElementSize : function(s){
26260 return this.basic.getElementSize(s);
26263 setElementSize : function(s, newSize, onComplete){
26264 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26267 moveSplitter : function(s){
26268 var yes = Roo.SplitBar;
26269 switch(s.placement){
26271 s.el.setX(s.resizingEl.getRight());
26274 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26277 s.el.setY(s.resizingEl.getBottom());
26280 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26287 * Orientation constant - Create a vertical SplitBar
26291 Roo.SplitBar.VERTICAL = 1;
26294 * Orientation constant - Create a horizontal SplitBar
26298 Roo.SplitBar.HORIZONTAL = 2;
26301 * Placement constant - The resizing element is to the left of the splitter element
26305 Roo.SplitBar.LEFT = 1;
26308 * Placement constant - The resizing element is to the right of the splitter element
26312 Roo.SplitBar.RIGHT = 2;
26315 * Placement constant - The resizing element is positioned above the splitter element
26319 Roo.SplitBar.TOP = 3;
26322 * Placement constant - The resizing element is positioned under splitter element
26326 Roo.SplitBar.BOTTOM = 4;
26329 * Ext JS Library 1.1.1
26330 * Copyright(c) 2006-2007, Ext JS, LLC.
26332 * Originally Released Under LGPL - original licence link has changed is not relivant.
26335 * <script type="text/javascript">
26340 * @extends Roo.util.Observable
26341 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26342 * This class also supports single and multi selection modes. <br>
26343 * Create a data model bound view:
26345 var store = new Roo.data.Store(...);
26347 var view = new Roo.View({
26349 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26351 singleSelect: true,
26352 selectedClass: "ydataview-selected",
26356 // listen for node click?
26357 view.on("click", function(vw, index, node, e){
26358 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26362 dataModel.load("foobar.xml");
26364 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26366 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26367 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26369 * Note: old style constructor is still suported (container, template, config)
26372 * Create a new View
26373 * @param {Object} config The config object
26376 Roo.View = function(config, depreciated_tpl, depreciated_config){
26378 this.parent = false;
26380 if (typeof(depreciated_tpl) == 'undefined') {
26381 // new way.. - universal constructor.
26382 Roo.apply(this, config);
26383 this.el = Roo.get(this.el);
26386 this.el = Roo.get(config);
26387 this.tpl = depreciated_tpl;
26388 Roo.apply(this, depreciated_config);
26390 this.wrapEl = this.el.wrap().wrap();
26391 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26394 if(typeof(this.tpl) == "string"){
26395 this.tpl = new Roo.Template(this.tpl);
26397 // support xtype ctors..
26398 this.tpl = new Roo.factory(this.tpl, Roo);
26402 this.tpl.compile();
26407 * @event beforeclick
26408 * Fires before a click is processed. Returns false to cancel the default action.
26409 * @param {Roo.View} this
26410 * @param {Number} index The index of the target node
26411 * @param {HTMLElement} node The target node
26412 * @param {Roo.EventObject} e The raw event object
26414 "beforeclick" : true,
26417 * Fires when a template node is clicked.
26418 * @param {Roo.View} this
26419 * @param {Number} index The index of the target node
26420 * @param {HTMLElement} node The target node
26421 * @param {Roo.EventObject} e The raw event object
26426 * Fires when a template node is double clicked.
26427 * @param {Roo.View} this
26428 * @param {Number} index The index of the target node
26429 * @param {HTMLElement} node The target node
26430 * @param {Roo.EventObject} e The raw event object
26434 * @event contextmenu
26435 * Fires when a template node is right clicked.
26436 * @param {Roo.View} this
26437 * @param {Number} index The index of the target node
26438 * @param {HTMLElement} node The target node
26439 * @param {Roo.EventObject} e The raw event object
26441 "contextmenu" : true,
26443 * @event selectionchange
26444 * Fires when the selected nodes change.
26445 * @param {Roo.View} this
26446 * @param {Array} selections Array of the selected nodes
26448 "selectionchange" : true,
26451 * @event beforeselect
26452 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26453 * @param {Roo.View} this
26454 * @param {HTMLElement} node The node to be selected
26455 * @param {Array} selections Array of currently selected nodes
26457 "beforeselect" : true,
26459 * @event preparedata
26460 * Fires on every row to render, to allow you to change the data.
26461 * @param {Roo.View} this
26462 * @param {Object} data to be rendered (change this)
26464 "preparedata" : true
26472 "click": this.onClick,
26473 "dblclick": this.onDblClick,
26474 "contextmenu": this.onContextMenu,
26478 this.selections = [];
26480 this.cmp = new Roo.CompositeElementLite([]);
26482 this.store = Roo.factory(this.store, Roo.data);
26483 this.setStore(this.store, true);
26486 if ( this.footer && this.footer.xtype) {
26488 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26490 this.footer.dataSource = this.store;
26491 this.footer.container = fctr;
26492 this.footer = Roo.factory(this.footer, Roo);
26493 fctr.insertFirst(this.el);
26495 // this is a bit insane - as the paging toolbar seems to detach the el..
26496 // dom.parentNode.parentNode.parentNode
26497 // they get detached?
26501 Roo.View.superclass.constructor.call(this);
26506 Roo.extend(Roo.View, Roo.util.Observable, {
26509 * @cfg {Roo.data.Store} store Data store to load data from.
26514 * @cfg {String|Roo.Element} el The container element.
26519 * @cfg {String|Roo.Template} tpl The template used by this View
26523 * @cfg {String} dataName the named area of the template to use as the data area
26524 * Works with domtemplates roo-name="name"
26528 * @cfg {String} selectedClass The css class to add to selected nodes
26530 selectedClass : "x-view-selected",
26532 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26537 * @cfg {String} text to display on mask (default Loading)
26541 * @cfg {Boolean} multiSelect Allow multiple selection
26543 multiSelect : false,
26545 * @cfg {Boolean} singleSelect Allow single selection
26547 singleSelect: false,
26550 * @cfg {Boolean} toggleSelect - selecting
26552 toggleSelect : false,
26555 * @cfg {Boolean} tickable - selecting
26560 * Returns the element this view is bound to.
26561 * @return {Roo.Element}
26563 getEl : function(){
26564 return this.wrapEl;
26570 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26572 refresh : function(){
26573 //Roo.log('refresh');
26576 // if we are using something like 'domtemplate', then
26577 // the what gets used is:
26578 // t.applySubtemplate(NAME, data, wrapping data..)
26579 // the outer template then get' applied with
26580 // the store 'extra data'
26581 // and the body get's added to the
26582 // roo-name="data" node?
26583 // <span class='roo-tpl-{name}'></span> ?????
26587 this.clearSelections();
26588 this.el.update("");
26590 var records = this.store.getRange();
26591 if(records.length < 1) {
26593 // is this valid?? = should it render a template??
26595 this.el.update(this.emptyText);
26599 if (this.dataName) {
26600 this.el.update(t.apply(this.store.meta)); //????
26601 el = this.el.child('.roo-tpl-' + this.dataName);
26604 for(var i = 0, len = records.length; i < len; i++){
26605 var data = this.prepareData(records[i].data, i, records[i]);
26606 this.fireEvent("preparedata", this, data, i, records[i]);
26608 var d = Roo.apply({}, data);
26611 Roo.apply(d, {'roo-id' : Roo.id()});
26615 Roo.each(this.parent.item, function(item){
26616 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26619 Roo.apply(d, {'roo-data-checked' : 'checked'});
26623 html[html.length] = Roo.util.Format.trim(
26625 t.applySubtemplate(this.dataName, d, this.store.meta) :
26632 el.update(html.join(""));
26633 this.nodes = el.dom.childNodes;
26634 this.updateIndexes(0);
26639 * Function to override to reformat the data that is sent to
26640 * the template for each node.
26641 * DEPRICATED - use the preparedata event handler.
26642 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26643 * a JSON object for an UpdateManager bound view).
26645 prepareData : function(data, index, record)
26647 this.fireEvent("preparedata", this, data, index, record);
26651 onUpdate : function(ds, record){
26652 // Roo.log('on update');
26653 this.clearSelections();
26654 var index = this.store.indexOf(record);
26655 var n = this.nodes[index];
26656 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26657 n.parentNode.removeChild(n);
26658 this.updateIndexes(index, index);
26664 onAdd : function(ds, records, index)
26666 //Roo.log(['on Add', ds, records, index] );
26667 this.clearSelections();
26668 if(this.nodes.length == 0){
26672 var n = this.nodes[index];
26673 for(var i = 0, len = records.length; i < len; i++){
26674 var d = this.prepareData(records[i].data, i, records[i]);
26676 this.tpl.insertBefore(n, d);
26679 this.tpl.append(this.el, d);
26682 this.updateIndexes(index);
26685 onRemove : function(ds, record, index){
26686 // Roo.log('onRemove');
26687 this.clearSelections();
26688 var el = this.dataName ?
26689 this.el.child('.roo-tpl-' + this.dataName) :
26692 el.dom.removeChild(this.nodes[index]);
26693 this.updateIndexes(index);
26697 * Refresh an individual node.
26698 * @param {Number} index
26700 refreshNode : function(index){
26701 this.onUpdate(this.store, this.store.getAt(index));
26704 updateIndexes : function(startIndex, endIndex){
26705 var ns = this.nodes;
26706 startIndex = startIndex || 0;
26707 endIndex = endIndex || ns.length - 1;
26708 for(var i = startIndex; i <= endIndex; i++){
26709 ns[i].nodeIndex = i;
26714 * Changes the data store this view uses and refresh the view.
26715 * @param {Store} store
26717 setStore : function(store, initial){
26718 if(!initial && this.store){
26719 this.store.un("datachanged", this.refresh);
26720 this.store.un("add", this.onAdd);
26721 this.store.un("remove", this.onRemove);
26722 this.store.un("update", this.onUpdate);
26723 this.store.un("clear", this.refresh);
26724 this.store.un("beforeload", this.onBeforeLoad);
26725 this.store.un("load", this.onLoad);
26726 this.store.un("loadexception", this.onLoad);
26730 store.on("datachanged", this.refresh, this);
26731 store.on("add", this.onAdd, this);
26732 store.on("remove", this.onRemove, this);
26733 store.on("update", this.onUpdate, this);
26734 store.on("clear", this.refresh, this);
26735 store.on("beforeload", this.onBeforeLoad, this);
26736 store.on("load", this.onLoad, this);
26737 store.on("loadexception", this.onLoad, this);
26745 * onbeforeLoad - masks the loading area.
26748 onBeforeLoad : function(store,opts)
26750 //Roo.log('onBeforeLoad');
26752 this.el.update("");
26754 this.el.mask(this.mask ? this.mask : "Loading" );
26756 onLoad : function ()
26763 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26764 * @param {HTMLElement} node
26765 * @return {HTMLElement} The template node
26767 findItemFromChild : function(node){
26768 var el = this.dataName ?
26769 this.el.child('.roo-tpl-' + this.dataName,true) :
26772 if(!node || node.parentNode == el){
26775 var p = node.parentNode;
26776 while(p && p != el){
26777 if(p.parentNode == el){
26786 onClick : function(e){
26787 var item = this.findItemFromChild(e.getTarget());
26789 var index = this.indexOf(item);
26790 if(this.onItemClick(item, index, e) !== false){
26791 this.fireEvent("click", this, index, item, e);
26794 this.clearSelections();
26799 onContextMenu : function(e){
26800 var item = this.findItemFromChild(e.getTarget());
26802 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26807 onDblClick : function(e){
26808 var item = this.findItemFromChild(e.getTarget());
26810 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26814 onItemClick : function(item, index, e)
26816 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26819 if (this.toggleSelect) {
26820 var m = this.isSelected(item) ? 'unselect' : 'select';
26823 _t[m](item, true, false);
26826 if(this.multiSelect || this.singleSelect){
26827 if(this.multiSelect && e.shiftKey && this.lastSelection){
26828 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26830 this.select(item, this.multiSelect && e.ctrlKey);
26831 this.lastSelection = item;
26834 if(!this.tickable){
26835 e.preventDefault();
26843 * Get the number of selected nodes.
26846 getSelectionCount : function(){
26847 return this.selections.length;
26851 * Get the currently selected nodes.
26852 * @return {Array} An array of HTMLElements
26854 getSelectedNodes : function(){
26855 return this.selections;
26859 * Get the indexes of the selected nodes.
26862 getSelectedIndexes : function(){
26863 var indexes = [], s = this.selections;
26864 for(var i = 0, len = s.length; i < len; i++){
26865 indexes.push(s[i].nodeIndex);
26871 * Clear all selections
26872 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
26874 clearSelections : function(suppressEvent){
26875 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
26876 this.cmp.elements = this.selections;
26877 this.cmp.removeClass(this.selectedClass);
26878 this.selections = [];
26879 if(!suppressEvent){
26880 this.fireEvent("selectionchange", this, this.selections);
26886 * Returns true if the passed node is selected
26887 * @param {HTMLElement/Number} node The node or node index
26888 * @return {Boolean}
26890 isSelected : function(node){
26891 var s = this.selections;
26895 node = this.getNode(node);
26896 return s.indexOf(node) !== -1;
26901 * @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
26902 * @param {Boolean} keepExisting (optional) true to keep existing selections
26903 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26905 select : function(nodeInfo, keepExisting, suppressEvent){
26906 if(nodeInfo instanceof Array){
26908 this.clearSelections(true);
26910 for(var i = 0, len = nodeInfo.length; i < len; i++){
26911 this.select(nodeInfo[i], true, true);
26915 var node = this.getNode(nodeInfo);
26916 if(!node || this.isSelected(node)){
26917 return; // already selected.
26920 this.clearSelections(true);
26923 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
26924 Roo.fly(node).addClass(this.selectedClass);
26925 this.selections.push(node);
26926 if(!suppressEvent){
26927 this.fireEvent("selectionchange", this, this.selections);
26935 * @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
26936 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
26937 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26939 unselect : function(nodeInfo, keepExisting, suppressEvent)
26941 if(nodeInfo instanceof Array){
26942 Roo.each(this.selections, function(s) {
26943 this.unselect(s, nodeInfo);
26947 var node = this.getNode(nodeInfo);
26948 if(!node || !this.isSelected(node)){
26949 //Roo.log("not selected");
26950 return; // not selected.
26954 Roo.each(this.selections, function(s) {
26956 Roo.fly(node).removeClass(this.selectedClass);
26963 this.selections= ns;
26964 this.fireEvent("selectionchange", this, this.selections);
26968 * Gets a template node.
26969 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26970 * @return {HTMLElement} The node or null if it wasn't found
26972 getNode : function(nodeInfo){
26973 if(typeof nodeInfo == "string"){
26974 return document.getElementById(nodeInfo);
26975 }else if(typeof nodeInfo == "number"){
26976 return this.nodes[nodeInfo];
26982 * Gets a range template nodes.
26983 * @param {Number} startIndex
26984 * @param {Number} endIndex
26985 * @return {Array} An array of nodes
26987 getNodes : function(start, end){
26988 var ns = this.nodes;
26989 start = start || 0;
26990 end = typeof end == "undefined" ? ns.length - 1 : end;
26993 for(var i = start; i <= end; i++){
26997 for(var i = start; i >= end; i--){
27005 * Finds the index of the passed node
27006 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27007 * @return {Number} The index of the node or -1
27009 indexOf : function(node){
27010 node = this.getNode(node);
27011 if(typeof node.nodeIndex == "number"){
27012 return node.nodeIndex;
27014 var ns = this.nodes;
27015 for(var i = 0, len = ns.length; i < len; i++){
27025 * Ext JS Library 1.1.1
27026 * Copyright(c) 2006-2007, Ext JS, LLC.
27028 * Originally Released Under LGPL - original licence link has changed is not relivant.
27031 * <script type="text/javascript">
27035 * @class Roo.JsonView
27036 * @extends Roo.View
27037 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27039 var view = new Roo.JsonView({
27040 container: "my-element",
27041 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27046 // listen for node click?
27047 view.on("click", function(vw, index, node, e){
27048 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27051 // direct load of JSON data
27052 view.load("foobar.php");
27054 // Example from my blog list
27055 var tpl = new Roo.Template(
27056 '<div class="entry">' +
27057 '<a class="entry-title" href="{link}">{title}</a>' +
27058 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27059 "</div><hr />"
27062 var moreView = new Roo.JsonView({
27063 container : "entry-list",
27067 moreView.on("beforerender", this.sortEntries, this);
27069 url: "/blog/get-posts.php",
27070 params: "allposts=true",
27071 text: "Loading Blog Entries..."
27075 * Note: old code is supported with arguments : (container, template, config)
27079 * Create a new JsonView
27081 * @param {Object} config The config object
27084 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27087 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27089 var um = this.el.getUpdateManager();
27090 um.setRenderer(this);
27091 um.on("update", this.onLoad, this);
27092 um.on("failure", this.onLoadException, this);
27095 * @event beforerender
27096 * Fires before rendering of the downloaded JSON data.
27097 * @param {Roo.JsonView} this
27098 * @param {Object} data The JSON data loaded
27102 * Fires when data is loaded.
27103 * @param {Roo.JsonView} this
27104 * @param {Object} data The JSON data loaded
27105 * @param {Object} response The raw Connect response object
27108 * @event loadexception
27109 * Fires when loading fails.
27110 * @param {Roo.JsonView} this
27111 * @param {Object} response The raw Connect response object
27114 'beforerender' : true,
27116 'loadexception' : true
27119 Roo.extend(Roo.JsonView, Roo.View, {
27121 * @type {String} The root property in the loaded JSON object that contains the data
27126 * Refreshes the view.
27128 refresh : function(){
27129 this.clearSelections();
27130 this.el.update("");
27132 var o = this.jsonData;
27133 if(o && o.length > 0){
27134 for(var i = 0, len = o.length; i < len; i++){
27135 var data = this.prepareData(o[i], i, o);
27136 html[html.length] = this.tpl.apply(data);
27139 html.push(this.emptyText);
27141 this.el.update(html.join(""));
27142 this.nodes = this.el.dom.childNodes;
27143 this.updateIndexes(0);
27147 * 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.
27148 * @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:
27151 url: "your-url.php",
27152 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27153 callback: yourFunction,
27154 scope: yourObject, //(optional scope)
27157 text: "Loading...",
27162 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27163 * 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.
27164 * @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}
27165 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27166 * @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.
27169 var um = this.el.getUpdateManager();
27170 um.update.apply(um, arguments);
27173 // note - render is a standard framework call...
27174 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27175 render : function(el, response){
27177 this.clearSelections();
27178 this.el.update("");
27181 if (response != '') {
27182 o = Roo.util.JSON.decode(response.responseText);
27185 o = o[this.jsonRoot];
27191 * The current JSON data or null
27194 this.beforeRender();
27199 * Get the number of records in the current JSON dataset
27202 getCount : function(){
27203 return this.jsonData ? this.jsonData.length : 0;
27207 * Returns the JSON object for the specified node(s)
27208 * @param {HTMLElement/Array} node The node or an array of nodes
27209 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27210 * you get the JSON object for the node
27212 getNodeData : function(node){
27213 if(node instanceof Array){
27215 for(var i = 0, len = node.length; i < len; i++){
27216 data.push(this.getNodeData(node[i]));
27220 return this.jsonData[this.indexOf(node)] || null;
27223 beforeRender : function(){
27224 this.snapshot = this.jsonData;
27226 this.sort.apply(this, this.sortInfo);
27228 this.fireEvent("beforerender", this, this.jsonData);
27231 onLoad : function(el, o){
27232 this.fireEvent("load", this, this.jsonData, o);
27235 onLoadException : function(el, o){
27236 this.fireEvent("loadexception", this, o);
27240 * Filter the data by a specific property.
27241 * @param {String} property A property on your JSON objects
27242 * @param {String/RegExp} value Either string that the property values
27243 * should start with, or a RegExp to test against the property
27245 filter : function(property, value){
27248 var ss = this.snapshot;
27249 if(typeof value == "string"){
27250 var vlen = value.length;
27252 this.clearFilter();
27255 value = value.toLowerCase();
27256 for(var i = 0, len = ss.length; i < len; i++){
27258 if(o[property].substr(0, vlen).toLowerCase() == value){
27262 } else if(value.exec){ // regex?
27263 for(var i = 0, len = ss.length; i < len; i++){
27265 if(value.test(o[property])){
27272 this.jsonData = data;
27278 * Filter by a function. The passed function will be called with each
27279 * object in the current dataset. If the function returns true the value is kept,
27280 * otherwise it is filtered.
27281 * @param {Function} fn
27282 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27284 filterBy : function(fn, scope){
27287 var ss = this.snapshot;
27288 for(var i = 0, len = ss.length; i < len; i++){
27290 if(fn.call(scope || this, o)){
27294 this.jsonData = data;
27300 * Clears the current filter.
27302 clearFilter : function(){
27303 if(this.snapshot && this.jsonData != this.snapshot){
27304 this.jsonData = this.snapshot;
27311 * Sorts the data for this view and refreshes it.
27312 * @param {String} property A property on your JSON objects to sort on
27313 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27314 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27316 sort : function(property, dir, sortType){
27317 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27320 var dsc = dir && dir.toLowerCase() == "desc";
27321 var f = function(o1, o2){
27322 var v1 = sortType ? sortType(o1[p]) : o1[p];
27323 var v2 = sortType ? sortType(o2[p]) : o2[p];
27326 return dsc ? +1 : -1;
27327 } else if(v1 > v2){
27328 return dsc ? -1 : +1;
27333 this.jsonData.sort(f);
27335 if(this.jsonData != this.snapshot){
27336 this.snapshot.sort(f);
27342 * Ext JS Library 1.1.1
27343 * Copyright(c) 2006-2007, Ext JS, LLC.
27345 * Originally Released Under LGPL - original licence link has changed is not relivant.
27348 * <script type="text/javascript">
27353 * @class Roo.ColorPalette
27354 * @extends Roo.Component
27355 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27356 * Here's an example of typical usage:
27358 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27359 cp.render('my-div');
27361 cp.on('select', function(palette, selColor){
27362 // do something with selColor
27366 * Create a new ColorPalette
27367 * @param {Object} config The config object
27369 Roo.ColorPalette = function(config){
27370 Roo.ColorPalette.superclass.constructor.call(this, config);
27374 * Fires when a color is selected
27375 * @param {ColorPalette} this
27376 * @param {String} color The 6-digit color hex code (without the # symbol)
27382 this.on("select", this.handler, this.scope, true);
27385 Roo.extend(Roo.ColorPalette, Roo.Component, {
27387 * @cfg {String} itemCls
27388 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27390 itemCls : "x-color-palette",
27392 * @cfg {String} value
27393 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27394 * the hex codes are case-sensitive.
27397 clickEvent:'click',
27399 ctype: "Roo.ColorPalette",
27402 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27404 allowReselect : false,
27407 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27408 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27409 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27410 * of colors with the width setting until the box is symmetrical.</p>
27411 * <p>You can override individual colors if needed:</p>
27413 var cp = new Roo.ColorPalette();
27414 cp.colors[0] = "FF0000"; // change the first box to red
27417 Or you can provide a custom array of your own for complete control:
27419 var cp = new Roo.ColorPalette();
27420 cp.colors = ["000000", "993300", "333300"];
27425 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27426 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27427 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27428 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27429 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27433 onRender : function(container, position){
27434 var t = new Roo.MasterTemplate(
27435 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27437 var c = this.colors;
27438 for(var i = 0, len = c.length; i < len; i++){
27441 var el = document.createElement("div");
27442 el.className = this.itemCls;
27444 container.dom.insertBefore(el, position);
27445 this.el = Roo.get(el);
27446 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27447 if(this.clickEvent != 'click'){
27448 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27453 afterRender : function(){
27454 Roo.ColorPalette.superclass.afterRender.call(this);
27456 var s = this.value;
27463 handleClick : function(e, t){
27464 e.preventDefault();
27465 if(!this.disabled){
27466 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27467 this.select(c.toUpperCase());
27472 * Selects the specified color in the palette (fires the select event)
27473 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27475 select : function(color){
27476 color = color.replace("#", "");
27477 if(color != this.value || this.allowReselect){
27480 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27482 el.child("a.color-"+color).addClass("x-color-palette-sel");
27483 this.value = color;
27484 this.fireEvent("select", this, color);
27489 * Ext JS Library 1.1.1
27490 * Copyright(c) 2006-2007, Ext JS, LLC.
27492 * Originally Released Under LGPL - original licence link has changed is not relivant.
27495 * <script type="text/javascript">
27499 * @class Roo.DatePicker
27500 * @extends Roo.Component
27501 * Simple date picker class.
27503 * Create a new DatePicker
27504 * @param {Object} config The config object
27506 Roo.DatePicker = function(config){
27507 Roo.DatePicker.superclass.constructor.call(this, config);
27509 this.value = config && config.value ?
27510 config.value.clearTime() : new Date().clearTime();
27515 * Fires when a date is selected
27516 * @param {DatePicker} this
27517 * @param {Date} date The selected date
27521 * @event monthchange
27522 * Fires when the displayed month changes
27523 * @param {DatePicker} this
27524 * @param {Date} date The selected month
27526 'monthchange': true
27530 this.on("select", this.handler, this.scope || this);
27532 // build the disabledDatesRE
27533 if(!this.disabledDatesRE && this.disabledDates){
27534 var dd = this.disabledDates;
27536 for(var i = 0; i < dd.length; i++){
27538 if(i != dd.length-1) {
27542 this.disabledDatesRE = new RegExp(re + ")");
27546 Roo.extend(Roo.DatePicker, Roo.Component, {
27548 * @cfg {String} todayText
27549 * The text to display on the button that selects the current date (defaults to "Today")
27551 todayText : "Today",
27553 * @cfg {String} okText
27554 * The text to display on the ok button
27556 okText : " OK ", //   to give the user extra clicking room
27558 * @cfg {String} cancelText
27559 * The text to display on the cancel button
27561 cancelText : "Cancel",
27563 * @cfg {String} todayTip
27564 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27566 todayTip : "{0} (Spacebar)",
27568 * @cfg {Date} minDate
27569 * Minimum allowable date (JavaScript date object, defaults to null)
27573 * @cfg {Date} maxDate
27574 * Maximum allowable date (JavaScript date object, defaults to null)
27578 * @cfg {String} minText
27579 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27581 minText : "This date is before the minimum date",
27583 * @cfg {String} maxText
27584 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27586 maxText : "This date is after the maximum date",
27588 * @cfg {String} format
27589 * The default date format string which can be overriden for localization support. The format must be
27590 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27594 * @cfg {Array} disabledDays
27595 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27597 disabledDays : null,
27599 * @cfg {String} disabledDaysText
27600 * The tooltip to display when the date falls on a disabled day (defaults to "")
27602 disabledDaysText : "",
27604 * @cfg {RegExp} disabledDatesRE
27605 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27607 disabledDatesRE : null,
27609 * @cfg {String} disabledDatesText
27610 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27612 disabledDatesText : "",
27614 * @cfg {Boolean} constrainToViewport
27615 * True to constrain the date picker to the viewport (defaults to true)
27617 constrainToViewport : true,
27619 * @cfg {Array} monthNames
27620 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27622 monthNames : Date.monthNames,
27624 * @cfg {Array} dayNames
27625 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27627 dayNames : Date.dayNames,
27629 * @cfg {String} nextText
27630 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27632 nextText: 'Next Month (Control+Right)',
27634 * @cfg {String} prevText
27635 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27637 prevText: 'Previous Month (Control+Left)',
27639 * @cfg {String} monthYearText
27640 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27642 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27644 * @cfg {Number} startDay
27645 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27649 * @cfg {Bool} showClear
27650 * Show a clear button (usefull for date form elements that can be blank.)
27656 * Sets the value of the date field
27657 * @param {Date} value The date to set
27659 setValue : function(value){
27660 var old = this.value;
27662 if (typeof(value) == 'string') {
27664 value = Date.parseDate(value, this.format);
27667 value = new Date();
27670 this.value = value.clearTime(true);
27672 this.update(this.value);
27677 * Gets the current selected value of the date field
27678 * @return {Date} The selected date
27680 getValue : function(){
27685 focus : function(){
27687 this.update(this.activeDate);
27692 onRender : function(container, position){
27695 '<table cellspacing="0">',
27696 '<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>',
27697 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27698 var dn = this.dayNames;
27699 for(var i = 0; i < 7; i++){
27700 var d = this.startDay+i;
27704 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27706 m[m.length] = "</tr></thead><tbody><tr>";
27707 for(var i = 0; i < 42; i++) {
27708 if(i % 7 == 0 && i != 0){
27709 m[m.length] = "</tr><tr>";
27711 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27713 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27714 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27716 var el = document.createElement("div");
27717 el.className = "x-date-picker";
27718 el.innerHTML = m.join("");
27720 container.dom.insertBefore(el, position);
27722 this.el = Roo.get(el);
27723 this.eventEl = Roo.get(el.firstChild);
27725 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27726 handler: this.showPrevMonth,
27728 preventDefault:true,
27732 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27733 handler: this.showNextMonth,
27735 preventDefault:true,
27739 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27741 this.monthPicker = this.el.down('div.x-date-mp');
27742 this.monthPicker.enableDisplayMode('block');
27744 var kn = new Roo.KeyNav(this.eventEl, {
27745 "left" : function(e){
27747 this.showPrevMonth() :
27748 this.update(this.activeDate.add("d", -1));
27751 "right" : function(e){
27753 this.showNextMonth() :
27754 this.update(this.activeDate.add("d", 1));
27757 "up" : function(e){
27759 this.showNextYear() :
27760 this.update(this.activeDate.add("d", -7));
27763 "down" : function(e){
27765 this.showPrevYear() :
27766 this.update(this.activeDate.add("d", 7));
27769 "pageUp" : function(e){
27770 this.showNextMonth();
27773 "pageDown" : function(e){
27774 this.showPrevMonth();
27777 "enter" : function(e){
27778 e.stopPropagation();
27785 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27787 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27789 this.el.unselectable();
27791 this.cells = this.el.select("table.x-date-inner tbody td");
27792 this.textNodes = this.el.query("table.x-date-inner tbody span");
27794 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27796 tooltip: this.monthYearText
27799 this.mbtn.on('click', this.showMonthPicker, this);
27800 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27803 var today = (new Date()).dateFormat(this.format);
27805 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27806 if (this.showClear) {
27807 baseTb.add( new Roo.Toolbar.Fill());
27810 text: String.format(this.todayText, today),
27811 tooltip: String.format(this.todayTip, today),
27812 handler: this.selectToday,
27816 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27819 if (this.showClear) {
27821 baseTb.add( new Roo.Toolbar.Fill());
27824 cls: 'x-btn-icon x-btn-clear',
27825 handler: function() {
27827 this.fireEvent("select", this, '');
27837 this.update(this.value);
27840 createMonthPicker : function(){
27841 if(!this.monthPicker.dom.firstChild){
27842 var buf = ['<table border="0" cellspacing="0">'];
27843 for(var i = 0; i < 6; i++){
27845 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27846 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27848 '<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>' :
27849 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27853 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27855 '</button><button type="button" class="x-date-mp-cancel">',
27857 '</button></td></tr>',
27860 this.monthPicker.update(buf.join(''));
27861 this.monthPicker.on('click', this.onMonthClick, this);
27862 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
27864 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
27865 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
27867 this.mpMonths.each(function(m, a, i){
27870 m.dom.xmonth = 5 + Math.round(i * .5);
27872 m.dom.xmonth = Math.round((i-1) * .5);
27878 showMonthPicker : function(){
27879 this.createMonthPicker();
27880 var size = this.el.getSize();
27881 this.monthPicker.setSize(size);
27882 this.monthPicker.child('table').setSize(size);
27884 this.mpSelMonth = (this.activeDate || this.value).getMonth();
27885 this.updateMPMonth(this.mpSelMonth);
27886 this.mpSelYear = (this.activeDate || this.value).getFullYear();
27887 this.updateMPYear(this.mpSelYear);
27889 this.monthPicker.slideIn('t', {duration:.2});
27892 updateMPYear : function(y){
27894 var ys = this.mpYears.elements;
27895 for(var i = 1; i <= 10; i++){
27896 var td = ys[i-1], y2;
27898 y2 = y + Math.round(i * .5);
27899 td.firstChild.innerHTML = y2;
27902 y2 = y - (5-Math.round(i * .5));
27903 td.firstChild.innerHTML = y2;
27906 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
27910 updateMPMonth : function(sm){
27911 this.mpMonths.each(function(m, a, i){
27912 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
27916 selectMPMonth: function(m){
27920 onMonthClick : function(e, t){
27922 var el = new Roo.Element(t), pn;
27923 if(el.is('button.x-date-mp-cancel')){
27924 this.hideMonthPicker();
27926 else if(el.is('button.x-date-mp-ok')){
27927 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27928 this.hideMonthPicker();
27930 else if(pn = el.up('td.x-date-mp-month', 2)){
27931 this.mpMonths.removeClass('x-date-mp-sel');
27932 pn.addClass('x-date-mp-sel');
27933 this.mpSelMonth = pn.dom.xmonth;
27935 else if(pn = el.up('td.x-date-mp-year', 2)){
27936 this.mpYears.removeClass('x-date-mp-sel');
27937 pn.addClass('x-date-mp-sel');
27938 this.mpSelYear = pn.dom.xyear;
27940 else if(el.is('a.x-date-mp-prev')){
27941 this.updateMPYear(this.mpyear-10);
27943 else if(el.is('a.x-date-mp-next')){
27944 this.updateMPYear(this.mpyear+10);
27948 onMonthDblClick : function(e, t){
27950 var el = new Roo.Element(t), pn;
27951 if(pn = el.up('td.x-date-mp-month', 2)){
27952 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
27953 this.hideMonthPicker();
27955 else if(pn = el.up('td.x-date-mp-year', 2)){
27956 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27957 this.hideMonthPicker();
27961 hideMonthPicker : function(disableAnim){
27962 if(this.monthPicker){
27963 if(disableAnim === true){
27964 this.monthPicker.hide();
27966 this.monthPicker.slideOut('t', {duration:.2});
27972 showPrevMonth : function(e){
27973 this.update(this.activeDate.add("mo", -1));
27977 showNextMonth : function(e){
27978 this.update(this.activeDate.add("mo", 1));
27982 showPrevYear : function(){
27983 this.update(this.activeDate.add("y", -1));
27987 showNextYear : function(){
27988 this.update(this.activeDate.add("y", 1));
27992 handleMouseWheel : function(e){
27993 var delta = e.getWheelDelta();
27995 this.showPrevMonth();
27997 } else if(delta < 0){
27998 this.showNextMonth();
28004 handleDateClick : function(e, t){
28006 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28007 this.setValue(new Date(t.dateValue));
28008 this.fireEvent("select", this, this.value);
28013 selectToday : function(){
28014 this.setValue(new Date().clearTime());
28015 this.fireEvent("select", this, this.value);
28019 update : function(date)
28021 var vd = this.activeDate;
28022 this.activeDate = date;
28024 var t = date.getTime();
28025 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28026 this.cells.removeClass("x-date-selected");
28027 this.cells.each(function(c){
28028 if(c.dom.firstChild.dateValue == t){
28029 c.addClass("x-date-selected");
28030 setTimeout(function(){
28031 try{c.dom.firstChild.focus();}catch(e){}
28040 var days = date.getDaysInMonth();
28041 var firstOfMonth = date.getFirstDateOfMonth();
28042 var startingPos = firstOfMonth.getDay()-this.startDay;
28044 if(startingPos <= this.startDay){
28048 var pm = date.add("mo", -1);
28049 var prevStart = pm.getDaysInMonth()-startingPos;
28051 var cells = this.cells.elements;
28052 var textEls = this.textNodes;
28053 days += startingPos;
28055 // convert everything to numbers so it's fast
28056 var day = 86400000;
28057 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28058 var today = new Date().clearTime().getTime();
28059 var sel = date.clearTime().getTime();
28060 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28061 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28062 var ddMatch = this.disabledDatesRE;
28063 var ddText = this.disabledDatesText;
28064 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28065 var ddaysText = this.disabledDaysText;
28066 var format = this.format;
28068 var setCellClass = function(cal, cell){
28070 var t = d.getTime();
28071 cell.firstChild.dateValue = t;
28073 cell.className += " x-date-today";
28074 cell.title = cal.todayText;
28077 cell.className += " x-date-selected";
28078 setTimeout(function(){
28079 try{cell.firstChild.focus();}catch(e){}
28084 cell.className = " x-date-disabled";
28085 cell.title = cal.minText;
28089 cell.className = " x-date-disabled";
28090 cell.title = cal.maxText;
28094 if(ddays.indexOf(d.getDay()) != -1){
28095 cell.title = ddaysText;
28096 cell.className = " x-date-disabled";
28099 if(ddMatch && format){
28100 var fvalue = d.dateFormat(format);
28101 if(ddMatch.test(fvalue)){
28102 cell.title = ddText.replace("%0", fvalue);
28103 cell.className = " x-date-disabled";
28109 for(; i < startingPos; i++) {
28110 textEls[i].innerHTML = (++prevStart);
28111 d.setDate(d.getDate()+1);
28112 cells[i].className = "x-date-prevday";
28113 setCellClass(this, cells[i]);
28115 for(; i < days; i++){
28116 intDay = i - startingPos + 1;
28117 textEls[i].innerHTML = (intDay);
28118 d.setDate(d.getDate()+1);
28119 cells[i].className = "x-date-active";
28120 setCellClass(this, cells[i]);
28123 for(; i < 42; i++) {
28124 textEls[i].innerHTML = (++extraDays);
28125 d.setDate(d.getDate()+1);
28126 cells[i].className = "x-date-nextday";
28127 setCellClass(this, cells[i]);
28130 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28131 this.fireEvent('monthchange', this, date);
28133 if(!this.internalRender){
28134 var main = this.el.dom.firstChild;
28135 var w = main.offsetWidth;
28136 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28137 Roo.fly(main).setWidth(w);
28138 this.internalRender = true;
28139 // opera does not respect the auto grow header center column
28140 // then, after it gets a width opera refuses to recalculate
28141 // without a second pass
28142 if(Roo.isOpera && !this.secondPass){
28143 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28144 this.secondPass = true;
28145 this.update.defer(10, this, [date]);
28153 * Ext JS Library 1.1.1
28154 * Copyright(c) 2006-2007, Ext JS, LLC.
28156 * Originally Released Under LGPL - original licence link has changed is not relivant.
28159 * <script type="text/javascript">
28162 * @class Roo.TabPanel
28163 * @extends Roo.util.Observable
28164 * A lightweight tab container.
28168 // basic tabs 1, built from existing content
28169 var tabs = new Roo.TabPanel("tabs1");
28170 tabs.addTab("script", "View Script");
28171 tabs.addTab("markup", "View Markup");
28172 tabs.activate("script");
28174 // more advanced tabs, built from javascript
28175 var jtabs = new Roo.TabPanel("jtabs");
28176 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28178 // set up the UpdateManager
28179 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28180 var updater = tab2.getUpdateManager();
28181 updater.setDefaultUrl("ajax1.htm");
28182 tab2.on('activate', updater.refresh, updater, true);
28184 // Use setUrl for Ajax loading
28185 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28186 tab3.setUrl("ajax2.htm", null, true);
28189 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28192 jtabs.activate("jtabs-1");
28195 * Create a new TabPanel.
28196 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28197 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28199 Roo.TabPanel = function(container, config){
28201 * The container element for this TabPanel.
28202 * @type Roo.Element
28204 this.el = Roo.get(container, true);
28206 if(typeof config == "boolean"){
28207 this.tabPosition = config ? "bottom" : "top";
28209 Roo.apply(this, config);
28212 if(this.tabPosition == "bottom"){
28213 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28214 this.el.addClass("x-tabs-bottom");
28216 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28217 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28218 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28220 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28222 if(this.tabPosition != "bottom"){
28223 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28224 * @type Roo.Element
28226 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28227 this.el.addClass("x-tabs-top");
28231 this.bodyEl.setStyle("position", "relative");
28233 this.active = null;
28234 this.activateDelegate = this.activate.createDelegate(this);
28239 * Fires when the active tab changes
28240 * @param {Roo.TabPanel} this
28241 * @param {Roo.TabPanelItem} activePanel The new active tab
28245 * @event beforetabchange
28246 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28247 * @param {Roo.TabPanel} this
28248 * @param {Object} e Set cancel to true on this object to cancel the tab change
28249 * @param {Roo.TabPanelItem} tab The tab being changed to
28251 "beforetabchange" : true
28254 Roo.EventManager.onWindowResize(this.onResize, this);
28255 this.cpad = this.el.getPadding("lr");
28256 this.hiddenCount = 0;
28259 // toolbar on the tabbar support...
28260 if (this.toolbar) {
28261 var tcfg = this.toolbar;
28262 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28263 this.toolbar = new Roo.Toolbar(tcfg);
28264 if (Roo.isSafari) {
28265 var tbl = tcfg.container.child('table', true);
28266 tbl.setAttribute('width', '100%');
28273 Roo.TabPanel.superclass.constructor.call(this);
28276 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28278 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28280 tabPosition : "top",
28282 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28284 currentTabWidth : 0,
28286 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28290 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28294 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28296 preferredTabWidth : 175,
28298 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28300 resizeTabs : false,
28302 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28304 monitorResize : true,
28306 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28311 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28312 * @param {String} id The id of the div to use <b>or create</b>
28313 * @param {String} text The text for the tab
28314 * @param {String} content (optional) Content to put in the TabPanelItem body
28315 * @param {Boolean} closable (optional) True to create a close icon on the tab
28316 * @return {Roo.TabPanelItem} The created TabPanelItem
28318 addTab : function(id, text, content, closable){
28319 var item = new Roo.TabPanelItem(this, id, text, closable);
28320 this.addTabItem(item);
28322 item.setContent(content);
28328 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28329 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28330 * @return {Roo.TabPanelItem}
28332 getTab : function(id){
28333 return this.items[id];
28337 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28338 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28340 hideTab : function(id){
28341 var t = this.items[id];
28344 this.hiddenCount++;
28345 this.autoSizeTabs();
28350 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28351 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28353 unhideTab : function(id){
28354 var t = this.items[id];
28356 t.setHidden(false);
28357 this.hiddenCount--;
28358 this.autoSizeTabs();
28363 * Adds an existing {@link Roo.TabPanelItem}.
28364 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28366 addTabItem : function(item){
28367 this.items[item.id] = item;
28368 this.items.push(item);
28369 if(this.resizeTabs){
28370 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28371 this.autoSizeTabs();
28378 * Removes a {@link Roo.TabPanelItem}.
28379 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28381 removeTab : function(id){
28382 var items = this.items;
28383 var tab = items[id];
28384 if(!tab) { return; }
28385 var index = items.indexOf(tab);
28386 if(this.active == tab && items.length > 1){
28387 var newTab = this.getNextAvailable(index);
28392 this.stripEl.dom.removeChild(tab.pnode.dom);
28393 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28394 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28396 items.splice(index, 1);
28397 delete this.items[tab.id];
28398 tab.fireEvent("close", tab);
28399 tab.purgeListeners();
28400 this.autoSizeTabs();
28403 getNextAvailable : function(start){
28404 var items = this.items;
28406 // look for a next tab that will slide over to
28407 // replace the one being removed
28408 while(index < items.length){
28409 var item = items[++index];
28410 if(item && !item.isHidden()){
28414 // if one isn't found select the previous tab (on the left)
28417 var item = items[--index];
28418 if(item && !item.isHidden()){
28426 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28427 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28429 disableTab : function(id){
28430 var tab = this.items[id];
28431 if(tab && this.active != tab){
28437 * Enables a {@link Roo.TabPanelItem} that is disabled.
28438 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28440 enableTab : function(id){
28441 var tab = this.items[id];
28446 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28447 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28448 * @return {Roo.TabPanelItem} The TabPanelItem.
28450 activate : function(id){
28451 var tab = this.items[id];
28455 if(tab == this.active || tab.disabled){
28459 this.fireEvent("beforetabchange", this, e, tab);
28460 if(e.cancel !== true && !tab.disabled){
28462 this.active.hide();
28464 this.active = this.items[id];
28465 this.active.show();
28466 this.fireEvent("tabchange", this, this.active);
28472 * Gets the active {@link Roo.TabPanelItem}.
28473 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28475 getActiveTab : function(){
28476 return this.active;
28480 * Updates the tab body element to fit the height of the container element
28481 * for overflow scrolling
28482 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28484 syncHeight : function(targetHeight){
28485 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28486 var bm = this.bodyEl.getMargins();
28487 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28488 this.bodyEl.setHeight(newHeight);
28492 onResize : function(){
28493 if(this.monitorResize){
28494 this.autoSizeTabs();
28499 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28501 beginUpdate : function(){
28502 this.updating = true;
28506 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28508 endUpdate : function(){
28509 this.updating = false;
28510 this.autoSizeTabs();
28514 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28516 autoSizeTabs : function(){
28517 var count = this.items.length;
28518 var vcount = count - this.hiddenCount;
28519 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28522 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28523 var availWidth = Math.floor(w / vcount);
28524 var b = this.stripBody;
28525 if(b.getWidth() > w){
28526 var tabs = this.items;
28527 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28528 if(availWidth < this.minTabWidth){
28529 /*if(!this.sleft){ // incomplete scrolling code
28530 this.createScrollButtons();
28533 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28536 if(this.currentTabWidth < this.preferredTabWidth){
28537 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28543 * Returns the number of tabs in this TabPanel.
28546 getCount : function(){
28547 return this.items.length;
28551 * Resizes all the tabs to the passed width
28552 * @param {Number} The new width
28554 setTabWidth : function(width){
28555 this.currentTabWidth = width;
28556 for(var i = 0, len = this.items.length; i < len; i++) {
28557 if(!this.items[i].isHidden()) {
28558 this.items[i].setWidth(width);
28564 * Destroys this TabPanel
28565 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28567 destroy : function(removeEl){
28568 Roo.EventManager.removeResizeListener(this.onResize, this);
28569 for(var i = 0, len = this.items.length; i < len; i++){
28570 this.items[i].purgeListeners();
28572 if(removeEl === true){
28573 this.el.update("");
28580 * @class Roo.TabPanelItem
28581 * @extends Roo.util.Observable
28582 * Represents an individual item (tab plus body) in a TabPanel.
28583 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28584 * @param {String} id The id of this TabPanelItem
28585 * @param {String} text The text for the tab of this TabPanelItem
28586 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28588 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28590 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28591 * @type Roo.TabPanel
28593 this.tabPanel = tabPanel;
28595 * The id for this TabPanelItem
28600 this.disabled = false;
28604 this.loaded = false;
28605 this.closable = closable;
28608 * The body element for this TabPanelItem.
28609 * @type Roo.Element
28611 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28612 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28613 this.bodyEl.setStyle("display", "block");
28614 this.bodyEl.setStyle("zoom", "1");
28617 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28619 this.el = Roo.get(els.el, true);
28620 this.inner = Roo.get(els.inner, true);
28621 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28622 this.pnode = Roo.get(els.el.parentNode, true);
28623 this.el.on("mousedown", this.onTabMouseDown, this);
28624 this.el.on("click", this.onTabClick, this);
28627 var c = Roo.get(els.close, true);
28628 c.dom.title = this.closeText;
28629 c.addClassOnOver("close-over");
28630 c.on("click", this.closeClick, this);
28636 * Fires when this tab becomes the active tab.
28637 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28638 * @param {Roo.TabPanelItem} this
28642 * @event beforeclose
28643 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28644 * @param {Roo.TabPanelItem} this
28645 * @param {Object} e Set cancel to true on this object to cancel the close.
28647 "beforeclose": true,
28650 * Fires when this tab is closed.
28651 * @param {Roo.TabPanelItem} this
28655 * @event deactivate
28656 * Fires when this tab is no longer the active tab.
28657 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28658 * @param {Roo.TabPanelItem} this
28660 "deactivate" : true
28662 this.hidden = false;
28664 Roo.TabPanelItem.superclass.constructor.call(this);
28667 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28668 purgeListeners : function(){
28669 Roo.util.Observable.prototype.purgeListeners.call(this);
28670 this.el.removeAllListeners();
28673 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28676 this.pnode.addClass("on");
28679 this.tabPanel.stripWrap.repaint();
28681 this.fireEvent("activate", this.tabPanel, this);
28685 * Returns true if this tab is the active tab.
28686 * @return {Boolean}
28688 isActive : function(){
28689 return this.tabPanel.getActiveTab() == this;
28693 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28696 this.pnode.removeClass("on");
28698 this.fireEvent("deactivate", this.tabPanel, this);
28701 hideAction : function(){
28702 this.bodyEl.hide();
28703 this.bodyEl.setStyle("position", "absolute");
28704 this.bodyEl.setLeft("-20000px");
28705 this.bodyEl.setTop("-20000px");
28708 showAction : function(){
28709 this.bodyEl.setStyle("position", "relative");
28710 this.bodyEl.setTop("");
28711 this.bodyEl.setLeft("");
28712 this.bodyEl.show();
28716 * Set the tooltip for the tab.
28717 * @param {String} tooltip The tab's tooltip
28719 setTooltip : function(text){
28720 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28721 this.textEl.dom.qtip = text;
28722 this.textEl.dom.removeAttribute('title');
28724 this.textEl.dom.title = text;
28728 onTabClick : function(e){
28729 e.preventDefault();
28730 this.tabPanel.activate(this.id);
28733 onTabMouseDown : function(e){
28734 e.preventDefault();
28735 this.tabPanel.activate(this.id);
28738 getWidth : function(){
28739 return this.inner.getWidth();
28742 setWidth : function(width){
28743 var iwidth = width - this.pnode.getPadding("lr");
28744 this.inner.setWidth(iwidth);
28745 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28746 this.pnode.setWidth(width);
28750 * Show or hide the tab
28751 * @param {Boolean} hidden True to hide or false to show.
28753 setHidden : function(hidden){
28754 this.hidden = hidden;
28755 this.pnode.setStyle("display", hidden ? "none" : "");
28759 * Returns true if this tab is "hidden"
28760 * @return {Boolean}
28762 isHidden : function(){
28763 return this.hidden;
28767 * Returns the text for this tab
28770 getText : function(){
28774 autoSize : function(){
28775 //this.el.beginMeasure();
28776 this.textEl.setWidth(1);
28778 * #2804 [new] Tabs in Roojs
28779 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28781 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28782 //this.el.endMeasure();
28786 * Sets the text for the tab (Note: this also sets the tooltip text)
28787 * @param {String} text The tab's text and tooltip
28789 setText : function(text){
28791 this.textEl.update(text);
28792 this.setTooltip(text);
28793 if(!this.tabPanel.resizeTabs){
28798 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28800 activate : function(){
28801 this.tabPanel.activate(this.id);
28805 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28807 disable : function(){
28808 if(this.tabPanel.active != this){
28809 this.disabled = true;
28810 this.pnode.addClass("disabled");
28815 * Enables this TabPanelItem if it was previously disabled.
28817 enable : function(){
28818 this.disabled = false;
28819 this.pnode.removeClass("disabled");
28823 * Sets the content for this TabPanelItem.
28824 * @param {String} content The content
28825 * @param {Boolean} loadScripts true to look for and load scripts
28827 setContent : function(content, loadScripts){
28828 this.bodyEl.update(content, loadScripts);
28832 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28833 * @return {Roo.UpdateManager} The UpdateManager
28835 getUpdateManager : function(){
28836 return this.bodyEl.getUpdateManager();
28840 * Set a URL to be used to load the content for this TabPanelItem.
28841 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28842 * @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)
28843 * @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)
28844 * @return {Roo.UpdateManager} The UpdateManager
28846 setUrl : function(url, params, loadOnce){
28847 if(this.refreshDelegate){
28848 this.un('activate', this.refreshDelegate);
28850 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28851 this.on("activate", this.refreshDelegate);
28852 return this.bodyEl.getUpdateManager();
28856 _handleRefresh : function(url, params, loadOnce){
28857 if(!loadOnce || !this.loaded){
28858 var updater = this.bodyEl.getUpdateManager();
28859 updater.update(url, params, this._setLoaded.createDelegate(this));
28864 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
28865 * Will fail silently if the setUrl method has not been called.
28866 * This does not activate the panel, just updates its content.
28868 refresh : function(){
28869 if(this.refreshDelegate){
28870 this.loaded = false;
28871 this.refreshDelegate();
28876 _setLoaded : function(){
28877 this.loaded = true;
28881 closeClick : function(e){
28884 this.fireEvent("beforeclose", this, o);
28885 if(o.cancel !== true){
28886 this.tabPanel.removeTab(this.id);
28890 * The text displayed in the tooltip for the close icon.
28893 closeText : "Close this tab"
28897 Roo.TabPanel.prototype.createStrip = function(container){
28898 var strip = document.createElement("div");
28899 strip.className = "x-tabs-wrap";
28900 container.appendChild(strip);
28904 Roo.TabPanel.prototype.createStripList = function(strip){
28905 // div wrapper for retard IE
28906 // returns the "tr" element.
28907 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
28908 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
28909 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
28910 return strip.firstChild.firstChild.firstChild.firstChild;
28913 Roo.TabPanel.prototype.createBody = function(container){
28914 var body = document.createElement("div");
28915 Roo.id(body, "tab-body");
28916 Roo.fly(body).addClass("x-tabs-body");
28917 container.appendChild(body);
28921 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
28922 var body = Roo.getDom(id);
28924 body = document.createElement("div");
28927 Roo.fly(body).addClass("x-tabs-item-body");
28928 bodyEl.insertBefore(body, bodyEl.firstChild);
28932 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
28933 var td = document.createElement("td");
28934 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
28935 //stripEl.appendChild(td);
28937 td.className = "x-tabs-closable";
28938 if(!this.closeTpl){
28939 this.closeTpl = new Roo.Template(
28940 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28941 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
28942 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
28945 var el = this.closeTpl.overwrite(td, {"text": text});
28946 var close = el.getElementsByTagName("div")[0];
28947 var inner = el.getElementsByTagName("em")[0];
28948 return {"el": el, "close": close, "inner": inner};
28951 this.tabTpl = new Roo.Template(
28952 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28953 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
28956 var el = this.tabTpl.overwrite(td, {"text": text});
28957 var inner = el.getElementsByTagName("em")[0];
28958 return {"el": el, "inner": inner};
28962 * Ext JS Library 1.1.1
28963 * Copyright(c) 2006-2007, Ext JS, LLC.
28965 * Originally Released Under LGPL - original licence link has changed is not relivant.
28968 * <script type="text/javascript">
28972 * @class Roo.Button
28973 * @extends Roo.util.Observable
28974 * Simple Button class
28975 * @cfg {String} text The button text
28976 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
28977 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
28978 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
28979 * @cfg {Object} scope The scope of the handler
28980 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
28981 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
28982 * @cfg {Boolean} hidden True to start hidden (defaults to false)
28983 * @cfg {Boolean} disabled True to start disabled (defaults to false)
28984 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
28985 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
28986 applies if enableToggle = true)
28987 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
28988 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
28989 an {@link Roo.util.ClickRepeater} config object (defaults to false).
28991 * Create a new button
28992 * @param {Object} config The config object
28994 Roo.Button = function(renderTo, config)
28998 renderTo = config.renderTo || false;
29001 Roo.apply(this, config);
29005 * Fires when this button is clicked
29006 * @param {Button} this
29007 * @param {EventObject} e The click event
29012 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29013 * @param {Button} this
29014 * @param {Boolean} pressed
29019 * Fires when the mouse hovers over the button
29020 * @param {Button} this
29021 * @param {Event} e The event object
29023 'mouseover' : true,
29026 * Fires when the mouse exits the button
29027 * @param {Button} this
29028 * @param {Event} e The event object
29033 * Fires when the button is rendered
29034 * @param {Button} this
29039 this.menu = Roo.menu.MenuMgr.get(this.menu);
29041 // register listeners first!! - so render can be captured..
29042 Roo.util.Observable.call(this);
29044 this.render(renderTo);
29050 Roo.extend(Roo.Button, Roo.util.Observable, {
29056 * Read-only. True if this button is hidden
29061 * Read-only. True if this button is disabled
29066 * Read-only. True if this button is pressed (only if enableToggle = true)
29072 * @cfg {Number} tabIndex
29073 * The DOM tabIndex for this button (defaults to undefined)
29075 tabIndex : undefined,
29078 * @cfg {Boolean} enableToggle
29079 * True to enable pressed/not pressed toggling (defaults to false)
29081 enableToggle: false,
29083 * @cfg {Mixed} menu
29084 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29088 * @cfg {String} menuAlign
29089 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29091 menuAlign : "tl-bl?",
29094 * @cfg {String} iconCls
29095 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29097 iconCls : undefined,
29099 * @cfg {String} type
29100 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29105 menuClassTarget: 'tr',
29108 * @cfg {String} clickEvent
29109 * The type of event to map to the button's event handler (defaults to 'click')
29111 clickEvent : 'click',
29114 * @cfg {Boolean} handleMouseEvents
29115 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29117 handleMouseEvents : true,
29120 * @cfg {String} tooltipType
29121 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29123 tooltipType : 'qtip',
29126 * @cfg {String} cls
29127 * A CSS class to apply to the button's main element.
29131 * @cfg {Roo.Template} template (Optional)
29132 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29133 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29134 * require code modifications if required elements (e.g. a button) aren't present.
29138 render : function(renderTo){
29140 if(this.hideParent){
29141 this.parentEl = Roo.get(renderTo);
29143 if(!this.dhconfig){
29144 if(!this.template){
29145 if(!Roo.Button.buttonTemplate){
29146 // hideous table template
29147 Roo.Button.buttonTemplate = new Roo.Template(
29148 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29149 '<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>',
29150 "</tr></tbody></table>");
29152 this.template = Roo.Button.buttonTemplate;
29154 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29155 var btnEl = btn.child("button:first");
29156 btnEl.on('focus', this.onFocus, this);
29157 btnEl.on('blur', this.onBlur, this);
29159 btn.addClass(this.cls);
29162 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29165 btnEl.addClass(this.iconCls);
29167 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29170 if(this.tabIndex !== undefined){
29171 btnEl.dom.tabIndex = this.tabIndex;
29174 if(typeof this.tooltip == 'object'){
29175 Roo.QuickTips.tips(Roo.apply({
29179 btnEl.dom[this.tooltipType] = this.tooltip;
29183 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29187 this.el.dom.id = this.el.id = this.id;
29190 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29191 this.menu.on("show", this.onMenuShow, this);
29192 this.menu.on("hide", this.onMenuHide, this);
29194 btn.addClass("x-btn");
29195 if(Roo.isIE && !Roo.isIE7){
29196 this.autoWidth.defer(1, this);
29200 if(this.handleMouseEvents){
29201 btn.on("mouseover", this.onMouseOver, this);
29202 btn.on("mouseout", this.onMouseOut, this);
29203 btn.on("mousedown", this.onMouseDown, this);
29205 btn.on(this.clickEvent, this.onClick, this);
29206 //btn.on("mouseup", this.onMouseUp, this);
29213 Roo.ButtonToggleMgr.register(this);
29215 this.el.addClass("x-btn-pressed");
29218 var repeater = new Roo.util.ClickRepeater(btn,
29219 typeof this.repeat == "object" ? this.repeat : {}
29221 repeater.on("click", this.onClick, this);
29224 this.fireEvent('render', this);
29228 * Returns the button's underlying element
29229 * @return {Roo.Element} The element
29231 getEl : function(){
29236 * Destroys this Button and removes any listeners.
29238 destroy : function(){
29239 Roo.ButtonToggleMgr.unregister(this);
29240 this.el.removeAllListeners();
29241 this.purgeListeners();
29246 autoWidth : function(){
29248 this.el.setWidth("auto");
29249 if(Roo.isIE7 && Roo.isStrict){
29250 var ib = this.el.child('button');
29251 if(ib && ib.getWidth() > 20){
29253 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29258 this.el.beginMeasure();
29260 if(this.el.getWidth() < this.minWidth){
29261 this.el.setWidth(this.minWidth);
29264 this.el.endMeasure();
29271 * Assigns this button's click handler
29272 * @param {Function} handler The function to call when the button is clicked
29273 * @param {Object} scope (optional) Scope for the function passed in
29275 setHandler : function(handler, scope){
29276 this.handler = handler;
29277 this.scope = scope;
29281 * Sets this button's text
29282 * @param {String} text The button text
29284 setText : function(text){
29287 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29293 * Gets the text for this button
29294 * @return {String} The button text
29296 getText : function(){
29304 this.hidden = false;
29306 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29314 this.hidden = true;
29316 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29321 * Convenience function for boolean show/hide
29322 * @param {Boolean} visible True to show, false to hide
29324 setVisible: function(visible){
29333 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29334 * @param {Boolean} state (optional) Force a particular state
29336 toggle : function(state){
29337 state = state === undefined ? !this.pressed : state;
29338 if(state != this.pressed){
29340 this.el.addClass("x-btn-pressed");
29341 this.pressed = true;
29342 this.fireEvent("toggle", this, true);
29344 this.el.removeClass("x-btn-pressed");
29345 this.pressed = false;
29346 this.fireEvent("toggle", this, false);
29348 if(this.toggleHandler){
29349 this.toggleHandler.call(this.scope || this, this, state);
29357 focus : function(){
29358 this.el.child('button:first').focus();
29362 * Disable this button
29364 disable : function(){
29366 this.el.addClass("x-btn-disabled");
29368 this.disabled = true;
29372 * Enable this button
29374 enable : function(){
29376 this.el.removeClass("x-btn-disabled");
29378 this.disabled = false;
29382 * Convenience function for boolean enable/disable
29383 * @param {Boolean} enabled True to enable, false to disable
29385 setDisabled : function(v){
29386 this[v !== true ? "enable" : "disable"]();
29390 onClick : function(e)
29393 e.preventDefault();
29398 if(!this.disabled){
29399 if(this.enableToggle){
29402 if(this.menu && !this.menu.isVisible()){
29403 this.menu.show(this.el, this.menuAlign);
29405 this.fireEvent("click", this, e);
29407 this.el.removeClass("x-btn-over");
29408 this.handler.call(this.scope || this, this, e);
29413 onMouseOver : function(e){
29414 if(!this.disabled){
29415 this.el.addClass("x-btn-over");
29416 this.fireEvent('mouseover', this, e);
29420 onMouseOut : function(e){
29421 if(!e.within(this.el, true)){
29422 this.el.removeClass("x-btn-over");
29423 this.fireEvent('mouseout', this, e);
29427 onFocus : function(e){
29428 if(!this.disabled){
29429 this.el.addClass("x-btn-focus");
29433 onBlur : function(e){
29434 this.el.removeClass("x-btn-focus");
29437 onMouseDown : function(e){
29438 if(!this.disabled && e.button == 0){
29439 this.el.addClass("x-btn-click");
29440 Roo.get(document).on('mouseup', this.onMouseUp, this);
29444 onMouseUp : function(e){
29446 this.el.removeClass("x-btn-click");
29447 Roo.get(document).un('mouseup', this.onMouseUp, this);
29451 onMenuShow : function(e){
29452 this.el.addClass("x-btn-menu-active");
29455 onMenuHide : function(e){
29456 this.el.removeClass("x-btn-menu-active");
29460 // Private utility class used by Button
29461 Roo.ButtonToggleMgr = function(){
29464 function toggleGroup(btn, state){
29466 var g = groups[btn.toggleGroup];
29467 for(var i = 0, l = g.length; i < l; i++){
29469 g[i].toggle(false);
29476 register : function(btn){
29477 if(!btn.toggleGroup){
29480 var g = groups[btn.toggleGroup];
29482 g = groups[btn.toggleGroup] = [];
29485 btn.on("toggle", toggleGroup);
29488 unregister : function(btn){
29489 if(!btn.toggleGroup){
29492 var g = groups[btn.toggleGroup];
29495 btn.un("toggle", toggleGroup);
29501 * Ext JS Library 1.1.1
29502 * Copyright(c) 2006-2007, Ext JS, LLC.
29504 * Originally Released Under LGPL - original licence link has changed is not relivant.
29507 * <script type="text/javascript">
29511 * @class Roo.SplitButton
29512 * @extends Roo.Button
29513 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29514 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29515 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29516 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29517 * @cfg {String} arrowTooltip The title attribute of the arrow
29519 * Create a new menu button
29520 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29521 * @param {Object} config The config object
29523 Roo.SplitButton = function(renderTo, config){
29524 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29526 * @event arrowclick
29527 * Fires when this button's arrow is clicked
29528 * @param {SplitButton} this
29529 * @param {EventObject} e The click event
29531 this.addEvents({"arrowclick":true});
29534 Roo.extend(Roo.SplitButton, Roo.Button, {
29535 render : function(renderTo){
29536 // this is one sweet looking template!
29537 var tpl = new Roo.Template(
29538 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29539 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29540 '<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>',
29541 "</tbody></table></td><td>",
29542 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29543 '<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>',
29544 "</tbody></table></td></tr></table>"
29546 var btn = tpl.append(renderTo, [this.text, this.type], true);
29547 var btnEl = btn.child("button");
29549 btn.addClass(this.cls);
29552 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29555 btnEl.addClass(this.iconCls);
29557 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29561 if(this.handleMouseEvents){
29562 btn.on("mouseover", this.onMouseOver, this);
29563 btn.on("mouseout", this.onMouseOut, this);
29564 btn.on("mousedown", this.onMouseDown, this);
29565 btn.on("mouseup", this.onMouseUp, this);
29567 btn.on(this.clickEvent, this.onClick, this);
29569 if(typeof this.tooltip == 'object'){
29570 Roo.QuickTips.tips(Roo.apply({
29574 btnEl.dom[this.tooltipType] = this.tooltip;
29577 if(this.arrowTooltip){
29578 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29587 this.el.addClass("x-btn-pressed");
29589 if(Roo.isIE && !Roo.isIE7){
29590 this.autoWidth.defer(1, this);
29595 this.menu.on("show", this.onMenuShow, this);
29596 this.menu.on("hide", this.onMenuHide, this);
29598 this.fireEvent('render', this);
29602 autoWidth : function(){
29604 var tbl = this.el.child("table:first");
29605 var tbl2 = this.el.child("table:last");
29606 this.el.setWidth("auto");
29607 tbl.setWidth("auto");
29608 if(Roo.isIE7 && Roo.isStrict){
29609 var ib = this.el.child('button:first');
29610 if(ib && ib.getWidth() > 20){
29612 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29617 this.el.beginMeasure();
29619 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29620 tbl.setWidth(this.minWidth-tbl2.getWidth());
29623 this.el.endMeasure();
29626 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29630 * Sets this button's click handler
29631 * @param {Function} handler The function to call when the button is clicked
29632 * @param {Object} scope (optional) Scope for the function passed above
29634 setHandler : function(handler, scope){
29635 this.handler = handler;
29636 this.scope = scope;
29640 * Sets this button's arrow click handler
29641 * @param {Function} handler The function to call when the arrow is clicked
29642 * @param {Object} scope (optional) Scope for the function passed above
29644 setArrowHandler : function(handler, scope){
29645 this.arrowHandler = handler;
29646 this.scope = scope;
29652 focus : function(){
29654 this.el.child("button:first").focus();
29659 onClick : function(e){
29660 e.preventDefault();
29661 if(!this.disabled){
29662 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29663 if(this.menu && !this.menu.isVisible()){
29664 this.menu.show(this.el, this.menuAlign);
29666 this.fireEvent("arrowclick", this, e);
29667 if(this.arrowHandler){
29668 this.arrowHandler.call(this.scope || this, this, e);
29671 this.fireEvent("click", this, e);
29673 this.handler.call(this.scope || this, this, e);
29679 onMouseDown : function(e){
29680 if(!this.disabled){
29681 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29685 onMouseUp : function(e){
29686 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29691 // backwards compat
29692 Roo.MenuButton = Roo.SplitButton;/*
29694 * Ext JS Library 1.1.1
29695 * Copyright(c) 2006-2007, Ext JS, LLC.
29697 * Originally Released Under LGPL - original licence link has changed is not relivant.
29700 * <script type="text/javascript">
29704 * @class Roo.Toolbar
29705 * Basic Toolbar class.
29707 * Creates a new Toolbar
29708 * @param {Object} container The config object
29710 Roo.Toolbar = function(container, buttons, config)
29712 /// old consturctor format still supported..
29713 if(container instanceof Array){ // omit the container for later rendering
29714 buttons = container;
29718 if (typeof(container) == 'object' && container.xtype) {
29719 config = container;
29720 container = config.container;
29721 buttons = config.buttons || []; // not really - use items!!
29724 if (config && config.items) {
29725 xitems = config.items;
29726 delete config.items;
29728 Roo.apply(this, config);
29729 this.buttons = buttons;
29732 this.render(container);
29734 this.xitems = xitems;
29735 Roo.each(xitems, function(b) {
29741 Roo.Toolbar.prototype = {
29743 * @cfg {Array} items
29744 * array of button configs or elements to add (will be converted to a MixedCollection)
29748 * @cfg {String/HTMLElement/Element} container
29749 * The id or element that will contain the toolbar
29752 render : function(ct){
29753 this.el = Roo.get(ct);
29755 this.el.addClass(this.cls);
29757 // using a table allows for vertical alignment
29758 // 100% width is needed by Safari...
29759 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29760 this.tr = this.el.child("tr", true);
29762 this.items = new Roo.util.MixedCollection(false, function(o){
29763 return o.id || ("item" + (++autoId));
29766 this.add.apply(this, this.buttons);
29767 delete this.buttons;
29772 * Adds element(s) to the toolbar -- this function takes a variable number of
29773 * arguments of mixed type and adds them to the toolbar.
29774 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29776 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29777 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29778 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29779 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29780 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29781 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29782 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29783 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29784 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29786 * @param {Mixed} arg2
29787 * @param {Mixed} etc.
29790 var a = arguments, l = a.length;
29791 for(var i = 0; i < l; i++){
29796 _add : function(el) {
29799 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29802 if (el.applyTo){ // some kind of form field
29803 return this.addField(el);
29805 if (el.render){ // some kind of Toolbar.Item
29806 return this.addItem(el);
29808 if (typeof el == "string"){ // string
29809 if(el == "separator" || el == "-"){
29810 return this.addSeparator();
29813 return this.addSpacer();
29816 return this.addFill();
29818 return this.addText(el);
29821 if(el.tagName){ // element
29822 return this.addElement(el);
29824 if(typeof el == "object"){ // must be button config?
29825 return this.addButton(el);
29827 // and now what?!?!
29833 * Add an Xtype element
29834 * @param {Object} xtype Xtype Object
29835 * @return {Object} created Object
29837 addxtype : function(e){
29838 return this.add(e);
29842 * Returns the Element for this toolbar.
29843 * @return {Roo.Element}
29845 getEl : function(){
29851 * @return {Roo.Toolbar.Item} The separator item
29853 addSeparator : function(){
29854 return this.addItem(new Roo.Toolbar.Separator());
29858 * Adds a spacer element
29859 * @return {Roo.Toolbar.Spacer} The spacer item
29861 addSpacer : function(){
29862 return this.addItem(new Roo.Toolbar.Spacer());
29866 * Adds a fill element that forces subsequent additions to the right side of the toolbar
29867 * @return {Roo.Toolbar.Fill} The fill item
29869 addFill : function(){
29870 return this.addItem(new Roo.Toolbar.Fill());
29874 * Adds any standard HTML element to the toolbar
29875 * @param {String/HTMLElement/Element} el The element or id of the element to add
29876 * @return {Roo.Toolbar.Item} The element's item
29878 addElement : function(el){
29879 return this.addItem(new Roo.Toolbar.Item(el));
29882 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
29883 * @type Roo.util.MixedCollection
29888 * Adds any Toolbar.Item or subclass
29889 * @param {Roo.Toolbar.Item} item
29890 * @return {Roo.Toolbar.Item} The item
29892 addItem : function(item){
29893 var td = this.nextBlock();
29895 this.items.add(item);
29900 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
29901 * @param {Object/Array} config A button config or array of configs
29902 * @return {Roo.Toolbar.Button/Array}
29904 addButton : function(config){
29905 if(config instanceof Array){
29907 for(var i = 0, len = config.length; i < len; i++) {
29908 buttons.push(this.addButton(config[i]));
29913 if(!(config instanceof Roo.Toolbar.Button)){
29915 new Roo.Toolbar.SplitButton(config) :
29916 new Roo.Toolbar.Button(config);
29918 var td = this.nextBlock();
29925 * Adds text to the toolbar
29926 * @param {String} text The text to add
29927 * @return {Roo.Toolbar.Item} The element's item
29929 addText : function(text){
29930 return this.addItem(new Roo.Toolbar.TextItem(text));
29934 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
29935 * @param {Number} index The index where the item is to be inserted
29936 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
29937 * @return {Roo.Toolbar.Button/Item}
29939 insertButton : function(index, item){
29940 if(item instanceof Array){
29942 for(var i = 0, len = item.length; i < len; i++) {
29943 buttons.push(this.insertButton(index + i, item[i]));
29947 if (!(item instanceof Roo.Toolbar.Button)){
29948 item = new Roo.Toolbar.Button(item);
29950 var td = document.createElement("td");
29951 this.tr.insertBefore(td, this.tr.childNodes[index]);
29953 this.items.insert(index, item);
29958 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
29959 * @param {Object} config
29960 * @return {Roo.Toolbar.Item} The element's item
29962 addDom : function(config, returnEl){
29963 var td = this.nextBlock();
29964 Roo.DomHelper.overwrite(td, config);
29965 var ti = new Roo.Toolbar.Item(td.firstChild);
29967 this.items.add(ti);
29972 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
29973 * @type Roo.util.MixedCollection
29978 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
29979 * Note: the field should not have been rendered yet. For a field that has already been
29980 * rendered, use {@link #addElement}.
29981 * @param {Roo.form.Field} field
29982 * @return {Roo.ToolbarItem}
29986 addField : function(field) {
29987 if (!this.fields) {
29989 this.fields = new Roo.util.MixedCollection(false, function(o){
29990 return o.id || ("item" + (++autoId));
29995 var td = this.nextBlock();
29997 var ti = new Roo.Toolbar.Item(td.firstChild);
29999 this.items.add(ti);
30000 this.fields.add(field);
30011 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30012 this.el.child('div').hide();
30020 this.el.child('div').show();
30024 nextBlock : function(){
30025 var td = document.createElement("td");
30026 this.tr.appendChild(td);
30031 destroy : function(){
30032 if(this.items){ // rendered?
30033 Roo.destroy.apply(Roo, this.items.items);
30035 if(this.fields){ // rendered?
30036 Roo.destroy.apply(Roo, this.fields.items);
30038 Roo.Element.uncache(this.el, this.tr);
30043 * @class Roo.Toolbar.Item
30044 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30046 * Creates a new Item
30047 * @param {HTMLElement} el
30049 Roo.Toolbar.Item = function(el){
30051 if (typeof (el.xtype) != 'undefined') {
30056 this.el = Roo.getDom(el);
30057 this.id = Roo.id(this.el);
30058 this.hidden = false;
30063 * Fires when the button is rendered
30064 * @param {Button} this
30068 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30070 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30071 //Roo.Toolbar.Item.prototype = {
30074 * Get this item's HTML Element
30075 * @return {HTMLElement}
30077 getEl : function(){
30082 render : function(td){
30085 td.appendChild(this.el);
30087 this.fireEvent('render', this);
30091 * Removes and destroys this item.
30093 destroy : function(){
30094 this.td.parentNode.removeChild(this.td);
30101 this.hidden = false;
30102 this.td.style.display = "";
30109 this.hidden = true;
30110 this.td.style.display = "none";
30114 * Convenience function for boolean show/hide.
30115 * @param {Boolean} visible true to show/false to hide
30117 setVisible: function(visible){
30126 * Try to focus this item.
30128 focus : function(){
30129 Roo.fly(this.el).focus();
30133 * Disables this item.
30135 disable : function(){
30136 Roo.fly(this.td).addClass("x-item-disabled");
30137 this.disabled = true;
30138 this.el.disabled = true;
30142 * Enables this item.
30144 enable : function(){
30145 Roo.fly(this.td).removeClass("x-item-disabled");
30146 this.disabled = false;
30147 this.el.disabled = false;
30153 * @class Roo.Toolbar.Separator
30154 * @extends Roo.Toolbar.Item
30155 * A simple toolbar separator class
30157 * Creates a new Separator
30159 Roo.Toolbar.Separator = function(cfg){
30161 var s = document.createElement("span");
30162 s.className = "ytb-sep";
30167 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30169 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30170 enable:Roo.emptyFn,
30171 disable:Roo.emptyFn,
30176 * @class Roo.Toolbar.Spacer
30177 * @extends Roo.Toolbar.Item
30178 * A simple element that adds extra horizontal space to a toolbar.
30180 * Creates a new Spacer
30182 Roo.Toolbar.Spacer = function(cfg){
30183 var s = document.createElement("div");
30184 s.className = "ytb-spacer";
30188 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30190 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30191 enable:Roo.emptyFn,
30192 disable:Roo.emptyFn,
30197 * @class Roo.Toolbar.Fill
30198 * @extends Roo.Toolbar.Spacer
30199 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30201 * Creates a new Spacer
30203 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30205 render : function(td){
30206 td.style.width = '100%';
30207 Roo.Toolbar.Fill.superclass.render.call(this, td);
30212 * @class Roo.Toolbar.TextItem
30213 * @extends Roo.Toolbar.Item
30214 * A simple class that renders text directly into a toolbar.
30216 * Creates a new TextItem
30217 * @param {String} text
30219 Roo.Toolbar.TextItem = function(cfg){
30220 var text = cfg || "";
30221 if (typeof(cfg) == 'object') {
30222 text = cfg.text || "";
30226 var s = document.createElement("span");
30227 s.className = "ytb-text";
30228 s.innerHTML = text;
30233 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30235 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30238 enable:Roo.emptyFn,
30239 disable:Roo.emptyFn,
30244 * @class Roo.Toolbar.Button
30245 * @extends Roo.Button
30246 * A button that renders into a toolbar.
30248 * Creates a new Button
30249 * @param {Object} config A standard {@link Roo.Button} config object
30251 Roo.Toolbar.Button = function(config){
30252 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30254 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30255 render : function(td){
30257 Roo.Toolbar.Button.superclass.render.call(this, td);
30261 * Removes and destroys this button
30263 destroy : function(){
30264 Roo.Toolbar.Button.superclass.destroy.call(this);
30265 this.td.parentNode.removeChild(this.td);
30269 * Shows this button
30272 this.hidden = false;
30273 this.td.style.display = "";
30277 * Hides this button
30280 this.hidden = true;
30281 this.td.style.display = "none";
30285 * Disables this item
30287 disable : function(){
30288 Roo.fly(this.td).addClass("x-item-disabled");
30289 this.disabled = true;
30293 * Enables this item
30295 enable : function(){
30296 Roo.fly(this.td).removeClass("x-item-disabled");
30297 this.disabled = false;
30300 // backwards compat
30301 Roo.ToolbarButton = Roo.Toolbar.Button;
30304 * @class Roo.Toolbar.SplitButton
30305 * @extends Roo.SplitButton
30306 * A menu button that renders into a toolbar.
30308 * Creates a new SplitButton
30309 * @param {Object} config A standard {@link Roo.SplitButton} config object
30311 Roo.Toolbar.SplitButton = function(config){
30312 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30314 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30315 render : function(td){
30317 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30321 * Removes and destroys this button
30323 destroy : function(){
30324 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30325 this.td.parentNode.removeChild(this.td);
30329 * Shows this button
30332 this.hidden = false;
30333 this.td.style.display = "";
30337 * Hides this button
30340 this.hidden = true;
30341 this.td.style.display = "none";
30345 // backwards compat
30346 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30348 * Ext JS Library 1.1.1
30349 * Copyright(c) 2006-2007, Ext JS, LLC.
30351 * Originally Released Under LGPL - original licence link has changed is not relivant.
30354 * <script type="text/javascript">
30358 * @class Roo.PagingToolbar
30359 * @extends Roo.Toolbar
30360 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30362 * Create a new PagingToolbar
30363 * @param {Object} config The config object
30365 Roo.PagingToolbar = function(el, ds, config)
30367 // old args format still supported... - xtype is prefered..
30368 if (typeof(el) == 'object' && el.xtype) {
30369 // created from xtype...
30371 ds = el.dataSource;
30372 el = config.container;
30375 if (config.items) {
30376 items = config.items;
30380 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30383 this.renderButtons(this.el);
30386 // supprot items array.
30388 Roo.each(items, function(e) {
30389 this.add(Roo.factory(e));
30394 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30396 * @cfg {Roo.data.Store} dataSource
30397 * The underlying data store providing the paged data
30400 * @cfg {String/HTMLElement/Element} container
30401 * container The id or element that will contain the toolbar
30404 * @cfg {Boolean} displayInfo
30405 * True to display the displayMsg (defaults to false)
30408 * @cfg {Number} pageSize
30409 * The number of records to display per page (defaults to 20)
30413 * @cfg {String} displayMsg
30414 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30416 displayMsg : 'Displaying {0} - {1} of {2}',
30418 * @cfg {String} emptyMsg
30419 * The message to display when no records are found (defaults to "No data to display")
30421 emptyMsg : 'No data to display',
30423 * Customizable piece of the default paging text (defaults to "Page")
30426 beforePageText : "Page",
30428 * Customizable piece of the default paging text (defaults to "of %0")
30431 afterPageText : "of {0}",
30433 * Customizable piece of the default paging text (defaults to "First Page")
30436 firstText : "First Page",
30438 * Customizable piece of the default paging text (defaults to "Previous Page")
30441 prevText : "Previous Page",
30443 * Customizable piece of the default paging text (defaults to "Next Page")
30446 nextText : "Next Page",
30448 * Customizable piece of the default paging text (defaults to "Last Page")
30451 lastText : "Last Page",
30453 * Customizable piece of the default paging text (defaults to "Refresh")
30456 refreshText : "Refresh",
30459 renderButtons : function(el){
30460 Roo.PagingToolbar.superclass.render.call(this, el);
30461 this.first = this.addButton({
30462 tooltip: this.firstText,
30463 cls: "x-btn-icon x-grid-page-first",
30465 handler: this.onClick.createDelegate(this, ["first"])
30467 this.prev = this.addButton({
30468 tooltip: this.prevText,
30469 cls: "x-btn-icon x-grid-page-prev",
30471 handler: this.onClick.createDelegate(this, ["prev"])
30473 //this.addSeparator();
30474 this.add(this.beforePageText);
30475 this.field = Roo.get(this.addDom({
30480 cls: "x-grid-page-number"
30482 this.field.on("keydown", this.onPagingKeydown, this);
30483 this.field.on("focus", function(){this.dom.select();});
30484 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30485 this.field.setHeight(18);
30486 //this.addSeparator();
30487 this.next = this.addButton({
30488 tooltip: this.nextText,
30489 cls: "x-btn-icon x-grid-page-next",
30491 handler: this.onClick.createDelegate(this, ["next"])
30493 this.last = this.addButton({
30494 tooltip: this.lastText,
30495 cls: "x-btn-icon x-grid-page-last",
30497 handler: this.onClick.createDelegate(this, ["last"])
30499 //this.addSeparator();
30500 this.loading = this.addButton({
30501 tooltip: this.refreshText,
30502 cls: "x-btn-icon x-grid-loading",
30503 handler: this.onClick.createDelegate(this, ["refresh"])
30506 if(this.displayInfo){
30507 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30512 updateInfo : function(){
30513 if(this.displayEl){
30514 var count = this.ds.getCount();
30515 var msg = count == 0 ?
30519 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30521 this.displayEl.update(msg);
30526 onLoad : function(ds, r, o){
30527 this.cursor = o.params ? o.params.start : 0;
30528 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30530 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30531 this.field.dom.value = ap;
30532 this.first.setDisabled(ap == 1);
30533 this.prev.setDisabled(ap == 1);
30534 this.next.setDisabled(ap == ps);
30535 this.last.setDisabled(ap == ps);
30536 this.loading.enable();
30541 getPageData : function(){
30542 var total = this.ds.getTotalCount();
30545 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30546 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30551 onLoadError : function(){
30552 this.loading.enable();
30556 onPagingKeydown : function(e){
30557 var k = e.getKey();
30558 var d = this.getPageData();
30560 var v = this.field.dom.value, pageNum;
30561 if(!v || isNaN(pageNum = parseInt(v, 10))){
30562 this.field.dom.value = d.activePage;
30565 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30566 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30569 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))
30571 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30572 this.field.dom.value = pageNum;
30573 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30576 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30578 var v = this.field.dom.value, pageNum;
30579 var increment = (e.shiftKey) ? 10 : 1;
30580 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30583 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30584 this.field.dom.value = d.activePage;
30587 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30589 this.field.dom.value = parseInt(v, 10) + increment;
30590 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30591 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30598 beforeLoad : function(){
30600 this.loading.disable();
30605 onClick : function(which){
30609 ds.load({params:{start: 0, limit: this.pageSize}});
30612 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30615 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30618 var total = ds.getTotalCount();
30619 var extra = total % this.pageSize;
30620 var lastStart = extra ? (total - extra) : total-this.pageSize;
30621 ds.load({params:{start: lastStart, limit: this.pageSize}});
30624 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30630 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30631 * @param {Roo.data.Store} store The data store to unbind
30633 unbind : function(ds){
30634 ds.un("beforeload", this.beforeLoad, this);
30635 ds.un("load", this.onLoad, this);
30636 ds.un("loadexception", this.onLoadError, this);
30637 ds.un("remove", this.updateInfo, this);
30638 ds.un("add", this.updateInfo, this);
30639 this.ds = undefined;
30643 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30644 * @param {Roo.data.Store} store The data store to bind
30646 bind : function(ds){
30647 ds.on("beforeload", this.beforeLoad, this);
30648 ds.on("load", this.onLoad, this);
30649 ds.on("loadexception", this.onLoadError, this);
30650 ds.on("remove", this.updateInfo, this);
30651 ds.on("add", this.updateInfo, this);
30656 * Ext JS Library 1.1.1
30657 * Copyright(c) 2006-2007, Ext JS, LLC.
30659 * Originally Released Under LGPL - original licence link has changed is not relivant.
30662 * <script type="text/javascript">
30666 * @class Roo.Resizable
30667 * @extends Roo.util.Observable
30668 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30669 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30670 * 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
30671 * the element will be wrapped for you automatically.</p>
30672 * <p>Here is the list of valid resize handles:</p>
30675 ------ -------------------
30684 'hd' horizontal drag
30687 * <p>Here's an example showing the creation of a typical Resizable:</p>
30689 var resizer = new Roo.Resizable("element-id", {
30697 resizer.on("resize", myHandler);
30699 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30700 * resizer.east.setDisplayed(false);</p>
30701 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30702 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30703 * resize operation's new size (defaults to [0, 0])
30704 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30705 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30706 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30707 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30708 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30709 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30710 * @cfg {Number} width The width of the element in pixels (defaults to null)
30711 * @cfg {Number} height The height of the element in pixels (defaults to null)
30712 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30713 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30714 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30715 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30716 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30717 * in favor of the handles config option (defaults to false)
30718 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30719 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30720 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30721 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30722 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30723 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30724 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30725 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30726 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30727 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30728 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30730 * Create a new resizable component
30731 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30732 * @param {Object} config configuration options
30734 Roo.Resizable = function(el, config)
30736 this.el = Roo.get(el);
30738 if(config && config.wrap){
30739 config.resizeChild = this.el;
30740 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30741 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30742 this.el.setStyle("overflow", "hidden");
30743 this.el.setPositioning(config.resizeChild.getPositioning());
30744 config.resizeChild.clearPositioning();
30745 if(!config.width || !config.height){
30746 var csize = config.resizeChild.getSize();
30747 this.el.setSize(csize.width, csize.height);
30749 if(config.pinned && !config.adjustments){
30750 config.adjustments = "auto";
30754 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30755 this.proxy.unselectable();
30756 this.proxy.enableDisplayMode('block');
30758 Roo.apply(this, config);
30761 this.disableTrackOver = true;
30762 this.el.addClass("x-resizable-pinned");
30764 // if the element isn't positioned, make it relative
30765 var position = this.el.getStyle("position");
30766 if(position != "absolute" && position != "fixed"){
30767 this.el.setStyle("position", "relative");
30769 if(!this.handles){ // no handles passed, must be legacy style
30770 this.handles = 's,e,se';
30771 if(this.multiDirectional){
30772 this.handles += ',n,w';
30775 if(this.handles == "all"){
30776 this.handles = "n s e w ne nw se sw";
30778 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30779 var ps = Roo.Resizable.positions;
30780 for(var i = 0, len = hs.length; i < len; i++){
30781 if(hs[i] && ps[hs[i]]){
30782 var pos = ps[hs[i]];
30783 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30787 this.corner = this.southeast;
30789 // updateBox = the box can move..
30790 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30791 this.updateBox = true;
30794 this.activeHandle = null;
30796 if(this.resizeChild){
30797 if(typeof this.resizeChild == "boolean"){
30798 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30800 this.resizeChild = Roo.get(this.resizeChild, true);
30804 if(this.adjustments == "auto"){
30805 var rc = this.resizeChild;
30806 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30807 if(rc && (hw || hn)){
30808 rc.position("relative");
30809 rc.setLeft(hw ? hw.el.getWidth() : 0);
30810 rc.setTop(hn ? hn.el.getHeight() : 0);
30812 this.adjustments = [
30813 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30814 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30818 if(this.draggable){
30819 this.dd = this.dynamic ?
30820 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30821 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30827 * @event beforeresize
30828 * Fired before resize is allowed. Set enabled to false to cancel resize.
30829 * @param {Roo.Resizable} this
30830 * @param {Roo.EventObject} e The mousedown event
30832 "beforeresize" : true,
30835 * Fired a resizing.
30836 * @param {Roo.Resizable} this
30837 * @param {Number} x The new x position
30838 * @param {Number} y The new y position
30839 * @param {Number} w The new w width
30840 * @param {Number} h The new h hight
30841 * @param {Roo.EventObject} e The mouseup event
30846 * Fired after a resize.
30847 * @param {Roo.Resizable} this
30848 * @param {Number} width The new width
30849 * @param {Number} height The new height
30850 * @param {Roo.EventObject} e The mouseup event
30855 if(this.width !== null && this.height !== null){
30856 this.resizeTo(this.width, this.height);
30858 this.updateChildSize();
30861 this.el.dom.style.zoom = 1;
30863 Roo.Resizable.superclass.constructor.call(this);
30866 Roo.extend(Roo.Resizable, Roo.util.Observable, {
30867 resizeChild : false,
30868 adjustments : [0, 0],
30878 multiDirectional : false,
30879 disableTrackOver : false,
30880 easing : 'easeOutStrong',
30881 widthIncrement : 0,
30882 heightIncrement : 0,
30886 preserveRatio : false,
30887 transparent: false,
30893 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
30895 constrainTo: undefined,
30897 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
30899 resizeRegion: undefined,
30903 * Perform a manual resize
30904 * @param {Number} width
30905 * @param {Number} height
30907 resizeTo : function(width, height){
30908 this.el.setSize(width, height);
30909 this.updateChildSize();
30910 this.fireEvent("resize", this, width, height, null);
30914 startSizing : function(e, handle){
30915 this.fireEvent("beforeresize", this, e);
30916 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
30919 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
30920 this.overlay.unselectable();
30921 this.overlay.enableDisplayMode("block");
30922 this.overlay.on("mousemove", this.onMouseMove, this);
30923 this.overlay.on("mouseup", this.onMouseUp, this);
30925 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
30927 this.resizing = true;
30928 this.startBox = this.el.getBox();
30929 this.startPoint = e.getXY();
30930 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
30931 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
30933 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30934 this.overlay.show();
30936 if(this.constrainTo) {
30937 var ct = Roo.get(this.constrainTo);
30938 this.resizeRegion = ct.getRegion().adjust(
30939 ct.getFrameWidth('t'),
30940 ct.getFrameWidth('l'),
30941 -ct.getFrameWidth('b'),
30942 -ct.getFrameWidth('r')
30946 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
30948 this.proxy.setBox(this.startBox);
30950 this.proxy.setStyle('visibility', 'visible');
30956 onMouseDown : function(handle, e){
30959 this.activeHandle = handle;
30960 this.startSizing(e, handle);
30965 onMouseUp : function(e){
30966 var size = this.resizeElement();
30967 this.resizing = false;
30969 this.overlay.hide();
30971 this.fireEvent("resize", this, size.width, size.height, e);
30975 updateChildSize : function(){
30977 if(this.resizeChild){
30979 var child = this.resizeChild;
30980 var adj = this.adjustments;
30981 if(el.dom.offsetWidth){
30982 var b = el.getSize(true);
30983 child.setSize(b.width+adj[0], b.height+adj[1]);
30985 // Second call here for IE
30986 // The first call enables instant resizing and
30987 // the second call corrects scroll bars if they
30990 setTimeout(function(){
30991 if(el.dom.offsetWidth){
30992 var b = el.getSize(true);
30993 child.setSize(b.width+adj[0], b.height+adj[1]);
31001 snap : function(value, inc, min){
31002 if(!inc || !value) {
31005 var newValue = value;
31006 var m = value % inc;
31009 newValue = value + (inc-m);
31011 newValue = value - m;
31014 return Math.max(min, newValue);
31018 resizeElement : function(){
31019 var box = this.proxy.getBox();
31020 if(this.updateBox){
31021 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31023 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31025 this.updateChildSize();
31033 constrain : function(v, diff, m, mx){
31036 }else if(v - diff > mx){
31043 onMouseMove : function(e){
31046 try{// try catch so if something goes wrong the user doesn't get hung
31048 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31052 //var curXY = this.startPoint;
31053 var curSize = this.curSize || this.startBox;
31054 var x = this.startBox.x, y = this.startBox.y;
31055 var ox = x, oy = y;
31056 var w = curSize.width, h = curSize.height;
31057 var ow = w, oh = h;
31058 var mw = this.minWidth, mh = this.minHeight;
31059 var mxw = this.maxWidth, mxh = this.maxHeight;
31060 var wi = this.widthIncrement;
31061 var hi = this.heightIncrement;
31063 var eventXY = e.getXY();
31064 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31065 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31067 var pos = this.activeHandle.position;
31072 w = Math.min(Math.max(mw, w), mxw);
31077 h = Math.min(Math.max(mh, h), mxh);
31082 w = Math.min(Math.max(mw, w), mxw);
31083 h = Math.min(Math.max(mh, h), mxh);
31086 diffY = this.constrain(h, diffY, mh, mxh);
31093 var adiffX = Math.abs(diffX);
31094 var sub = (adiffX % wi); // how much
31095 if (sub > (wi/2)) { // far enough to snap
31096 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31098 // remove difference..
31099 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31103 x = Math.max(this.minX, x);
31106 diffX = this.constrain(w, diffX, mw, mxw);
31112 w = Math.min(Math.max(mw, w), mxw);
31113 diffY = this.constrain(h, diffY, mh, mxh);
31118 diffX = this.constrain(w, diffX, mw, mxw);
31119 diffY = this.constrain(h, diffY, mh, mxh);
31126 diffX = this.constrain(w, diffX, mw, mxw);
31128 h = Math.min(Math.max(mh, h), mxh);
31134 var sw = this.snap(w, wi, mw);
31135 var sh = this.snap(h, hi, mh);
31136 if(sw != w || sh != h){
31159 if(this.preserveRatio){
31164 h = Math.min(Math.max(mh, h), mxh);
31169 w = Math.min(Math.max(mw, w), mxw);
31174 w = Math.min(Math.max(mw, w), mxw);
31180 w = Math.min(Math.max(mw, w), mxw);
31186 h = Math.min(Math.max(mh, h), mxh);
31194 h = Math.min(Math.max(mh, h), mxh);
31204 h = Math.min(Math.max(mh, h), mxh);
31212 if (pos == 'hdrag') {
31215 this.proxy.setBounds(x, y, w, h);
31217 this.resizeElement();
31221 this.fireEvent("resizing", this, x, y, w, h, e);
31225 handleOver : function(){
31227 this.el.addClass("x-resizable-over");
31232 handleOut : function(){
31233 if(!this.resizing){
31234 this.el.removeClass("x-resizable-over");
31239 * Returns the element this component is bound to.
31240 * @return {Roo.Element}
31242 getEl : function(){
31247 * Returns the resizeChild element (or null).
31248 * @return {Roo.Element}
31250 getResizeChild : function(){
31251 return this.resizeChild;
31253 groupHandler : function()
31258 * Destroys this resizable. If the element was wrapped and
31259 * removeEl is not true then the element remains.
31260 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31262 destroy : function(removeEl){
31263 this.proxy.remove();
31265 this.overlay.removeAllListeners();
31266 this.overlay.remove();
31268 var ps = Roo.Resizable.positions;
31270 if(typeof ps[k] != "function" && this[ps[k]]){
31271 var h = this[ps[k]];
31272 h.el.removeAllListeners();
31277 this.el.update("");
31284 // hash to map config positions to true positions
31285 Roo.Resizable.positions = {
31286 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31291 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31293 // only initialize the template if resizable is used
31294 var tpl = Roo.DomHelper.createTemplate(
31295 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31298 Roo.Resizable.Handle.prototype.tpl = tpl;
31300 this.position = pos;
31302 // show north drag fro topdra
31303 var handlepos = pos == 'hdrag' ? 'north' : pos;
31305 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31306 if (pos == 'hdrag') {
31307 this.el.setStyle('cursor', 'pointer');
31309 this.el.unselectable();
31311 this.el.setOpacity(0);
31313 this.el.on("mousedown", this.onMouseDown, this);
31314 if(!disableTrackOver){
31315 this.el.on("mouseover", this.onMouseOver, this);
31316 this.el.on("mouseout", this.onMouseOut, this);
31321 Roo.Resizable.Handle.prototype = {
31322 afterResize : function(rz){
31327 onMouseDown : function(e){
31328 this.rz.onMouseDown(this, e);
31331 onMouseOver : function(e){
31332 this.rz.handleOver(this, e);
31335 onMouseOut : function(e){
31336 this.rz.handleOut(this, e);
31340 * Ext JS Library 1.1.1
31341 * Copyright(c) 2006-2007, Ext JS, LLC.
31343 * Originally Released Under LGPL - original licence link has changed is not relivant.
31346 * <script type="text/javascript">
31350 * @class Roo.Editor
31351 * @extends Roo.Component
31352 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31354 * Create a new Editor
31355 * @param {Roo.form.Field} field The Field object (or descendant)
31356 * @param {Object} config The config object
31358 Roo.Editor = function(field, config){
31359 Roo.Editor.superclass.constructor.call(this, config);
31360 this.field = field;
31363 * @event beforestartedit
31364 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31365 * false from the handler of this event.
31366 * @param {Editor} this
31367 * @param {Roo.Element} boundEl The underlying element bound to this editor
31368 * @param {Mixed} value The field value being set
31370 "beforestartedit" : true,
31373 * Fires when this editor is displayed
31374 * @param {Roo.Element} boundEl The underlying element bound to this editor
31375 * @param {Mixed} value The starting field value
31377 "startedit" : true,
31379 * @event beforecomplete
31380 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31381 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31382 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31383 * event will not fire since no edit actually occurred.
31384 * @param {Editor} this
31385 * @param {Mixed} value The current field value
31386 * @param {Mixed} startValue The original field value
31388 "beforecomplete" : true,
31391 * Fires after editing is complete and any changed value has been written to the underlying field.
31392 * @param {Editor} this
31393 * @param {Mixed} value The current field value
31394 * @param {Mixed} startValue The original field value
31398 * @event specialkey
31399 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31400 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31401 * @param {Roo.form.Field} this
31402 * @param {Roo.EventObject} e The event object
31404 "specialkey" : true
31408 Roo.extend(Roo.Editor, Roo.Component, {
31410 * @cfg {Boolean/String} autosize
31411 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31412 * or "height" to adopt the height only (defaults to false)
31415 * @cfg {Boolean} revertInvalid
31416 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31417 * validation fails (defaults to true)
31420 * @cfg {Boolean} ignoreNoChange
31421 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31422 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31423 * will never be ignored.
31426 * @cfg {Boolean} hideEl
31427 * False to keep the bound element visible while the editor is displayed (defaults to true)
31430 * @cfg {Mixed} value
31431 * The data value of the underlying field (defaults to "")
31435 * @cfg {String} alignment
31436 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31440 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31441 * for bottom-right shadow (defaults to "frame")
31445 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31449 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31451 completeOnEnter : false,
31453 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31455 cancelOnEsc : false,
31457 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31462 onRender : function(ct, position){
31463 this.el = new Roo.Layer({
31464 shadow: this.shadow,
31470 constrain: this.constrain
31472 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31473 if(this.field.msgTarget != 'title'){
31474 this.field.msgTarget = 'qtip';
31476 this.field.render(this.el);
31478 this.field.el.dom.setAttribute('autocomplete', 'off');
31480 this.field.on("specialkey", this.onSpecialKey, this);
31481 if(this.swallowKeys){
31482 this.field.el.swallowEvent(['keydown','keypress']);
31485 this.field.on("blur", this.onBlur, this);
31486 if(this.field.grow){
31487 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31491 onSpecialKey : function(field, e)
31493 //Roo.log('editor onSpecialKey');
31494 if(this.completeOnEnter && e.getKey() == e.ENTER){
31496 this.completeEdit();
31499 // do not fire special key otherwise it might hide close the editor...
31500 if(e.getKey() == e.ENTER){
31503 if(this.cancelOnEsc && e.getKey() == e.ESC){
31507 this.fireEvent('specialkey', field, e);
31512 * Starts the editing process and shows the editor.
31513 * @param {String/HTMLElement/Element} el The element to edit
31514 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31515 * to the innerHTML of el.
31517 startEdit : function(el, value){
31519 this.completeEdit();
31521 this.boundEl = Roo.get(el);
31522 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31523 if(!this.rendered){
31524 this.render(this.parentEl || document.body);
31526 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31529 this.startValue = v;
31530 this.field.setValue(v);
31532 var sz = this.boundEl.getSize();
31533 switch(this.autoSize){
31535 this.setSize(sz.width, "");
31538 this.setSize("", sz.height);
31541 this.setSize(sz.width, sz.height);
31544 this.el.alignTo(this.boundEl, this.alignment);
31545 this.editing = true;
31547 Roo.QuickTips.disable();
31553 * Sets the height and width of this editor.
31554 * @param {Number} width The new width
31555 * @param {Number} height The new height
31557 setSize : function(w, h){
31558 this.field.setSize(w, h);
31565 * Realigns the editor to the bound field based on the current alignment config value.
31567 realign : function(){
31568 this.el.alignTo(this.boundEl, this.alignment);
31572 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31573 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31575 completeEdit : function(remainVisible){
31579 var v = this.getValue();
31580 if(this.revertInvalid !== false && !this.field.isValid()){
31581 v = this.startValue;
31582 this.cancelEdit(true);
31584 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31585 this.editing = false;
31589 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31590 this.editing = false;
31591 if(this.updateEl && this.boundEl){
31592 this.boundEl.update(v);
31594 if(remainVisible !== true){
31597 this.fireEvent("complete", this, v, this.startValue);
31602 onShow : function(){
31604 if(this.hideEl !== false){
31605 this.boundEl.hide();
31608 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31609 this.fixIEFocus = true;
31610 this.deferredFocus.defer(50, this);
31612 this.field.focus();
31614 this.fireEvent("startedit", this.boundEl, this.startValue);
31617 deferredFocus : function(){
31619 this.field.focus();
31624 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31625 * reverted to the original starting value.
31626 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31627 * cancel (defaults to false)
31629 cancelEdit : function(remainVisible){
31631 this.setValue(this.startValue);
31632 if(remainVisible !== true){
31639 onBlur : function(){
31640 if(this.allowBlur !== true && this.editing){
31641 this.completeEdit();
31646 onHide : function(){
31648 this.completeEdit();
31652 if(this.field.collapse){
31653 this.field.collapse();
31656 if(this.hideEl !== false){
31657 this.boundEl.show();
31660 Roo.QuickTips.enable();
31665 * Sets the data value of the editor
31666 * @param {Mixed} value Any valid value supported by the underlying field
31668 setValue : function(v){
31669 this.field.setValue(v);
31673 * Gets the data value of the editor
31674 * @return {Mixed} The data value
31676 getValue : function(){
31677 return this.field.getValue();
31681 * Ext JS Library 1.1.1
31682 * Copyright(c) 2006-2007, Ext JS, LLC.
31684 * Originally Released Under LGPL - original licence link has changed is not relivant.
31687 * <script type="text/javascript">
31691 * @class Roo.BasicDialog
31692 * @extends Roo.util.Observable
31693 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31695 var dlg = new Roo.BasicDialog("my-dlg", {
31704 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31705 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31706 dlg.addButton('Cancel', dlg.hide, dlg);
31709 <b>A Dialog should always be a direct child of the body element.</b>
31710 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31711 * @cfg {String} title Default text to display in the title bar (defaults to null)
31712 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31713 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31714 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31715 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31716 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31717 * (defaults to null with no animation)
31718 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31719 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31720 * property for valid values (defaults to 'all')
31721 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31722 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31723 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31724 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31725 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31726 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31727 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31728 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31729 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31730 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31731 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31732 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31733 * draggable = true (defaults to false)
31734 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31735 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31736 * shadow (defaults to false)
31737 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31738 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31739 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31740 * @cfg {Array} buttons Array of buttons
31741 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31743 * Create a new BasicDialog.
31744 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31745 * @param {Object} config Configuration options
31747 Roo.BasicDialog = function(el, config){
31748 this.el = Roo.get(el);
31749 var dh = Roo.DomHelper;
31750 if(!this.el && config && config.autoCreate){
31751 if(typeof config.autoCreate == "object"){
31752 if(!config.autoCreate.id){
31753 config.autoCreate.id = el;
31755 this.el = dh.append(document.body,
31756 config.autoCreate, true);
31758 this.el = dh.append(document.body,
31759 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31763 el.setDisplayed(true);
31764 el.hide = this.hideAction;
31766 el.addClass("x-dlg");
31768 Roo.apply(this, config);
31770 this.proxy = el.createProxy("x-dlg-proxy");
31771 this.proxy.hide = this.hideAction;
31772 this.proxy.setOpacity(.5);
31776 el.setWidth(config.width);
31779 el.setHeight(config.height);
31781 this.size = el.getSize();
31782 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31783 this.xy = [config.x,config.y];
31785 this.xy = el.getCenterXY(true);
31787 /** The header element @type Roo.Element */
31788 this.header = el.child("> .x-dlg-hd");
31789 /** The body element @type Roo.Element */
31790 this.body = el.child("> .x-dlg-bd");
31791 /** The footer element @type Roo.Element */
31792 this.footer = el.child("> .x-dlg-ft");
31795 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31798 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31801 this.header.unselectable();
31803 this.header.update(this.title);
31805 // this element allows the dialog to be focused for keyboard event
31806 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31807 this.focusEl.swallowEvent("click", true);
31809 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31811 // wrap the body and footer for special rendering
31812 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31814 this.bwrap.dom.appendChild(this.footer.dom);
31817 this.bg = this.el.createChild({
31818 tag: "div", cls:"x-dlg-bg",
31819 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31821 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31824 if(this.autoScroll !== false && !this.autoTabs){
31825 this.body.setStyle("overflow", "auto");
31828 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31830 if(this.closable !== false){
31831 this.el.addClass("x-dlg-closable");
31832 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31833 this.close.on("click", this.closeClick, this);
31834 this.close.addClassOnOver("x-dlg-close-over");
31836 if(this.collapsible !== false){
31837 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31838 this.collapseBtn.on("click", this.collapseClick, this);
31839 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31840 this.header.on("dblclick", this.collapseClick, this);
31842 if(this.resizable !== false){
31843 this.el.addClass("x-dlg-resizable");
31844 this.resizer = new Roo.Resizable(el, {
31845 minWidth: this.minWidth || 80,
31846 minHeight:this.minHeight || 80,
31847 handles: this.resizeHandles || "all",
31850 this.resizer.on("beforeresize", this.beforeResize, this);
31851 this.resizer.on("resize", this.onResize, this);
31853 if(this.draggable !== false){
31854 el.addClass("x-dlg-draggable");
31855 if (!this.proxyDrag) {
31856 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
31859 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
31861 dd.setHandleElId(this.header.id);
31862 dd.endDrag = this.endMove.createDelegate(this);
31863 dd.startDrag = this.startMove.createDelegate(this);
31864 dd.onDrag = this.onDrag.createDelegate(this);
31869 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
31870 this.mask.enableDisplayMode("block");
31872 this.el.addClass("x-dlg-modal");
31875 this.shadow = new Roo.Shadow({
31876 mode : typeof this.shadow == "string" ? this.shadow : "sides",
31877 offset : this.shadowOffset
31880 this.shadowOffset = 0;
31882 if(Roo.useShims && this.shim !== false){
31883 this.shim = this.el.createShim();
31884 this.shim.hide = this.hideAction;
31892 if (this.buttons) {
31893 var bts= this.buttons;
31895 Roo.each(bts, function(b) {
31904 * Fires when a key is pressed
31905 * @param {Roo.BasicDialog} this
31906 * @param {Roo.EventObject} e
31911 * Fires when this dialog is moved by the user.
31912 * @param {Roo.BasicDialog} this
31913 * @param {Number} x The new page X
31914 * @param {Number} y The new page Y
31919 * Fires when this dialog is resized by the user.
31920 * @param {Roo.BasicDialog} this
31921 * @param {Number} width The new width
31922 * @param {Number} height The new height
31926 * @event beforehide
31927 * Fires before this dialog is hidden.
31928 * @param {Roo.BasicDialog} this
31930 "beforehide" : true,
31933 * Fires when this dialog is hidden.
31934 * @param {Roo.BasicDialog} this
31938 * @event beforeshow
31939 * Fires before this dialog is shown.
31940 * @param {Roo.BasicDialog} this
31942 "beforeshow" : true,
31945 * Fires when this dialog is shown.
31946 * @param {Roo.BasicDialog} this
31950 el.on("keydown", this.onKeyDown, this);
31951 el.on("mousedown", this.toFront, this);
31952 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
31954 Roo.DialogManager.register(this);
31955 Roo.BasicDialog.superclass.constructor.call(this);
31958 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
31959 shadowOffset: Roo.isIE ? 6 : 5,
31962 minButtonWidth: 75,
31963 defaultButton: null,
31964 buttonAlign: "right",
31969 * Sets the dialog title text
31970 * @param {String} text The title text to display
31971 * @return {Roo.BasicDialog} this
31973 setTitle : function(text){
31974 this.header.update(text);
31979 closeClick : function(){
31984 collapseClick : function(){
31985 this[this.collapsed ? "expand" : "collapse"]();
31989 * Collapses the dialog to its minimized state (only the title bar is visible).
31990 * Equivalent to the user clicking the collapse dialog button.
31992 collapse : function(){
31993 if(!this.collapsed){
31994 this.collapsed = true;
31995 this.el.addClass("x-dlg-collapsed");
31996 this.restoreHeight = this.el.getHeight();
31997 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32002 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32003 * clicking the expand dialog button.
32005 expand : function(){
32006 if(this.collapsed){
32007 this.collapsed = false;
32008 this.el.removeClass("x-dlg-collapsed");
32009 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32014 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32015 * @return {Roo.TabPanel} The tabs component
32017 initTabs : function(){
32018 var tabs = this.getTabs();
32019 while(tabs.getTab(0)){
32022 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32024 tabs.addTab(Roo.id(dom), dom.title);
32032 beforeResize : function(){
32033 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32037 onResize : function(){
32038 this.refreshSize();
32039 this.syncBodyHeight();
32040 this.adjustAssets();
32042 this.fireEvent("resize", this, this.size.width, this.size.height);
32046 onKeyDown : function(e){
32047 if(this.isVisible()){
32048 this.fireEvent("keydown", this, e);
32053 * Resizes the dialog.
32054 * @param {Number} width
32055 * @param {Number} height
32056 * @return {Roo.BasicDialog} this
32058 resizeTo : function(width, height){
32059 this.el.setSize(width, height);
32060 this.size = {width: width, height: height};
32061 this.syncBodyHeight();
32062 if(this.fixedcenter){
32065 if(this.isVisible()){
32066 this.constrainXY();
32067 this.adjustAssets();
32069 this.fireEvent("resize", this, width, height);
32075 * Resizes the dialog to fit the specified content size.
32076 * @param {Number} width
32077 * @param {Number} height
32078 * @return {Roo.BasicDialog} this
32080 setContentSize : function(w, h){
32081 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32082 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32083 //if(!this.el.isBorderBox()){
32084 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32085 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32088 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32089 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32091 this.resizeTo(w, h);
32096 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32097 * executed in response to a particular key being pressed while the dialog is active.
32098 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32099 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32100 * @param {Function} fn The function to call
32101 * @param {Object} scope (optional) The scope of the function
32102 * @return {Roo.BasicDialog} this
32104 addKeyListener : function(key, fn, scope){
32105 var keyCode, shift, ctrl, alt;
32106 if(typeof key == "object" && !(key instanceof Array)){
32107 keyCode = key["key"];
32108 shift = key["shift"];
32109 ctrl = key["ctrl"];
32114 var handler = function(dlg, e){
32115 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32116 var k = e.getKey();
32117 if(keyCode instanceof Array){
32118 for(var i = 0, len = keyCode.length; i < len; i++){
32119 if(keyCode[i] == k){
32120 fn.call(scope || window, dlg, k, e);
32126 fn.call(scope || window, dlg, k, e);
32131 this.on("keydown", handler);
32136 * Returns the TabPanel component (creates it if it doesn't exist).
32137 * Note: If you wish to simply check for the existence of tabs without creating them,
32138 * check for a null 'tabs' property.
32139 * @return {Roo.TabPanel} The tabs component
32141 getTabs : function(){
32143 this.el.addClass("x-dlg-auto-tabs");
32144 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32145 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32151 * Adds a button to the footer section of the dialog.
32152 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32153 * object or a valid Roo.DomHelper element config
32154 * @param {Function} handler The function called when the button is clicked
32155 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32156 * @return {Roo.Button} The new button
32158 addButton : function(config, handler, scope){
32159 var dh = Roo.DomHelper;
32161 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32163 if(!this.btnContainer){
32164 var tb = this.footer.createChild({
32166 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32167 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32169 this.btnContainer = tb.firstChild.firstChild.firstChild;
32174 minWidth: this.minButtonWidth,
32177 if(typeof config == "string"){
32178 bconfig.text = config;
32181 bconfig.dhconfig = config;
32183 Roo.apply(bconfig, config);
32187 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32188 bconfig.position = Math.max(0, bconfig.position);
32189 fc = this.btnContainer.childNodes[bconfig.position];
32192 var btn = new Roo.Button(
32194 this.btnContainer.insertBefore(document.createElement("td"),fc)
32195 : this.btnContainer.appendChild(document.createElement("td")),
32196 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32199 this.syncBodyHeight();
32202 * Array of all the buttons that have been added to this dialog via addButton
32207 this.buttons.push(btn);
32212 * Sets the default button to be focused when the dialog is displayed.
32213 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32214 * @return {Roo.BasicDialog} this
32216 setDefaultButton : function(btn){
32217 this.defaultButton = btn;
32222 getHeaderFooterHeight : function(safe){
32225 height += this.header.getHeight();
32228 var fm = this.footer.getMargins();
32229 height += (this.footer.getHeight()+fm.top+fm.bottom);
32231 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32232 height += this.centerBg.getPadding("tb");
32237 syncBodyHeight : function()
32239 var bd = this.body, // the text
32240 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32242 var height = this.size.height - this.getHeaderFooterHeight(false);
32243 bd.setHeight(height-bd.getMargins("tb"));
32244 var hh = this.header.getHeight();
32245 var h = this.size.height-hh;
32248 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32249 bw.setHeight(h-cb.getPadding("tb"));
32251 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32252 bd.setWidth(bw.getWidth(true));
32254 this.tabs.syncHeight();
32256 this.tabs.el.repaint();
32262 * Restores the previous state of the dialog if Roo.state is configured.
32263 * @return {Roo.BasicDialog} this
32265 restoreState : function(){
32266 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32267 if(box && box.width){
32268 this.xy = [box.x, box.y];
32269 this.resizeTo(box.width, box.height);
32275 beforeShow : function(){
32277 if(this.fixedcenter){
32278 this.xy = this.el.getCenterXY(true);
32281 Roo.get(document.body).addClass("x-body-masked");
32282 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32285 this.constrainXY();
32289 animShow : function(){
32290 var b = Roo.get(this.animateTarget).getBox();
32291 this.proxy.setSize(b.width, b.height);
32292 this.proxy.setLocation(b.x, b.y);
32294 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32295 true, .35, this.showEl.createDelegate(this));
32299 * Shows the dialog.
32300 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32301 * @return {Roo.BasicDialog} this
32303 show : function(animateTarget){
32304 if (this.fireEvent("beforeshow", this) === false){
32307 if(this.syncHeightBeforeShow){
32308 this.syncBodyHeight();
32309 }else if(this.firstShow){
32310 this.firstShow = false;
32311 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32313 this.animateTarget = animateTarget || this.animateTarget;
32314 if(!this.el.isVisible()){
32316 if(this.animateTarget && Roo.get(this.animateTarget)){
32326 showEl : function(){
32328 this.el.setXY(this.xy);
32330 this.adjustAssets(true);
32333 // IE peekaboo bug - fix found by Dave Fenwick
32337 this.fireEvent("show", this);
32341 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32342 * dialog itself will receive focus.
32344 focus : function(){
32345 if(this.defaultButton){
32346 this.defaultButton.focus();
32348 this.focusEl.focus();
32353 constrainXY : function(){
32354 if(this.constraintoviewport !== false){
32355 if(!this.viewSize){
32356 if(this.container){
32357 var s = this.container.getSize();
32358 this.viewSize = [s.width, s.height];
32360 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32363 var s = Roo.get(this.container||document).getScroll();
32365 var x = this.xy[0], y = this.xy[1];
32366 var w = this.size.width, h = this.size.height;
32367 var vw = this.viewSize[0], vh = this.viewSize[1];
32368 // only move it if it needs it
32370 // first validate right/bottom
32371 if(x + w > vw+s.left){
32375 if(y + h > vh+s.top){
32379 // then make sure top/left isn't negative
32391 if(this.isVisible()){
32392 this.el.setLocation(x, y);
32393 this.adjustAssets();
32400 onDrag : function(){
32401 if(!this.proxyDrag){
32402 this.xy = this.el.getXY();
32403 this.adjustAssets();
32408 adjustAssets : function(doShow){
32409 var x = this.xy[0], y = this.xy[1];
32410 var w = this.size.width, h = this.size.height;
32411 if(doShow === true){
32413 this.shadow.show(this.el);
32419 if(this.shadow && this.shadow.isVisible()){
32420 this.shadow.show(this.el);
32422 if(this.shim && this.shim.isVisible()){
32423 this.shim.setBounds(x, y, w, h);
32428 adjustViewport : function(w, h){
32430 w = Roo.lib.Dom.getViewWidth();
32431 h = Roo.lib.Dom.getViewHeight();
32434 this.viewSize = [w, h];
32435 if(this.modal && this.mask.isVisible()){
32436 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32437 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32439 if(this.isVisible()){
32440 this.constrainXY();
32445 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32446 * shadow, proxy, mask, etc.) Also removes all event listeners.
32447 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32449 destroy : function(removeEl){
32450 if(this.isVisible()){
32451 this.animateTarget = null;
32454 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32456 this.tabs.destroy(removeEl);
32469 for(var i = 0, len = this.buttons.length; i < len; i++){
32470 this.buttons[i].destroy();
32473 this.el.removeAllListeners();
32474 if(removeEl === true){
32475 this.el.update("");
32478 Roo.DialogManager.unregister(this);
32482 startMove : function(){
32483 if(this.proxyDrag){
32486 if(this.constraintoviewport !== false){
32487 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32492 endMove : function(){
32493 if(!this.proxyDrag){
32494 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32496 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32499 this.refreshSize();
32500 this.adjustAssets();
32502 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32506 * Brings this dialog to the front of any other visible dialogs
32507 * @return {Roo.BasicDialog} this
32509 toFront : function(){
32510 Roo.DialogManager.bringToFront(this);
32515 * Sends this dialog to the back (under) of any other visible dialogs
32516 * @return {Roo.BasicDialog} this
32518 toBack : function(){
32519 Roo.DialogManager.sendToBack(this);
32524 * Centers this dialog in the viewport
32525 * @return {Roo.BasicDialog} this
32527 center : function(){
32528 var xy = this.el.getCenterXY(true);
32529 this.moveTo(xy[0], xy[1]);
32534 * Moves the dialog's top-left corner to the specified point
32535 * @param {Number} x
32536 * @param {Number} y
32537 * @return {Roo.BasicDialog} this
32539 moveTo : function(x, y){
32541 if(this.isVisible()){
32542 this.el.setXY(this.xy);
32543 this.adjustAssets();
32549 * Aligns the dialog to the specified element
32550 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32551 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32552 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32553 * @return {Roo.BasicDialog} this
32555 alignTo : function(element, position, offsets){
32556 this.xy = this.el.getAlignToXY(element, position, offsets);
32557 if(this.isVisible()){
32558 this.el.setXY(this.xy);
32559 this.adjustAssets();
32565 * Anchors an element to another element and realigns it when the window is resized.
32566 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32567 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32568 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32569 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32570 * is a number, it is used as the buffer delay (defaults to 50ms).
32571 * @return {Roo.BasicDialog} this
32573 anchorTo : function(el, alignment, offsets, monitorScroll){
32574 var action = function(){
32575 this.alignTo(el, alignment, offsets);
32577 Roo.EventManager.onWindowResize(action, this);
32578 var tm = typeof monitorScroll;
32579 if(tm != 'undefined'){
32580 Roo.EventManager.on(window, 'scroll', action, this,
32581 {buffer: tm == 'number' ? monitorScroll : 50});
32588 * Returns true if the dialog is visible
32589 * @return {Boolean}
32591 isVisible : function(){
32592 return this.el.isVisible();
32596 animHide : function(callback){
32597 var b = Roo.get(this.animateTarget).getBox();
32599 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32601 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32602 this.hideEl.createDelegate(this, [callback]));
32606 * Hides the dialog.
32607 * @param {Function} callback (optional) Function to call when the dialog is hidden
32608 * @return {Roo.BasicDialog} this
32610 hide : function(callback){
32611 if (this.fireEvent("beforehide", this) === false){
32615 this.shadow.hide();
32620 // sometimes animateTarget seems to get set.. causing problems...
32621 // this just double checks..
32622 if(this.animateTarget && Roo.get(this.animateTarget)) {
32623 this.animHide(callback);
32626 this.hideEl(callback);
32632 hideEl : function(callback){
32636 Roo.get(document.body).removeClass("x-body-masked");
32638 this.fireEvent("hide", this);
32639 if(typeof callback == "function"){
32645 hideAction : function(){
32646 this.setLeft("-10000px");
32647 this.setTop("-10000px");
32648 this.setStyle("visibility", "hidden");
32652 refreshSize : function(){
32653 this.size = this.el.getSize();
32654 this.xy = this.el.getXY();
32655 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32659 // z-index is managed by the DialogManager and may be overwritten at any time
32660 setZIndex : function(index){
32662 this.mask.setStyle("z-index", index);
32665 this.shim.setStyle("z-index", ++index);
32668 this.shadow.setZIndex(++index);
32670 this.el.setStyle("z-index", ++index);
32672 this.proxy.setStyle("z-index", ++index);
32675 this.resizer.proxy.setStyle("z-index", ++index);
32678 this.lastZIndex = index;
32682 * Returns the element for this dialog
32683 * @return {Roo.Element} The underlying dialog Element
32685 getEl : function(){
32691 * @class Roo.DialogManager
32692 * Provides global access to BasicDialogs that have been created and
32693 * support for z-indexing (layering) multiple open dialogs.
32695 Roo.DialogManager = function(){
32697 var accessList = [];
32701 var sortDialogs = function(d1, d2){
32702 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32706 var orderDialogs = function(){
32707 accessList.sort(sortDialogs);
32708 var seed = Roo.DialogManager.zseed;
32709 for(var i = 0, len = accessList.length; i < len; i++){
32710 var dlg = accessList[i];
32712 dlg.setZIndex(seed + (i*10));
32719 * The starting z-index for BasicDialogs (defaults to 9000)
32720 * @type Number The z-index value
32725 register : function(dlg){
32726 list[dlg.id] = dlg;
32727 accessList.push(dlg);
32731 unregister : function(dlg){
32732 delete list[dlg.id];
32735 if(!accessList.indexOf){
32736 for( i = 0, len = accessList.length; i < len; i++){
32737 if(accessList[i] == dlg){
32738 accessList.splice(i, 1);
32743 i = accessList.indexOf(dlg);
32745 accessList.splice(i, 1);
32751 * Gets a registered dialog by id
32752 * @param {String/Object} id The id of the dialog or a dialog
32753 * @return {Roo.BasicDialog} this
32755 get : function(id){
32756 return typeof id == "object" ? id : list[id];
32760 * Brings the specified dialog to the front
32761 * @param {String/Object} dlg The id of the dialog or a dialog
32762 * @return {Roo.BasicDialog} this
32764 bringToFront : function(dlg){
32765 dlg = this.get(dlg);
32768 dlg._lastAccess = new Date().getTime();
32775 * Sends the specified dialog to the back
32776 * @param {String/Object} dlg The id of the dialog or a dialog
32777 * @return {Roo.BasicDialog} this
32779 sendToBack : function(dlg){
32780 dlg = this.get(dlg);
32781 dlg._lastAccess = -(new Date().getTime());
32787 * Hides all dialogs
32789 hideAll : function(){
32790 for(var id in list){
32791 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32800 * @class Roo.LayoutDialog
32801 * @extends Roo.BasicDialog
32802 * Dialog which provides adjustments for working with a layout in a Dialog.
32803 * Add your necessary layout config options to the dialog's config.<br>
32804 * Example usage (including a nested layout):
32807 dialog = new Roo.LayoutDialog("download-dlg", {
32816 // layout config merges with the dialog config
32818 tabPosition: "top",
32819 alwaysShowTabs: true
32822 dialog.addKeyListener(27, dialog.hide, dialog);
32823 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32824 dialog.addButton("Build It!", this.getDownload, this);
32826 // we can even add nested layouts
32827 var innerLayout = new Roo.BorderLayout("dl-inner", {
32837 innerLayout.beginUpdate();
32838 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32839 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32840 innerLayout.endUpdate(true);
32842 var layout = dialog.getLayout();
32843 layout.beginUpdate();
32844 layout.add("center", new Roo.ContentPanel("standard-panel",
32845 {title: "Download the Source", fitToFrame:true}));
32846 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32847 {title: "Build your own roo.js"}));
32848 layout.getRegion("center").showPanel(sp);
32849 layout.endUpdate();
32853 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32854 * @param {Object} config configuration options
32856 Roo.LayoutDialog = function(el, cfg){
32859 if (typeof(cfg) == 'undefined') {
32860 config = Roo.apply({}, el);
32861 // not sure why we use documentElement here.. - it should always be body.
32862 // IE7 borks horribly if we use documentElement.
32863 // webkit also does not like documentElement - it creates a body element...
32864 el = Roo.get( document.body || document.documentElement ).createChild();
32865 //config.autoCreate = true;
32869 config.autoTabs = false;
32870 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
32871 this.body.setStyle({overflow:"hidden", position:"relative"});
32872 this.layout = new Roo.BorderLayout(this.body.dom, config);
32873 this.layout.monitorWindowResize = false;
32874 this.el.addClass("x-dlg-auto-layout");
32875 // fix case when center region overwrites center function
32876 this.center = Roo.BasicDialog.prototype.center;
32877 this.on("show", this.layout.layout, this.layout, true);
32878 if (config.items) {
32879 var xitems = config.items;
32880 delete config.items;
32881 Roo.each(xitems, this.addxtype, this);
32886 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
32888 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
32891 endUpdate : function(){
32892 this.layout.endUpdate();
32896 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
32899 beginUpdate : function(){
32900 this.layout.beginUpdate();
32904 * Get the BorderLayout for this dialog
32905 * @return {Roo.BorderLayout}
32907 getLayout : function(){
32908 return this.layout;
32911 showEl : function(){
32912 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
32914 this.layout.layout();
32919 // Use the syncHeightBeforeShow config option to control this automatically
32920 syncBodyHeight : function(){
32921 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
32922 if(this.layout){this.layout.layout();}
32926 * Add an xtype element (actually adds to the layout.)
32927 * @return {Object} xdata xtype object data.
32930 addxtype : function(c) {
32931 return this.layout.addxtype(c);
32935 * Ext JS Library 1.1.1
32936 * Copyright(c) 2006-2007, Ext JS, LLC.
32938 * Originally Released Under LGPL - original licence link has changed is not relivant.
32941 * <script type="text/javascript">
32945 * @class Roo.MessageBox
32946 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
32950 Roo.Msg.alert('Status', 'Changes saved successfully.');
32952 // Prompt for user data:
32953 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
32955 // process text value...
32959 // Show a dialog using config options:
32961 title:'Save Changes?',
32962 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
32963 buttons: Roo.Msg.YESNOCANCEL,
32970 Roo.MessageBox = function(){
32971 var dlg, opt, mask, waitTimer;
32972 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
32973 var buttons, activeTextEl, bwidth;
32976 var handleButton = function(button){
32978 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
32982 var handleHide = function(){
32983 if(opt && opt.cls){
32984 dlg.el.removeClass(opt.cls);
32987 Roo.TaskMgr.stop(waitTimer);
32993 var updateButtons = function(b){
32996 buttons["ok"].hide();
32997 buttons["cancel"].hide();
32998 buttons["yes"].hide();
32999 buttons["no"].hide();
33000 dlg.footer.dom.style.display = 'none';
33003 dlg.footer.dom.style.display = '';
33004 for(var k in buttons){
33005 if(typeof buttons[k] != "function"){
33008 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33009 width += buttons[k].el.getWidth()+15;
33019 var handleEsc = function(d, k, e){
33020 if(opt && opt.closable !== false){
33030 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33031 * @return {Roo.BasicDialog} The BasicDialog element
33033 getDialog : function(){
33035 dlg = new Roo.BasicDialog("x-msg-box", {
33040 constraintoviewport:false,
33042 collapsible : false,
33045 width:400, height:100,
33046 buttonAlign:"center",
33047 closeClick : function(){
33048 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33049 handleButton("no");
33051 handleButton("cancel");
33055 dlg.on("hide", handleHide);
33057 dlg.addKeyListener(27, handleEsc);
33059 var bt = this.buttonText;
33060 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33061 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33062 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33063 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33064 bodyEl = dlg.body.createChild({
33066 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>'
33068 msgEl = bodyEl.dom.firstChild;
33069 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33070 textboxEl.enableDisplayMode();
33071 textboxEl.addKeyListener([10,13], function(){
33072 if(dlg.isVisible() && opt && opt.buttons){
33073 if(opt.buttons.ok){
33074 handleButton("ok");
33075 }else if(opt.buttons.yes){
33076 handleButton("yes");
33080 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33081 textareaEl.enableDisplayMode();
33082 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33083 progressEl.enableDisplayMode();
33084 var pf = progressEl.dom.firstChild;
33086 pp = Roo.get(pf.firstChild);
33087 pp.setHeight(pf.offsetHeight);
33095 * Updates the message box body text
33096 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33097 * the XHTML-compliant non-breaking space character '&#160;')
33098 * @return {Roo.MessageBox} This message box
33100 updateText : function(text){
33101 if(!dlg.isVisible() && !opt.width){
33102 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33104 msgEl.innerHTML = text || ' ';
33106 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33107 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33109 Math.min(opt.width || cw , this.maxWidth),
33110 Math.max(opt.minWidth || this.minWidth, bwidth)
33113 activeTextEl.setWidth(w);
33115 if(dlg.isVisible()){
33116 dlg.fixedcenter = false;
33118 // to big, make it scroll. = But as usual stupid IE does not support
33121 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33122 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33123 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33125 bodyEl.dom.style.height = '';
33126 bodyEl.dom.style.overflowY = '';
33129 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33131 bodyEl.dom.style.overflowX = '';
33134 dlg.setContentSize(w, bodyEl.getHeight());
33135 if(dlg.isVisible()){
33136 dlg.fixedcenter = true;
33142 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33143 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33144 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33145 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33146 * @return {Roo.MessageBox} This message box
33148 updateProgress : function(value, text){
33150 this.updateText(text);
33152 if (pp) { // weird bug on my firefox - for some reason this is not defined
33153 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33159 * Returns true if the message box is currently displayed
33160 * @return {Boolean} True if the message box is visible, else false
33162 isVisible : function(){
33163 return dlg && dlg.isVisible();
33167 * Hides the message box if it is displayed
33170 if(this.isVisible()){
33176 * Displays a new message box, or reinitializes an existing message box, based on the config options
33177 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33178 * The following config object properties are supported:
33180 Property Type Description
33181 ---------- --------------- ------------------------------------------------------------------------------------
33182 animEl String/Element An id or Element from which the message box should animate as it opens and
33183 closes (defaults to undefined)
33184 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33185 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33186 closable Boolean False to hide the top-right close button (defaults to true). Note that
33187 progress and wait dialogs will ignore this property and always hide the
33188 close button as they can only be closed programmatically.
33189 cls String A custom CSS class to apply to the message box element
33190 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33191 displayed (defaults to 75)
33192 fn Function A callback function to execute after closing the dialog. The arguments to the
33193 function will be btn (the name of the button that was clicked, if applicable,
33194 e.g. "ok"), and text (the value of the active text field, if applicable).
33195 Progress and wait dialogs will ignore this option since they do not respond to
33196 user actions and can only be closed programmatically, so any required function
33197 should be called by the same code after it closes the dialog.
33198 icon String A CSS class that provides a background image to be used as an icon for
33199 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33200 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33201 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33202 modal Boolean False to allow user interaction with the page while the message box is
33203 displayed (defaults to true)
33204 msg String A string that will replace the existing message box body text (defaults
33205 to the XHTML-compliant non-breaking space character ' ')
33206 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33207 progress Boolean True to display a progress bar (defaults to false)
33208 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33209 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33210 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33211 title String The title text
33212 value String The string value to set into the active textbox element if displayed
33213 wait Boolean True to display a progress bar (defaults to false)
33214 width Number The width of the dialog in pixels
33221 msg: 'Please enter your address:',
33223 buttons: Roo.MessageBox.OKCANCEL,
33226 animEl: 'addAddressBtn'
33229 * @param {Object} config Configuration options
33230 * @return {Roo.MessageBox} This message box
33232 show : function(options)
33235 // this causes nightmares if you show one dialog after another
33236 // especially on callbacks..
33238 if(this.isVisible()){
33241 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33242 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33243 Roo.log("New Dialog Message:" + options.msg )
33244 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33245 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33248 var d = this.getDialog();
33250 d.setTitle(opt.title || " ");
33251 d.close.setDisplayed(opt.closable !== false);
33252 activeTextEl = textboxEl;
33253 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33258 textareaEl.setHeight(typeof opt.multiline == "number" ?
33259 opt.multiline : this.defaultTextHeight);
33260 activeTextEl = textareaEl;
33269 progressEl.setDisplayed(opt.progress === true);
33270 this.updateProgress(0);
33271 activeTextEl.dom.value = opt.value || "";
33273 dlg.setDefaultButton(activeTextEl);
33275 var bs = opt.buttons;
33278 db = buttons["ok"];
33279 }else if(bs && bs.yes){
33280 db = buttons["yes"];
33282 dlg.setDefaultButton(db);
33284 bwidth = updateButtons(opt.buttons);
33285 this.updateText(opt.msg);
33287 d.el.addClass(opt.cls);
33289 d.proxyDrag = opt.proxyDrag === true;
33290 d.modal = opt.modal !== false;
33291 d.mask = opt.modal !== false ? mask : false;
33292 if(!d.isVisible()){
33293 // force it to the end of the z-index stack so it gets a cursor in FF
33294 document.body.appendChild(dlg.el.dom);
33295 d.animateTarget = null;
33296 d.show(options.animEl);
33302 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33303 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33304 * and closing the message box when the process is complete.
33305 * @param {String} title The title bar text
33306 * @param {String} msg The message box body text
33307 * @return {Roo.MessageBox} This message box
33309 progress : function(title, msg){
33316 minWidth: this.minProgressWidth,
33323 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33324 * If a callback function is passed it will be called after the user clicks the button, and the
33325 * id of the button that was clicked will be passed as the only parameter to the callback
33326 * (could also be the top-right close button).
33327 * @param {String} title The title bar text
33328 * @param {String} msg The message box body text
33329 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33330 * @param {Object} scope (optional) The scope of the callback function
33331 * @return {Roo.MessageBox} This message box
33333 alert : function(title, msg, fn, scope){
33346 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33347 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33348 * You are responsible for closing the message box when the process is complete.
33349 * @param {String} msg The message box body text
33350 * @param {String} title (optional) The title bar text
33351 * @return {Roo.MessageBox} This message box
33353 wait : function(msg, title){
33364 waitTimer = Roo.TaskMgr.start({
33366 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33374 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33375 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33376 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
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 * @return {Roo.MessageBox} This message box
33383 confirm : function(title, msg, fn, scope){
33387 buttons: this.YESNO,
33396 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33397 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33398 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33399 * (could also be the top-right close button) and the text that was entered will be passed as the two
33400 * parameters to the callback.
33401 * @param {String} title The title bar text
33402 * @param {String} msg The message box body text
33403 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33404 * @param {Object} scope (optional) The scope of the callback function
33405 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33406 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33407 * @return {Roo.MessageBox} This message box
33409 prompt : function(title, msg, fn, scope, multiline){
33413 buttons: this.OKCANCEL,
33418 multiline: multiline,
33425 * Button config that displays a single OK button
33430 * Button config that displays Yes and No buttons
33433 YESNO : {yes:true, no:true},
33435 * Button config that displays OK and Cancel buttons
33438 OKCANCEL : {ok:true, cancel:true},
33440 * Button config that displays Yes, No and Cancel buttons
33443 YESNOCANCEL : {yes:true, no:true, cancel:true},
33446 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33449 defaultTextHeight : 75,
33451 * The maximum width in pixels of the message box (defaults to 600)
33456 * The minimum width in pixels of the message box (defaults to 100)
33461 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33462 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33465 minProgressWidth : 250,
33467 * An object containing the default button text strings that can be overriden for localized language support.
33468 * Supported properties are: ok, cancel, yes and no.
33469 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33482 * Shorthand for {@link Roo.MessageBox}
33484 Roo.Msg = Roo.MessageBox;/*
33486 * Ext JS Library 1.1.1
33487 * Copyright(c) 2006-2007, Ext JS, LLC.
33489 * Originally Released Under LGPL - original licence link has changed is not relivant.
33492 * <script type="text/javascript">
33495 * @class Roo.QuickTips
33496 * Provides attractive and customizable tooltips for any element.
33499 Roo.QuickTips = function(){
33500 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33501 var ce, bd, xy, dd;
33502 var visible = false, disabled = true, inited = false;
33503 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33505 var onOver = function(e){
33509 var t = e.getTarget();
33510 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33513 if(ce && t == ce.el){
33514 clearTimeout(hideProc);
33517 if(t && tagEls[t.id]){
33518 tagEls[t.id].el = t;
33519 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33522 var ttp, et = Roo.fly(t);
33523 var ns = cfg.namespace;
33524 if(tm.interceptTitles && t.title){
33527 t.removeAttribute("title");
33528 e.preventDefault();
33530 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33533 showProc = show.defer(tm.showDelay, tm, [{
33536 width: et.getAttributeNS(ns, cfg.width),
33537 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33538 title: et.getAttributeNS(ns, cfg.title),
33539 cls: et.getAttributeNS(ns, cfg.cls)
33544 var onOut = function(e){
33545 clearTimeout(showProc);
33546 var t = e.getTarget();
33547 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33548 hideProc = setTimeout(hide, tm.hideDelay);
33552 var onMove = function(e){
33558 if(tm.trackMouse && ce){
33563 var onDown = function(e){
33564 clearTimeout(showProc);
33565 clearTimeout(hideProc);
33567 if(tm.hideOnClick){
33570 tm.enable.defer(100, tm);
33575 var getPad = function(){
33576 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33579 var show = function(o){
33583 clearTimeout(dismissProc);
33585 if(removeCls){ // in case manually hidden
33586 el.removeClass(removeCls);
33590 el.addClass(ce.cls);
33591 removeCls = ce.cls;
33594 tipTitle.update(ce.title);
33597 tipTitle.update('');
33600 el.dom.style.width = tm.maxWidth+'px';
33601 //tipBody.dom.style.width = '';
33602 tipBodyText.update(o.text);
33603 var p = getPad(), w = ce.width;
33605 var td = tipBodyText.dom;
33606 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33607 if(aw > tm.maxWidth){
33609 }else if(aw < tm.minWidth){
33615 //tipBody.setWidth(w);
33616 el.setWidth(parseInt(w, 10) + p);
33617 if(ce.autoHide === false){
33618 close.setDisplayed(true);
33623 close.setDisplayed(false);
33629 el.avoidY = xy[1]-18;
33634 el.setStyle("visibility", "visible");
33635 el.fadeIn({callback: afterShow});
33641 var afterShow = function(){
33645 if(tm.autoDismiss && ce.autoHide !== false){
33646 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33651 var hide = function(noanim){
33652 clearTimeout(dismissProc);
33653 clearTimeout(hideProc);
33655 if(el.isVisible()){
33657 if(noanim !== true && tm.animate){
33658 el.fadeOut({callback: afterHide});
33665 var afterHide = function(){
33668 el.removeClass(removeCls);
33675 * @cfg {Number} minWidth
33676 * The minimum width of the quick tip (defaults to 40)
33680 * @cfg {Number} maxWidth
33681 * The maximum width of the quick tip (defaults to 300)
33685 * @cfg {Boolean} interceptTitles
33686 * True to automatically use the element's DOM title value if available (defaults to false)
33688 interceptTitles : false,
33690 * @cfg {Boolean} trackMouse
33691 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33693 trackMouse : false,
33695 * @cfg {Boolean} hideOnClick
33696 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33698 hideOnClick : true,
33700 * @cfg {Number} showDelay
33701 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33705 * @cfg {Number} hideDelay
33706 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33710 * @cfg {Boolean} autoHide
33711 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33712 * Used in conjunction with hideDelay.
33717 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33718 * (defaults to true). Used in conjunction with autoDismissDelay.
33720 autoDismiss : true,
33723 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33725 autoDismissDelay : 5000,
33727 * @cfg {Boolean} animate
33728 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33733 * @cfg {String} title
33734 * Title text to display (defaults to ''). This can be any valid HTML markup.
33738 * @cfg {String} text
33739 * Body text to display (defaults to ''). This can be any valid HTML markup.
33743 * @cfg {String} cls
33744 * A CSS class to apply to the base quick tip element (defaults to '').
33748 * @cfg {Number} width
33749 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33750 * minWidth or maxWidth.
33755 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33756 * or display QuickTips in a page.
33759 tm = Roo.QuickTips;
33760 cfg = tm.tagConfig;
33762 if(!Roo.isReady){ // allow calling of init() before onReady
33763 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33766 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33767 el.fxDefaults = {stopFx: true};
33768 // maximum custom styling
33769 //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>');
33770 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>');
33771 tipTitle = el.child('h3');
33772 tipTitle.enableDisplayMode("block");
33773 tipBody = el.child('div.x-tip-bd');
33774 tipBodyText = el.child('div.x-tip-bd-inner');
33775 //bdLeft = el.child('div.x-tip-bd-left');
33776 //bdRight = el.child('div.x-tip-bd-right');
33777 close = el.child('div.x-tip-close');
33778 close.enableDisplayMode("block");
33779 close.on("click", hide);
33780 var d = Roo.get(document);
33781 d.on("mousedown", onDown);
33782 d.on("mouseover", onOver);
33783 d.on("mouseout", onOut);
33784 d.on("mousemove", onMove);
33785 esc = d.addKeyListener(27, hide);
33788 dd = el.initDD("default", null, {
33789 onDrag : function(){
33793 dd.setHandleElId(tipTitle.id);
33802 * Configures a new quick tip instance and assigns it to a target element. The following config options
33805 Property Type Description
33806 ---------- --------------------- ------------------------------------------------------------------------
33807 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33809 * @param {Object} config The config object
33811 register : function(config){
33812 var cs = config instanceof Array ? config : arguments;
33813 for(var i = 0, len = cs.length; i < len; i++) {
33815 var target = c.target;
33817 if(target instanceof Array){
33818 for(var j = 0, jlen = target.length; j < jlen; j++){
33819 tagEls[target[j]] = c;
33822 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33829 * Removes this quick tip from its element and destroys it.
33830 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33832 unregister : function(el){
33833 delete tagEls[Roo.id(el)];
33837 * Enable this quick tip.
33839 enable : function(){
33840 if(inited && disabled){
33842 if(locks.length < 1){
33849 * Disable this quick tip.
33851 disable : function(){
33853 clearTimeout(showProc);
33854 clearTimeout(hideProc);
33855 clearTimeout(dismissProc);
33863 * Returns true if the quick tip is enabled, else false.
33865 isEnabled : function(){
33871 namespace : "roo", // was ext?? this may break..
33872 alt_namespace : "ext",
33873 attribute : "qtip",
33883 // backwards compat
33884 Roo.QuickTips.tips = Roo.QuickTips.register;/*
33886 * Ext JS Library 1.1.1
33887 * Copyright(c) 2006-2007, Ext JS, LLC.
33889 * Originally Released Under LGPL - original licence link has changed is not relivant.
33892 * <script type="text/javascript">
33897 * @class Roo.tree.TreePanel
33898 * @extends Roo.data.Tree
33900 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
33901 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
33902 * @cfg {Boolean} enableDD true to enable drag and drop
33903 * @cfg {Boolean} enableDrag true to enable just drag
33904 * @cfg {Boolean} enableDrop true to enable just drop
33905 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
33906 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
33907 * @cfg {String} ddGroup The DD group this TreePanel belongs to
33908 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
33909 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
33910 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
33911 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
33912 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
33913 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
33914 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
33915 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
33916 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
33917 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
33918 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
33919 * @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>
33920 * @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>
33923 * @param {String/HTMLElement/Element} el The container element
33924 * @param {Object} config
33926 Roo.tree.TreePanel = function(el, config){
33928 var loader = false;
33930 root = config.root;
33931 delete config.root;
33933 if (config.loader) {
33934 loader = config.loader;
33935 delete config.loader;
33938 Roo.apply(this, config);
33939 Roo.tree.TreePanel.superclass.constructor.call(this);
33940 this.el = Roo.get(el);
33941 this.el.addClass('x-tree');
33942 //console.log(root);
33944 this.setRootNode( Roo.factory(root, Roo.tree));
33947 this.loader = Roo.factory(loader, Roo.tree);
33950 * Read-only. The id of the container element becomes this TreePanel's id.
33952 this.id = this.el.id;
33955 * @event beforeload
33956 * Fires before a node is loaded, return false to cancel
33957 * @param {Node} node The node being loaded
33959 "beforeload" : true,
33962 * Fires when a node is loaded
33963 * @param {Node} node The node that was loaded
33967 * @event textchange
33968 * Fires when the text for a node is changed
33969 * @param {Node} node The node
33970 * @param {String} text The new text
33971 * @param {String} oldText The old text
33973 "textchange" : true,
33975 * @event beforeexpand
33976 * Fires before a node is expanded, return false to cancel.
33977 * @param {Node} node The node
33978 * @param {Boolean} deep
33979 * @param {Boolean} anim
33981 "beforeexpand" : true,
33983 * @event beforecollapse
33984 * Fires before a node is collapsed, return false to cancel.
33985 * @param {Node} node The node
33986 * @param {Boolean} deep
33987 * @param {Boolean} anim
33989 "beforecollapse" : true,
33992 * Fires when a node is expanded
33993 * @param {Node} node The node
33997 * @event disabledchange
33998 * Fires when the disabled status of a node changes
33999 * @param {Node} node The node
34000 * @param {Boolean} disabled
34002 "disabledchange" : true,
34005 * Fires when a node is collapsed
34006 * @param {Node} node The node
34010 * @event beforeclick
34011 * Fires before click processing on a node. Return false to cancel the default action.
34012 * @param {Node} node The node
34013 * @param {Roo.EventObject} e The event object
34015 "beforeclick":true,
34017 * @event checkchange
34018 * Fires when a node with a checkbox's checked property changes
34019 * @param {Node} this This node
34020 * @param {Boolean} checked
34022 "checkchange":true,
34025 * Fires when a node is clicked
34026 * @param {Node} node The node
34027 * @param {Roo.EventObject} e The event object
34032 * Fires when a node is double clicked
34033 * @param {Node} node The node
34034 * @param {Roo.EventObject} e The event object
34038 * @event contextmenu
34039 * Fires when a node is right clicked
34040 * @param {Node} node The node
34041 * @param {Roo.EventObject} e The event object
34043 "contextmenu":true,
34045 * @event beforechildrenrendered
34046 * Fires right before the child nodes for a node are rendered
34047 * @param {Node} node The node
34049 "beforechildrenrendered":true,
34052 * Fires when a node starts being dragged
34053 * @param {Roo.tree.TreePanel} this
34054 * @param {Roo.tree.TreeNode} node
34055 * @param {event} e The raw browser event
34057 "startdrag" : true,
34060 * Fires when a drag operation is complete
34061 * @param {Roo.tree.TreePanel} this
34062 * @param {Roo.tree.TreeNode} node
34063 * @param {event} e The raw browser event
34068 * Fires when a dragged node is dropped on a valid DD target
34069 * @param {Roo.tree.TreePanel} this
34070 * @param {Roo.tree.TreeNode} node
34071 * @param {DD} dd The dd it was dropped on
34072 * @param {event} e The raw browser event
34076 * @event beforenodedrop
34077 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34078 * passed to handlers has the following properties:<br />
34079 * <ul style="padding:5px;padding-left:16px;">
34080 * <li>tree - The TreePanel</li>
34081 * <li>target - The node being targeted for the drop</li>
34082 * <li>data - The drag data from the drag source</li>
34083 * <li>point - The point of the drop - append, above or below</li>
34084 * <li>source - The drag source</li>
34085 * <li>rawEvent - Raw mouse event</li>
34086 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34087 * to be inserted by setting them on this object.</li>
34088 * <li>cancel - Set this to true to cancel the drop.</li>
34090 * @param {Object} dropEvent
34092 "beforenodedrop" : true,
34095 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34096 * passed to handlers has the following properties:<br />
34097 * <ul style="padding:5px;padding-left:16px;">
34098 * <li>tree - The TreePanel</li>
34099 * <li>target - The node being targeted for the drop</li>
34100 * <li>data - The drag data from the drag source</li>
34101 * <li>point - The point of the drop - append, above or below</li>
34102 * <li>source - The drag source</li>
34103 * <li>rawEvent - Raw mouse event</li>
34104 * <li>dropNode - Dropped node(s).</li>
34106 * @param {Object} dropEvent
34110 * @event nodedragover
34111 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34112 * passed to handlers has the following properties:<br />
34113 * <ul style="padding:5px;padding-left:16px;">
34114 * <li>tree - The TreePanel</li>
34115 * <li>target - The node being targeted for the drop</li>
34116 * <li>data - The drag data from the drag source</li>
34117 * <li>point - The point of the drop - append, above or below</li>
34118 * <li>source - The drag source</li>
34119 * <li>rawEvent - Raw mouse event</li>
34120 * <li>dropNode - Drop node(s) provided by the source.</li>
34121 * <li>cancel - Set this to true to signal drop not allowed.</li>
34123 * @param {Object} dragOverEvent
34125 "nodedragover" : true
34128 if(this.singleExpand){
34129 this.on("beforeexpand", this.restrictExpand, this);
34132 this.editor.tree = this;
34133 this.editor = Roo.factory(this.editor, Roo.tree);
34136 if (this.selModel) {
34137 this.selModel = Roo.factory(this.selModel, Roo.tree);
34141 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34142 rootVisible : true,
34143 animate: Roo.enableFx,
34146 hlDrop : Roo.enableFx,
34150 rendererTip: false,
34152 restrictExpand : function(node){
34153 var p = node.parentNode;
34155 if(p.expandedChild && p.expandedChild.parentNode == p){
34156 p.expandedChild.collapse();
34158 p.expandedChild = node;
34162 // private override
34163 setRootNode : function(node){
34164 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34165 if(!this.rootVisible){
34166 node.ui = new Roo.tree.RootTreeNodeUI(node);
34172 * Returns the container element for this TreePanel
34174 getEl : function(){
34179 * Returns the default TreeLoader for this TreePanel
34181 getLoader : function(){
34182 return this.loader;
34188 expandAll : function(){
34189 this.root.expand(true);
34193 * Collapse all nodes
34195 collapseAll : function(){
34196 this.root.collapse(true);
34200 * Returns the selection model used by this TreePanel
34202 getSelectionModel : function(){
34203 if(!this.selModel){
34204 this.selModel = new Roo.tree.DefaultSelectionModel();
34206 return this.selModel;
34210 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34211 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34212 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34215 getChecked : function(a, startNode){
34216 startNode = startNode || this.root;
34218 var f = function(){
34219 if(this.attributes.checked){
34220 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34223 startNode.cascade(f);
34228 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34229 * @param {String} path
34230 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34231 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34232 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34234 expandPath : function(path, attr, callback){
34235 attr = attr || "id";
34236 var keys = path.split(this.pathSeparator);
34237 var curNode = this.root;
34238 if(curNode.attributes[attr] != keys[1]){ // invalid root
34240 callback(false, null);
34245 var f = function(){
34246 if(++index == keys.length){
34248 callback(true, curNode);
34252 var c = curNode.findChild(attr, keys[index]);
34255 callback(false, curNode);
34260 c.expand(false, false, f);
34262 curNode.expand(false, false, f);
34266 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34267 * @param {String} path
34268 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34269 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34270 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34272 selectPath : function(path, attr, callback){
34273 attr = attr || "id";
34274 var keys = path.split(this.pathSeparator);
34275 var v = keys.pop();
34276 if(keys.length > 0){
34277 var f = function(success, node){
34278 if(success && node){
34279 var n = node.findChild(attr, v);
34285 }else if(callback){
34286 callback(false, n);
34290 callback(false, n);
34294 this.expandPath(keys.join(this.pathSeparator), attr, f);
34296 this.root.select();
34298 callback(true, this.root);
34303 getTreeEl : function(){
34308 * Trigger rendering of this TreePanel
34310 render : function(){
34311 if (this.innerCt) {
34312 return this; // stop it rendering more than once!!
34315 this.innerCt = this.el.createChild({tag:"ul",
34316 cls:"x-tree-root-ct " +
34317 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34319 if(this.containerScroll){
34320 Roo.dd.ScrollManager.register(this.el);
34322 if((this.enableDD || this.enableDrop) && !this.dropZone){
34324 * The dropZone used by this tree if drop is enabled
34325 * @type Roo.tree.TreeDropZone
34327 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34328 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34331 if((this.enableDD || this.enableDrag) && !this.dragZone){
34333 * The dragZone used by this tree if drag is enabled
34334 * @type Roo.tree.TreeDragZone
34336 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34337 ddGroup: this.ddGroup || "TreeDD",
34338 scroll: this.ddScroll
34341 this.getSelectionModel().init(this);
34343 Roo.log("ROOT not set in tree");
34346 this.root.render();
34347 if(!this.rootVisible){
34348 this.root.renderChildren();
34354 * Ext JS Library 1.1.1
34355 * Copyright(c) 2006-2007, Ext JS, LLC.
34357 * Originally Released Under LGPL - original licence link has changed is not relivant.
34360 * <script type="text/javascript">
34365 * @class Roo.tree.DefaultSelectionModel
34366 * @extends Roo.util.Observable
34367 * The default single selection for a TreePanel.
34368 * @param {Object} cfg Configuration
34370 Roo.tree.DefaultSelectionModel = function(cfg){
34371 this.selNode = null;
34377 * @event selectionchange
34378 * Fires when the selected node changes
34379 * @param {DefaultSelectionModel} this
34380 * @param {TreeNode} node the new selection
34382 "selectionchange" : true,
34385 * @event beforeselect
34386 * Fires before the selected node changes, return false to cancel the change
34387 * @param {DefaultSelectionModel} this
34388 * @param {TreeNode} node the new selection
34389 * @param {TreeNode} node the old selection
34391 "beforeselect" : true
34394 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34397 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34398 init : function(tree){
34400 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34401 tree.on("click", this.onNodeClick, this);
34404 onNodeClick : function(node, e){
34405 if (e.ctrlKey && this.selNode == node) {
34406 this.unselect(node);
34414 * @param {TreeNode} node The node to select
34415 * @return {TreeNode} The selected node
34417 select : function(node){
34418 var last = this.selNode;
34419 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34421 last.ui.onSelectedChange(false);
34423 this.selNode = node;
34424 node.ui.onSelectedChange(true);
34425 this.fireEvent("selectionchange", this, node, last);
34432 * @param {TreeNode} node The node to unselect
34434 unselect : function(node){
34435 if(this.selNode == node){
34436 this.clearSelections();
34441 * Clear all selections
34443 clearSelections : function(){
34444 var n = this.selNode;
34446 n.ui.onSelectedChange(false);
34447 this.selNode = null;
34448 this.fireEvent("selectionchange", this, null);
34454 * Get the selected node
34455 * @return {TreeNode} The selected node
34457 getSelectedNode : function(){
34458 return this.selNode;
34462 * Returns true if the node is selected
34463 * @param {TreeNode} node The node to check
34464 * @return {Boolean}
34466 isSelected : function(node){
34467 return this.selNode == node;
34471 * Selects the node above the selected node in the tree, intelligently walking the nodes
34472 * @return TreeNode The new selection
34474 selectPrevious : function(){
34475 var s = this.selNode || this.lastSelNode;
34479 var ps = s.previousSibling;
34481 if(!ps.isExpanded() || ps.childNodes.length < 1){
34482 return this.select(ps);
34484 var lc = ps.lastChild;
34485 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34488 return this.select(lc);
34490 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34491 return this.select(s.parentNode);
34497 * Selects the node above the selected node in the tree, intelligently walking the nodes
34498 * @return TreeNode The new selection
34500 selectNext : function(){
34501 var s = this.selNode || this.lastSelNode;
34505 if(s.firstChild && s.isExpanded()){
34506 return this.select(s.firstChild);
34507 }else if(s.nextSibling){
34508 return this.select(s.nextSibling);
34509 }else if(s.parentNode){
34511 s.parentNode.bubble(function(){
34512 if(this.nextSibling){
34513 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34522 onKeyDown : function(e){
34523 var s = this.selNode || this.lastSelNode;
34524 // undesirable, but required
34529 var k = e.getKey();
34537 this.selectPrevious();
34540 e.preventDefault();
34541 if(s.hasChildNodes()){
34542 if(!s.isExpanded()){
34544 }else if(s.firstChild){
34545 this.select(s.firstChild, e);
34550 e.preventDefault();
34551 if(s.hasChildNodes() && s.isExpanded()){
34553 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34554 this.select(s.parentNode, e);
34562 * @class Roo.tree.MultiSelectionModel
34563 * @extends Roo.util.Observable
34564 * Multi selection for a TreePanel.
34565 * @param {Object} cfg Configuration
34567 Roo.tree.MultiSelectionModel = function(){
34568 this.selNodes = [];
34572 * @event selectionchange
34573 * Fires when the selected nodes change
34574 * @param {MultiSelectionModel} this
34575 * @param {Array} nodes Array of the selected nodes
34577 "selectionchange" : true
34579 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34583 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34584 init : function(tree){
34586 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34587 tree.on("click", this.onNodeClick, this);
34590 onNodeClick : function(node, e){
34591 this.select(node, e, e.ctrlKey);
34596 * @param {TreeNode} node The node to select
34597 * @param {EventObject} e (optional) An event associated with the selection
34598 * @param {Boolean} keepExisting True to retain existing selections
34599 * @return {TreeNode} The selected node
34601 select : function(node, e, keepExisting){
34602 if(keepExisting !== true){
34603 this.clearSelections(true);
34605 if(this.isSelected(node)){
34606 this.lastSelNode = node;
34609 this.selNodes.push(node);
34610 this.selMap[node.id] = node;
34611 this.lastSelNode = node;
34612 node.ui.onSelectedChange(true);
34613 this.fireEvent("selectionchange", this, this.selNodes);
34619 * @param {TreeNode} node The node to unselect
34621 unselect : function(node){
34622 if(this.selMap[node.id]){
34623 node.ui.onSelectedChange(false);
34624 var sn = this.selNodes;
34627 index = sn.indexOf(node);
34629 for(var i = 0, len = sn.length; i < len; i++){
34637 this.selNodes.splice(index, 1);
34639 delete this.selMap[node.id];
34640 this.fireEvent("selectionchange", this, this.selNodes);
34645 * Clear all selections
34647 clearSelections : function(suppressEvent){
34648 var sn = this.selNodes;
34650 for(var i = 0, len = sn.length; i < len; i++){
34651 sn[i].ui.onSelectedChange(false);
34653 this.selNodes = [];
34655 if(suppressEvent !== true){
34656 this.fireEvent("selectionchange", this, this.selNodes);
34662 * Returns true if the node is selected
34663 * @param {TreeNode} node The node to check
34664 * @return {Boolean}
34666 isSelected : function(node){
34667 return this.selMap[node.id] ? true : false;
34671 * Returns an array of the selected nodes
34674 getSelectedNodes : function(){
34675 return this.selNodes;
34678 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34680 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34682 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34685 * Ext JS Library 1.1.1
34686 * Copyright(c) 2006-2007, Ext JS, LLC.
34688 * Originally Released Under LGPL - original licence link has changed is not relivant.
34691 * <script type="text/javascript">
34695 * @class Roo.tree.TreeNode
34696 * @extends Roo.data.Node
34697 * @cfg {String} text The text for this node
34698 * @cfg {Boolean} expanded true to start the node expanded
34699 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34700 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34701 * @cfg {Boolean} disabled true to start the node disabled
34702 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34703 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34704 * @cfg {String} cls A css class to be added to the node
34705 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34706 * @cfg {String} href URL of the link used for the node (defaults to #)
34707 * @cfg {String} hrefTarget target frame for the link
34708 * @cfg {String} qtip An Ext QuickTip for the node
34709 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34710 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34711 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34712 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34713 * (defaults to undefined with no checkbox rendered)
34715 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34717 Roo.tree.TreeNode = function(attributes){
34718 attributes = attributes || {};
34719 if(typeof attributes == "string"){
34720 attributes = {text: attributes};
34722 this.childrenRendered = false;
34723 this.rendered = false;
34724 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34725 this.expanded = attributes.expanded === true;
34726 this.isTarget = attributes.isTarget !== false;
34727 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34728 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34731 * Read-only. The text for this node. To change it use setText().
34734 this.text = attributes.text;
34736 * True if this node is disabled.
34739 this.disabled = attributes.disabled === true;
34743 * @event textchange
34744 * Fires when the text for this node is changed
34745 * @param {Node} this This node
34746 * @param {String} text The new text
34747 * @param {String} oldText The old text
34749 "textchange" : true,
34751 * @event beforeexpand
34752 * Fires before this node is expanded, return false to cancel.
34753 * @param {Node} this This node
34754 * @param {Boolean} deep
34755 * @param {Boolean} anim
34757 "beforeexpand" : true,
34759 * @event beforecollapse
34760 * Fires before this node is collapsed, return false to cancel.
34761 * @param {Node} this This node
34762 * @param {Boolean} deep
34763 * @param {Boolean} anim
34765 "beforecollapse" : true,
34768 * Fires when this node is expanded
34769 * @param {Node} this This node
34773 * @event disabledchange
34774 * Fires when the disabled status of this node changes
34775 * @param {Node} this This node
34776 * @param {Boolean} disabled
34778 "disabledchange" : true,
34781 * Fires when this node is collapsed
34782 * @param {Node} this This node
34786 * @event beforeclick
34787 * Fires before click processing. Return false to cancel the default action.
34788 * @param {Node} this This node
34789 * @param {Roo.EventObject} e The event object
34791 "beforeclick":true,
34793 * @event checkchange
34794 * Fires when a node with a checkbox's checked property changes
34795 * @param {Node} this This node
34796 * @param {Boolean} checked
34798 "checkchange":true,
34801 * Fires when this node is clicked
34802 * @param {Node} this This node
34803 * @param {Roo.EventObject} e The event object
34808 * Fires when this node is double clicked
34809 * @param {Node} this This node
34810 * @param {Roo.EventObject} e The event object
34814 * @event contextmenu
34815 * Fires when this node is right clicked
34816 * @param {Node} this This node
34817 * @param {Roo.EventObject} e The event object
34819 "contextmenu":true,
34821 * @event beforechildrenrendered
34822 * Fires right before the child nodes for this node are rendered
34823 * @param {Node} this This node
34825 "beforechildrenrendered":true
34828 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34831 * Read-only. The UI for this node
34834 this.ui = new uiClass(this);
34836 // finally support items[]
34837 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34842 Roo.each(this.attributes.items, function(c) {
34843 this.appendChild(Roo.factory(c,Roo.Tree));
34845 delete this.attributes.items;
34850 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34851 preventHScroll: true,
34853 * Returns true if this node is expanded
34854 * @return {Boolean}
34856 isExpanded : function(){
34857 return this.expanded;
34861 * Returns the UI object for this node
34862 * @return {TreeNodeUI}
34864 getUI : function(){
34868 // private override
34869 setFirstChild : function(node){
34870 var of = this.firstChild;
34871 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
34872 if(this.childrenRendered && of && node != of){
34873 of.renderIndent(true, true);
34876 this.renderIndent(true, true);
34880 // private override
34881 setLastChild : function(node){
34882 var ol = this.lastChild;
34883 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
34884 if(this.childrenRendered && ol && node != ol){
34885 ol.renderIndent(true, true);
34888 this.renderIndent(true, true);
34892 // these methods are overridden to provide lazy rendering support
34893 // private override
34894 appendChild : function()
34896 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
34897 if(node && this.childrenRendered){
34900 this.ui.updateExpandIcon();
34904 // private override
34905 removeChild : function(node){
34906 this.ownerTree.getSelectionModel().unselect(node);
34907 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
34908 // if it's been rendered remove dom node
34909 if(this.childrenRendered){
34912 if(this.childNodes.length < 1){
34913 this.collapse(false, false);
34915 this.ui.updateExpandIcon();
34917 if(!this.firstChild) {
34918 this.childrenRendered = false;
34923 // private override
34924 insertBefore : function(node, refNode){
34925 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
34926 if(newNode && refNode && this.childrenRendered){
34929 this.ui.updateExpandIcon();
34934 * Sets the text for this node
34935 * @param {String} text
34937 setText : function(text){
34938 var oldText = this.text;
34940 this.attributes.text = text;
34941 if(this.rendered){ // event without subscribing
34942 this.ui.onTextChange(this, text, oldText);
34944 this.fireEvent("textchange", this, text, oldText);
34948 * Triggers selection of this node
34950 select : function(){
34951 this.getOwnerTree().getSelectionModel().select(this);
34955 * Triggers deselection of this node
34957 unselect : function(){
34958 this.getOwnerTree().getSelectionModel().unselect(this);
34962 * Returns true if this node is selected
34963 * @return {Boolean}
34965 isSelected : function(){
34966 return this.getOwnerTree().getSelectionModel().isSelected(this);
34970 * Expand this node.
34971 * @param {Boolean} deep (optional) True to expand all children as well
34972 * @param {Boolean} anim (optional) false to cancel the default animation
34973 * @param {Function} callback (optional) A callback to be called when
34974 * expanding this node completes (does not wait for deep expand to complete).
34975 * Called with 1 parameter, this node.
34977 expand : function(deep, anim, callback){
34978 if(!this.expanded){
34979 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
34982 if(!this.childrenRendered){
34983 this.renderChildren();
34985 this.expanded = true;
34986 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
34987 this.ui.animExpand(function(){
34988 this.fireEvent("expand", this);
34989 if(typeof callback == "function"){
34993 this.expandChildNodes(true);
34995 }.createDelegate(this));
34999 this.fireEvent("expand", this);
35000 if(typeof callback == "function"){
35005 if(typeof callback == "function"){
35010 this.expandChildNodes(true);
35014 isHiddenRoot : function(){
35015 return this.isRoot && !this.getOwnerTree().rootVisible;
35019 * Collapse this node.
35020 * @param {Boolean} deep (optional) True to collapse all children as well
35021 * @param {Boolean} anim (optional) false to cancel the default animation
35023 collapse : function(deep, anim){
35024 if(this.expanded && !this.isHiddenRoot()){
35025 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35028 this.expanded = false;
35029 if((this.getOwnerTree().animate && anim !== false) || anim){
35030 this.ui.animCollapse(function(){
35031 this.fireEvent("collapse", this);
35033 this.collapseChildNodes(true);
35035 }.createDelegate(this));
35038 this.ui.collapse();
35039 this.fireEvent("collapse", this);
35043 var cs = this.childNodes;
35044 for(var i = 0, len = cs.length; i < len; i++) {
35045 cs[i].collapse(true, false);
35051 delayedExpand : function(delay){
35052 if(!this.expandProcId){
35053 this.expandProcId = this.expand.defer(delay, this);
35058 cancelExpand : function(){
35059 if(this.expandProcId){
35060 clearTimeout(this.expandProcId);
35062 this.expandProcId = false;
35066 * Toggles expanded/collapsed state of the node
35068 toggle : function(){
35077 * Ensures all parent nodes are expanded
35079 ensureVisible : function(callback){
35080 var tree = this.getOwnerTree();
35081 tree.expandPath(this.parentNode.getPath(), false, function(){
35082 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35083 Roo.callback(callback);
35084 }.createDelegate(this));
35088 * Expand all child nodes
35089 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35091 expandChildNodes : function(deep){
35092 var cs = this.childNodes;
35093 for(var i = 0, len = cs.length; i < len; i++) {
35094 cs[i].expand(deep);
35099 * Collapse all child nodes
35100 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35102 collapseChildNodes : function(deep){
35103 var cs = this.childNodes;
35104 for(var i = 0, len = cs.length; i < len; i++) {
35105 cs[i].collapse(deep);
35110 * Disables this node
35112 disable : function(){
35113 this.disabled = true;
35115 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35116 this.ui.onDisableChange(this, true);
35118 this.fireEvent("disabledchange", this, true);
35122 * Enables this node
35124 enable : function(){
35125 this.disabled = false;
35126 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35127 this.ui.onDisableChange(this, false);
35129 this.fireEvent("disabledchange", this, false);
35133 renderChildren : function(suppressEvent){
35134 if(suppressEvent !== false){
35135 this.fireEvent("beforechildrenrendered", this);
35137 var cs = this.childNodes;
35138 for(var i = 0, len = cs.length; i < len; i++){
35139 cs[i].render(true);
35141 this.childrenRendered = true;
35145 sort : function(fn, scope){
35146 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35147 if(this.childrenRendered){
35148 var cs = this.childNodes;
35149 for(var i = 0, len = cs.length; i < len; i++){
35150 cs[i].render(true);
35156 render : function(bulkRender){
35157 this.ui.render(bulkRender);
35158 if(!this.rendered){
35159 this.rendered = true;
35161 this.expanded = false;
35162 this.expand(false, false);
35168 renderIndent : function(deep, refresh){
35170 this.ui.childIndent = null;
35172 this.ui.renderIndent();
35173 if(deep === true && this.childrenRendered){
35174 var cs = this.childNodes;
35175 for(var i = 0, len = cs.length; i < len; i++){
35176 cs[i].renderIndent(true, refresh);
35182 * Ext JS Library 1.1.1
35183 * Copyright(c) 2006-2007, Ext JS, LLC.
35185 * Originally Released Under LGPL - original licence link has changed is not relivant.
35188 * <script type="text/javascript">
35192 * @class Roo.tree.AsyncTreeNode
35193 * @extends Roo.tree.TreeNode
35194 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35196 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35198 Roo.tree.AsyncTreeNode = function(config){
35199 this.loaded = false;
35200 this.loading = false;
35201 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35203 * @event beforeload
35204 * Fires before this node is loaded, return false to cancel
35205 * @param {Node} this This node
35207 this.addEvents({'beforeload':true, 'load': true});
35210 * Fires when this node is loaded
35211 * @param {Node} this This node
35214 * The loader used by this node (defaults to using the tree's defined loader)
35219 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35220 expand : function(deep, anim, callback){
35221 if(this.loading){ // if an async load is already running, waiting til it's done
35223 var f = function(){
35224 if(!this.loading){ // done loading
35225 clearInterval(timer);
35226 this.expand(deep, anim, callback);
35228 }.createDelegate(this);
35229 timer = setInterval(f, 200);
35233 if(this.fireEvent("beforeload", this) === false){
35236 this.loading = true;
35237 this.ui.beforeLoad(this);
35238 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35240 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35244 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35248 * Returns true if this node is currently loading
35249 * @return {Boolean}
35251 isLoading : function(){
35252 return this.loading;
35255 loadComplete : function(deep, anim, callback){
35256 this.loading = false;
35257 this.loaded = true;
35258 this.ui.afterLoad(this);
35259 this.fireEvent("load", this);
35260 this.expand(deep, anim, callback);
35264 * Returns true if this node has been loaded
35265 * @return {Boolean}
35267 isLoaded : function(){
35268 return this.loaded;
35271 hasChildNodes : function(){
35272 if(!this.isLeaf() && !this.loaded){
35275 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35280 * Trigger a reload for this node
35281 * @param {Function} callback
35283 reload : function(callback){
35284 this.collapse(false, false);
35285 while(this.firstChild){
35286 this.removeChild(this.firstChild);
35288 this.childrenRendered = false;
35289 this.loaded = false;
35290 if(this.isHiddenRoot()){
35291 this.expanded = false;
35293 this.expand(false, false, callback);
35297 * Ext JS Library 1.1.1
35298 * Copyright(c) 2006-2007, Ext JS, LLC.
35300 * Originally Released Under LGPL - original licence link has changed is not relivant.
35303 * <script type="text/javascript">
35307 * @class Roo.tree.TreeNodeUI
35309 * @param {Object} node The node to render
35310 * The TreeNode UI implementation is separate from the
35311 * tree implementation. Unless you are customizing the tree UI,
35312 * you should never have to use this directly.
35314 Roo.tree.TreeNodeUI = function(node){
35316 this.rendered = false;
35317 this.animating = false;
35318 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35321 Roo.tree.TreeNodeUI.prototype = {
35322 removeChild : function(node){
35324 this.ctNode.removeChild(node.ui.getEl());
35328 beforeLoad : function(){
35329 this.addClass("x-tree-node-loading");
35332 afterLoad : function(){
35333 this.removeClass("x-tree-node-loading");
35336 onTextChange : function(node, text, oldText){
35338 this.textNode.innerHTML = text;
35342 onDisableChange : function(node, state){
35343 this.disabled = state;
35345 this.addClass("x-tree-node-disabled");
35347 this.removeClass("x-tree-node-disabled");
35351 onSelectedChange : function(state){
35354 this.addClass("x-tree-selected");
35357 this.removeClass("x-tree-selected");
35361 onMove : function(tree, node, oldParent, newParent, index, refNode){
35362 this.childIndent = null;
35364 var targetNode = newParent.ui.getContainer();
35365 if(!targetNode){//target not rendered
35366 this.holder = document.createElement("div");
35367 this.holder.appendChild(this.wrap);
35370 var insertBefore = refNode ? refNode.ui.getEl() : null;
35372 targetNode.insertBefore(this.wrap, insertBefore);
35374 targetNode.appendChild(this.wrap);
35376 this.node.renderIndent(true);
35380 addClass : function(cls){
35382 Roo.fly(this.elNode).addClass(cls);
35386 removeClass : function(cls){
35388 Roo.fly(this.elNode).removeClass(cls);
35392 remove : function(){
35394 this.holder = document.createElement("div");
35395 this.holder.appendChild(this.wrap);
35399 fireEvent : function(){
35400 return this.node.fireEvent.apply(this.node, arguments);
35403 initEvents : function(){
35404 this.node.on("move", this.onMove, this);
35405 var E = Roo.EventManager;
35406 var a = this.anchor;
35408 var el = Roo.fly(a, '_treeui');
35410 if(Roo.isOpera){ // opera render bug ignores the CSS
35411 el.setStyle("text-decoration", "none");
35414 el.on("click", this.onClick, this);
35415 el.on("dblclick", this.onDblClick, this);
35418 Roo.EventManager.on(this.checkbox,
35419 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35422 el.on("contextmenu", this.onContextMenu, this);
35424 var icon = Roo.fly(this.iconNode);
35425 icon.on("click", this.onClick, this);
35426 icon.on("dblclick", this.onDblClick, this);
35427 icon.on("contextmenu", this.onContextMenu, this);
35428 E.on(this.ecNode, "click", this.ecClick, this, true);
35430 if(this.node.disabled){
35431 this.addClass("x-tree-node-disabled");
35433 if(this.node.hidden){
35434 this.addClass("x-tree-node-disabled");
35436 var ot = this.node.getOwnerTree();
35437 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35438 if(dd && (!this.node.isRoot || ot.rootVisible)){
35439 Roo.dd.Registry.register(this.elNode, {
35441 handles: this.getDDHandles(),
35447 getDDHandles : function(){
35448 return [this.iconNode, this.textNode];
35453 this.wrap.style.display = "none";
35459 this.wrap.style.display = "";
35463 onContextMenu : function(e){
35464 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35465 e.preventDefault();
35467 this.fireEvent("contextmenu", this.node, e);
35471 onClick : function(e){
35476 if(this.fireEvent("beforeclick", this.node, e) !== false){
35477 if(!this.disabled && this.node.attributes.href){
35478 this.fireEvent("click", this.node, e);
35481 e.preventDefault();
35486 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35487 this.node.toggle();
35490 this.fireEvent("click", this.node, e);
35496 onDblClick : function(e){
35497 e.preventDefault();
35502 this.toggleCheck();
35504 if(!this.animating && this.node.hasChildNodes()){
35505 this.node.toggle();
35507 this.fireEvent("dblclick", this.node, e);
35510 onCheckChange : function(){
35511 var checked = this.checkbox.checked;
35512 this.node.attributes.checked = checked;
35513 this.fireEvent('checkchange', this.node, checked);
35516 ecClick : function(e){
35517 if(!this.animating && this.node.hasChildNodes()){
35518 this.node.toggle();
35522 startDrop : function(){
35523 this.dropping = true;
35526 // delayed drop so the click event doesn't get fired on a drop
35527 endDrop : function(){
35528 setTimeout(function(){
35529 this.dropping = false;
35530 }.createDelegate(this), 50);
35533 expand : function(){
35534 this.updateExpandIcon();
35535 this.ctNode.style.display = "";
35538 focus : function(){
35539 if(!this.node.preventHScroll){
35540 try{this.anchor.focus();
35542 }else if(!Roo.isIE){
35544 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35545 var l = noscroll.scrollLeft;
35546 this.anchor.focus();
35547 noscroll.scrollLeft = l;
35552 toggleCheck : function(value){
35553 var cb = this.checkbox;
35555 cb.checked = (value === undefined ? !cb.checked : value);
35561 this.anchor.blur();
35565 animExpand : function(callback){
35566 var ct = Roo.get(this.ctNode);
35568 if(!this.node.hasChildNodes()){
35569 this.updateExpandIcon();
35570 this.ctNode.style.display = "";
35571 Roo.callback(callback);
35574 this.animating = true;
35575 this.updateExpandIcon();
35578 callback : function(){
35579 this.animating = false;
35580 Roo.callback(callback);
35583 duration: this.node.ownerTree.duration || .25
35587 highlight : function(){
35588 var tree = this.node.getOwnerTree();
35589 Roo.fly(this.wrap).highlight(
35590 tree.hlColor || "C3DAF9",
35591 {endColor: tree.hlBaseColor}
35595 collapse : function(){
35596 this.updateExpandIcon();
35597 this.ctNode.style.display = "none";
35600 animCollapse : function(callback){
35601 var ct = Roo.get(this.ctNode);
35602 ct.enableDisplayMode('block');
35605 this.animating = true;
35606 this.updateExpandIcon();
35609 callback : function(){
35610 this.animating = false;
35611 Roo.callback(callback);
35614 duration: this.node.ownerTree.duration || .25
35618 getContainer : function(){
35619 return this.ctNode;
35622 getEl : function(){
35626 appendDDGhost : function(ghostNode){
35627 ghostNode.appendChild(this.elNode.cloneNode(true));
35630 getDDRepairXY : function(){
35631 return Roo.lib.Dom.getXY(this.iconNode);
35634 onRender : function(){
35638 render : function(bulkRender){
35639 var n = this.node, a = n.attributes;
35640 var targetNode = n.parentNode ?
35641 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35643 if(!this.rendered){
35644 this.rendered = true;
35646 this.renderElements(n, a, targetNode, bulkRender);
35649 if(this.textNode.setAttributeNS){
35650 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35652 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35655 this.textNode.setAttribute("ext:qtip", a.qtip);
35657 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35660 }else if(a.qtipCfg){
35661 a.qtipCfg.target = Roo.id(this.textNode);
35662 Roo.QuickTips.register(a.qtipCfg);
35665 if(!this.node.expanded){
35666 this.updateExpandIcon();
35669 if(bulkRender === true) {
35670 targetNode.appendChild(this.wrap);
35675 renderElements : function(n, a, targetNode, bulkRender)
35677 // add some indent caching, this helps performance when rendering a large tree
35678 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35679 var t = n.getOwnerTree();
35680 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35681 if (typeof(n.attributes.html) != 'undefined') {
35682 txt = n.attributes.html;
35684 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35685 var cb = typeof a.checked == 'boolean';
35686 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35687 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35688 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35689 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35690 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35691 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35692 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35693 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35694 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35695 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35698 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35699 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35700 n.nextSibling.ui.getEl(), buf.join(""));
35702 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35705 this.elNode = this.wrap.childNodes[0];
35706 this.ctNode = this.wrap.childNodes[1];
35707 var cs = this.elNode.childNodes;
35708 this.indentNode = cs[0];
35709 this.ecNode = cs[1];
35710 this.iconNode = cs[2];
35713 this.checkbox = cs[3];
35716 this.anchor = cs[index];
35717 this.textNode = cs[index].firstChild;
35720 getAnchor : function(){
35721 return this.anchor;
35724 getTextEl : function(){
35725 return this.textNode;
35728 getIconEl : function(){
35729 return this.iconNode;
35732 isChecked : function(){
35733 return this.checkbox ? this.checkbox.checked : false;
35736 updateExpandIcon : function(){
35738 var n = this.node, c1, c2;
35739 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35740 var hasChild = n.hasChildNodes();
35744 c1 = "x-tree-node-collapsed";
35745 c2 = "x-tree-node-expanded";
35748 c1 = "x-tree-node-expanded";
35749 c2 = "x-tree-node-collapsed";
35752 this.removeClass("x-tree-node-leaf");
35753 this.wasLeaf = false;
35755 if(this.c1 != c1 || this.c2 != c2){
35756 Roo.fly(this.elNode).replaceClass(c1, c2);
35757 this.c1 = c1; this.c2 = c2;
35760 // this changes non-leafs into leafs if they have no children.
35761 // it's not very rational behaviour..
35763 if(!this.wasLeaf && this.node.leaf){
35764 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35767 this.wasLeaf = true;
35770 var ecc = "x-tree-ec-icon "+cls;
35771 if(this.ecc != ecc){
35772 this.ecNode.className = ecc;
35778 getChildIndent : function(){
35779 if(!this.childIndent){
35783 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35785 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35787 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35792 this.childIndent = buf.join("");
35794 return this.childIndent;
35797 renderIndent : function(){
35800 var p = this.node.parentNode;
35802 indent = p.ui.getChildIndent();
35804 if(this.indentMarkup != indent){ // don't rerender if not required
35805 this.indentNode.innerHTML = indent;
35806 this.indentMarkup = indent;
35808 this.updateExpandIcon();
35813 Roo.tree.RootTreeNodeUI = function(){
35814 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35816 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35817 render : function(){
35818 if(!this.rendered){
35819 var targetNode = this.node.ownerTree.innerCt.dom;
35820 this.node.expanded = true;
35821 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35822 this.wrap = this.ctNode = targetNode.firstChild;
35825 collapse : function(){
35827 expand : function(){
35831 * Ext JS Library 1.1.1
35832 * Copyright(c) 2006-2007, Ext JS, LLC.
35834 * Originally Released Under LGPL - original licence link has changed is not relivant.
35837 * <script type="text/javascript">
35840 * @class Roo.tree.TreeLoader
35841 * @extends Roo.util.Observable
35842 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35843 * nodes from a specified URL. The response must be a javascript Array definition
35844 * who's elements are node definition objects. eg:
35849 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35850 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
35857 * The old style respose with just an array is still supported, but not recommended.
35860 * A server request is sent, and child nodes are loaded only when a node is expanded.
35861 * The loading node's id is passed to the server under the parameter name "node" to
35862 * enable the server to produce the correct child nodes.
35864 * To pass extra parameters, an event handler may be attached to the "beforeload"
35865 * event, and the parameters specified in the TreeLoader's baseParams property:
35867 myTreeLoader.on("beforeload", function(treeLoader, node) {
35868 this.baseParams.category = node.attributes.category;
35871 * This would pass an HTTP parameter called "category" to the server containing
35872 * the value of the Node's "category" attribute.
35874 * Creates a new Treeloader.
35875 * @param {Object} config A config object containing config properties.
35877 Roo.tree.TreeLoader = function(config){
35878 this.baseParams = {};
35879 this.requestMethod = "POST";
35880 Roo.apply(this, config);
35885 * @event beforeload
35886 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
35887 * @param {Object} This TreeLoader object.
35888 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35889 * @param {Object} callback The callback function specified in the {@link #load} call.
35894 * Fires when the node has been successfuly loaded.
35895 * @param {Object} This TreeLoader object.
35896 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35897 * @param {Object} response The response object containing the data from the server.
35901 * @event loadexception
35902 * Fires if the network request failed.
35903 * @param {Object} This TreeLoader object.
35904 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35905 * @param {Object} response The response object containing the data from the server.
35907 loadexception : true,
35910 * Fires before a node is created, enabling you to return custom Node types
35911 * @param {Object} This TreeLoader object.
35912 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
35917 Roo.tree.TreeLoader.superclass.constructor.call(this);
35920 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
35922 * @cfg {String} dataUrl The URL from which to request a Json string which
35923 * specifies an array of node definition object representing the child nodes
35927 * @cfg {String} requestMethod either GET or POST
35928 * defaults to POST (due to BC)
35932 * @cfg {Object} baseParams (optional) An object containing properties which
35933 * specify HTTP parameters to be passed to each request for child nodes.
35936 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
35937 * created by this loader. If the attributes sent by the server have an attribute in this object,
35938 * they take priority.
35941 * @cfg {Object} uiProviders (optional) An object containing properties which
35943 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
35944 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
35945 * <i>uiProvider</i> attribute of a returned child node is a string rather
35946 * than a reference to a TreeNodeUI implementation, this that string value
35947 * is used as a property name in the uiProviders object. You can define the provider named
35948 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
35953 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
35954 * child nodes before loading.
35956 clearOnLoad : true,
35959 * @cfg {String} root (optional) Default to false. Use this to read data from an object
35960 * property on loading, rather than expecting an array. (eg. more compatible to a standard
35961 * Grid query { data : [ .....] }
35966 * @cfg {String} queryParam (optional)
35967 * Name of the query as it will be passed on the querystring (defaults to 'node')
35968 * eg. the request will be ?node=[id]
35975 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
35976 * This is called automatically when a node is expanded, but may be used to reload
35977 * a node (or append new children if the {@link #clearOnLoad} option is false.)
35978 * @param {Roo.tree.TreeNode} node
35979 * @param {Function} callback
35981 load : function(node, callback){
35982 if(this.clearOnLoad){
35983 while(node.firstChild){
35984 node.removeChild(node.firstChild);
35987 if(node.attributes.children){ // preloaded json children
35988 var cs = node.attributes.children;
35989 for(var i = 0, len = cs.length; i < len; i++){
35990 node.appendChild(this.createNode(cs[i]));
35992 if(typeof callback == "function"){
35995 }else if(this.dataUrl){
35996 this.requestData(node, callback);
36000 getParams: function(node){
36001 var buf = [], bp = this.baseParams;
36002 for(var key in bp){
36003 if(typeof bp[key] != "function"){
36004 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36007 var n = this.queryParam === false ? 'node' : this.queryParam;
36008 buf.push(n + "=", encodeURIComponent(node.id));
36009 return buf.join("");
36012 requestData : function(node, callback){
36013 if(this.fireEvent("beforeload", this, node, callback) !== false){
36014 this.transId = Roo.Ajax.request({
36015 method:this.requestMethod,
36016 url: this.dataUrl||this.url,
36017 success: this.handleResponse,
36018 failure: this.handleFailure,
36020 argument: {callback: callback, node: node},
36021 params: this.getParams(node)
36024 // if the load is cancelled, make sure we notify
36025 // the node that we are done
36026 if(typeof callback == "function"){
36032 isLoading : function(){
36033 return this.transId ? true : false;
36036 abort : function(){
36037 if(this.isLoading()){
36038 Roo.Ajax.abort(this.transId);
36043 createNode : function(attr)
36045 // apply baseAttrs, nice idea Corey!
36046 if(this.baseAttrs){
36047 Roo.applyIf(attr, this.baseAttrs);
36049 if(this.applyLoader !== false){
36050 attr.loader = this;
36052 // uiProvider = depreciated..
36054 if(typeof(attr.uiProvider) == 'string'){
36055 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36056 /** eval:var:attr */ eval(attr.uiProvider);
36058 if(typeof(this.uiProviders['default']) != 'undefined') {
36059 attr.uiProvider = this.uiProviders['default'];
36062 this.fireEvent('create', this, attr);
36064 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36066 new Roo.tree.TreeNode(attr) :
36067 new Roo.tree.AsyncTreeNode(attr));
36070 processResponse : function(response, node, callback)
36072 var json = response.responseText;
36075 var o = Roo.decode(json);
36077 if (this.root === false && typeof(o.success) != undefined) {
36078 this.root = 'data'; // the default behaviour for list like data..
36081 if (this.root !== false && !o.success) {
36082 // it's a failure condition.
36083 var a = response.argument;
36084 this.fireEvent("loadexception", this, a.node, response);
36085 Roo.log("Load failed - should have a handler really");
36091 if (this.root !== false) {
36095 for(var i = 0, len = o.length; i < len; i++){
36096 var n = this.createNode(o[i]);
36098 node.appendChild(n);
36101 if(typeof callback == "function"){
36102 callback(this, node);
36105 this.handleFailure(response);
36109 handleResponse : function(response){
36110 this.transId = false;
36111 var a = response.argument;
36112 this.processResponse(response, a.node, a.callback);
36113 this.fireEvent("load", this, a.node, response);
36116 handleFailure : function(response)
36118 // should handle failure better..
36119 this.transId = false;
36120 var a = response.argument;
36121 this.fireEvent("loadexception", this, a.node, response);
36122 if(typeof a.callback == "function"){
36123 a.callback(this, a.node);
36128 * Ext JS Library 1.1.1
36129 * Copyright(c) 2006-2007, Ext JS, LLC.
36131 * Originally Released Under LGPL - original licence link has changed is not relivant.
36134 * <script type="text/javascript">
36138 * @class Roo.tree.TreeFilter
36139 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36140 * @param {TreePanel} tree
36141 * @param {Object} config (optional)
36143 Roo.tree.TreeFilter = function(tree, config){
36145 this.filtered = {};
36146 Roo.apply(this, config);
36149 Roo.tree.TreeFilter.prototype = {
36156 * Filter the data by a specific attribute.
36157 * @param {String/RegExp} value Either string that the attribute value
36158 * should start with or a RegExp to test against the attribute
36159 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36160 * @param {TreeNode} startNode (optional) The node to start the filter at.
36162 filter : function(value, attr, startNode){
36163 attr = attr || "text";
36165 if(typeof value == "string"){
36166 var vlen = value.length;
36167 // auto clear empty filter
36168 if(vlen == 0 && this.clearBlank){
36172 value = value.toLowerCase();
36174 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36176 }else if(value.exec){ // regex?
36178 return value.test(n.attributes[attr]);
36181 throw 'Illegal filter type, must be string or regex';
36183 this.filterBy(f, null, startNode);
36187 * Filter by a function. The passed function will be called with each
36188 * node in the tree (or from the startNode). If the function returns true, the node is kept
36189 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36190 * @param {Function} fn The filter function
36191 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36193 filterBy : function(fn, scope, startNode){
36194 startNode = startNode || this.tree.root;
36195 if(this.autoClear){
36198 var af = this.filtered, rv = this.reverse;
36199 var f = function(n){
36200 if(n == startNode){
36206 var m = fn.call(scope || n, n);
36214 startNode.cascade(f);
36217 if(typeof id != "function"){
36219 if(n && n.parentNode){
36220 n.parentNode.removeChild(n);
36228 * Clears the current filter. Note: with the "remove" option
36229 * set a filter cannot be cleared.
36231 clear : function(){
36233 var af = this.filtered;
36235 if(typeof id != "function"){
36242 this.filtered = {};
36247 * Ext JS Library 1.1.1
36248 * Copyright(c) 2006-2007, Ext JS, LLC.
36250 * Originally Released Under LGPL - original licence link has changed is not relivant.
36253 * <script type="text/javascript">
36258 * @class Roo.tree.TreeSorter
36259 * Provides sorting of nodes in a TreePanel
36261 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36262 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36263 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36264 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36265 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36266 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36268 * @param {TreePanel} tree
36269 * @param {Object} config
36271 Roo.tree.TreeSorter = function(tree, config){
36272 Roo.apply(this, config);
36273 tree.on("beforechildrenrendered", this.doSort, this);
36274 tree.on("append", this.updateSort, this);
36275 tree.on("insert", this.updateSort, this);
36277 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36278 var p = this.property || "text";
36279 var sortType = this.sortType;
36280 var fs = this.folderSort;
36281 var cs = this.caseSensitive === true;
36282 var leafAttr = this.leafAttr || 'leaf';
36284 this.sortFn = function(n1, n2){
36286 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36289 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36293 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36294 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36296 return dsc ? +1 : -1;
36298 return dsc ? -1 : +1;
36305 Roo.tree.TreeSorter.prototype = {
36306 doSort : function(node){
36307 node.sort(this.sortFn);
36310 compareNodes : function(n1, n2){
36311 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36314 updateSort : function(tree, node){
36315 if(node.childrenRendered){
36316 this.doSort.defer(1, this, [node]);
36321 * Ext JS Library 1.1.1
36322 * Copyright(c) 2006-2007, Ext JS, LLC.
36324 * Originally Released Under LGPL - original licence link has changed is not relivant.
36327 * <script type="text/javascript">
36330 if(Roo.dd.DropZone){
36332 Roo.tree.TreeDropZone = function(tree, config){
36333 this.allowParentInsert = false;
36334 this.allowContainerDrop = false;
36335 this.appendOnly = false;
36336 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36338 this.lastInsertClass = "x-tree-no-status";
36339 this.dragOverData = {};
36342 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36343 ddGroup : "TreeDD",
36346 expandDelay : 1000,
36348 expandNode : function(node){
36349 if(node.hasChildNodes() && !node.isExpanded()){
36350 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36354 queueExpand : function(node){
36355 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36358 cancelExpand : function(){
36359 if(this.expandProcId){
36360 clearTimeout(this.expandProcId);
36361 this.expandProcId = false;
36365 isValidDropPoint : function(n, pt, dd, e, data){
36366 if(!n || !data){ return false; }
36367 var targetNode = n.node;
36368 var dropNode = data.node;
36369 // default drop rules
36370 if(!(targetNode && targetNode.isTarget && pt)){
36373 if(pt == "append" && targetNode.allowChildren === false){
36376 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36379 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36382 // reuse the object
36383 var overEvent = this.dragOverData;
36384 overEvent.tree = this.tree;
36385 overEvent.target = targetNode;
36386 overEvent.data = data;
36387 overEvent.point = pt;
36388 overEvent.source = dd;
36389 overEvent.rawEvent = e;
36390 overEvent.dropNode = dropNode;
36391 overEvent.cancel = false;
36392 var result = this.tree.fireEvent("nodedragover", overEvent);
36393 return overEvent.cancel === false && result !== false;
36396 getDropPoint : function(e, n, dd)
36400 return tn.allowChildren !== false ? "append" : false; // always append for root
36402 var dragEl = n.ddel;
36403 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36404 var y = Roo.lib.Event.getPageY(e);
36405 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36407 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36408 var noAppend = tn.allowChildren === false;
36409 if(this.appendOnly || tn.parentNode.allowChildren === false){
36410 return noAppend ? false : "append";
36412 var noBelow = false;
36413 if(!this.allowParentInsert){
36414 noBelow = tn.hasChildNodes() && tn.isExpanded();
36416 var q = (b - t) / (noAppend ? 2 : 3);
36417 if(y >= t && y < (t + q)){
36419 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36426 onNodeEnter : function(n, dd, e, data)
36428 this.cancelExpand();
36431 onNodeOver : function(n, dd, e, data)
36434 var pt = this.getDropPoint(e, n, dd);
36437 // auto node expand check
36438 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36439 this.queueExpand(node);
36440 }else if(pt != "append"){
36441 this.cancelExpand();
36444 // set the insert point style on the target node
36445 var returnCls = this.dropNotAllowed;
36446 if(this.isValidDropPoint(n, pt, dd, e, data)){
36451 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36452 cls = "x-tree-drag-insert-above";
36453 }else if(pt == "below"){
36454 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36455 cls = "x-tree-drag-insert-below";
36457 returnCls = "x-tree-drop-ok-append";
36458 cls = "x-tree-drag-append";
36460 if(this.lastInsertClass != cls){
36461 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36462 this.lastInsertClass = cls;
36469 onNodeOut : function(n, dd, e, data){
36471 this.cancelExpand();
36472 this.removeDropIndicators(n);
36475 onNodeDrop : function(n, dd, e, data){
36476 var point = this.getDropPoint(e, n, dd);
36477 var targetNode = n.node;
36478 targetNode.ui.startDrop();
36479 if(!this.isValidDropPoint(n, point, dd, e, data)){
36480 targetNode.ui.endDrop();
36483 // first try to find the drop node
36484 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36487 target: targetNode,
36492 dropNode: dropNode,
36495 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36496 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36497 targetNode.ui.endDrop();
36500 // allow target changing
36501 targetNode = dropEvent.target;
36502 if(point == "append" && !targetNode.isExpanded()){
36503 targetNode.expand(false, null, function(){
36504 this.completeDrop(dropEvent);
36505 }.createDelegate(this));
36507 this.completeDrop(dropEvent);
36512 completeDrop : function(de){
36513 var ns = de.dropNode, p = de.point, t = de.target;
36514 if(!(ns instanceof Array)){
36518 for(var i = 0, len = ns.length; i < len; i++){
36521 t.parentNode.insertBefore(n, t);
36522 }else if(p == "below"){
36523 t.parentNode.insertBefore(n, t.nextSibling);
36529 if(this.tree.hlDrop){
36533 this.tree.fireEvent("nodedrop", de);
36536 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36537 if(this.tree.hlDrop){
36538 dropNode.ui.focus();
36539 dropNode.ui.highlight();
36541 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36544 getTree : function(){
36548 removeDropIndicators : function(n){
36551 Roo.fly(el).removeClass([
36552 "x-tree-drag-insert-above",
36553 "x-tree-drag-insert-below",
36554 "x-tree-drag-append"]);
36555 this.lastInsertClass = "_noclass";
36559 beforeDragDrop : function(target, e, id){
36560 this.cancelExpand();
36564 afterRepair : function(data){
36565 if(data && Roo.enableFx){
36566 data.node.ui.highlight();
36576 * Ext JS Library 1.1.1
36577 * Copyright(c) 2006-2007, Ext JS, LLC.
36579 * Originally Released Under LGPL - original licence link has changed is not relivant.
36582 * <script type="text/javascript">
36586 if(Roo.dd.DragZone){
36587 Roo.tree.TreeDragZone = function(tree, config){
36588 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36592 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36593 ddGroup : "TreeDD",
36595 onBeforeDrag : function(data, e){
36597 return n && n.draggable && !n.disabled;
36601 onInitDrag : function(e){
36602 var data = this.dragData;
36603 this.tree.getSelectionModel().select(data.node);
36604 this.proxy.update("");
36605 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36606 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36609 getRepairXY : function(e, data){
36610 return data.node.ui.getDDRepairXY();
36613 onEndDrag : function(data, e){
36614 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36619 onValidDrop : function(dd, e, id){
36620 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36624 beforeInvalidDrop : function(e, id){
36625 // this scrolls the original position back into view
36626 var sm = this.tree.getSelectionModel();
36627 sm.clearSelections();
36628 sm.select(this.dragData.node);
36633 * Ext JS Library 1.1.1
36634 * Copyright(c) 2006-2007, Ext JS, LLC.
36636 * Originally Released Under LGPL - original licence link has changed is not relivant.
36639 * <script type="text/javascript">
36642 * @class Roo.tree.TreeEditor
36643 * @extends Roo.Editor
36644 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36645 * as the editor field.
36647 * @param {Object} config (used to be the tree panel.)
36648 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36650 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36651 * @cfg {Roo.form.TextField|Object} field The field configuration
36655 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36658 if (oldconfig) { // old style..
36659 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36662 tree = config.tree;
36663 config.field = config.field || {};
36664 config.field.xtype = 'TextField';
36665 field = Roo.factory(config.field, Roo.form);
36667 config = config || {};
36672 * @event beforenodeedit
36673 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36674 * false from the handler of this event.
36675 * @param {Editor} this
36676 * @param {Roo.tree.Node} node
36678 "beforenodeedit" : true
36682 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36686 tree.on('beforeclick', this.beforeNodeClick, this);
36687 tree.getTreeEl().on('mousedown', this.hide, this);
36688 this.on('complete', this.updateNode, this);
36689 this.on('beforestartedit', this.fitToTree, this);
36690 this.on('startedit', this.bindScroll, this, {delay:10});
36691 this.on('specialkey', this.onSpecialKey, this);
36694 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36696 * @cfg {String} alignment
36697 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36703 * @cfg {Boolean} hideEl
36704 * True to hide the bound element while the editor is displayed (defaults to false)
36708 * @cfg {String} cls
36709 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36711 cls: "x-small-editor x-tree-editor",
36713 * @cfg {Boolean} shim
36714 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36720 * @cfg {Number} maxWidth
36721 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36722 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36723 * scroll and client offsets into account prior to each edit.
36730 fitToTree : function(ed, el){
36731 var td = this.tree.getTreeEl().dom, nd = el.dom;
36732 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36733 td.scrollLeft = nd.offsetLeft;
36737 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36738 this.setSize(w, '');
36740 return this.fireEvent('beforenodeedit', this, this.editNode);
36745 triggerEdit : function(node){
36746 this.completeEdit();
36747 this.editNode = node;
36748 this.startEdit(node.ui.textNode, node.text);
36752 bindScroll : function(){
36753 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36757 beforeNodeClick : function(node, e){
36758 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36759 this.lastClick = new Date();
36760 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36762 this.triggerEdit(node);
36769 updateNode : function(ed, value){
36770 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36771 this.editNode.setText(value);
36775 onHide : function(){
36776 Roo.tree.TreeEditor.superclass.onHide.call(this);
36778 this.editNode.ui.focus();
36783 onSpecialKey : function(field, e){
36784 var k = e.getKey();
36788 }else if(k == e.ENTER && !e.hasModifier()){
36790 this.completeEdit();
36793 });//<Script type="text/javascript">
36796 * Ext JS Library 1.1.1
36797 * Copyright(c) 2006-2007, Ext JS, LLC.
36799 * Originally Released Under LGPL - original licence link has changed is not relivant.
36802 * <script type="text/javascript">
36806 * Not documented??? - probably should be...
36809 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36810 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36812 renderElements : function(n, a, targetNode, bulkRender){
36813 //consel.log("renderElements?");
36814 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36816 var t = n.getOwnerTree();
36817 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36819 var cols = t.columns;
36820 var bw = t.borderWidth;
36822 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36823 var cb = typeof a.checked == "boolean";
36824 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36825 var colcls = 'x-t-' + tid + '-c0';
36827 '<li class="x-tree-node">',
36830 '<div class="x-tree-node-el ', a.cls,'">',
36832 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36835 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36836 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36837 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36838 (a.icon ? ' x-tree-node-inline-icon' : ''),
36839 (a.iconCls ? ' '+a.iconCls : ''),
36840 '" unselectable="on" />',
36841 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36842 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36844 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36845 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36846 '<span unselectable="on" qtip="' + tx + '">',
36850 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36851 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36853 for(var i = 1, len = cols.length; i < len; i++){
36855 colcls = 'x-t-' + tid + '-c' +i;
36856 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36857 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
36858 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
36864 '<div class="x-clear"></div></div>',
36865 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36868 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36869 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36870 n.nextSibling.ui.getEl(), buf.join(""));
36872 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36874 var el = this.wrap.firstChild;
36876 this.elNode = el.firstChild;
36877 this.ranchor = el.childNodes[1];
36878 this.ctNode = this.wrap.childNodes[1];
36879 var cs = el.firstChild.childNodes;
36880 this.indentNode = cs[0];
36881 this.ecNode = cs[1];
36882 this.iconNode = cs[2];
36885 this.checkbox = cs[3];
36888 this.anchor = cs[index];
36890 this.textNode = cs[index].firstChild;
36892 //el.on("click", this.onClick, this);
36893 //el.on("dblclick", this.onDblClick, this);
36896 // console.log(this);
36898 initEvents : function(){
36899 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
36902 var a = this.ranchor;
36904 var el = Roo.get(a);
36906 if(Roo.isOpera){ // opera render bug ignores the CSS
36907 el.setStyle("text-decoration", "none");
36910 el.on("click", this.onClick, this);
36911 el.on("dblclick", this.onDblClick, this);
36912 el.on("contextmenu", this.onContextMenu, this);
36916 /*onSelectedChange : function(state){
36919 this.addClass("x-tree-selected");
36922 this.removeClass("x-tree-selected");
36925 addClass : function(cls){
36927 Roo.fly(this.elRow).addClass(cls);
36933 removeClass : function(cls){
36935 Roo.fly(this.elRow).removeClass(cls);
36941 });//<Script type="text/javascript">
36945 * Ext JS Library 1.1.1
36946 * Copyright(c) 2006-2007, Ext JS, LLC.
36948 * Originally Released Under LGPL - original licence link has changed is not relivant.
36951 * <script type="text/javascript">
36956 * @class Roo.tree.ColumnTree
36957 * @extends Roo.data.TreePanel
36958 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
36959 * @cfg {int} borderWidth compined right/left border allowance
36961 * @param {String/HTMLElement/Element} el The container element
36962 * @param {Object} config
36964 Roo.tree.ColumnTree = function(el, config)
36966 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
36970 * Fire this event on a container when it resizes
36971 * @param {int} w Width
36972 * @param {int} h Height
36976 this.on('resize', this.onResize, this);
36979 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
36983 borderWidth: Roo.isBorderBox ? 0 : 2,
36986 render : function(){
36987 // add the header.....
36989 Roo.tree.ColumnTree.superclass.render.apply(this);
36991 this.el.addClass('x-column-tree');
36993 this.headers = this.el.createChild(
36994 {cls:'x-tree-headers'},this.innerCt.dom);
36996 var cols = this.columns, c;
36997 var totalWidth = 0;
36999 var len = cols.length;
37000 for(var i = 0; i < len; i++){
37002 totalWidth += c.width;
37003 this.headEls.push(this.headers.createChild({
37004 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37006 cls:'x-tree-hd-text',
37009 style:'width:'+(c.width-this.borderWidth)+'px;'
37012 this.headers.createChild({cls:'x-clear'});
37013 // prevent floats from wrapping when clipped
37014 this.headers.setWidth(totalWidth);
37015 //this.innerCt.setWidth(totalWidth);
37016 this.innerCt.setStyle({ overflow: 'auto' });
37017 this.onResize(this.width, this.height);
37021 onResize : function(w,h)
37026 this.innerCt.setWidth(this.width);
37027 this.innerCt.setHeight(this.height-20);
37030 var cols = this.columns, c;
37031 var totalWidth = 0;
37033 var len = cols.length;
37034 for(var i = 0; i < len; i++){
37036 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37037 // it's the expander..
37038 expEl = this.headEls[i];
37041 totalWidth += c.width;
37045 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37047 this.headers.setWidth(w-20);
37056 * Ext JS Library 1.1.1
37057 * Copyright(c) 2006-2007, Ext JS, LLC.
37059 * Originally Released Under LGPL - original licence link has changed is not relivant.
37062 * <script type="text/javascript">
37066 * @class Roo.menu.Menu
37067 * @extends Roo.util.Observable
37068 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37069 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37071 * Creates a new Menu
37072 * @param {Object} config Configuration options
37074 Roo.menu.Menu = function(config){
37075 Roo.apply(this, config);
37076 this.id = this.id || Roo.id();
37079 * @event beforeshow
37080 * Fires before this menu is displayed
37081 * @param {Roo.menu.Menu} this
37085 * @event beforehide
37086 * Fires before this menu is hidden
37087 * @param {Roo.menu.Menu} this
37092 * Fires after this menu is displayed
37093 * @param {Roo.menu.Menu} this
37098 * Fires after this menu is hidden
37099 * @param {Roo.menu.Menu} this
37104 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37105 * @param {Roo.menu.Menu} this
37106 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37107 * @param {Roo.EventObject} e
37112 * Fires when the mouse is hovering over this menu
37113 * @param {Roo.menu.Menu} this
37114 * @param {Roo.EventObject} e
37115 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37120 * Fires when the mouse exits this menu
37121 * @param {Roo.menu.Menu} this
37122 * @param {Roo.EventObject} e
37123 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37128 * Fires when a menu item contained in this menu is clicked
37129 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37130 * @param {Roo.EventObject} e
37134 if (this.registerMenu) {
37135 Roo.menu.MenuMgr.register(this);
37138 var mis = this.items;
37139 this.items = new Roo.util.MixedCollection();
37141 this.add.apply(this, mis);
37145 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37147 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37151 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37152 * for bottom-right shadow (defaults to "sides")
37156 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37157 * this menu (defaults to "tl-tr?")
37159 subMenuAlign : "tl-tr?",
37161 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37162 * relative to its element of origin (defaults to "tl-bl?")
37164 defaultAlign : "tl-bl?",
37166 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37168 allowOtherMenus : false,
37170 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37172 registerMenu : true,
37177 render : function(){
37181 var el = this.el = new Roo.Layer({
37183 shadow:this.shadow,
37185 parentEl: this.parentEl || document.body,
37189 this.keyNav = new Roo.menu.MenuNav(this);
37192 el.addClass("x-menu-plain");
37195 el.addClass(this.cls);
37197 // generic focus element
37198 this.focusEl = el.createChild({
37199 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37201 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37202 //disabling touch- as it's causing issues ..
37203 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37204 ul.on('click' , this.onClick, this);
37207 ul.on("mouseover", this.onMouseOver, this);
37208 ul.on("mouseout", this.onMouseOut, this);
37209 this.items.each(function(item){
37214 var li = document.createElement("li");
37215 li.className = "x-menu-list-item";
37216 ul.dom.appendChild(li);
37217 item.render(li, this);
37224 autoWidth : function(){
37225 var el = this.el, ul = this.ul;
37229 var w = this.width;
37232 }else if(Roo.isIE){
37233 el.setWidth(this.minWidth);
37234 var t = el.dom.offsetWidth; // force recalc
37235 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37240 delayAutoWidth : function(){
37243 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37245 this.awTask.delay(20);
37250 findTargetItem : function(e){
37251 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37252 if(t && t.menuItemId){
37253 return this.items.get(t.menuItemId);
37258 onClick : function(e){
37259 Roo.log("menu.onClick");
37260 var t = this.findTargetItem(e);
37265 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37266 if(t == this.activeItem && t.shouldDeactivate(e)){
37267 this.activeItem.deactivate();
37268 delete this.activeItem;
37272 this.setActiveItem(t, true);
37280 this.fireEvent("click", this, t, e);
37284 setActiveItem : function(item, autoExpand){
37285 if(item != this.activeItem){
37286 if(this.activeItem){
37287 this.activeItem.deactivate();
37289 this.activeItem = item;
37290 item.activate(autoExpand);
37291 }else if(autoExpand){
37297 tryActivate : function(start, step){
37298 var items = this.items;
37299 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37300 var item = items.get(i);
37301 if(!item.disabled && item.canActivate){
37302 this.setActiveItem(item, false);
37310 onMouseOver : function(e){
37312 if(t = this.findTargetItem(e)){
37313 if(t.canActivate && !t.disabled){
37314 this.setActiveItem(t, true);
37317 this.fireEvent("mouseover", this, e, t);
37321 onMouseOut : function(e){
37323 if(t = this.findTargetItem(e)){
37324 if(t == this.activeItem && t.shouldDeactivate(e)){
37325 this.activeItem.deactivate();
37326 delete this.activeItem;
37329 this.fireEvent("mouseout", this, e, t);
37333 * Read-only. Returns true if the menu is currently displayed, else false.
37336 isVisible : function(){
37337 return this.el && !this.hidden;
37341 * Displays this menu relative to another element
37342 * @param {String/HTMLElement/Roo.Element} element The element to align to
37343 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37344 * the element (defaults to this.defaultAlign)
37345 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37347 show : function(el, pos, parentMenu){
37348 this.parentMenu = parentMenu;
37352 this.fireEvent("beforeshow", this);
37353 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37357 * Displays this menu at a specific xy position
37358 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37359 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37361 showAt : function(xy, parentMenu, /* private: */_e){
37362 this.parentMenu = parentMenu;
37367 this.fireEvent("beforeshow", this);
37368 xy = this.el.adjustForConstraints(xy);
37372 this.hidden = false;
37374 this.fireEvent("show", this);
37377 focus : function(){
37379 this.doFocus.defer(50, this);
37383 doFocus : function(){
37385 this.focusEl.focus();
37390 * Hides this menu and optionally all parent menus
37391 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37393 hide : function(deep){
37394 if(this.el && this.isVisible()){
37395 this.fireEvent("beforehide", this);
37396 if(this.activeItem){
37397 this.activeItem.deactivate();
37398 this.activeItem = null;
37401 this.hidden = true;
37402 this.fireEvent("hide", this);
37404 if(deep === true && this.parentMenu){
37405 this.parentMenu.hide(true);
37410 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37411 * Any of the following are valid:
37413 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37414 * <li>An HTMLElement object which will be converted to a menu item</li>
37415 * <li>A menu item config object that will be created as a new menu item</li>
37416 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37417 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37422 var menu = new Roo.menu.Menu();
37424 // Create a menu item to add by reference
37425 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37427 // Add a bunch of items at once using different methods.
37428 // Only the last item added will be returned.
37429 var item = menu.add(
37430 menuItem, // add existing item by ref
37431 'Dynamic Item', // new TextItem
37432 '-', // new separator
37433 { text: 'Config Item' } // new item by config
37436 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37437 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37440 var a = arguments, l = a.length, item;
37441 for(var i = 0; i < l; i++){
37443 if ((typeof(el) == "object") && el.xtype && el.xns) {
37444 el = Roo.factory(el, Roo.menu);
37447 if(el.render){ // some kind of Item
37448 item = this.addItem(el);
37449 }else if(typeof el == "string"){ // string
37450 if(el == "separator" || el == "-"){
37451 item = this.addSeparator();
37453 item = this.addText(el);
37455 }else if(el.tagName || el.el){ // element
37456 item = this.addElement(el);
37457 }else if(typeof el == "object"){ // must be menu item config?
37458 item = this.addMenuItem(el);
37465 * Returns this menu's underlying {@link Roo.Element} object
37466 * @return {Roo.Element} The element
37468 getEl : function(){
37476 * Adds a separator bar to the menu
37477 * @return {Roo.menu.Item} The menu item that was added
37479 addSeparator : function(){
37480 return this.addItem(new Roo.menu.Separator());
37484 * Adds an {@link Roo.Element} object to the menu
37485 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37486 * @return {Roo.menu.Item} The menu item that was added
37488 addElement : function(el){
37489 return this.addItem(new Roo.menu.BaseItem(el));
37493 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37494 * @param {Roo.menu.Item} item The menu item to add
37495 * @return {Roo.menu.Item} The menu item that was added
37497 addItem : function(item){
37498 this.items.add(item);
37500 var li = document.createElement("li");
37501 li.className = "x-menu-list-item";
37502 this.ul.dom.appendChild(li);
37503 item.render(li, this);
37504 this.delayAutoWidth();
37510 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37511 * @param {Object} config A MenuItem config object
37512 * @return {Roo.menu.Item} The menu item that was added
37514 addMenuItem : function(config){
37515 if(!(config instanceof Roo.menu.Item)){
37516 if(typeof config.checked == "boolean"){ // must be check menu item config?
37517 config = new Roo.menu.CheckItem(config);
37519 config = new Roo.menu.Item(config);
37522 return this.addItem(config);
37526 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37527 * @param {String} text The text to display in the menu item
37528 * @return {Roo.menu.Item} The menu item that was added
37530 addText : function(text){
37531 return this.addItem(new Roo.menu.TextItem({ text : text }));
37535 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37536 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37537 * @param {Roo.menu.Item} item The menu item to add
37538 * @return {Roo.menu.Item} The menu item that was added
37540 insert : function(index, item){
37541 this.items.insert(index, item);
37543 var li = document.createElement("li");
37544 li.className = "x-menu-list-item";
37545 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37546 item.render(li, this);
37547 this.delayAutoWidth();
37553 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37554 * @param {Roo.menu.Item} item The menu item to remove
37556 remove : function(item){
37557 this.items.removeKey(item.id);
37562 * Removes and destroys all items in the menu
37564 removeAll : function(){
37566 while(f = this.items.first()){
37572 // MenuNav is a private utility class used internally by the Menu
37573 Roo.menu.MenuNav = function(menu){
37574 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37575 this.scope = this.menu = menu;
37578 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37579 doRelay : function(e, h){
37580 var k = e.getKey();
37581 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37582 this.menu.tryActivate(0, 1);
37585 return h.call(this.scope || this, e, this.menu);
37588 up : function(e, m){
37589 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37590 m.tryActivate(m.items.length-1, -1);
37594 down : function(e, m){
37595 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37596 m.tryActivate(0, 1);
37600 right : function(e, m){
37602 m.activeItem.expandMenu(true);
37606 left : function(e, m){
37608 if(m.parentMenu && m.parentMenu.activeItem){
37609 m.parentMenu.activeItem.activate();
37613 enter : function(e, m){
37615 e.stopPropagation();
37616 m.activeItem.onClick(e);
37617 m.fireEvent("click", this, m.activeItem);
37623 * Ext JS Library 1.1.1
37624 * Copyright(c) 2006-2007, Ext JS, LLC.
37626 * Originally Released Under LGPL - original licence link has changed is not relivant.
37629 * <script type="text/javascript">
37633 * @class Roo.menu.MenuMgr
37634 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37637 Roo.menu.MenuMgr = function(){
37638 var menus, active, groups = {}, attached = false, lastShow = new Date();
37640 // private - called when first menu is created
37643 active = new Roo.util.MixedCollection();
37644 Roo.get(document).addKeyListener(27, function(){
37645 if(active.length > 0){
37652 function hideAll(){
37653 if(active && active.length > 0){
37654 var c = active.clone();
37655 c.each(function(m){
37662 function onHide(m){
37664 if(active.length < 1){
37665 Roo.get(document).un("mousedown", onMouseDown);
37671 function onShow(m){
37672 var last = active.last();
37673 lastShow = new Date();
37676 Roo.get(document).on("mousedown", onMouseDown);
37680 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37681 m.parentMenu.activeChild = m;
37682 }else if(last && last.isVisible()){
37683 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37688 function onBeforeHide(m){
37690 m.activeChild.hide();
37692 if(m.autoHideTimer){
37693 clearTimeout(m.autoHideTimer);
37694 delete m.autoHideTimer;
37699 function onBeforeShow(m){
37700 var pm = m.parentMenu;
37701 if(!pm && !m.allowOtherMenus){
37703 }else if(pm && pm.activeChild && active != m){
37704 pm.activeChild.hide();
37709 function onMouseDown(e){
37710 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37716 function onBeforeCheck(mi, state){
37718 var g = groups[mi.group];
37719 for(var i = 0, l = g.length; i < l; i++){
37721 g[i].setChecked(false);
37730 * Hides all menus that are currently visible
37732 hideAll : function(){
37737 register : function(menu){
37741 menus[menu.id] = menu;
37742 menu.on("beforehide", onBeforeHide);
37743 menu.on("hide", onHide);
37744 menu.on("beforeshow", onBeforeShow);
37745 menu.on("show", onShow);
37746 var g = menu.group;
37747 if(g && menu.events["checkchange"]){
37751 groups[g].push(menu);
37752 menu.on("checkchange", onCheck);
37757 * Returns a {@link Roo.menu.Menu} object
37758 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37759 * be used to generate and return a new Menu instance.
37761 get : function(menu){
37762 if(typeof menu == "string"){ // menu id
37763 return menus[menu];
37764 }else if(menu.events){ // menu instance
37766 }else if(typeof menu.length == 'number'){ // array of menu items?
37767 return new Roo.menu.Menu({items:menu});
37768 }else{ // otherwise, must be a config
37769 return new Roo.menu.Menu(menu);
37774 unregister : function(menu){
37775 delete menus[menu.id];
37776 menu.un("beforehide", onBeforeHide);
37777 menu.un("hide", onHide);
37778 menu.un("beforeshow", onBeforeShow);
37779 menu.un("show", onShow);
37780 var g = menu.group;
37781 if(g && menu.events["checkchange"]){
37782 groups[g].remove(menu);
37783 menu.un("checkchange", onCheck);
37788 registerCheckable : function(menuItem){
37789 var g = menuItem.group;
37794 groups[g].push(menuItem);
37795 menuItem.on("beforecheckchange", onBeforeCheck);
37800 unregisterCheckable : function(menuItem){
37801 var g = menuItem.group;
37803 groups[g].remove(menuItem);
37804 menuItem.un("beforecheckchange", onBeforeCheck);
37810 * Ext JS Library 1.1.1
37811 * Copyright(c) 2006-2007, Ext JS, LLC.
37813 * Originally Released Under LGPL - original licence link has changed is not relivant.
37816 * <script type="text/javascript">
37821 * @class Roo.menu.BaseItem
37822 * @extends Roo.Component
37823 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37824 * management and base configuration options shared by all menu components.
37826 * Creates a new BaseItem
37827 * @param {Object} config Configuration options
37829 Roo.menu.BaseItem = function(config){
37830 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37835 * Fires when this item is clicked
37836 * @param {Roo.menu.BaseItem} this
37837 * @param {Roo.EventObject} e
37842 * Fires when this item is activated
37843 * @param {Roo.menu.BaseItem} this
37847 * @event deactivate
37848 * Fires when this item is deactivated
37849 * @param {Roo.menu.BaseItem} this
37855 this.on("click", this.handler, this.scope, true);
37859 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
37861 * @cfg {Function} handler
37862 * A function that will handle the click event of this menu item (defaults to undefined)
37865 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
37867 canActivate : false,
37870 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
37875 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
37877 activeClass : "x-menu-item-active",
37879 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
37881 hideOnClick : true,
37883 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
37888 ctype: "Roo.menu.BaseItem",
37891 actionMode : "container",
37894 render : function(container, parentMenu){
37895 this.parentMenu = parentMenu;
37896 Roo.menu.BaseItem.superclass.render.call(this, container);
37897 this.container.menuItemId = this.id;
37901 onRender : function(container, position){
37902 this.el = Roo.get(this.el);
37903 container.dom.appendChild(this.el.dom);
37907 onClick : function(e){
37908 if(!this.disabled && this.fireEvent("click", this, e) !== false
37909 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
37910 this.handleClick(e);
37917 activate : function(){
37921 var li = this.container;
37922 li.addClass(this.activeClass);
37923 this.region = li.getRegion().adjust(2, 2, -2, -2);
37924 this.fireEvent("activate", this);
37929 deactivate : function(){
37930 this.container.removeClass(this.activeClass);
37931 this.fireEvent("deactivate", this);
37935 shouldDeactivate : function(e){
37936 return !this.region || !this.region.contains(e.getPoint());
37940 handleClick : function(e){
37941 if(this.hideOnClick){
37942 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
37947 expandMenu : function(autoActivate){
37952 hideMenu : function(){
37957 * Ext JS Library 1.1.1
37958 * Copyright(c) 2006-2007, Ext JS, LLC.
37960 * Originally Released Under LGPL - original licence link has changed is not relivant.
37963 * <script type="text/javascript">
37967 * @class Roo.menu.Adapter
37968 * @extends Roo.menu.BaseItem
37969 * 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.
37970 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
37972 * Creates a new Adapter
37973 * @param {Object} config Configuration options
37975 Roo.menu.Adapter = function(component, config){
37976 Roo.menu.Adapter.superclass.constructor.call(this, config);
37977 this.component = component;
37979 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
37981 canActivate : true,
37984 onRender : function(container, position){
37985 this.component.render(container);
37986 this.el = this.component.getEl();
37990 activate : function(){
37994 this.component.focus();
37995 this.fireEvent("activate", this);
38000 deactivate : function(){
38001 this.fireEvent("deactivate", this);
38005 disable : function(){
38006 this.component.disable();
38007 Roo.menu.Adapter.superclass.disable.call(this);
38011 enable : function(){
38012 this.component.enable();
38013 Roo.menu.Adapter.superclass.enable.call(this);
38017 * Ext JS Library 1.1.1
38018 * Copyright(c) 2006-2007, Ext JS, LLC.
38020 * Originally Released Under LGPL - original licence link has changed is not relivant.
38023 * <script type="text/javascript">
38027 * @class Roo.menu.TextItem
38028 * @extends Roo.menu.BaseItem
38029 * Adds a static text string to a menu, usually used as either a heading or group separator.
38030 * Note: old style constructor with text is still supported.
38033 * Creates a new TextItem
38034 * @param {Object} cfg Configuration
38036 Roo.menu.TextItem = function(cfg){
38037 if (typeof(cfg) == 'string') {
38040 Roo.apply(this,cfg);
38043 Roo.menu.TextItem.superclass.constructor.call(this);
38046 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38048 * @cfg {Boolean} text Text to show on item.
38053 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38055 hideOnClick : false,
38057 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38059 itemCls : "x-menu-text",
38062 onRender : function(){
38063 var s = document.createElement("span");
38064 s.className = this.itemCls;
38065 s.innerHTML = this.text;
38067 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38071 * Ext JS Library 1.1.1
38072 * Copyright(c) 2006-2007, Ext JS, LLC.
38074 * Originally Released Under LGPL - original licence link has changed is not relivant.
38077 * <script type="text/javascript">
38081 * @class Roo.menu.Separator
38082 * @extends Roo.menu.BaseItem
38083 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38084 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38086 * @param {Object} config Configuration options
38088 Roo.menu.Separator = function(config){
38089 Roo.menu.Separator.superclass.constructor.call(this, config);
38092 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38094 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38096 itemCls : "x-menu-sep",
38098 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38100 hideOnClick : false,
38103 onRender : function(li){
38104 var s = document.createElement("span");
38105 s.className = this.itemCls;
38106 s.innerHTML = " ";
38108 li.addClass("x-menu-sep-li");
38109 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38113 * Ext JS Library 1.1.1
38114 * Copyright(c) 2006-2007, Ext JS, LLC.
38116 * Originally Released Under LGPL - original licence link has changed is not relivant.
38119 * <script type="text/javascript">
38122 * @class Roo.menu.Item
38123 * @extends Roo.menu.BaseItem
38124 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38125 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38126 * activation and click handling.
38128 * Creates a new Item
38129 * @param {Object} config Configuration options
38131 Roo.menu.Item = function(config){
38132 Roo.menu.Item.superclass.constructor.call(this, config);
38134 this.menu = Roo.menu.MenuMgr.get(this.menu);
38137 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38140 * @cfg {String} text
38141 * The text to show on the menu item.
38145 * @cfg {String} HTML to render in menu
38146 * The text to show on the menu item (HTML version).
38150 * @cfg {String} icon
38151 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38155 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38157 itemCls : "x-menu-item",
38159 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38161 canActivate : true,
38163 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38166 // doc'd in BaseItem
38170 ctype: "Roo.menu.Item",
38173 onRender : function(container, position){
38174 var el = document.createElement("a");
38175 el.hideFocus = true;
38176 el.unselectable = "on";
38177 el.href = this.href || "#";
38178 if(this.hrefTarget){
38179 el.target = this.hrefTarget;
38181 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38183 var html = this.html.length ? this.html : String.format('{0}',this.text);
38185 el.innerHTML = String.format(
38186 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38187 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38189 Roo.menu.Item.superclass.onRender.call(this, container, position);
38193 * Sets the text to display in this menu item
38194 * @param {String} text The text to display
38195 * @param {Boolean} isHTML true to indicate text is pure html.
38197 setText : function(text, isHTML){
38205 var html = this.html.length ? this.html : String.format('{0}',this.text);
38207 this.el.update(String.format(
38208 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38209 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38210 this.parentMenu.autoWidth();
38215 handleClick : function(e){
38216 if(!this.href){ // if no link defined, stop the event automatically
38219 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38223 activate : function(autoExpand){
38224 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38234 shouldDeactivate : function(e){
38235 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38236 if(this.menu && this.menu.isVisible()){
38237 return !this.menu.getEl().getRegion().contains(e.getPoint());
38245 deactivate : function(){
38246 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38251 expandMenu : function(autoActivate){
38252 if(!this.disabled && this.menu){
38253 clearTimeout(this.hideTimer);
38254 delete this.hideTimer;
38255 if(!this.menu.isVisible() && !this.showTimer){
38256 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38257 }else if (this.menu.isVisible() && autoActivate){
38258 this.menu.tryActivate(0, 1);
38264 deferExpand : function(autoActivate){
38265 delete this.showTimer;
38266 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38268 this.menu.tryActivate(0, 1);
38273 hideMenu : function(){
38274 clearTimeout(this.showTimer);
38275 delete this.showTimer;
38276 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38277 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38282 deferHide : function(){
38283 delete this.hideTimer;
38288 * Ext JS Library 1.1.1
38289 * Copyright(c) 2006-2007, Ext JS, LLC.
38291 * Originally Released Under LGPL - original licence link has changed is not relivant.
38294 * <script type="text/javascript">
38298 * @class Roo.menu.CheckItem
38299 * @extends Roo.menu.Item
38300 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38302 * Creates a new CheckItem
38303 * @param {Object} config Configuration options
38305 Roo.menu.CheckItem = function(config){
38306 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38309 * @event beforecheckchange
38310 * Fires before the checked value is set, providing an opportunity to cancel if needed
38311 * @param {Roo.menu.CheckItem} this
38312 * @param {Boolean} checked The new checked value that will be set
38314 "beforecheckchange" : true,
38316 * @event checkchange
38317 * Fires after the checked value has been set
38318 * @param {Roo.menu.CheckItem} this
38319 * @param {Boolean} checked The checked value that was set
38321 "checkchange" : true
38323 if(this.checkHandler){
38324 this.on('checkchange', this.checkHandler, this.scope);
38327 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38329 * @cfg {String} group
38330 * All check items with the same group name will automatically be grouped into a single-select
38331 * radio button group (defaults to '')
38334 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38336 itemCls : "x-menu-item x-menu-check-item",
38338 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38340 groupClass : "x-menu-group-item",
38343 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38344 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38345 * initialized with checked = true will be rendered as checked.
38350 ctype: "Roo.menu.CheckItem",
38353 onRender : function(c){
38354 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38356 this.el.addClass(this.groupClass);
38358 Roo.menu.MenuMgr.registerCheckable(this);
38360 this.checked = false;
38361 this.setChecked(true, true);
38366 destroy : function(){
38368 Roo.menu.MenuMgr.unregisterCheckable(this);
38370 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38374 * Set the checked state of this item
38375 * @param {Boolean} checked The new checked value
38376 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38378 setChecked : function(state, suppressEvent){
38379 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38380 if(this.container){
38381 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38383 this.checked = state;
38384 if(suppressEvent !== true){
38385 this.fireEvent("checkchange", this, state);
38391 handleClick : function(e){
38392 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38393 this.setChecked(!this.checked);
38395 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38399 * Ext JS Library 1.1.1
38400 * Copyright(c) 2006-2007, Ext JS, LLC.
38402 * Originally Released Under LGPL - original licence link has changed is not relivant.
38405 * <script type="text/javascript">
38409 * @class Roo.menu.DateItem
38410 * @extends Roo.menu.Adapter
38411 * A menu item that wraps the {@link Roo.DatPicker} component.
38413 * Creates a new DateItem
38414 * @param {Object} config Configuration options
38416 Roo.menu.DateItem = function(config){
38417 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38418 /** The Roo.DatePicker object @type Roo.DatePicker */
38419 this.picker = this.component;
38420 this.addEvents({select: true});
38422 this.picker.on("render", function(picker){
38423 picker.getEl().swallowEvent("click");
38424 picker.container.addClass("x-menu-date-item");
38427 this.picker.on("select", this.onSelect, this);
38430 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38432 onSelect : function(picker, date){
38433 this.fireEvent("select", this, date, picker);
38434 Roo.menu.DateItem.superclass.handleClick.call(this);
38438 * Ext JS Library 1.1.1
38439 * Copyright(c) 2006-2007, Ext JS, LLC.
38441 * Originally Released Under LGPL - original licence link has changed is not relivant.
38444 * <script type="text/javascript">
38448 * @class Roo.menu.ColorItem
38449 * @extends Roo.menu.Adapter
38450 * A menu item that wraps the {@link Roo.ColorPalette} component.
38452 * Creates a new ColorItem
38453 * @param {Object} config Configuration options
38455 Roo.menu.ColorItem = function(config){
38456 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38457 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38458 this.palette = this.component;
38459 this.relayEvents(this.palette, ["select"]);
38460 if(this.selectHandler){
38461 this.on('select', this.selectHandler, this.scope);
38464 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38466 * Ext JS Library 1.1.1
38467 * Copyright(c) 2006-2007, Ext JS, LLC.
38469 * Originally Released Under LGPL - original licence link has changed is not relivant.
38472 * <script type="text/javascript">
38477 * @class Roo.menu.DateMenu
38478 * @extends Roo.menu.Menu
38479 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38481 * Creates a new DateMenu
38482 * @param {Object} config Configuration options
38484 Roo.menu.DateMenu = function(config){
38485 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38487 var di = new Roo.menu.DateItem(config);
38490 * The {@link Roo.DatePicker} instance for this DateMenu
38493 this.picker = di.picker;
38496 * @param {DatePicker} picker
38497 * @param {Date} date
38499 this.relayEvents(di, ["select"]);
38500 this.on('beforeshow', function(){
38502 this.picker.hideMonthPicker(false);
38506 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38510 * Ext JS Library 1.1.1
38511 * Copyright(c) 2006-2007, Ext JS, LLC.
38513 * Originally Released Under LGPL - original licence link has changed is not relivant.
38516 * <script type="text/javascript">
38521 * @class Roo.menu.ColorMenu
38522 * @extends Roo.menu.Menu
38523 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38525 * Creates a new ColorMenu
38526 * @param {Object} config Configuration options
38528 Roo.menu.ColorMenu = function(config){
38529 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38531 var ci = new Roo.menu.ColorItem(config);
38534 * The {@link Roo.ColorPalette} instance for this ColorMenu
38535 * @type ColorPalette
38537 this.palette = ci.palette;
38540 * @param {ColorPalette} palette
38541 * @param {String} color
38543 this.relayEvents(ci, ["select"]);
38545 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38547 * Ext JS Library 1.1.1
38548 * Copyright(c) 2006-2007, Ext JS, LLC.
38550 * Originally Released Under LGPL - original licence link has changed is not relivant.
38553 * <script type="text/javascript">
38557 * @class Roo.form.Field
38558 * @extends Roo.BoxComponent
38559 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38561 * Creates a new Field
38562 * @param {Object} config Configuration options
38564 Roo.form.Field = function(config){
38565 Roo.form.Field.superclass.constructor.call(this, config);
38568 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38570 * @cfg {String} fieldLabel Label to use when rendering a form.
38573 * @cfg {String} qtip Mouse over tip
38577 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38579 invalidClass : "x-form-invalid",
38581 * @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")
38583 invalidText : "The value in this field is invalid",
38585 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38587 focusClass : "x-form-focus",
38589 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38590 automatic validation (defaults to "keyup").
38592 validationEvent : "keyup",
38594 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38596 validateOnBlur : true,
38598 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38600 validationDelay : 250,
38602 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38603 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38605 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38607 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38609 fieldClass : "x-form-field",
38611 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38614 ----------- ----------------------------------------------------------------------
38615 qtip Display a quick tip when the user hovers over the field
38616 title Display a default browser title attribute popup
38617 under Add a block div beneath the field containing the error text
38618 side Add an error icon to the right of the field with a popup on hover
38619 [element id] Add the error text directly to the innerHTML of the specified element
38622 msgTarget : 'qtip',
38624 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38629 * @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.
38634 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38639 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38641 inputType : undefined,
38644 * @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).
38646 tabIndex : undefined,
38649 isFormField : true,
38654 * @property {Roo.Element} fieldEl
38655 * Element Containing the rendered Field (with label etc.)
38658 * @cfg {Mixed} value A value to initialize this field with.
38663 * @cfg {String} name The field's HTML name attribute.
38666 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38669 loadedValue : false,
38673 initComponent : function(){
38674 Roo.form.Field.superclass.initComponent.call(this);
38678 * Fires when this field receives input focus.
38679 * @param {Roo.form.Field} this
38684 * Fires when this field loses input focus.
38685 * @param {Roo.form.Field} this
38689 * @event specialkey
38690 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38691 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38692 * @param {Roo.form.Field} this
38693 * @param {Roo.EventObject} e The event object
38698 * Fires just before the field blurs if the field value has changed.
38699 * @param {Roo.form.Field} this
38700 * @param {Mixed} newValue The new value
38701 * @param {Mixed} oldValue The original value
38706 * Fires after the field has been marked as invalid.
38707 * @param {Roo.form.Field} this
38708 * @param {String} msg The validation message
38713 * Fires after the field has been validated with no errors.
38714 * @param {Roo.form.Field} this
38719 * Fires after the key up
38720 * @param {Roo.form.Field} this
38721 * @param {Roo.EventObject} e The event Object
38728 * Returns the name attribute of the field if available
38729 * @return {String} name The field name
38731 getName: function(){
38732 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38736 onRender : function(ct, position){
38737 Roo.form.Field.superclass.onRender.call(this, ct, position);
38739 var cfg = this.getAutoCreate();
38741 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38743 if (!cfg.name.length) {
38746 if(this.inputType){
38747 cfg.type = this.inputType;
38749 this.el = ct.createChild(cfg, position);
38751 var type = this.el.dom.type;
38753 if(type == 'password'){
38756 this.el.addClass('x-form-'+type);
38759 this.el.dom.readOnly = true;
38761 if(this.tabIndex !== undefined){
38762 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38765 this.el.addClass([this.fieldClass, this.cls]);
38770 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38771 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38772 * @return {Roo.form.Field} this
38774 applyTo : function(target){
38775 this.allowDomMove = false;
38776 this.el = Roo.get(target);
38777 this.render(this.el.dom.parentNode);
38782 initValue : function(){
38783 if(this.value !== undefined){
38784 this.setValue(this.value);
38785 }else if(this.el.dom.value.length > 0){
38786 this.setValue(this.el.dom.value);
38791 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38792 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38794 isDirty : function() {
38795 if(this.disabled) {
38798 return String(this.getValue()) !== String(this.originalValue);
38802 * stores the current value in loadedValue
38804 resetHasChanged : function()
38806 this.loadedValue = String(this.getValue());
38809 * checks the current value against the 'loaded' value.
38810 * Note - will return false if 'resetHasChanged' has not been called first.
38812 hasChanged : function()
38814 if(this.disabled || this.readOnly) {
38817 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38823 afterRender : function(){
38824 Roo.form.Field.superclass.afterRender.call(this);
38829 fireKey : function(e){
38830 //Roo.log('field ' + e.getKey());
38831 if(e.isNavKeyPress()){
38832 this.fireEvent("specialkey", this, e);
38837 * Resets the current field value to the originally loaded value and clears any validation messages
38839 reset : function(){
38840 this.setValue(this.resetValue);
38841 this.clearInvalid();
38845 initEvents : function(){
38846 // safari killled keypress - so keydown is now used..
38847 this.el.on("keydown" , this.fireKey, this);
38848 this.el.on("focus", this.onFocus, this);
38849 this.el.on("blur", this.onBlur, this);
38850 this.el.relayEvent('keyup', this);
38852 // reference to original value for reset
38853 this.originalValue = this.getValue();
38854 this.resetValue = this.getValue();
38858 onFocus : function(){
38859 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38860 this.el.addClass(this.focusClass);
38862 if(!this.hasFocus){
38863 this.hasFocus = true;
38864 this.startValue = this.getValue();
38865 this.fireEvent("focus", this);
38869 beforeBlur : Roo.emptyFn,
38872 onBlur : function(){
38874 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38875 this.el.removeClass(this.focusClass);
38877 this.hasFocus = false;
38878 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
38881 var v = this.getValue();
38882 if(String(v) !== String(this.startValue)){
38883 this.fireEvent('change', this, v, this.startValue);
38885 this.fireEvent("blur", this);
38889 * Returns whether or not the field value is currently valid
38890 * @param {Boolean} preventMark True to disable marking the field invalid
38891 * @return {Boolean} True if the value is valid, else false
38893 isValid : function(preventMark){
38897 var restore = this.preventMark;
38898 this.preventMark = preventMark === true;
38899 var v = this.validateValue(this.processValue(this.getRawValue()));
38900 this.preventMark = restore;
38905 * Validates the field value
38906 * @return {Boolean} True if the value is valid, else false
38908 validate : function(){
38909 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
38910 this.clearInvalid();
38916 processValue : function(value){
38921 // Subclasses should provide the validation implementation by overriding this
38922 validateValue : function(value){
38927 * Mark this field as invalid
38928 * @param {String} msg The validation message
38930 markInvalid : function(msg){
38931 if(!this.rendered || this.preventMark){ // not rendered
38935 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38937 obj.el.addClass(this.invalidClass);
38938 msg = msg || this.invalidText;
38939 switch(this.msgTarget){
38941 obj.el.dom.qtip = msg;
38942 obj.el.dom.qclass = 'x-form-invalid-tip';
38943 if(Roo.QuickTips){ // fix for floating editors interacting with DND
38944 Roo.QuickTips.enable();
38948 this.el.dom.title = msg;
38952 var elp = this.el.findParent('.x-form-element', 5, true);
38953 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
38954 this.errorEl.setWidth(elp.getWidth(true)-20);
38956 this.errorEl.update(msg);
38957 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
38960 if(!this.errorIcon){
38961 var elp = this.el.findParent('.x-form-element', 5, true);
38962 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
38964 this.alignErrorIcon();
38965 this.errorIcon.dom.qtip = msg;
38966 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
38967 this.errorIcon.show();
38968 this.on('resize', this.alignErrorIcon, this);
38971 var t = Roo.getDom(this.msgTarget);
38973 t.style.display = this.msgDisplay;
38976 this.fireEvent('invalid', this, msg);
38980 alignErrorIcon : function(){
38981 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
38985 * Clear any invalid styles/messages for this field
38987 clearInvalid : function(){
38988 if(!this.rendered || this.preventMark){ // not rendered
38991 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38993 obj.el.removeClass(this.invalidClass);
38994 switch(this.msgTarget){
38996 obj.el.dom.qtip = '';
38999 this.el.dom.title = '';
39003 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39007 if(this.errorIcon){
39008 this.errorIcon.dom.qtip = '';
39009 this.errorIcon.hide();
39010 this.un('resize', this.alignErrorIcon, this);
39014 var t = Roo.getDom(this.msgTarget);
39016 t.style.display = 'none';
39019 this.fireEvent('valid', this);
39023 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39024 * @return {Mixed} value The field value
39026 getRawValue : function(){
39027 var v = this.el.getValue();
39033 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39034 * @return {Mixed} value The field value
39036 getValue : function(){
39037 var v = this.el.getValue();
39043 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39044 * @param {Mixed} value The value to set
39046 setRawValue : function(v){
39047 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39051 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39052 * @param {Mixed} value The value to set
39054 setValue : function(v){
39057 this.el.dom.value = (v === null || v === undefined ? '' : v);
39062 adjustSize : function(w, h){
39063 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39064 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39068 adjustWidth : function(tag, w){
39069 tag = tag.toLowerCase();
39070 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39071 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39072 if(tag == 'input'){
39075 if(tag == 'textarea'){
39078 }else if(Roo.isOpera){
39079 if(tag == 'input'){
39082 if(tag == 'textarea'){
39092 // anything other than normal should be considered experimental
39093 Roo.form.Field.msgFx = {
39095 show: function(msgEl, f){
39096 msgEl.setDisplayed('block');
39099 hide : function(msgEl, f){
39100 msgEl.setDisplayed(false).update('');
39105 show: function(msgEl, f){
39106 msgEl.slideIn('t', {stopFx:true});
39109 hide : function(msgEl, f){
39110 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39115 show: function(msgEl, f){
39116 msgEl.fixDisplay();
39117 msgEl.alignTo(f.el, 'tl-tr');
39118 msgEl.slideIn('l', {stopFx:true});
39121 hide : function(msgEl, f){
39122 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39127 * Ext JS Library 1.1.1
39128 * Copyright(c) 2006-2007, Ext JS, LLC.
39130 * Originally Released Under LGPL - original licence link has changed is not relivant.
39133 * <script type="text/javascript">
39138 * @class Roo.form.TextField
39139 * @extends Roo.form.Field
39140 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39141 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39143 * Creates a new TextField
39144 * @param {Object} config Configuration options
39146 Roo.form.TextField = function(config){
39147 Roo.form.TextField.superclass.constructor.call(this, config);
39151 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39152 * according to the default logic, but this event provides a hook for the developer to apply additional
39153 * logic at runtime to resize the field if needed.
39154 * @param {Roo.form.Field} this This text field
39155 * @param {Number} width The new field width
39161 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39163 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39167 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39171 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39175 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39179 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39183 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39185 disableKeyFilter : false,
39187 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39191 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39195 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39197 maxLength : Number.MAX_VALUE,
39199 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39201 minLengthText : "The minimum length for this field is {0}",
39203 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39205 maxLengthText : "The maximum length for this field is {0}",
39207 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39209 selectOnFocus : false,
39211 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39213 blankText : "This field is required",
39215 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39216 * If available, this function will be called only after the basic validators all return true, and will be passed the
39217 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39221 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39222 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39223 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39227 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39231 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39237 initEvents : function()
39239 if (this.emptyText) {
39240 this.el.attr('placeholder', this.emptyText);
39243 Roo.form.TextField.superclass.initEvents.call(this);
39244 if(this.validationEvent == 'keyup'){
39245 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39246 this.el.on('keyup', this.filterValidation, this);
39248 else if(this.validationEvent !== false){
39249 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39252 if(this.selectOnFocus){
39253 this.on("focus", this.preFocus, this);
39256 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39257 this.el.on("keypress", this.filterKeys, this);
39260 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39261 this.el.on("click", this.autoSize, this);
39263 if(this.el.is('input[type=password]') && Roo.isSafari){
39264 this.el.on('keydown', this.SafariOnKeyDown, this);
39268 processValue : function(value){
39269 if(this.stripCharsRe){
39270 var newValue = value.replace(this.stripCharsRe, '');
39271 if(newValue !== value){
39272 this.setRawValue(newValue);
39279 filterValidation : function(e){
39280 if(!e.isNavKeyPress()){
39281 this.validationTask.delay(this.validationDelay);
39286 onKeyUp : function(e){
39287 if(!e.isNavKeyPress()){
39293 * Resets the current field value to the originally-loaded value and clears any validation messages.
39296 reset : function(){
39297 Roo.form.TextField.superclass.reset.call(this);
39303 preFocus : function(){
39305 if(this.selectOnFocus){
39306 this.el.dom.select();
39312 filterKeys : function(e){
39313 var k = e.getKey();
39314 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39317 var c = e.getCharCode(), cc = String.fromCharCode(c);
39318 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39321 if(!this.maskRe.test(cc)){
39326 setValue : function(v){
39328 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39334 * Validates a value according to the field's validation rules and marks the field as invalid
39335 * if the validation fails
39336 * @param {Mixed} value The value to validate
39337 * @return {Boolean} True if the value is valid, else false
39339 validateValue : function(value){
39340 if(value.length < 1) { // if it's blank
39341 if(this.allowBlank){
39342 this.clearInvalid();
39345 this.markInvalid(this.blankText);
39349 if(value.length < this.minLength){
39350 this.markInvalid(String.format(this.minLengthText, this.minLength));
39353 if(value.length > this.maxLength){
39354 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39358 var vt = Roo.form.VTypes;
39359 if(!vt[this.vtype](value, this)){
39360 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39364 if(typeof this.validator == "function"){
39365 var msg = this.validator(value);
39367 this.markInvalid(msg);
39371 if(this.regex && !this.regex.test(value)){
39372 this.markInvalid(this.regexText);
39379 * Selects text in this field
39380 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39381 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39383 selectText : function(start, end){
39384 var v = this.getRawValue();
39386 start = start === undefined ? 0 : start;
39387 end = end === undefined ? v.length : end;
39388 var d = this.el.dom;
39389 if(d.setSelectionRange){
39390 d.setSelectionRange(start, end);
39391 }else if(d.createTextRange){
39392 var range = d.createTextRange();
39393 range.moveStart("character", start);
39394 range.moveEnd("character", v.length-end);
39401 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39402 * This only takes effect if grow = true, and fires the autosize event.
39404 autoSize : function(){
39405 if(!this.grow || !this.rendered){
39409 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39412 var v = el.dom.value;
39413 var d = document.createElement('div');
39414 d.appendChild(document.createTextNode(v));
39418 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39419 this.el.setWidth(w);
39420 this.fireEvent("autosize", this, w);
39424 SafariOnKeyDown : function(event)
39426 // this is a workaround for a password hang bug on chrome/ webkit.
39428 var isSelectAll = false;
39430 if(this.el.dom.selectionEnd > 0){
39431 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39433 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39434 event.preventDefault();
39439 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39441 event.preventDefault();
39442 // this is very hacky as keydown always get's upper case.
39444 var cc = String.fromCharCode(event.getCharCode());
39447 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39455 * Ext JS Library 1.1.1
39456 * Copyright(c) 2006-2007, Ext JS, LLC.
39458 * Originally Released Under LGPL - original licence link has changed is not relivant.
39461 * <script type="text/javascript">
39465 * @class Roo.form.Hidden
39466 * @extends Roo.form.TextField
39467 * Simple Hidden element used on forms
39469 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39472 * Creates a new Hidden form element.
39473 * @param {Object} config Configuration options
39478 // easy hidden field...
39479 Roo.form.Hidden = function(config){
39480 Roo.form.Hidden.superclass.constructor.call(this, config);
39483 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39485 inputType: 'hidden',
39488 labelSeparator: '',
39490 itemCls : 'x-form-item-display-none'
39498 * Ext JS Library 1.1.1
39499 * Copyright(c) 2006-2007, Ext JS, LLC.
39501 * Originally Released Under LGPL - original licence link has changed is not relivant.
39504 * <script type="text/javascript">
39508 * @class Roo.form.TriggerField
39509 * @extends Roo.form.TextField
39510 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39511 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39512 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39513 * for which you can provide a custom implementation. For example:
39515 var trigger = new Roo.form.TriggerField();
39516 trigger.onTriggerClick = myTriggerFn;
39517 trigger.applyTo('my-field');
39520 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39521 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39522 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39523 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39525 * Create a new TriggerField.
39526 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39527 * to the base TextField)
39529 Roo.form.TriggerField = function(config){
39530 this.mimicing = false;
39531 Roo.form.TriggerField.superclass.constructor.call(this, config);
39534 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39536 * @cfg {String} triggerClass A CSS class to apply to the trigger
39539 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39540 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39542 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39544 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39548 /** @cfg {Boolean} grow @hide */
39549 /** @cfg {Number} growMin @hide */
39550 /** @cfg {Number} growMax @hide */
39556 autoSize: Roo.emptyFn,
39560 deferHeight : true,
39563 actionMode : 'wrap',
39565 onResize : function(w, h){
39566 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39567 if(typeof w == 'number'){
39568 var x = w - this.trigger.getWidth();
39569 this.el.setWidth(this.adjustWidth('input', x));
39570 this.trigger.setStyle('left', x+'px');
39575 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39578 getResizeEl : function(){
39583 getPositionEl : function(){
39588 alignErrorIcon : function(){
39589 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39593 onRender : function(ct, position){
39594 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39595 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39596 this.trigger = this.wrap.createChild(this.triggerConfig ||
39597 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39598 if(this.hideTrigger){
39599 this.trigger.setDisplayed(false);
39601 this.initTrigger();
39603 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39608 initTrigger : function(){
39609 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39610 this.trigger.addClassOnOver('x-form-trigger-over');
39611 this.trigger.addClassOnClick('x-form-trigger-click');
39615 onDestroy : function(){
39617 this.trigger.removeAllListeners();
39618 this.trigger.remove();
39621 this.wrap.remove();
39623 Roo.form.TriggerField.superclass.onDestroy.call(this);
39627 onFocus : function(){
39628 Roo.form.TriggerField.superclass.onFocus.call(this);
39629 if(!this.mimicing){
39630 this.wrap.addClass('x-trigger-wrap-focus');
39631 this.mimicing = true;
39632 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39633 if(this.monitorTab){
39634 this.el.on("keydown", this.checkTab, this);
39640 checkTab : function(e){
39641 if(e.getKey() == e.TAB){
39642 this.triggerBlur();
39647 onBlur : function(){
39652 mimicBlur : function(e, t){
39653 if(!this.wrap.contains(t) && this.validateBlur()){
39654 this.triggerBlur();
39659 triggerBlur : function(){
39660 this.mimicing = false;
39661 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39662 if(this.monitorTab){
39663 this.el.un("keydown", this.checkTab, this);
39665 this.wrap.removeClass('x-trigger-wrap-focus');
39666 Roo.form.TriggerField.superclass.onBlur.call(this);
39670 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39671 validateBlur : function(e, t){
39676 onDisable : function(){
39677 Roo.form.TriggerField.superclass.onDisable.call(this);
39679 this.wrap.addClass('x-item-disabled');
39684 onEnable : function(){
39685 Roo.form.TriggerField.superclass.onEnable.call(this);
39687 this.wrap.removeClass('x-item-disabled');
39692 onShow : function(){
39693 var ae = this.getActionEl();
39696 ae.dom.style.display = '';
39697 ae.dom.style.visibility = 'visible';
39703 onHide : function(){
39704 var ae = this.getActionEl();
39705 ae.dom.style.display = 'none';
39709 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39710 * by an implementing function.
39712 * @param {EventObject} e
39714 onTriggerClick : Roo.emptyFn
39717 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39718 // to be extended by an implementing class. For an example of implementing this class, see the custom
39719 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39720 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39721 initComponent : function(){
39722 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39724 this.triggerConfig = {
39725 tag:'span', cls:'x-form-twin-triggers', cn:[
39726 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39727 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39731 getTrigger : function(index){
39732 return this.triggers[index];
39735 initTrigger : function(){
39736 var ts = this.trigger.select('.x-form-trigger', true);
39737 this.wrap.setStyle('overflow', 'hidden');
39738 var triggerField = this;
39739 ts.each(function(t, all, index){
39740 t.hide = function(){
39741 var w = triggerField.wrap.getWidth();
39742 this.dom.style.display = 'none';
39743 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39745 t.show = function(){
39746 var w = triggerField.wrap.getWidth();
39747 this.dom.style.display = '';
39748 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39750 var triggerIndex = 'Trigger'+(index+1);
39752 if(this['hide'+triggerIndex]){
39753 t.dom.style.display = 'none';
39755 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39756 t.addClassOnOver('x-form-trigger-over');
39757 t.addClassOnClick('x-form-trigger-click');
39759 this.triggers = ts.elements;
39762 onTrigger1Click : Roo.emptyFn,
39763 onTrigger2Click : Roo.emptyFn
39766 * Ext JS Library 1.1.1
39767 * Copyright(c) 2006-2007, Ext JS, LLC.
39769 * Originally Released Under LGPL - original licence link has changed is not relivant.
39772 * <script type="text/javascript">
39776 * @class Roo.form.TextArea
39777 * @extends Roo.form.TextField
39778 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39779 * support for auto-sizing.
39781 * Creates a new TextArea
39782 * @param {Object} config Configuration options
39784 Roo.form.TextArea = function(config){
39785 Roo.form.TextArea.superclass.constructor.call(this, config);
39786 // these are provided exchanges for backwards compat
39787 // minHeight/maxHeight were replaced by growMin/growMax to be
39788 // compatible with TextField growing config values
39789 if(this.minHeight !== undefined){
39790 this.growMin = this.minHeight;
39792 if(this.maxHeight !== undefined){
39793 this.growMax = this.maxHeight;
39797 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39799 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39803 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39807 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39808 * in the field (equivalent to setting overflow: hidden, defaults to false)
39810 preventScrollbars: false,
39812 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39813 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39817 onRender : function(ct, position){
39819 this.defaultAutoCreate = {
39821 style:"width:300px;height:60px;",
39822 autocomplete: "new-password"
39825 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39827 this.textSizeEl = Roo.DomHelper.append(document.body, {
39828 tag: "pre", cls: "x-form-grow-sizer"
39830 if(this.preventScrollbars){
39831 this.el.setStyle("overflow", "hidden");
39833 this.el.setHeight(this.growMin);
39837 onDestroy : function(){
39838 if(this.textSizeEl){
39839 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39841 Roo.form.TextArea.superclass.onDestroy.call(this);
39845 onKeyUp : function(e){
39846 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39852 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39853 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39855 autoSize : function(){
39856 if(!this.grow || !this.textSizeEl){
39860 var v = el.dom.value;
39861 var ts = this.textSizeEl;
39864 ts.appendChild(document.createTextNode(v));
39867 Roo.fly(ts).setWidth(this.el.getWidth());
39869 v = "  ";
39872 v = v.replace(/\n/g, '<p> </p>');
39874 v += " \n ";
39877 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
39878 if(h != this.lastHeight){
39879 this.lastHeight = h;
39880 this.el.setHeight(h);
39881 this.fireEvent("autosize", this, h);
39886 * Ext JS Library 1.1.1
39887 * Copyright(c) 2006-2007, Ext JS, LLC.
39889 * Originally Released Under LGPL - original licence link has changed is not relivant.
39892 * <script type="text/javascript">
39897 * @class Roo.form.NumberField
39898 * @extends Roo.form.TextField
39899 * Numeric text field that provides automatic keystroke filtering and numeric validation.
39901 * Creates a new NumberField
39902 * @param {Object} config Configuration options
39904 Roo.form.NumberField = function(config){
39905 Roo.form.NumberField.superclass.constructor.call(this, config);
39908 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
39910 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
39912 fieldClass: "x-form-field x-form-num-field",
39914 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39916 allowDecimals : true,
39918 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39920 decimalSeparator : ".",
39922 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39924 decimalPrecision : 2,
39926 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39928 allowNegative : true,
39930 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39932 minValue : Number.NEGATIVE_INFINITY,
39934 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39936 maxValue : Number.MAX_VALUE,
39938 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39940 minText : "The minimum value for this field is {0}",
39942 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39944 maxText : "The maximum value for this field is {0}",
39946 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39947 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39949 nanText : "{0} is not a valid number",
39952 initEvents : function(){
39953 Roo.form.NumberField.superclass.initEvents.call(this);
39954 var allowed = "0123456789";
39955 if(this.allowDecimals){
39956 allowed += this.decimalSeparator;
39958 if(this.allowNegative){
39961 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
39962 var keyPress = function(e){
39963 var k = e.getKey();
39964 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39967 var c = e.getCharCode();
39968 if(allowed.indexOf(String.fromCharCode(c)) === -1){
39972 this.el.on("keypress", keyPress, this);
39976 validateValue : function(value){
39977 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
39980 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39983 var num = this.parseValue(value);
39985 this.markInvalid(String.format(this.nanText, value));
39988 if(num < this.minValue){
39989 this.markInvalid(String.format(this.minText, this.minValue));
39992 if(num > this.maxValue){
39993 this.markInvalid(String.format(this.maxText, this.maxValue));
39999 getValue : function(){
40000 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40004 parseValue : function(value){
40005 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40006 return isNaN(value) ? '' : value;
40010 fixPrecision : function(value){
40011 var nan = isNaN(value);
40012 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40013 return nan ? '' : value;
40015 return parseFloat(value).toFixed(this.decimalPrecision);
40018 setValue : function(v){
40019 v = this.fixPrecision(v);
40020 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40024 decimalPrecisionFcn : function(v){
40025 return Math.floor(v);
40028 beforeBlur : function(){
40029 var v = this.parseValue(this.getRawValue());
40036 * Ext JS Library 1.1.1
40037 * Copyright(c) 2006-2007, Ext JS, LLC.
40039 * Originally Released Under LGPL - original licence link has changed is not relivant.
40042 * <script type="text/javascript">
40046 * @class Roo.form.DateField
40047 * @extends Roo.form.TriggerField
40048 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40050 * Create a new DateField
40051 * @param {Object} config
40053 Roo.form.DateField = function(config){
40054 Roo.form.DateField.superclass.constructor.call(this, config);
40060 * Fires when a date is selected
40061 * @param {Roo.form.DateField} combo This combo box
40062 * @param {Date} date The date selected
40069 if(typeof this.minValue == "string") {
40070 this.minValue = this.parseDate(this.minValue);
40072 if(typeof this.maxValue == "string") {
40073 this.maxValue = this.parseDate(this.maxValue);
40075 this.ddMatch = null;
40076 if(this.disabledDates){
40077 var dd = this.disabledDates;
40079 for(var i = 0; i < dd.length; i++){
40081 if(i != dd.length-1) {
40085 this.ddMatch = new RegExp(re + ")");
40089 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40091 * @cfg {String} format
40092 * The default date format string which can be overriden for localization support. The format must be
40093 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40097 * @cfg {String} altFormats
40098 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40099 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40101 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40103 * @cfg {Array} disabledDays
40104 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40106 disabledDays : null,
40108 * @cfg {String} disabledDaysText
40109 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40111 disabledDaysText : "Disabled",
40113 * @cfg {Array} disabledDates
40114 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40115 * expression so they are very powerful. Some examples:
40117 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40118 * <li>["03/08", "09/16"] would disable those days for every year</li>
40119 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40120 * <li>["03/../2006"] would disable every day in March 2006</li>
40121 * <li>["^03"] would disable every day in every March</li>
40123 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40124 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40126 disabledDates : null,
40128 * @cfg {String} disabledDatesText
40129 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40131 disabledDatesText : "Disabled",
40133 * @cfg {Date/String} minValue
40134 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40135 * valid format (defaults to null).
40139 * @cfg {Date/String} maxValue
40140 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40141 * valid format (defaults to null).
40145 * @cfg {String} minText
40146 * The error text to display when the date in the cell is before minValue (defaults to
40147 * 'The date in this field must be after {minValue}').
40149 minText : "The date in this field must be equal to or after {0}",
40151 * @cfg {String} maxText
40152 * The error text to display when the date in the cell is after maxValue (defaults to
40153 * 'The date in this field must be before {maxValue}').
40155 maxText : "The date in this field must be equal to or before {0}",
40157 * @cfg {String} invalidText
40158 * The error text to display when the date in the field is invalid (defaults to
40159 * '{value} is not a valid date - it must be in the format {format}').
40161 invalidText : "{0} is not a valid date - it must be in the format {1}",
40163 * @cfg {String} triggerClass
40164 * An additional CSS class used to style the trigger button. The trigger will always get the
40165 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40166 * which displays a calendar icon).
40168 triggerClass : 'x-form-date-trigger',
40172 * @cfg {Boolean} useIso
40173 * if enabled, then the date field will use a hidden field to store the
40174 * real value as iso formated date. default (false)
40178 * @cfg {String/Object} autoCreate
40179 * A DomHelper element spec, or true for a default element spec (defaults to
40180 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40183 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40186 hiddenField: false,
40188 onRender : function(ct, position)
40190 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40192 //this.el.dom.removeAttribute('name');
40193 Roo.log("Changing name?");
40194 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40195 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40197 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40198 // prevent input submission
40199 this.hiddenName = this.name;
40206 validateValue : function(value)
40208 value = this.formatDate(value);
40209 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40210 Roo.log('super failed');
40213 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40216 var svalue = value;
40217 value = this.parseDate(value);
40219 Roo.log('parse date failed' + svalue);
40220 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40223 var time = value.getTime();
40224 if(this.minValue && time < this.minValue.getTime()){
40225 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40228 if(this.maxValue && time > this.maxValue.getTime()){
40229 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40232 if(this.disabledDays){
40233 var day = value.getDay();
40234 for(var i = 0; i < this.disabledDays.length; i++) {
40235 if(day === this.disabledDays[i]){
40236 this.markInvalid(this.disabledDaysText);
40241 var fvalue = this.formatDate(value);
40242 if(this.ddMatch && this.ddMatch.test(fvalue)){
40243 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40250 // Provides logic to override the default TriggerField.validateBlur which just returns true
40251 validateBlur : function(){
40252 return !this.menu || !this.menu.isVisible();
40255 getName: function()
40257 // returns hidden if it's set..
40258 if (!this.rendered) {return ''};
40259 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40264 * Returns the current date value of the date field.
40265 * @return {Date} The date value
40267 getValue : function(){
40269 return this.hiddenField ?
40270 this.hiddenField.value :
40271 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40275 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40276 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40277 * (the default format used is "m/d/y").
40280 //All of these calls set the same date value (May 4, 2006)
40282 //Pass a date object:
40283 var dt = new Date('5/4/06');
40284 dateField.setValue(dt);
40286 //Pass a date string (default format):
40287 dateField.setValue('5/4/06');
40289 //Pass a date string (custom format):
40290 dateField.format = 'Y-m-d';
40291 dateField.setValue('2006-5-4');
40293 * @param {String/Date} date The date or valid date string
40295 setValue : function(date){
40296 if (this.hiddenField) {
40297 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40299 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40300 // make sure the value field is always stored as a date..
40301 this.value = this.parseDate(date);
40307 parseDate : function(value){
40308 if(!value || value instanceof Date){
40311 var v = Date.parseDate(value, this.format);
40312 if (!v && this.useIso) {
40313 v = Date.parseDate(value, 'Y-m-d');
40315 if(!v && this.altFormats){
40316 if(!this.altFormatsArray){
40317 this.altFormatsArray = this.altFormats.split("|");
40319 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40320 v = Date.parseDate(value, this.altFormatsArray[i]);
40327 formatDate : function(date, fmt){
40328 return (!date || !(date instanceof Date)) ?
40329 date : date.dateFormat(fmt || this.format);
40334 select: function(m, d){
40337 this.fireEvent('select', this, d);
40339 show : function(){ // retain focus styling
40343 this.focus.defer(10, this);
40344 var ml = this.menuListeners;
40345 this.menu.un("select", ml.select, this);
40346 this.menu.un("show", ml.show, this);
40347 this.menu.un("hide", ml.hide, this);
40352 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40353 onTriggerClick : function(){
40357 if(this.menu == null){
40358 this.menu = new Roo.menu.DateMenu();
40360 Roo.apply(this.menu.picker, {
40361 showClear: this.allowBlank,
40362 minDate : this.minValue,
40363 maxDate : this.maxValue,
40364 disabledDatesRE : this.ddMatch,
40365 disabledDatesText : this.disabledDatesText,
40366 disabledDays : this.disabledDays,
40367 disabledDaysText : this.disabledDaysText,
40368 format : this.useIso ? 'Y-m-d' : this.format,
40369 minText : String.format(this.minText, this.formatDate(this.minValue)),
40370 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40372 this.menu.on(Roo.apply({}, this.menuListeners, {
40375 this.menu.picker.setValue(this.getValue() || new Date());
40376 this.menu.show(this.el, "tl-bl?");
40379 beforeBlur : function(){
40380 var v = this.parseDate(this.getRawValue());
40390 isDirty : function() {
40391 if(this.disabled) {
40395 if(typeof(this.startValue) === 'undefined'){
40399 return String(this.getValue()) !== String(this.startValue);
40404 * Ext JS Library 1.1.1
40405 * Copyright(c) 2006-2007, Ext JS, LLC.
40407 * Originally Released Under LGPL - original licence link has changed is not relivant.
40410 * <script type="text/javascript">
40414 * @class Roo.form.MonthField
40415 * @extends Roo.form.TriggerField
40416 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40418 * Create a new MonthField
40419 * @param {Object} config
40421 Roo.form.MonthField = function(config){
40423 Roo.form.MonthField.superclass.constructor.call(this, config);
40429 * Fires when a date is selected
40430 * @param {Roo.form.MonthFieeld} combo This combo box
40431 * @param {Date} date The date selected
40438 if(typeof this.minValue == "string") {
40439 this.minValue = this.parseDate(this.minValue);
40441 if(typeof this.maxValue == "string") {
40442 this.maxValue = this.parseDate(this.maxValue);
40444 this.ddMatch = null;
40445 if(this.disabledDates){
40446 var dd = this.disabledDates;
40448 for(var i = 0; i < dd.length; i++){
40450 if(i != dd.length-1) {
40454 this.ddMatch = new RegExp(re + ")");
40458 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40460 * @cfg {String} format
40461 * The default date format string which can be overriden for localization support. The format must be
40462 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40466 * @cfg {String} altFormats
40467 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40468 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40470 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40472 * @cfg {Array} disabledDays
40473 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40475 disabledDays : [0,1,2,3,4,5,6],
40477 * @cfg {String} disabledDaysText
40478 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40480 disabledDaysText : "Disabled",
40482 * @cfg {Array} disabledDates
40483 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40484 * expression so they are very powerful. Some examples:
40486 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40487 * <li>["03/08", "09/16"] would disable those days for every year</li>
40488 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40489 * <li>["03/../2006"] would disable every day in March 2006</li>
40490 * <li>["^03"] would disable every day in every March</li>
40492 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40493 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40495 disabledDates : null,
40497 * @cfg {String} disabledDatesText
40498 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40500 disabledDatesText : "Disabled",
40502 * @cfg {Date/String} minValue
40503 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40504 * valid format (defaults to null).
40508 * @cfg {Date/String} maxValue
40509 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40510 * valid format (defaults to null).
40514 * @cfg {String} minText
40515 * The error text to display when the date in the cell is before minValue (defaults to
40516 * 'The date in this field must be after {minValue}').
40518 minText : "The date in this field must be equal to or after {0}",
40520 * @cfg {String} maxTextf
40521 * The error text to display when the date in the cell is after maxValue (defaults to
40522 * 'The date in this field must be before {maxValue}').
40524 maxText : "The date in this field must be equal to or before {0}",
40526 * @cfg {String} invalidText
40527 * The error text to display when the date in the field is invalid (defaults to
40528 * '{value} is not a valid date - it must be in the format {format}').
40530 invalidText : "{0} is not a valid date - it must be in the format {1}",
40532 * @cfg {String} triggerClass
40533 * An additional CSS class used to style the trigger button. The trigger will always get the
40534 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40535 * which displays a calendar icon).
40537 triggerClass : 'x-form-date-trigger',
40541 * @cfg {Boolean} useIso
40542 * if enabled, then the date field will use a hidden field to store the
40543 * real value as iso formated date. default (true)
40547 * @cfg {String/Object} autoCreate
40548 * A DomHelper element spec, or true for a default element spec (defaults to
40549 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40552 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40555 hiddenField: false,
40557 hideMonthPicker : false,
40559 onRender : function(ct, position)
40561 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40563 this.el.dom.removeAttribute('name');
40564 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40566 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40567 // prevent input submission
40568 this.hiddenName = this.name;
40575 validateValue : function(value)
40577 value = this.formatDate(value);
40578 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40581 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40584 var svalue = value;
40585 value = this.parseDate(value);
40587 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40590 var time = value.getTime();
40591 if(this.minValue && time < this.minValue.getTime()){
40592 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40595 if(this.maxValue && time > this.maxValue.getTime()){
40596 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40599 /*if(this.disabledDays){
40600 var day = value.getDay();
40601 for(var i = 0; i < this.disabledDays.length; i++) {
40602 if(day === this.disabledDays[i]){
40603 this.markInvalid(this.disabledDaysText);
40609 var fvalue = this.formatDate(value);
40610 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40611 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40619 // Provides logic to override the default TriggerField.validateBlur which just returns true
40620 validateBlur : function(){
40621 return !this.menu || !this.menu.isVisible();
40625 * Returns the current date value of the date field.
40626 * @return {Date} The date value
40628 getValue : function(){
40632 return this.hiddenField ?
40633 this.hiddenField.value :
40634 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40638 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40639 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40640 * (the default format used is "m/d/y").
40643 //All of these calls set the same date value (May 4, 2006)
40645 //Pass a date object:
40646 var dt = new Date('5/4/06');
40647 monthField.setValue(dt);
40649 //Pass a date string (default format):
40650 monthField.setValue('5/4/06');
40652 //Pass a date string (custom format):
40653 monthField.format = 'Y-m-d';
40654 monthField.setValue('2006-5-4');
40656 * @param {String/Date} date The date or valid date string
40658 setValue : function(date){
40659 Roo.log('month setValue' + date);
40660 // can only be first of month..
40662 var val = this.parseDate(date);
40664 if (this.hiddenField) {
40665 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40667 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40668 this.value = this.parseDate(date);
40672 parseDate : function(value){
40673 if(!value || value instanceof Date){
40674 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40677 var v = Date.parseDate(value, this.format);
40678 if (!v && this.useIso) {
40679 v = Date.parseDate(value, 'Y-m-d');
40683 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40687 if(!v && this.altFormats){
40688 if(!this.altFormatsArray){
40689 this.altFormatsArray = this.altFormats.split("|");
40691 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40692 v = Date.parseDate(value, this.altFormatsArray[i]);
40699 formatDate : function(date, fmt){
40700 return (!date || !(date instanceof Date)) ?
40701 date : date.dateFormat(fmt || this.format);
40706 select: function(m, d){
40708 this.fireEvent('select', this, d);
40710 show : function(){ // retain focus styling
40714 this.focus.defer(10, this);
40715 var ml = this.menuListeners;
40716 this.menu.un("select", ml.select, this);
40717 this.menu.un("show", ml.show, this);
40718 this.menu.un("hide", ml.hide, this);
40722 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40723 onTriggerClick : function(){
40727 if(this.menu == null){
40728 this.menu = new Roo.menu.DateMenu();
40732 Roo.apply(this.menu.picker, {
40734 showClear: this.allowBlank,
40735 minDate : this.minValue,
40736 maxDate : this.maxValue,
40737 disabledDatesRE : this.ddMatch,
40738 disabledDatesText : this.disabledDatesText,
40740 format : this.useIso ? 'Y-m-d' : this.format,
40741 minText : String.format(this.minText, this.formatDate(this.minValue)),
40742 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40745 this.menu.on(Roo.apply({}, this.menuListeners, {
40753 // hide month picker get's called when we called by 'before hide';
40755 var ignorehide = true;
40756 p.hideMonthPicker = function(disableAnim){
40760 if(this.monthPicker){
40761 Roo.log("hideMonthPicker called");
40762 if(disableAnim === true){
40763 this.monthPicker.hide();
40765 this.monthPicker.slideOut('t', {duration:.2});
40766 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40767 p.fireEvent("select", this, this.value);
40773 Roo.log('picker set value');
40774 Roo.log(this.getValue());
40775 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40776 m.show(this.el, 'tl-bl?');
40777 ignorehide = false;
40778 // this will trigger hideMonthPicker..
40781 // hidden the day picker
40782 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40788 p.showMonthPicker.defer(100, p);
40794 beforeBlur : function(){
40795 var v = this.parseDate(this.getRawValue());
40801 /** @cfg {Boolean} grow @hide */
40802 /** @cfg {Number} growMin @hide */
40803 /** @cfg {Number} growMax @hide */
40810 * Ext JS Library 1.1.1
40811 * Copyright(c) 2006-2007, Ext JS, LLC.
40813 * Originally Released Under LGPL - original licence link has changed is not relivant.
40816 * <script type="text/javascript">
40821 * @class Roo.form.ComboBox
40822 * @extends Roo.form.TriggerField
40823 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40825 * Create a new ComboBox.
40826 * @param {Object} config Configuration options
40828 Roo.form.ComboBox = function(config){
40829 Roo.form.ComboBox.superclass.constructor.call(this, config);
40833 * Fires when the dropdown list is expanded
40834 * @param {Roo.form.ComboBox} combo This combo box
40839 * Fires when the dropdown list is collapsed
40840 * @param {Roo.form.ComboBox} combo This combo box
40844 * @event beforeselect
40845 * Fires before a list item is selected. Return false to cancel the selection.
40846 * @param {Roo.form.ComboBox} combo This combo box
40847 * @param {Roo.data.Record} record The data record returned from the underlying store
40848 * @param {Number} index The index of the selected item in the dropdown list
40850 'beforeselect' : true,
40853 * Fires when a list item is selected
40854 * @param {Roo.form.ComboBox} combo This combo box
40855 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
40856 * @param {Number} index The index of the selected item in the dropdown list
40860 * @event beforequery
40861 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
40862 * The event object passed has these properties:
40863 * @param {Roo.form.ComboBox} combo This combo box
40864 * @param {String} query The query
40865 * @param {Boolean} forceAll true to force "all" query
40866 * @param {Boolean} cancel true to cancel the query
40867 * @param {Object} e The query event object
40869 'beforequery': true,
40872 * Fires when the 'add' icon is pressed (add a listener to enable add button)
40873 * @param {Roo.form.ComboBox} combo This combo box
40878 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
40879 * @param {Roo.form.ComboBox} combo This combo box
40880 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
40886 if(this.transform){
40887 this.allowDomMove = false;
40888 var s = Roo.getDom(this.transform);
40889 if(!this.hiddenName){
40890 this.hiddenName = s.name;
40893 this.mode = 'local';
40894 var d = [], opts = s.options;
40895 for(var i = 0, len = opts.length;i < len; i++){
40897 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
40899 this.value = value;
40901 d.push([value, o.text]);
40903 this.store = new Roo.data.SimpleStore({
40905 fields: ['value', 'text'],
40908 this.valueField = 'value';
40909 this.displayField = 'text';
40911 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
40912 if(!this.lazyRender){
40913 this.target = true;
40914 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
40915 s.parentNode.removeChild(s); // remove it
40916 this.render(this.el.parentNode);
40918 s.parentNode.removeChild(s); // remove it
40923 this.store = Roo.factory(this.store, Roo.data);
40926 this.selectedIndex = -1;
40927 if(this.mode == 'local'){
40928 if(config.queryDelay === undefined){
40929 this.queryDelay = 10;
40931 if(config.minChars === undefined){
40937 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
40939 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
40942 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
40943 * rendering into an Roo.Editor, defaults to false)
40946 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
40947 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
40950 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
40953 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
40954 * the dropdown list (defaults to undefined, with no header element)
40958 * @cfg {String/Roo.Template} tpl The template to use to render the output
40962 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
40964 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
40966 listWidth: undefined,
40968 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
40969 * mode = 'remote' or 'text' if mode = 'local')
40971 displayField: undefined,
40973 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
40974 * mode = 'remote' or 'value' if mode = 'local').
40975 * Note: use of a valueField requires the user make a selection
40976 * in order for a value to be mapped.
40978 valueField: undefined,
40982 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
40983 * field's data value (defaults to the underlying DOM element's name)
40985 hiddenName: undefined,
40987 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
40991 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
40993 selectedClass: 'x-combo-selected',
40995 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40996 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
40997 * which displays a downward arrow icon).
40999 triggerClass : 'x-form-arrow-trigger',
41001 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41005 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41006 * anchor positions (defaults to 'tl-bl')
41008 listAlign: 'tl-bl?',
41010 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41014 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41015 * query specified by the allQuery config option (defaults to 'query')
41017 triggerAction: 'query',
41019 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41020 * (defaults to 4, does not apply if editable = false)
41024 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41025 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41029 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41030 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41034 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41035 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41039 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41040 * when editable = true (defaults to false)
41042 selectOnFocus:false,
41044 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41046 queryParam: 'query',
41048 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41049 * when mode = 'remote' (defaults to 'Loading...')
41051 loadingText: 'Loading...',
41053 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41057 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41061 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41062 * traditional select (defaults to true)
41066 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41070 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41074 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41075 * listWidth has a higher value)
41079 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41080 * allow the user to set arbitrary text into the field (defaults to false)
41082 forceSelection:false,
41084 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41085 * if typeAhead = true (defaults to 250)
41087 typeAheadDelay : 250,
41089 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41090 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41092 valueNotFoundText : undefined,
41094 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41096 blockFocus : false,
41099 * @cfg {Boolean} disableClear Disable showing of clear button.
41101 disableClear : false,
41103 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41105 alwaysQuery : false,
41111 // element that contains real text value.. (when hidden is used..)
41114 onRender : function(ct, position){
41115 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41116 if(this.hiddenName){
41117 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41119 this.hiddenField.value =
41120 this.hiddenValue !== undefined ? this.hiddenValue :
41121 this.value !== undefined ? this.value : '';
41123 // prevent input submission
41124 this.el.dom.removeAttribute('name');
41129 this.el.dom.setAttribute('autocomplete', 'off');
41132 var cls = 'x-combo-list';
41134 this.list = new Roo.Layer({
41135 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41138 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41139 this.list.setWidth(lw);
41140 this.list.swallowEvent('mousewheel');
41141 this.assetHeight = 0;
41144 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41145 this.assetHeight += this.header.getHeight();
41148 this.innerList = this.list.createChild({cls:cls+'-inner'});
41149 this.innerList.on('mouseover', this.onViewOver, this);
41150 this.innerList.on('mousemove', this.onViewMove, this);
41151 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41153 if(this.allowBlank && !this.pageSize && !this.disableClear){
41154 this.footer = this.list.createChild({cls:cls+'-ft'});
41155 this.pageTb = new Roo.Toolbar(this.footer);
41159 this.footer = this.list.createChild({cls:cls+'-ft'});
41160 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41161 {pageSize: this.pageSize});
41165 if (this.pageTb && this.allowBlank && !this.disableClear) {
41167 this.pageTb.add(new Roo.Toolbar.Fill(), {
41168 cls: 'x-btn-icon x-btn-clear',
41170 handler: function()
41173 _this.clearValue();
41174 _this.onSelect(false, -1);
41179 this.assetHeight += this.footer.getHeight();
41184 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41187 this.view = new Roo.View(this.innerList, this.tpl, {
41188 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41191 this.view.on('click', this.onViewClick, this);
41193 this.store.on('beforeload', this.onBeforeLoad, this);
41194 this.store.on('load', this.onLoad, this);
41195 this.store.on('loadexception', this.onLoadException, this);
41197 if(this.resizable){
41198 this.resizer = new Roo.Resizable(this.list, {
41199 pinned:true, handles:'se'
41201 this.resizer.on('resize', function(r, w, h){
41202 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41203 this.listWidth = w;
41204 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41205 this.restrictHeight();
41207 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41209 if(!this.editable){
41210 this.editable = true;
41211 this.setEditable(false);
41215 if (typeof(this.events.add.listeners) != 'undefined') {
41217 this.addicon = this.wrap.createChild(
41218 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41220 this.addicon.on('click', function(e) {
41221 this.fireEvent('add', this);
41224 if (typeof(this.events.edit.listeners) != 'undefined') {
41226 this.editicon = this.wrap.createChild(
41227 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41228 if (this.addicon) {
41229 this.editicon.setStyle('margin-left', '40px');
41231 this.editicon.on('click', function(e) {
41233 // we fire even if inothing is selected..
41234 this.fireEvent('edit', this, this.lastData );
41244 initEvents : function(){
41245 Roo.form.ComboBox.superclass.initEvents.call(this);
41247 this.keyNav = new Roo.KeyNav(this.el, {
41248 "up" : function(e){
41249 this.inKeyMode = true;
41253 "down" : function(e){
41254 if(!this.isExpanded()){
41255 this.onTriggerClick();
41257 this.inKeyMode = true;
41262 "enter" : function(e){
41263 this.onViewClick();
41267 "esc" : function(e){
41271 "tab" : function(e){
41272 this.onViewClick(false);
41273 this.fireEvent("specialkey", this, e);
41279 doRelay : function(foo, bar, hname){
41280 if(hname == 'down' || this.scope.isExpanded()){
41281 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41288 this.queryDelay = Math.max(this.queryDelay || 10,
41289 this.mode == 'local' ? 10 : 250);
41290 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41291 if(this.typeAhead){
41292 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41294 if(this.editable !== false){
41295 this.el.on("keyup", this.onKeyUp, this);
41297 if(this.forceSelection){
41298 this.on('blur', this.doForce, this);
41302 onDestroy : function(){
41304 this.view.setStore(null);
41305 this.view.el.removeAllListeners();
41306 this.view.el.remove();
41307 this.view.purgeListeners();
41310 this.list.destroy();
41313 this.store.un('beforeload', this.onBeforeLoad, this);
41314 this.store.un('load', this.onLoad, this);
41315 this.store.un('loadexception', this.onLoadException, this);
41317 Roo.form.ComboBox.superclass.onDestroy.call(this);
41321 fireKey : function(e){
41322 if(e.isNavKeyPress() && !this.list.isVisible()){
41323 this.fireEvent("specialkey", this, e);
41328 onResize: function(w, h){
41329 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41331 if(typeof w != 'number'){
41332 // we do not handle it!?!?
41335 var tw = this.trigger.getWidth();
41336 tw += this.addicon ? this.addicon.getWidth() : 0;
41337 tw += this.editicon ? this.editicon.getWidth() : 0;
41339 this.el.setWidth( this.adjustWidth('input', x));
41341 this.trigger.setStyle('left', x+'px');
41343 if(this.list && this.listWidth === undefined){
41344 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41345 this.list.setWidth(lw);
41346 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41354 * Allow or prevent the user from directly editing the field text. If false is passed,
41355 * the user will only be able to select from the items defined in the dropdown list. This method
41356 * is the runtime equivalent of setting the 'editable' config option at config time.
41357 * @param {Boolean} value True to allow the user to directly edit the field text
41359 setEditable : function(value){
41360 if(value == this.editable){
41363 this.editable = value;
41365 this.el.dom.setAttribute('readOnly', true);
41366 this.el.on('mousedown', this.onTriggerClick, this);
41367 this.el.addClass('x-combo-noedit');
41369 this.el.dom.setAttribute('readOnly', false);
41370 this.el.un('mousedown', this.onTriggerClick, this);
41371 this.el.removeClass('x-combo-noedit');
41376 onBeforeLoad : function(){
41377 if(!this.hasFocus){
41380 this.innerList.update(this.loadingText ?
41381 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41382 this.restrictHeight();
41383 this.selectedIndex = -1;
41387 onLoad : function(){
41388 if(!this.hasFocus){
41391 if(this.store.getCount() > 0){
41393 this.restrictHeight();
41394 if(this.lastQuery == this.allQuery){
41396 this.el.dom.select();
41398 if(!this.selectByValue(this.value, true)){
41399 this.select(0, true);
41403 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41404 this.taTask.delay(this.typeAheadDelay);
41408 this.onEmptyResults();
41413 onLoadException : function()
41416 Roo.log(this.store.reader.jsonData);
41417 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41418 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41424 onTypeAhead : function(){
41425 if(this.store.getCount() > 0){
41426 var r = this.store.getAt(0);
41427 var newValue = r.data[this.displayField];
41428 var len = newValue.length;
41429 var selStart = this.getRawValue().length;
41430 if(selStart != len){
41431 this.setRawValue(newValue);
41432 this.selectText(selStart, newValue.length);
41438 onSelect : function(record, index){
41439 if(this.fireEvent('beforeselect', this, record, index) !== false){
41440 this.setFromData(index > -1 ? record.data : false);
41442 this.fireEvent('select', this, record, index);
41447 * Returns the currently selected field value or empty string if no value is set.
41448 * @return {String} value The selected value
41450 getValue : function(){
41451 if(this.valueField){
41452 return typeof this.value != 'undefined' ? this.value : '';
41454 return Roo.form.ComboBox.superclass.getValue.call(this);
41458 * Clears any text/value currently set in the field
41460 clearValue : function(){
41461 if(this.hiddenField){
41462 this.hiddenField.value = '';
41465 this.setRawValue('');
41466 this.lastSelectionText = '';
41471 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41472 * will be displayed in the field. If the value does not match the data value of an existing item,
41473 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41474 * Otherwise the field will be blank (although the value will still be set).
41475 * @param {String} value The value to match
41477 setValue : function(v){
41479 if(this.valueField){
41480 var r = this.findRecord(this.valueField, v);
41482 text = r.data[this.displayField];
41483 }else if(this.valueNotFoundText !== undefined){
41484 text = this.valueNotFoundText;
41487 this.lastSelectionText = text;
41488 if(this.hiddenField){
41489 this.hiddenField.value = v;
41491 Roo.form.ComboBox.superclass.setValue.call(this, text);
41495 * @property {Object} the last set data for the element
41500 * Sets the value of the field based on a object which is related to the record format for the store.
41501 * @param {Object} value the value to set as. or false on reset?
41503 setFromData : function(o){
41504 var dv = ''; // display value
41505 var vv = ''; // value value..
41507 if (this.displayField) {
41508 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41510 // this is an error condition!!!
41511 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41514 if(this.valueField){
41515 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41517 if(this.hiddenField){
41518 this.hiddenField.value = vv;
41520 this.lastSelectionText = dv;
41521 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41525 // no hidden field.. - we store the value in 'value', but still display
41526 // display field!!!!
41527 this.lastSelectionText = dv;
41528 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41534 reset : function(){
41535 // overridden so that last data is reset..
41536 this.setValue(this.resetValue);
41537 this.clearInvalid();
41538 this.lastData = false;
41540 this.view.clearSelections();
41544 findRecord : function(prop, value){
41546 if(this.store.getCount() > 0){
41547 this.store.each(function(r){
41548 if(r.data[prop] == value){
41558 getName: function()
41560 // returns hidden if it's set..
41561 if (!this.rendered) {return ''};
41562 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41566 onViewMove : function(e, t){
41567 this.inKeyMode = false;
41571 onViewOver : function(e, t){
41572 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41575 var item = this.view.findItemFromChild(t);
41577 var index = this.view.indexOf(item);
41578 this.select(index, false);
41583 onViewClick : function(doFocus)
41585 var index = this.view.getSelectedIndexes()[0];
41586 var r = this.store.getAt(index);
41588 this.onSelect(r, index);
41590 if(doFocus !== false && !this.blockFocus){
41596 restrictHeight : function(){
41597 this.innerList.dom.style.height = '';
41598 var inner = this.innerList.dom;
41599 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41600 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41601 this.list.beginUpdate();
41602 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41603 this.list.alignTo(this.el, this.listAlign);
41604 this.list.endUpdate();
41608 onEmptyResults : function(){
41613 * Returns true if the dropdown list is expanded, else false.
41615 isExpanded : function(){
41616 return this.list.isVisible();
41620 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41621 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41622 * @param {String} value The data value of the item to select
41623 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41624 * selected item if it is not currently in view (defaults to true)
41625 * @return {Boolean} True if the value matched an item in the list, else false
41627 selectByValue : function(v, scrollIntoView){
41628 if(v !== undefined && v !== null){
41629 var r = this.findRecord(this.valueField || this.displayField, v);
41631 this.select(this.store.indexOf(r), scrollIntoView);
41639 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41640 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41641 * @param {Number} index The zero-based index of the list item to select
41642 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41643 * selected item if it is not currently in view (defaults to true)
41645 select : function(index, scrollIntoView){
41646 this.selectedIndex = index;
41647 this.view.select(index);
41648 if(scrollIntoView !== false){
41649 var el = this.view.getNode(index);
41651 this.innerList.scrollChildIntoView(el, false);
41657 selectNext : function(){
41658 var ct = this.store.getCount();
41660 if(this.selectedIndex == -1){
41662 }else if(this.selectedIndex < ct-1){
41663 this.select(this.selectedIndex+1);
41669 selectPrev : function(){
41670 var ct = this.store.getCount();
41672 if(this.selectedIndex == -1){
41674 }else if(this.selectedIndex != 0){
41675 this.select(this.selectedIndex-1);
41681 onKeyUp : function(e){
41682 if(this.editable !== false && !e.isSpecialKey()){
41683 this.lastKey = e.getKey();
41684 this.dqTask.delay(this.queryDelay);
41689 validateBlur : function(){
41690 return !this.list || !this.list.isVisible();
41694 initQuery : function(){
41695 this.doQuery(this.getRawValue());
41699 doForce : function(){
41700 if(this.el.dom.value.length > 0){
41701 this.el.dom.value =
41702 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41708 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41709 * query allowing the query action to be canceled if needed.
41710 * @param {String} query The SQL query to execute
41711 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41712 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41713 * saved in the current store (defaults to false)
41715 doQuery : function(q, forceAll){
41716 if(q === undefined || q === null){
41721 forceAll: forceAll,
41725 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41729 forceAll = qe.forceAll;
41730 if(forceAll === true || (q.length >= this.minChars)){
41731 if(this.lastQuery != q || this.alwaysQuery){
41732 this.lastQuery = q;
41733 if(this.mode == 'local'){
41734 this.selectedIndex = -1;
41736 this.store.clearFilter();
41738 this.store.filter(this.displayField, q);
41742 this.store.baseParams[this.queryParam] = q;
41744 params: this.getParams(q)
41749 this.selectedIndex = -1;
41756 getParams : function(q){
41758 //p[this.queryParam] = q;
41761 p.limit = this.pageSize;
41767 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41769 collapse : function(){
41770 if(!this.isExpanded()){
41774 Roo.get(document).un('mousedown', this.collapseIf, this);
41775 Roo.get(document).un('mousewheel', this.collapseIf, this);
41776 if (!this.editable) {
41777 Roo.get(document).un('keydown', this.listKeyPress, this);
41779 this.fireEvent('collapse', this);
41783 collapseIf : function(e){
41784 if(!e.within(this.wrap) && !e.within(this.list)){
41790 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41792 expand : function(){
41793 if(this.isExpanded() || !this.hasFocus){
41796 this.list.alignTo(this.el, this.listAlign);
41798 Roo.get(document).on('mousedown', this.collapseIf, this);
41799 Roo.get(document).on('mousewheel', this.collapseIf, this);
41800 if (!this.editable) {
41801 Roo.get(document).on('keydown', this.listKeyPress, this);
41804 this.fireEvent('expand', this);
41808 // Implements the default empty TriggerField.onTriggerClick function
41809 onTriggerClick : function(){
41813 if(this.isExpanded()){
41815 if (!this.blockFocus) {
41820 this.hasFocus = true;
41821 if(this.triggerAction == 'all') {
41822 this.doQuery(this.allQuery, true);
41824 this.doQuery(this.getRawValue());
41826 if (!this.blockFocus) {
41831 listKeyPress : function(e)
41833 //Roo.log('listkeypress');
41834 // scroll to first matching element based on key pres..
41835 if (e.isSpecialKey()) {
41838 var k = String.fromCharCode(e.getKey()).toUpperCase();
41841 var csel = this.view.getSelectedNodes();
41842 var cselitem = false;
41844 var ix = this.view.indexOf(csel[0]);
41845 cselitem = this.store.getAt(ix);
41846 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41852 this.store.each(function(v) {
41854 // start at existing selection.
41855 if (cselitem.id == v.id) {
41861 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
41862 match = this.store.indexOf(v);
41867 if (match === false) {
41868 return true; // no more action?
41871 this.view.select(match);
41872 var sn = Roo.get(this.view.getSelectedNodes()[0]);
41873 sn.scrollIntoView(sn.dom.parentNode, false);
41877 * @cfg {Boolean} grow
41881 * @cfg {Number} growMin
41885 * @cfg {Number} growMax
41893 * Copyright(c) 2010-2012, Roo J Solutions Limited
41900 * @class Roo.form.ComboBoxArray
41901 * @extends Roo.form.TextField
41902 * A facebook style adder... for lists of email / people / countries etc...
41903 * pick multiple items from a combo box, and shows each one.
41905 * Fred [x] Brian [x] [Pick another |v]
41908 * For this to work: it needs various extra information
41909 * - normal combo problay has
41911 * + displayField, valueField
41913 * For our purpose...
41916 * If we change from 'extends' to wrapping...
41923 * Create a new ComboBoxArray.
41924 * @param {Object} config Configuration options
41928 Roo.form.ComboBoxArray = function(config)
41932 * @event beforeremove
41933 * Fires before remove the value from the list
41934 * @param {Roo.form.ComboBoxArray} _self This combo box array
41935 * @param {Roo.form.ComboBoxArray.Item} item removed item
41937 'beforeremove' : true,
41940 * Fires when remove the value from the list
41941 * @param {Roo.form.ComboBoxArray} _self This combo box array
41942 * @param {Roo.form.ComboBoxArray.Item} item removed item
41949 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
41951 this.items = new Roo.util.MixedCollection(false);
41953 // construct the child combo...
41963 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
41966 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
41971 // behavies liek a hiddne field
41972 inputType: 'hidden',
41974 * @cfg {Number} width The width of the box that displays the selected element
41981 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
41985 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
41987 hiddenName : false,
41990 // private the array of items that are displayed..
41992 // private - the hidden field el.
41994 // private - the filed el..
41997 //validateValue : function() { return true; }, // all values are ok!
41998 //onAddClick: function() { },
42000 onRender : function(ct, position)
42003 // create the standard hidden element
42004 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42007 // give fake names to child combo;
42008 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42009 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
42011 this.combo = Roo.factory(this.combo, Roo.form);
42012 this.combo.onRender(ct, position);
42013 if (typeof(this.combo.width) != 'undefined') {
42014 this.combo.onResize(this.combo.width,0);
42017 this.combo.initEvents();
42019 // assigned so form know we need to do this..
42020 this.store = this.combo.store;
42021 this.valueField = this.combo.valueField;
42022 this.displayField = this.combo.displayField ;
42025 this.combo.wrap.addClass('x-cbarray-grp');
42027 var cbwrap = this.combo.wrap.createChild(
42028 {tag: 'div', cls: 'x-cbarray-cb'},
42033 this.hiddenEl = this.combo.wrap.createChild({
42034 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42036 this.el = this.combo.wrap.createChild({
42037 tag: 'input', type:'hidden' , name: this.name, value : ''
42039 // this.el.dom.removeAttribute("name");
42042 this.outerWrap = this.combo.wrap;
42043 this.wrap = cbwrap;
42045 this.outerWrap.setWidth(this.width);
42046 this.outerWrap.dom.removeChild(this.el.dom);
42048 this.wrap.dom.appendChild(this.el.dom);
42049 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42050 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42052 this.combo.trigger.setStyle('position','relative');
42053 this.combo.trigger.setStyle('left', '0px');
42054 this.combo.trigger.setStyle('top', '2px');
42056 this.combo.el.setStyle('vertical-align', 'text-bottom');
42058 //this.trigger.setStyle('vertical-align', 'top');
42060 // this should use the code from combo really... on('add' ....)
42064 this.adder = this.outerWrap.createChild(
42065 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42067 this.adder.on('click', function(e) {
42068 _t.fireEvent('adderclick', this, e);
42072 //this.adder.on('click', this.onAddClick, _t);
42075 this.combo.on('select', function(cb, rec, ix) {
42076 this.addItem(rec.data);
42079 cb.el.dom.value = '';
42080 //cb.lastData = rec.data;
42089 getName: function()
42091 // returns hidden if it's set..
42092 if (!this.rendered) {return ''};
42093 return this.hiddenName ? this.hiddenName : this.name;
42098 onResize: function(w, h){
42101 // not sure if this is needed..
42102 //this.combo.onResize(w,h);
42104 if(typeof w != 'number'){
42105 // we do not handle it!?!?
42108 var tw = this.combo.trigger.getWidth();
42109 tw += this.addicon ? this.addicon.getWidth() : 0;
42110 tw += this.editicon ? this.editicon.getWidth() : 0;
42112 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42114 this.combo.trigger.setStyle('left', '0px');
42116 if(this.list && this.listWidth === undefined){
42117 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42118 this.list.setWidth(lw);
42119 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42126 addItem: function(rec)
42128 var valueField = this.combo.valueField;
42129 var displayField = this.combo.displayField;
42130 if (this.items.indexOfKey(rec[valueField]) > -1) {
42131 //console.log("GOT " + rec.data.id);
42135 var x = new Roo.form.ComboBoxArray.Item({
42136 //id : rec[this.idField],
42138 displayField : displayField ,
42139 tipField : displayField ,
42143 this.items.add(rec[valueField],x);
42144 // add it before the element..
42145 this.updateHiddenEl();
42146 x.render(this.outerWrap, this.wrap.dom);
42147 // add the image handler..
42150 updateHiddenEl : function()
42153 if (!this.hiddenEl) {
42157 var idField = this.combo.valueField;
42159 this.items.each(function(f) {
42160 ar.push(f.data[idField]);
42163 this.hiddenEl.dom.value = ar.join(',');
42169 this.items.clear();
42171 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42175 this.el.dom.value = '';
42176 if (this.hiddenEl) {
42177 this.hiddenEl.dom.value = '';
42181 getValue: function()
42183 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42185 setValue: function(v) // not a valid action - must use addItems..
42192 if (this.store.isLocal && (typeof(v) == 'string')) {
42193 // then we can use the store to find the values..
42194 // comma seperated at present.. this needs to allow JSON based encoding..
42195 this.hiddenEl.value = v;
42197 Roo.each(v.split(','), function(k) {
42198 Roo.log("CHECK " + this.valueField + ',' + k);
42199 var li = this.store.query(this.valueField, k);
42204 add[this.valueField] = k;
42205 add[this.displayField] = li.item(0).data[this.displayField];
42211 if (typeof(v) == 'object' ) {
42212 // then let's assume it's an array of objects..
42213 Roo.each(v, function(l) {
42221 setFromData: function(v)
42223 // this recieves an object, if setValues is called.
42225 this.el.dom.value = v[this.displayField];
42226 this.hiddenEl.dom.value = v[this.valueField];
42227 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42230 var kv = v[this.valueField];
42231 var dv = v[this.displayField];
42232 kv = typeof(kv) != 'string' ? '' : kv;
42233 dv = typeof(dv) != 'string' ? '' : dv;
42236 var keys = kv.split(',');
42237 var display = dv.split(',');
42238 for (var i = 0 ; i < keys.length; i++) {
42241 add[this.valueField] = keys[i];
42242 add[this.displayField] = display[i];
42250 * Validates the combox array value
42251 * @return {Boolean} True if the value is valid, else false
42253 validate : function(){
42254 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42255 this.clearInvalid();
42261 validateValue : function(value){
42262 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42270 isDirty : function() {
42271 if(this.disabled) {
42276 var d = Roo.decode(String(this.originalValue));
42278 return String(this.getValue()) !== String(this.originalValue);
42281 var originalValue = [];
42283 for (var i = 0; i < d.length; i++){
42284 originalValue.push(d[i][this.valueField]);
42287 return String(this.getValue()) !== String(originalValue.join(','));
42296 * @class Roo.form.ComboBoxArray.Item
42297 * @extends Roo.BoxComponent
42298 * A selected item in the list
42299 * Fred [x] Brian [x] [Pick another |v]
42302 * Create a new item.
42303 * @param {Object} config Configuration options
42306 Roo.form.ComboBoxArray.Item = function(config) {
42307 config.id = Roo.id();
42308 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42311 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42314 displayField : false,
42318 defaultAutoCreate : {
42320 cls: 'x-cbarray-item',
42327 src : Roo.BLANK_IMAGE_URL ,
42335 onRender : function(ct, position)
42337 Roo.form.Field.superclass.onRender.call(this, ct, position);
42340 var cfg = this.getAutoCreate();
42341 this.el = ct.createChild(cfg, position);
42344 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42346 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42347 this.cb.renderer(this.data) :
42348 String.format('{0}',this.data[this.displayField]);
42351 this.el.child('div').dom.setAttribute('qtip',
42352 String.format('{0}',this.data[this.tipField])
42355 this.el.child('img').on('click', this.remove, this);
42359 remove : function()
42361 if(this.cb.disabled){
42365 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42366 this.cb.items.remove(this);
42367 this.el.child('img').un('click', this.remove, this);
42369 this.cb.updateHiddenEl();
42371 this.cb.fireEvent('remove', this.cb, this);
42377 * Ext JS Library 1.1.1
42378 * Copyright(c) 2006-2007, Ext JS, LLC.
42380 * Originally Released Under LGPL - original licence link has changed is not relivant.
42383 * <script type="text/javascript">
42386 * @class Roo.form.Checkbox
42387 * @extends Roo.form.Field
42388 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42390 * Creates a new Checkbox
42391 * @param {Object} config Configuration options
42393 Roo.form.Checkbox = function(config){
42394 Roo.form.Checkbox.superclass.constructor.call(this, config);
42398 * Fires when the checkbox is checked or unchecked.
42399 * @param {Roo.form.Checkbox} this This checkbox
42400 * @param {Boolean} checked The new checked value
42406 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42408 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42410 focusClass : undefined,
42412 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42414 fieldClass: "x-form-field",
42416 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42420 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42421 * {tag: "input", type: "checkbox", autocomplete: "off"})
42423 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42425 * @cfg {String} boxLabel The text that appears beside the checkbox
42429 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42433 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42435 valueOff: '0', // value when not checked..
42437 actionMode : 'viewEl',
42440 itemCls : 'x-menu-check-item x-form-item',
42441 groupClass : 'x-menu-group-item',
42442 inputType : 'hidden',
42445 inSetChecked: false, // check that we are not calling self...
42447 inputElement: false, // real input element?
42448 basedOn: false, // ????
42450 isFormField: true, // not sure where this is needed!!!!
42452 onResize : function(){
42453 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42454 if(!this.boxLabel){
42455 this.el.alignTo(this.wrap, 'c-c');
42459 initEvents : function(){
42460 Roo.form.Checkbox.superclass.initEvents.call(this);
42461 this.el.on("click", this.onClick, this);
42462 this.el.on("change", this.onClick, this);
42466 getResizeEl : function(){
42470 getPositionEl : function(){
42475 onRender : function(ct, position){
42476 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42478 if(this.inputValue !== undefined){
42479 this.el.dom.value = this.inputValue;
42482 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42483 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42484 var viewEl = this.wrap.createChild({
42485 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42486 this.viewEl = viewEl;
42487 this.wrap.on('click', this.onClick, this);
42489 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42490 this.el.on('propertychange', this.setFromHidden, this); //ie
42495 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42496 // viewEl.on('click', this.onClick, this);
42498 //if(this.checked){
42499 this.setChecked(this.checked);
42501 //this.checked = this.el.dom;
42507 initValue : Roo.emptyFn,
42510 * Returns the checked state of the checkbox.
42511 * @return {Boolean} True if checked, else false
42513 getValue : function(){
42515 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42517 return this.valueOff;
42522 onClick : function(){
42523 if (this.disabled) {
42526 this.setChecked(!this.checked);
42528 //if(this.el.dom.checked != this.checked){
42529 // this.setValue(this.el.dom.checked);
42534 * Sets the checked state of the checkbox.
42535 * On is always based on a string comparison between inputValue and the param.
42536 * @param {Boolean/String} value - the value to set
42537 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42539 setValue : function(v,suppressEvent){
42542 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42543 //if(this.el && this.el.dom){
42544 // this.el.dom.checked = this.checked;
42545 // this.el.dom.defaultChecked = this.checked;
42547 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42548 //this.fireEvent("check", this, this.checked);
42551 setChecked : function(state,suppressEvent)
42553 if (this.inSetChecked) {
42554 this.checked = state;
42560 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42562 this.checked = state;
42563 if(suppressEvent !== true){
42564 this.fireEvent('check', this, state);
42566 this.inSetChecked = true;
42567 this.el.dom.value = state ? this.inputValue : this.valueOff;
42568 this.inSetChecked = false;
42571 // handle setting of hidden value by some other method!!?!?
42572 setFromHidden: function()
42577 //console.log("SET FROM HIDDEN");
42578 //alert('setFrom hidden');
42579 this.setValue(this.el.dom.value);
42582 onDestroy : function()
42585 Roo.get(this.viewEl).remove();
42588 Roo.form.Checkbox.superclass.onDestroy.call(this);
42591 setBoxLabel : function(str)
42593 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42598 * Ext JS Library 1.1.1
42599 * Copyright(c) 2006-2007, Ext JS, LLC.
42601 * Originally Released Under LGPL - original licence link has changed is not relivant.
42604 * <script type="text/javascript">
42608 * @class Roo.form.Radio
42609 * @extends Roo.form.Checkbox
42610 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42611 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42613 * Creates a new Radio
42614 * @param {Object} config Configuration options
42616 Roo.form.Radio = function(){
42617 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42619 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42620 inputType: 'radio',
42623 * If this radio is part of a group, it will return the selected value
42626 getGroupValue : function(){
42627 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42631 onRender : function(ct, position){
42632 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42634 if(this.inputValue !== undefined){
42635 this.el.dom.value = this.inputValue;
42638 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42639 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42640 //var viewEl = this.wrap.createChild({
42641 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42642 //this.viewEl = viewEl;
42643 //this.wrap.on('click', this.onClick, this);
42645 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42646 //this.el.on('propertychange', this.setFromHidden, this); //ie
42651 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42652 // viewEl.on('click', this.onClick, this);
42655 this.el.dom.checked = 'checked' ;
42661 });//<script type="text/javascript">
42664 * Based Ext JS Library 1.1.1
42665 * Copyright(c) 2006-2007, Ext JS, LLC.
42671 * @class Roo.HtmlEditorCore
42672 * @extends Roo.Component
42673 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42675 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42678 Roo.HtmlEditorCore = function(config){
42681 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42686 * @event initialize
42687 * Fires when the editor is fully initialized (including the iframe)
42688 * @param {Roo.HtmlEditorCore} this
42693 * Fires when the editor is first receives the focus. Any insertion must wait
42694 * until after this event.
42695 * @param {Roo.HtmlEditorCore} this
42699 * @event beforesync
42700 * Fires before the textarea is updated with content from the editor iframe. Return false
42701 * to cancel the sync.
42702 * @param {Roo.HtmlEditorCore} this
42703 * @param {String} html
42707 * @event beforepush
42708 * Fires before the iframe editor is updated with content from the textarea. Return false
42709 * to cancel the push.
42710 * @param {Roo.HtmlEditorCore} this
42711 * @param {String} html
42716 * Fires when the textarea is updated with content from the editor iframe.
42717 * @param {Roo.HtmlEditorCore} this
42718 * @param {String} html
42723 * Fires when the iframe editor is updated with content from the textarea.
42724 * @param {Roo.HtmlEditorCore} this
42725 * @param {String} html
42730 * @event editorevent
42731 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42732 * @param {Roo.HtmlEditorCore} this
42738 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42740 // defaults : white / black...
42741 this.applyBlacklists();
42748 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42752 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42758 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42763 * @cfg {Number} height (in pixels)
42767 * @cfg {Number} width (in pixels)
42772 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42775 stylesheets: false,
42780 // private properties
42781 validationEvent : false,
42783 initialized : false,
42785 sourceEditMode : false,
42786 onFocus : Roo.emptyFn,
42788 hideMode:'offsets',
42792 // blacklist + whitelisted elements..
42799 * Protected method that will not generally be called directly. It
42800 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42801 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42803 getDocMarkup : function(){
42807 // inherit styels from page...??
42808 if (this.stylesheets === false) {
42810 Roo.get(document.head).select('style').each(function(node) {
42811 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42814 Roo.get(document.head).select('link').each(function(node) {
42815 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42818 } else if (!this.stylesheets.length) {
42820 st = '<style type="text/css">' +
42821 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42827 st += '<style type="text/css">' +
42828 'IMG { cursor: pointer } ' +
42832 return '<html><head>' + st +
42833 //<style type="text/css">' +
42834 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42836 ' </head><body class="roo-htmleditor-body"></body></html>';
42840 onRender : function(ct, position)
42843 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42844 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42847 this.el.dom.style.border = '0 none';
42848 this.el.dom.setAttribute('tabIndex', -1);
42849 this.el.addClass('x-hidden hide');
42853 if(Roo.isIE){ // fix IE 1px bogus margin
42854 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42858 this.frameId = Roo.id();
42862 var iframe = this.owner.wrap.createChild({
42864 cls: 'form-control', // bootstrap..
42866 name: this.frameId,
42867 frameBorder : 'no',
42868 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42873 this.iframe = iframe.dom;
42875 this.assignDocWin();
42877 this.doc.designMode = 'on';
42880 this.doc.write(this.getDocMarkup());
42884 var task = { // must defer to wait for browser to be ready
42886 //console.log("run task?" + this.doc.readyState);
42887 this.assignDocWin();
42888 if(this.doc.body || this.doc.readyState == 'complete'){
42890 this.doc.designMode="on";
42894 Roo.TaskMgr.stop(task);
42895 this.initEditor.defer(10, this);
42902 Roo.TaskMgr.start(task);
42907 onResize : function(w, h)
42909 Roo.log('resize: ' +w + ',' + h );
42910 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
42914 if(typeof w == 'number'){
42916 this.iframe.style.width = w + 'px';
42918 if(typeof h == 'number'){
42920 this.iframe.style.height = h + 'px';
42922 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
42929 * Toggles the editor between standard and source edit mode.
42930 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42932 toggleSourceEdit : function(sourceEditMode){
42934 this.sourceEditMode = sourceEditMode === true;
42936 if(this.sourceEditMode){
42938 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
42941 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
42942 //this.iframe.className = '';
42945 //this.setSize(this.owner.wrap.getSize());
42946 //this.fireEvent('editmodechange', this, this.sourceEditMode);
42953 * Protected method that will not generally be called directly. If you need/want
42954 * custom HTML cleanup, this is the method you should override.
42955 * @param {String} html The HTML to be cleaned
42956 * return {String} The cleaned HTML
42958 cleanHtml : function(html){
42959 html = String(html);
42960 if(html.length > 5){
42961 if(Roo.isSafari){ // strip safari nonsense
42962 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
42965 if(html == ' '){
42972 * HTML Editor -> Textarea
42973 * Protected method that will not generally be called directly. Syncs the contents
42974 * of the editor iframe with the textarea.
42976 syncValue : function(){
42977 if(this.initialized){
42978 var bd = (this.doc.body || this.doc.documentElement);
42979 //this.cleanUpPaste(); -- this is done else where and causes havoc..
42980 var html = bd.innerHTML;
42982 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
42983 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
42985 html = '<div style="'+m[0]+'">' + html + '</div>';
42988 html = this.cleanHtml(html);
42989 // fix up the special chars.. normaly like back quotes in word...
42990 // however we do not want to do this with chinese..
42991 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
42992 var cc = b.charCodeAt();
42994 (cc >= 0x4E00 && cc < 0xA000 ) ||
42995 (cc >= 0x3400 && cc < 0x4E00 ) ||
42996 (cc >= 0xf900 && cc < 0xfb00 )
43002 if(this.owner.fireEvent('beforesync', this, html) !== false){
43003 this.el.dom.value = html;
43004 this.owner.fireEvent('sync', this, html);
43010 * Protected method that will not generally be called directly. Pushes the value of the textarea
43011 * into the iframe editor.
43013 pushValue : function(){
43014 if(this.initialized){
43015 var v = this.el.dom.value.trim();
43017 // if(v.length < 1){
43021 if(this.owner.fireEvent('beforepush', this, v) !== false){
43022 var d = (this.doc.body || this.doc.documentElement);
43024 this.cleanUpPaste();
43025 this.el.dom.value = d.innerHTML;
43026 this.owner.fireEvent('push', this, v);
43032 deferFocus : function(){
43033 this.focus.defer(10, this);
43037 focus : function(){
43038 if(this.win && !this.sourceEditMode){
43045 assignDocWin: function()
43047 var iframe = this.iframe;
43050 this.doc = iframe.contentWindow.document;
43051 this.win = iframe.contentWindow;
43053 // if (!Roo.get(this.frameId)) {
43056 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43057 // this.win = Roo.get(this.frameId).dom.contentWindow;
43059 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43063 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43064 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43069 initEditor : function(){
43070 //console.log("INIT EDITOR");
43071 this.assignDocWin();
43075 this.doc.designMode="on";
43077 this.doc.write(this.getDocMarkup());
43080 var dbody = (this.doc.body || this.doc.documentElement);
43081 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43082 // this copies styles from the containing element into thsi one..
43083 // not sure why we need all of this..
43084 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43086 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43087 //ss['background-attachment'] = 'fixed'; // w3c
43088 dbody.bgProperties = 'fixed'; // ie
43089 //Roo.DomHelper.applyStyles(dbody, ss);
43090 Roo.EventManager.on(this.doc, {
43091 //'mousedown': this.onEditorEvent,
43092 'mouseup': this.onEditorEvent,
43093 'dblclick': this.onEditorEvent,
43094 'click': this.onEditorEvent,
43095 'keyup': this.onEditorEvent,
43100 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43102 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43103 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43105 this.initialized = true;
43107 this.owner.fireEvent('initialize', this);
43112 onDestroy : function(){
43118 //for (var i =0; i < this.toolbars.length;i++) {
43119 // // fixme - ask toolbars for heights?
43120 // this.toolbars[i].onDestroy();
43123 //this.wrap.dom.innerHTML = '';
43124 //this.wrap.remove();
43129 onFirstFocus : function(){
43131 this.assignDocWin();
43134 this.activated = true;
43137 if(Roo.isGecko){ // prevent silly gecko errors
43139 var s = this.win.getSelection();
43140 if(!s.focusNode || s.focusNode.nodeType != 3){
43141 var r = s.getRangeAt(0);
43142 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43147 this.execCmd('useCSS', true);
43148 this.execCmd('styleWithCSS', false);
43151 this.owner.fireEvent('activate', this);
43155 adjustFont: function(btn){
43156 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43157 //if(Roo.isSafari){ // safari
43160 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43161 if(Roo.isSafari){ // safari
43162 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43163 v = (v < 10) ? 10 : v;
43164 v = (v > 48) ? 48 : v;
43165 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43170 v = Math.max(1, v+adjust);
43172 this.execCmd('FontSize', v );
43175 onEditorEvent : function(e)
43177 this.owner.fireEvent('editorevent', this, e);
43178 // this.updateToolbar();
43179 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43182 insertTag : function(tg)
43184 // could be a bit smarter... -> wrap the current selected tRoo..
43185 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43187 range = this.createRange(this.getSelection());
43188 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43189 wrappingNode.appendChild(range.extractContents());
43190 range.insertNode(wrappingNode);
43197 this.execCmd("formatblock", tg);
43201 insertText : function(txt)
43205 var range = this.createRange();
43206 range.deleteContents();
43207 //alert(Sender.getAttribute('label'));
43209 range.insertNode(this.doc.createTextNode(txt));
43215 * Executes a Midas editor command on the editor document and performs necessary focus and
43216 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43217 * @param {String} cmd The Midas command
43218 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43220 relayCmd : function(cmd, value){
43222 this.execCmd(cmd, value);
43223 this.owner.fireEvent('editorevent', this);
43224 //this.updateToolbar();
43225 this.owner.deferFocus();
43229 * Executes a Midas editor command directly on the editor document.
43230 * For visual commands, you should use {@link #relayCmd} instead.
43231 * <b>This should only be called after the editor is initialized.</b>
43232 * @param {String} cmd The Midas command
43233 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43235 execCmd : function(cmd, value){
43236 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43243 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43245 * @param {String} text | dom node..
43247 insertAtCursor : function(text)
43252 if(!this.activated){
43258 var r = this.doc.selection.createRange();
43269 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43273 // from jquery ui (MIT licenced)
43275 var win = this.win;
43277 if (win.getSelection && win.getSelection().getRangeAt) {
43278 range = win.getSelection().getRangeAt(0);
43279 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43280 range.insertNode(node);
43281 } else if (win.document.selection && win.document.selection.createRange) {
43282 // no firefox support
43283 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43284 win.document.selection.createRange().pasteHTML(txt);
43286 // no firefox support
43287 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43288 this.execCmd('InsertHTML', txt);
43297 mozKeyPress : function(e){
43299 var c = e.getCharCode(), cmd;
43302 c = String.fromCharCode(c).toLowerCase();
43316 this.cleanUpPaste.defer(100, this);
43324 e.preventDefault();
43332 fixKeys : function(){ // load time branching for fastest keydown performance
43334 return function(e){
43335 var k = e.getKey(), r;
43338 r = this.doc.selection.createRange();
43341 r.pasteHTML('    ');
43348 r = this.doc.selection.createRange();
43350 var target = r.parentElement();
43351 if(!target || target.tagName.toLowerCase() != 'li'){
43353 r.pasteHTML('<br />');
43359 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43360 this.cleanUpPaste.defer(100, this);
43366 }else if(Roo.isOpera){
43367 return function(e){
43368 var k = e.getKey();
43372 this.execCmd('InsertHTML','    ');
43375 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43376 this.cleanUpPaste.defer(100, this);
43381 }else if(Roo.isSafari){
43382 return function(e){
43383 var k = e.getKey();
43387 this.execCmd('InsertText','\t');
43391 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43392 this.cleanUpPaste.defer(100, this);
43400 getAllAncestors: function()
43402 var p = this.getSelectedNode();
43405 a.push(p); // push blank onto stack..
43406 p = this.getParentElement();
43410 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43414 a.push(this.doc.body);
43418 lastSelNode : false,
43421 getSelection : function()
43423 this.assignDocWin();
43424 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43427 getSelectedNode: function()
43429 // this may only work on Gecko!!!
43431 // should we cache this!!!!
43436 var range = this.createRange(this.getSelection()).cloneRange();
43439 var parent = range.parentElement();
43441 var testRange = range.duplicate();
43442 testRange.moveToElementText(parent);
43443 if (testRange.inRange(range)) {
43446 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43449 parent = parent.parentElement;
43454 // is ancestor a text element.
43455 var ac = range.commonAncestorContainer;
43456 if (ac.nodeType == 3) {
43457 ac = ac.parentNode;
43460 var ar = ac.childNodes;
43463 var other_nodes = [];
43464 var has_other_nodes = false;
43465 for (var i=0;i<ar.length;i++) {
43466 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43469 // fullly contained node.
43471 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43476 // probably selected..
43477 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43478 other_nodes.push(ar[i]);
43482 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43487 has_other_nodes = true;
43489 if (!nodes.length && other_nodes.length) {
43490 nodes= other_nodes;
43492 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43498 createRange: function(sel)
43500 // this has strange effects when using with
43501 // top toolbar - not sure if it's a great idea.
43502 //this.editor.contentWindow.focus();
43503 if (typeof sel != "undefined") {
43505 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43507 return this.doc.createRange();
43510 return this.doc.createRange();
43513 getParentElement: function()
43516 this.assignDocWin();
43517 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43519 var range = this.createRange(sel);
43522 var p = range.commonAncestorContainer;
43523 while (p.nodeType == 3) { // text node
43534 * Range intersection.. the hard stuff...
43538 * [ -- selected range --- ]
43542 * if end is before start or hits it. fail.
43543 * if start is after end or hits it fail.
43545 * if either hits (but other is outside. - then it's not
43551 // @see http://www.thismuchiknow.co.uk/?p=64.
43552 rangeIntersectsNode : function(range, node)
43554 var nodeRange = node.ownerDocument.createRange();
43556 nodeRange.selectNode(node);
43558 nodeRange.selectNodeContents(node);
43561 var rangeStartRange = range.cloneRange();
43562 rangeStartRange.collapse(true);
43564 var rangeEndRange = range.cloneRange();
43565 rangeEndRange.collapse(false);
43567 var nodeStartRange = nodeRange.cloneRange();
43568 nodeStartRange.collapse(true);
43570 var nodeEndRange = nodeRange.cloneRange();
43571 nodeEndRange.collapse(false);
43573 return rangeStartRange.compareBoundaryPoints(
43574 Range.START_TO_START, nodeEndRange) == -1 &&
43575 rangeEndRange.compareBoundaryPoints(
43576 Range.START_TO_START, nodeStartRange) == 1;
43580 rangeCompareNode : function(range, node)
43582 var nodeRange = node.ownerDocument.createRange();
43584 nodeRange.selectNode(node);
43586 nodeRange.selectNodeContents(node);
43590 range.collapse(true);
43592 nodeRange.collapse(true);
43594 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43595 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43597 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43599 var nodeIsBefore = ss == 1;
43600 var nodeIsAfter = ee == -1;
43602 if (nodeIsBefore && nodeIsAfter) {
43605 if (!nodeIsBefore && nodeIsAfter) {
43606 return 1; //right trailed.
43609 if (nodeIsBefore && !nodeIsAfter) {
43610 return 2; // left trailed.
43616 // private? - in a new class?
43617 cleanUpPaste : function()
43619 // cleans up the whole document..
43620 Roo.log('cleanuppaste');
43622 this.cleanUpChildren(this.doc.body);
43623 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43624 if (clean != this.doc.body.innerHTML) {
43625 this.doc.body.innerHTML = clean;
43630 cleanWordChars : function(input) {// change the chars to hex code
43631 var he = Roo.HtmlEditorCore;
43633 var output = input;
43634 Roo.each(he.swapCodes, function(sw) {
43635 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43637 output = output.replace(swapper, sw[1]);
43644 cleanUpChildren : function (n)
43646 if (!n.childNodes.length) {
43649 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43650 this.cleanUpChild(n.childNodes[i]);
43657 cleanUpChild : function (node)
43660 //console.log(node);
43661 if (node.nodeName == "#text") {
43662 // clean up silly Windows -- stuff?
43665 if (node.nodeName == "#comment") {
43666 node.parentNode.removeChild(node);
43667 // clean up silly Windows -- stuff?
43670 var lcname = node.tagName.toLowerCase();
43671 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43672 // whitelist of tags..
43674 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43676 node.parentNode.removeChild(node);
43681 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43683 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43684 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43686 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43687 // remove_keep_children = true;
43690 if (remove_keep_children) {
43691 this.cleanUpChildren(node);
43692 // inserts everything just before this node...
43693 while (node.childNodes.length) {
43694 var cn = node.childNodes[0];
43695 node.removeChild(cn);
43696 node.parentNode.insertBefore(cn, node);
43698 node.parentNode.removeChild(node);
43702 if (!node.attributes || !node.attributes.length) {
43703 this.cleanUpChildren(node);
43707 function cleanAttr(n,v)
43710 if (v.match(/^\./) || v.match(/^\//)) {
43713 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
43716 if (v.match(/^#/)) {
43719 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43720 node.removeAttribute(n);
43724 var cwhite = this.cwhite;
43725 var cblack = this.cblack;
43727 function cleanStyle(n,v)
43729 if (v.match(/expression/)) { //XSS?? should we even bother..
43730 node.removeAttribute(n);
43734 var parts = v.split(/;/);
43737 Roo.each(parts, function(p) {
43738 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43742 var l = p.split(':').shift().replace(/\s+/g,'');
43743 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43745 if ( cwhite.length && cblack.indexOf(l) > -1) {
43746 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43747 //node.removeAttribute(n);
43751 // only allow 'c whitelisted system attributes'
43752 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43753 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43754 //node.removeAttribute(n);
43764 if (clean.length) {
43765 node.setAttribute(n, clean.join(';'));
43767 node.removeAttribute(n);
43773 for (var i = node.attributes.length-1; i > -1 ; i--) {
43774 var a = node.attributes[i];
43777 if (a.name.toLowerCase().substr(0,2)=='on') {
43778 node.removeAttribute(a.name);
43781 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43782 node.removeAttribute(a.name);
43785 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43786 cleanAttr(a.name,a.value); // fixme..
43789 if (a.name == 'style') {
43790 cleanStyle(a.name,a.value);
43793 /// clean up MS crap..
43794 // tecnically this should be a list of valid class'es..
43797 if (a.name == 'class') {
43798 if (a.value.match(/^Mso/)) {
43799 node.className = '';
43802 if (a.value.match(/body/)) {
43803 node.className = '';
43814 this.cleanUpChildren(node);
43820 * Clean up MS wordisms...
43822 cleanWord : function(node)
43827 this.cleanWord(this.doc.body);
43830 if (node.nodeName == "#text") {
43831 // clean up silly Windows -- stuff?
43834 if (node.nodeName == "#comment") {
43835 node.parentNode.removeChild(node);
43836 // clean up silly Windows -- stuff?
43840 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43841 node.parentNode.removeChild(node);
43845 // remove - but keep children..
43846 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43847 while (node.childNodes.length) {
43848 var cn = node.childNodes[0];
43849 node.removeChild(cn);
43850 node.parentNode.insertBefore(cn, node);
43852 node.parentNode.removeChild(node);
43853 this.iterateChildren(node, this.cleanWord);
43857 if (node.className.length) {
43859 var cn = node.className.split(/\W+/);
43861 Roo.each(cn, function(cls) {
43862 if (cls.match(/Mso[a-zA-Z]+/)) {
43867 node.className = cna.length ? cna.join(' ') : '';
43869 node.removeAttribute("class");
43873 if (node.hasAttribute("lang")) {
43874 node.removeAttribute("lang");
43877 if (node.hasAttribute("style")) {
43879 var styles = node.getAttribute("style").split(";");
43881 Roo.each(styles, function(s) {
43882 if (!s.match(/:/)) {
43885 var kv = s.split(":");
43886 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
43889 // what ever is left... we allow.
43892 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43893 if (!nstyle.length) {
43894 node.removeAttribute('style');
43897 this.iterateChildren(node, this.cleanWord);
43903 * iterateChildren of a Node, calling fn each time, using this as the scole..
43904 * @param {DomNode} node node to iterate children of.
43905 * @param {Function} fn method of this class to call on each item.
43907 iterateChildren : function(node, fn)
43909 if (!node.childNodes.length) {
43912 for (var i = node.childNodes.length-1; i > -1 ; i--) {
43913 fn.call(this, node.childNodes[i])
43919 * cleanTableWidths.
43921 * Quite often pasting from word etc.. results in tables with column and widths.
43922 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
43925 cleanTableWidths : function(node)
43930 this.cleanTableWidths(this.doc.body);
43935 if (node.nodeName == "#text" || node.nodeName == "#comment") {
43938 Roo.log(node.tagName);
43939 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
43940 this.iterateChildren(node, this.cleanTableWidths);
43943 if (node.hasAttribute('width')) {
43944 node.removeAttribute('width');
43948 if (node.hasAttribute("style")) {
43951 var styles = node.getAttribute("style").split(";");
43953 Roo.each(styles, function(s) {
43954 if (!s.match(/:/)) {
43957 var kv = s.split(":");
43958 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
43961 // what ever is left... we allow.
43964 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43965 if (!nstyle.length) {
43966 node.removeAttribute('style');
43970 this.iterateChildren(node, this.cleanTableWidths);
43978 domToHTML : function(currentElement, depth, nopadtext) {
43980 depth = depth || 0;
43981 nopadtext = nopadtext || false;
43983 if (!currentElement) {
43984 return this.domToHTML(this.doc.body);
43987 //Roo.log(currentElement);
43989 var allText = false;
43990 var nodeName = currentElement.nodeName;
43991 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
43993 if (nodeName == '#text') {
43995 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44000 if (nodeName != 'BODY') {
44003 // Prints the node tagName, such as <A>, <IMG>, etc
44006 for(i = 0; i < currentElement.attributes.length;i++) {
44008 var aname = currentElement.attributes.item(i).name;
44009 if (!currentElement.attributes.item(i).value.length) {
44012 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44015 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44024 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44027 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44032 // Traverse the tree
44034 var currentElementChild = currentElement.childNodes.item(i);
44035 var allText = true;
44036 var innerHTML = '';
44038 while (currentElementChild) {
44039 // Formatting code (indent the tree so it looks nice on the screen)
44040 var nopad = nopadtext;
44041 if (lastnode == 'SPAN') {
44045 if (currentElementChild.nodeName == '#text') {
44046 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44047 toadd = nopadtext ? toadd : toadd.trim();
44048 if (!nopad && toadd.length > 80) {
44049 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44051 innerHTML += toadd;
44054 currentElementChild = currentElement.childNodes.item(i);
44060 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44062 // Recursively traverse the tree structure of the child node
44063 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44064 lastnode = currentElementChild.nodeName;
44066 currentElementChild=currentElement.childNodes.item(i);
44072 // The remaining code is mostly for formatting the tree
44073 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44078 ret+= "</"+tagName+">";
44084 applyBlacklists : function()
44086 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44087 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44091 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44092 if (b.indexOf(tag) > -1) {
44095 this.white.push(tag);
44099 Roo.each(w, function(tag) {
44100 if (b.indexOf(tag) > -1) {
44103 if (this.white.indexOf(tag) > -1) {
44106 this.white.push(tag);
44111 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44112 if (w.indexOf(tag) > -1) {
44115 this.black.push(tag);
44119 Roo.each(b, function(tag) {
44120 if (w.indexOf(tag) > -1) {
44123 if (this.black.indexOf(tag) > -1) {
44126 this.black.push(tag);
44131 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44132 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44136 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44137 if (b.indexOf(tag) > -1) {
44140 this.cwhite.push(tag);
44144 Roo.each(w, function(tag) {
44145 if (b.indexOf(tag) > -1) {
44148 if (this.cwhite.indexOf(tag) > -1) {
44151 this.cwhite.push(tag);
44156 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44157 if (w.indexOf(tag) > -1) {
44160 this.cblack.push(tag);
44164 Roo.each(b, function(tag) {
44165 if (w.indexOf(tag) > -1) {
44168 if (this.cblack.indexOf(tag) > -1) {
44171 this.cblack.push(tag);
44176 setStylesheets : function(stylesheets)
44178 if(typeof(stylesheets) == 'string'){
44179 Roo.get(this.iframe.contentDocument.head).createChild({
44181 rel : 'stylesheet',
44190 Roo.each(stylesheets, function(s) {
44195 Roo.get(_this.iframe.contentDocument.head).createChild({
44197 rel : 'stylesheet',
44206 removeStylesheets : function()
44210 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44215 // hide stuff that is not compatible
44229 * @event specialkey
44233 * @cfg {String} fieldClass @hide
44236 * @cfg {String} focusClass @hide
44239 * @cfg {String} autoCreate @hide
44242 * @cfg {String} inputType @hide
44245 * @cfg {String} invalidClass @hide
44248 * @cfg {String} invalidText @hide
44251 * @cfg {String} msgFx @hide
44254 * @cfg {String} validateOnBlur @hide
44258 Roo.HtmlEditorCore.white = [
44259 'area', 'br', 'img', 'input', 'hr', 'wbr',
44261 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44262 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44263 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44264 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44265 'table', 'ul', 'xmp',
44267 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44270 'dir', 'menu', 'ol', 'ul', 'dl',
44276 Roo.HtmlEditorCore.black = [
44277 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44279 'base', 'basefont', 'bgsound', 'blink', 'body',
44280 'frame', 'frameset', 'head', 'html', 'ilayer',
44281 'iframe', 'layer', 'link', 'meta', 'object',
44282 'script', 'style' ,'title', 'xml' // clean later..
44284 Roo.HtmlEditorCore.clean = [
44285 'script', 'style', 'title', 'xml'
44287 Roo.HtmlEditorCore.remove = [
44292 Roo.HtmlEditorCore.ablack = [
44296 Roo.HtmlEditorCore.aclean = [
44297 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44301 Roo.HtmlEditorCore.pwhite= [
44302 'http', 'https', 'mailto'
44305 // white listed style attributes.
44306 Roo.HtmlEditorCore.cwhite= [
44307 // 'text-align', /// default is to allow most things..
44313 // black listed style attributes.
44314 Roo.HtmlEditorCore.cblack= [
44315 // 'font-size' -- this can be set by the project
44319 Roo.HtmlEditorCore.swapCodes =[
44330 //<script type="text/javascript">
44333 * Ext JS Library 1.1.1
44334 * Copyright(c) 2006-2007, Ext JS, LLC.
44340 Roo.form.HtmlEditor = function(config){
44344 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44346 if (!this.toolbars) {
44347 this.toolbars = [];
44349 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44355 * @class Roo.form.HtmlEditor
44356 * @extends Roo.form.Field
44357 * Provides a lightweight HTML Editor component.
44359 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44361 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44362 * supported by this editor.</b><br/><br/>
44363 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44364 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44366 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44368 * @cfg {Boolean} clearUp
44372 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44377 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44382 * @cfg {Number} height (in pixels)
44386 * @cfg {Number} width (in pixels)
44391 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44394 stylesheets: false,
44398 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44403 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44409 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44414 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44422 // private properties
44423 validationEvent : false,
44425 initialized : false,
44428 onFocus : Roo.emptyFn,
44430 hideMode:'offsets',
44432 actionMode : 'container', // defaults to hiding it...
44434 defaultAutoCreate : { // modified by initCompnoent..
44436 style:"width:500px;height:300px;",
44437 autocomplete: "new-password"
44441 initComponent : function(){
44444 * @event initialize
44445 * Fires when the editor is fully initialized (including the iframe)
44446 * @param {HtmlEditor} this
44451 * Fires when the editor is first receives the focus. Any insertion must wait
44452 * until after this event.
44453 * @param {HtmlEditor} this
44457 * @event beforesync
44458 * Fires before the textarea is updated with content from the editor iframe. Return false
44459 * to cancel the sync.
44460 * @param {HtmlEditor} this
44461 * @param {String} html
44465 * @event beforepush
44466 * Fires before the iframe editor is updated with content from the textarea. Return false
44467 * to cancel the push.
44468 * @param {HtmlEditor} this
44469 * @param {String} html
44474 * Fires when the textarea is updated with content from the editor iframe.
44475 * @param {HtmlEditor} this
44476 * @param {String} html
44481 * Fires when the iframe editor is updated with content from the textarea.
44482 * @param {HtmlEditor} this
44483 * @param {String} html
44487 * @event editmodechange
44488 * Fires when the editor switches edit modes
44489 * @param {HtmlEditor} this
44490 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44492 editmodechange: true,
44494 * @event editorevent
44495 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44496 * @param {HtmlEditor} this
44500 * @event firstfocus
44501 * Fires when on first focus - needed by toolbars..
44502 * @param {HtmlEditor} this
44507 * Auto save the htmlEditor value as a file into Events
44508 * @param {HtmlEditor} this
44512 * @event savedpreview
44513 * preview the saved version of htmlEditor
44514 * @param {HtmlEditor} this
44516 savedpreview: true,
44519 * @event stylesheetsclick
44520 * Fires when press the Sytlesheets button
44521 * @param {Roo.HtmlEditorCore} this
44523 stylesheetsclick: true
44525 this.defaultAutoCreate = {
44527 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44528 autocomplete: "new-password"
44533 * Protected method that will not generally be called directly. It
44534 * is called when the editor creates its toolbar. Override this method if you need to
44535 * add custom toolbar buttons.
44536 * @param {HtmlEditor} editor
44538 createToolbar : function(editor){
44539 Roo.log("create toolbars");
44540 if (!editor.toolbars || !editor.toolbars.length) {
44541 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44544 for (var i =0 ; i < editor.toolbars.length;i++) {
44545 editor.toolbars[i] = Roo.factory(
44546 typeof(editor.toolbars[i]) == 'string' ?
44547 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44548 Roo.form.HtmlEditor);
44549 editor.toolbars[i].init(editor);
44557 onRender : function(ct, position)
44560 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44562 this.wrap = this.el.wrap({
44563 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44566 this.editorcore.onRender(ct, position);
44568 if (this.resizable) {
44569 this.resizeEl = new Roo.Resizable(this.wrap, {
44573 minHeight : this.height,
44574 height: this.height,
44575 handles : this.resizable,
44578 resize : function(r, w, h) {
44579 _t.onResize(w,h); // -something
44585 this.createToolbar(this);
44589 this.setSize(this.wrap.getSize());
44591 if (this.resizeEl) {
44592 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44593 // should trigger onReize..
44596 this.keyNav = new Roo.KeyNav(this.el, {
44598 "tab" : function(e){
44599 e.preventDefault();
44601 var value = this.getValue();
44603 var start = this.el.dom.selectionStart;
44604 var end = this.el.dom.selectionEnd;
44608 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44609 this.el.dom.setSelectionRange(end + 1, end + 1);
44613 var f = value.substring(0, start).split("\t");
44615 if(f.pop().length != 0){
44619 this.setValue(f.join("\t") + value.substring(end));
44620 this.el.dom.setSelectionRange(start - 1, start - 1);
44624 "home" : function(e){
44625 e.preventDefault();
44627 var curr = this.el.dom.selectionStart;
44628 var lines = this.getValue().split("\n");
44635 this.el.dom.setSelectionRange(0, 0);
44641 for (var i = 0; i < lines.length;i++) {
44642 pos += lines[i].length;
44652 pos -= lines[i].length;
44658 this.el.dom.setSelectionRange(pos, pos);
44662 this.el.dom.selectionStart = pos;
44663 this.el.dom.selectionEnd = curr;
44666 "end" : function(e){
44667 e.preventDefault();
44669 var curr = this.el.dom.selectionStart;
44670 var lines = this.getValue().split("\n");
44677 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44683 for (var i = 0; i < lines.length;i++) {
44685 pos += lines[i].length;
44699 this.el.dom.setSelectionRange(pos, pos);
44703 this.el.dom.selectionStart = curr;
44704 this.el.dom.selectionEnd = pos;
44709 doRelay : function(foo, bar, hname){
44710 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44716 // if(this.autosave && this.w){
44717 // this.autoSaveFn = setInterval(this.autosave, 1000);
44722 onResize : function(w, h)
44724 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44729 if(typeof w == 'number'){
44730 var aw = w - this.wrap.getFrameWidth('lr');
44731 this.el.setWidth(this.adjustWidth('textarea', aw));
44734 if(typeof h == 'number'){
44736 for (var i =0; i < this.toolbars.length;i++) {
44737 // fixme - ask toolbars for heights?
44738 tbh += this.toolbars[i].tb.el.getHeight();
44739 if (this.toolbars[i].footer) {
44740 tbh += this.toolbars[i].footer.el.getHeight();
44747 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44748 ah -= 5; // knock a few pixes off for look..
44750 this.el.setHeight(this.adjustWidth('textarea', ah));
44754 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44755 this.editorcore.onResize(ew,eh);
44760 * Toggles the editor between standard and source edit mode.
44761 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44763 toggleSourceEdit : function(sourceEditMode)
44765 this.editorcore.toggleSourceEdit(sourceEditMode);
44767 if(this.editorcore.sourceEditMode){
44768 Roo.log('editor - showing textarea');
44771 // Roo.log(this.syncValue());
44772 this.editorcore.syncValue();
44773 this.el.removeClass('x-hidden');
44774 this.el.dom.removeAttribute('tabIndex');
44777 for (var i = 0; i < this.toolbars.length; i++) {
44778 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44779 this.toolbars[i].tb.hide();
44780 this.toolbars[i].footer.hide();
44785 Roo.log('editor - hiding textarea');
44787 // Roo.log(this.pushValue());
44788 this.editorcore.pushValue();
44790 this.el.addClass('x-hidden');
44791 this.el.dom.setAttribute('tabIndex', -1);
44793 for (var i = 0; i < this.toolbars.length; i++) {
44794 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44795 this.toolbars[i].tb.show();
44796 this.toolbars[i].footer.show();
44800 //this.deferFocus();
44803 this.setSize(this.wrap.getSize());
44804 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44806 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44809 // private (for BoxComponent)
44810 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44812 // private (for BoxComponent)
44813 getResizeEl : function(){
44817 // private (for BoxComponent)
44818 getPositionEl : function(){
44823 initEvents : function(){
44824 this.originalValue = this.getValue();
44828 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44831 markInvalid : Roo.emptyFn,
44833 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44836 clearInvalid : Roo.emptyFn,
44838 setValue : function(v){
44839 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44840 this.editorcore.pushValue();
44845 deferFocus : function(){
44846 this.focus.defer(10, this);
44850 focus : function(){
44851 this.editorcore.focus();
44857 onDestroy : function(){
44863 for (var i =0; i < this.toolbars.length;i++) {
44864 // fixme - ask toolbars for heights?
44865 this.toolbars[i].onDestroy();
44868 this.wrap.dom.innerHTML = '';
44869 this.wrap.remove();
44874 onFirstFocus : function(){
44875 //Roo.log("onFirstFocus");
44876 this.editorcore.onFirstFocus();
44877 for (var i =0; i < this.toolbars.length;i++) {
44878 this.toolbars[i].onFirstFocus();
44884 syncValue : function()
44886 this.editorcore.syncValue();
44889 pushValue : function()
44891 this.editorcore.pushValue();
44894 setStylesheets : function(stylesheets)
44896 this.editorcore.setStylesheets(stylesheets);
44899 removeStylesheets : function()
44901 this.editorcore.removeStylesheets();
44905 // hide stuff that is not compatible
44919 * @event specialkey
44923 * @cfg {String} fieldClass @hide
44926 * @cfg {String} focusClass @hide
44929 * @cfg {String} autoCreate @hide
44932 * @cfg {String} inputType @hide
44935 * @cfg {String} invalidClass @hide
44938 * @cfg {String} invalidText @hide
44941 * @cfg {String} msgFx @hide
44944 * @cfg {String} validateOnBlur @hide
44948 // <script type="text/javascript">
44951 * Ext JS Library 1.1.1
44952 * Copyright(c) 2006-2007, Ext JS, LLC.
44958 * @class Roo.form.HtmlEditorToolbar1
44963 new Roo.form.HtmlEditor({
44966 new Roo.form.HtmlEditorToolbar1({
44967 disable : { fonts: 1 , format: 1, ..., ... , ...],
44973 * @cfg {Object} disable List of elements to disable..
44974 * @cfg {Array} btns List of additional buttons.
44978 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
44981 Roo.form.HtmlEditor.ToolbarStandard = function(config)
44984 Roo.apply(this, config);
44986 // default disabled, based on 'good practice'..
44987 this.disable = this.disable || {};
44988 Roo.applyIf(this.disable, {
44991 specialElements : true
44995 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44996 // dont call parent... till later.
44999 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45006 editorcore : false,
45008 * @cfg {Object} disable List of toolbar elements to disable
45015 * @cfg {String} createLinkText The default text for the create link prompt
45017 createLinkText : 'Please enter the URL for the link:',
45019 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45021 defaultLinkValue : 'http:/'+'/',
45025 * @cfg {Array} fontFamilies An array of available font families
45043 // "á" , ?? a acute?
45048 "°" // , // degrees
45050 // "é" , // e ecute
45051 // "ú" , // u ecute?
45054 specialElements : [
45056 text: "Insert Table",
45059 ihtml : '<table><tr><td>Cell</td></tr></table>'
45063 text: "Insert Image",
45066 ihtml : '<img src="about:blank"/>'
45075 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45076 "input:submit", "input:button", "select", "textarea", "label" ],
45079 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45081 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45089 * @cfg {String} defaultFont default font to use.
45091 defaultFont: 'tahoma',
45093 fontSelect : false,
45096 formatCombo : false,
45098 init : function(editor)
45100 this.editor = editor;
45101 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45102 var editorcore = this.editorcore;
45106 var fid = editorcore.frameId;
45108 function btn(id, toggle, handler){
45109 var xid = fid + '-'+ id ;
45113 cls : 'x-btn-icon x-edit-'+id,
45114 enableToggle:toggle !== false,
45115 scope: _t, // was editor...
45116 handler:handler||_t.relayBtnCmd,
45117 clickEvent:'mousedown',
45118 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45125 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45127 // stop form submits
45128 tb.el.on('click', function(e){
45129 e.preventDefault(); // what does this do?
45132 if(!this.disable.font) { // && !Roo.isSafari){
45133 /* why no safari for fonts
45134 editor.fontSelect = tb.el.createChild({
45137 cls:'x-font-select',
45138 html: this.createFontOptions()
45141 editor.fontSelect.on('change', function(){
45142 var font = editor.fontSelect.dom.value;
45143 editor.relayCmd('fontname', font);
45144 editor.deferFocus();
45148 editor.fontSelect.dom,
45154 if(!this.disable.formats){
45155 this.formatCombo = new Roo.form.ComboBox({
45156 store: new Roo.data.SimpleStore({
45159 data : this.formats // from states.js
45163 //autoCreate : {tag: "div", size: "20"},
45164 displayField:'tag',
45168 triggerAction: 'all',
45169 emptyText:'Add tag',
45170 selectOnFocus:true,
45173 'select': function(c, r, i) {
45174 editorcore.insertTag(r.get('tag'));
45180 tb.addField(this.formatCombo);
45184 if(!this.disable.format){
45189 btn('strikethrough')
45192 if(!this.disable.fontSize){
45197 btn('increasefontsize', false, editorcore.adjustFont),
45198 btn('decreasefontsize', false, editorcore.adjustFont)
45203 if(!this.disable.colors){
45206 id:editorcore.frameId +'-forecolor',
45207 cls:'x-btn-icon x-edit-forecolor',
45208 clickEvent:'mousedown',
45209 tooltip: this.buttonTips['forecolor'] || undefined,
45211 menu : new Roo.menu.ColorMenu({
45212 allowReselect: true,
45213 focus: Roo.emptyFn,
45216 selectHandler: function(cp, color){
45217 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45218 editor.deferFocus();
45221 clickEvent:'mousedown'
45224 id:editorcore.frameId +'backcolor',
45225 cls:'x-btn-icon x-edit-backcolor',
45226 clickEvent:'mousedown',
45227 tooltip: this.buttonTips['backcolor'] || undefined,
45229 menu : new Roo.menu.ColorMenu({
45230 focus: Roo.emptyFn,
45233 allowReselect: true,
45234 selectHandler: function(cp, color){
45236 editorcore.execCmd('useCSS', false);
45237 editorcore.execCmd('hilitecolor', color);
45238 editorcore.execCmd('useCSS', true);
45239 editor.deferFocus();
45241 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45242 Roo.isSafari || Roo.isIE ? '#'+color : color);
45243 editor.deferFocus();
45247 clickEvent:'mousedown'
45252 // now add all the items...
45255 if(!this.disable.alignments){
45258 btn('justifyleft'),
45259 btn('justifycenter'),
45260 btn('justifyright')
45264 //if(!Roo.isSafari){
45265 if(!this.disable.links){
45268 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45272 if(!this.disable.lists){
45275 btn('insertorderedlist'),
45276 btn('insertunorderedlist')
45279 if(!this.disable.sourceEdit){
45282 btn('sourceedit', true, function(btn){
45283 this.toggleSourceEdit(btn.pressed);
45290 // special menu.. - needs to be tidied up..
45291 if (!this.disable.special) {
45294 cls: 'x-edit-none',
45300 for (var i =0; i < this.specialChars.length; i++) {
45301 smenu.menu.items.push({
45303 html: this.specialChars[i],
45304 handler: function(a,b) {
45305 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45306 //editor.insertAtCursor(a.html);
45320 if (!this.disable.cleanStyles) {
45322 cls: 'x-btn-icon x-btn-clear',
45328 for (var i =0; i < this.cleanStyles.length; i++) {
45329 cmenu.menu.items.push({
45330 actiontype : this.cleanStyles[i],
45331 html: 'Remove ' + this.cleanStyles[i],
45332 handler: function(a,b) {
45335 var c = Roo.get(editorcore.doc.body);
45336 c.select('[style]').each(function(s) {
45337 s.dom.style.removeProperty(a.actiontype);
45339 editorcore.syncValue();
45344 cmenu.menu.items.push({
45345 actiontype : 'tablewidths',
45346 html: 'Remove Table Widths',
45347 handler: function(a,b) {
45348 editorcore.cleanTableWidths();
45349 editorcore.syncValue();
45353 cmenu.menu.items.push({
45354 actiontype : 'word',
45355 html: 'Remove MS Word Formating',
45356 handler: function(a,b) {
45357 editorcore.cleanWord();
45358 editorcore.syncValue();
45363 cmenu.menu.items.push({
45364 actiontype : 'all',
45365 html: 'Remove All Styles',
45366 handler: function(a,b) {
45368 var c = Roo.get(editorcore.doc.body);
45369 c.select('[style]').each(function(s) {
45370 s.dom.removeAttribute('style');
45372 editorcore.syncValue();
45377 cmenu.menu.items.push({
45378 actiontype : 'all',
45379 html: 'Remove All CSS Classes',
45380 handler: function(a,b) {
45382 var c = Roo.get(editorcore.doc.body);
45383 c.select('[class]').each(function(s) {
45384 s.dom.className = '';
45386 editorcore.syncValue();
45391 cmenu.menu.items.push({
45392 actiontype : 'tidy',
45393 html: 'Tidy HTML Source',
45394 handler: function(a,b) {
45395 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45396 editorcore.syncValue();
45405 if (!this.disable.specialElements) {
45408 cls: 'x-edit-none',
45413 for (var i =0; i < this.specialElements.length; i++) {
45414 semenu.menu.items.push(
45416 handler: function(a,b) {
45417 editor.insertAtCursor(this.ihtml);
45419 }, this.specialElements[i])
45431 for(var i =0; i< this.btns.length;i++) {
45432 var b = Roo.factory(this.btns[i],Roo.form);
45433 b.cls = 'x-edit-none';
45435 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45436 b.cls += ' x-init-enable';
45439 b.scope = editorcore;
45447 // disable everything...
45449 this.tb.items.each(function(item){
45452 item.id != editorcore.frameId+ '-sourceedit' &&
45453 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45459 this.rendered = true;
45461 // the all the btns;
45462 editor.on('editorevent', this.updateToolbar, this);
45463 // other toolbars need to implement this..
45464 //editor.on('editmodechange', this.updateToolbar, this);
45468 relayBtnCmd : function(btn) {
45469 this.editorcore.relayCmd(btn.cmd);
45471 // private used internally
45472 createLink : function(){
45473 Roo.log("create link?");
45474 var url = prompt(this.createLinkText, this.defaultLinkValue);
45475 if(url && url != 'http:/'+'/'){
45476 this.editorcore.relayCmd('createlink', url);
45482 * Protected method that will not generally be called directly. It triggers
45483 * a toolbar update by reading the markup state of the current selection in the editor.
45485 updateToolbar: function(){
45487 if(!this.editorcore.activated){
45488 this.editor.onFirstFocus();
45492 var btns = this.tb.items.map,
45493 doc = this.editorcore.doc,
45494 frameId = this.editorcore.frameId;
45496 if(!this.disable.font && !Roo.isSafari){
45498 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45499 if(name != this.fontSelect.dom.value){
45500 this.fontSelect.dom.value = name;
45504 if(!this.disable.format){
45505 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45506 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45507 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45508 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45510 if(!this.disable.alignments){
45511 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45512 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45513 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45515 if(!Roo.isSafari && !this.disable.lists){
45516 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45517 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45520 var ans = this.editorcore.getAllAncestors();
45521 if (this.formatCombo) {
45524 var store = this.formatCombo.store;
45525 this.formatCombo.setValue("");
45526 for (var i =0; i < ans.length;i++) {
45527 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45529 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45537 // hides menus... - so this cant be on a menu...
45538 Roo.menu.MenuMgr.hideAll();
45540 //this.editorsyncValue();
45544 createFontOptions : function(){
45545 var buf = [], fs = this.fontFamilies, ff, lc;
45549 for(var i = 0, len = fs.length; i< len; i++){
45551 lc = ff.toLowerCase();
45553 '<option value="',lc,'" style="font-family:',ff,';"',
45554 (this.defaultFont == lc ? ' selected="true">' : '>'),
45559 return buf.join('');
45562 toggleSourceEdit : function(sourceEditMode){
45564 Roo.log("toolbar toogle");
45565 if(sourceEditMode === undefined){
45566 sourceEditMode = !this.sourceEditMode;
45568 this.sourceEditMode = sourceEditMode === true;
45569 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45570 // just toggle the button?
45571 if(btn.pressed !== this.sourceEditMode){
45572 btn.toggle(this.sourceEditMode);
45576 if(sourceEditMode){
45577 Roo.log("disabling buttons");
45578 this.tb.items.each(function(item){
45579 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45585 Roo.log("enabling buttons");
45586 if(this.editorcore.initialized){
45587 this.tb.items.each(function(item){
45593 Roo.log("calling toggole on editor");
45594 // tell the editor that it's been pressed..
45595 this.editor.toggleSourceEdit(sourceEditMode);
45599 * Object collection of toolbar tooltips for the buttons in the editor. The key
45600 * is the command id associated with that button and the value is a valid QuickTips object.
45605 title: 'Bold (Ctrl+B)',
45606 text: 'Make the selected text bold.',
45607 cls: 'x-html-editor-tip'
45610 title: 'Italic (Ctrl+I)',
45611 text: 'Make the selected text italic.',
45612 cls: 'x-html-editor-tip'
45620 title: 'Bold (Ctrl+B)',
45621 text: 'Make the selected text bold.',
45622 cls: 'x-html-editor-tip'
45625 title: 'Italic (Ctrl+I)',
45626 text: 'Make the selected text italic.',
45627 cls: 'x-html-editor-tip'
45630 title: 'Underline (Ctrl+U)',
45631 text: 'Underline the selected text.',
45632 cls: 'x-html-editor-tip'
45635 title: 'Strikethrough',
45636 text: 'Strikethrough the selected text.',
45637 cls: 'x-html-editor-tip'
45639 increasefontsize : {
45640 title: 'Grow Text',
45641 text: 'Increase the font size.',
45642 cls: 'x-html-editor-tip'
45644 decreasefontsize : {
45645 title: 'Shrink Text',
45646 text: 'Decrease the font size.',
45647 cls: 'x-html-editor-tip'
45650 title: 'Text Highlight Color',
45651 text: 'Change the background color of the selected text.',
45652 cls: 'x-html-editor-tip'
45655 title: 'Font Color',
45656 text: 'Change the color of the selected text.',
45657 cls: 'x-html-editor-tip'
45660 title: 'Align Text Left',
45661 text: 'Align text to the left.',
45662 cls: 'x-html-editor-tip'
45665 title: 'Center Text',
45666 text: 'Center text in the editor.',
45667 cls: 'x-html-editor-tip'
45670 title: 'Align Text Right',
45671 text: 'Align text to the right.',
45672 cls: 'x-html-editor-tip'
45674 insertunorderedlist : {
45675 title: 'Bullet List',
45676 text: 'Start a bulleted list.',
45677 cls: 'x-html-editor-tip'
45679 insertorderedlist : {
45680 title: 'Numbered List',
45681 text: 'Start a numbered list.',
45682 cls: 'x-html-editor-tip'
45685 title: 'Hyperlink',
45686 text: 'Make the selected text a hyperlink.',
45687 cls: 'x-html-editor-tip'
45690 title: 'Source Edit',
45691 text: 'Switch to source editing mode.',
45692 cls: 'x-html-editor-tip'
45696 onDestroy : function(){
45699 this.tb.items.each(function(item){
45701 item.menu.removeAll();
45703 item.menu.el.destroy();
45711 onFirstFocus: function() {
45712 this.tb.items.each(function(item){
45721 // <script type="text/javascript">
45724 * Ext JS Library 1.1.1
45725 * Copyright(c) 2006-2007, Ext JS, LLC.
45732 * @class Roo.form.HtmlEditor.ToolbarContext
45737 new Roo.form.HtmlEditor({
45740 { xtype: 'ToolbarStandard', styles : {} }
45741 { xtype: 'ToolbarContext', disable : {} }
45747 * @config : {Object} disable List of elements to disable.. (not done yet.)
45748 * @config : {Object} styles Map of styles available.
45752 Roo.form.HtmlEditor.ToolbarContext = function(config)
45755 Roo.apply(this, config);
45756 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45757 // dont call parent... till later.
45758 this.styles = this.styles || {};
45763 Roo.form.HtmlEditor.ToolbarContext.types = {
45775 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45841 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45846 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45856 style : 'fontFamily',
45857 displayField: 'display',
45858 optname : 'font-family',
45907 // should we really allow this??
45908 // should this just be
45919 style : 'fontFamily',
45920 displayField: 'display',
45921 optname : 'font-family',
45928 style : 'fontFamily',
45929 displayField: 'display',
45930 optname : 'font-family',
45937 style : 'fontFamily',
45938 displayField: 'display',
45939 optname : 'font-family',
45950 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
45951 Roo.form.HtmlEditor.ToolbarContext.stores = false;
45953 Roo.form.HtmlEditor.ToolbarContext.options = {
45955 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
45956 [ 'Courier New', 'Courier New'],
45957 [ 'Tahoma', 'Tahoma'],
45958 [ 'Times New Roman,serif', 'Times'],
45959 [ 'Verdana','Verdana' ]
45963 // fixme - these need to be configurable..
45966 //Roo.form.HtmlEditor.ToolbarContext.types
45969 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
45976 editorcore : false,
45978 * @cfg {Object} disable List of toolbar elements to disable
45983 * @cfg {Object} styles List of styles
45984 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
45986 * These must be defined in the page, so they get rendered correctly..
45997 init : function(editor)
45999 this.editor = editor;
46000 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46001 var editorcore = this.editorcore;
46003 var fid = editorcore.frameId;
46005 function btn(id, toggle, handler){
46006 var xid = fid + '-'+ id ;
46010 cls : 'x-btn-icon x-edit-'+id,
46011 enableToggle:toggle !== false,
46012 scope: editorcore, // was editor...
46013 handler:handler||editorcore.relayBtnCmd,
46014 clickEvent:'mousedown',
46015 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46019 // create a new element.
46020 var wdiv = editor.wrap.createChild({
46022 }, editor.wrap.dom.firstChild.nextSibling, true);
46024 // can we do this more than once??
46026 // stop form submits
46029 // disable everything...
46030 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46031 this.toolbars = {};
46033 for (var i in ty) {
46035 this.toolbars[i] = this.buildToolbar(ty[i],i);
46037 this.tb = this.toolbars.BODY;
46039 this.buildFooter();
46040 this.footer.show();
46041 editor.on('hide', function( ) { this.footer.hide() }, this);
46042 editor.on('show', function( ) { this.footer.show() }, this);
46045 this.rendered = true;
46047 // the all the btns;
46048 editor.on('editorevent', this.updateToolbar, this);
46049 // other toolbars need to implement this..
46050 //editor.on('editmodechange', this.updateToolbar, this);
46056 * Protected method that will not generally be called directly. It triggers
46057 * a toolbar update by reading the markup state of the current selection in the editor.
46059 * Note you can force an update by calling on('editorevent', scope, false)
46061 updateToolbar: function(editor,ev,sel){
46064 // capture mouse up - this is handy for selecting images..
46065 // perhaps should go somewhere else...
46066 if(!this.editorcore.activated){
46067 this.editor.onFirstFocus();
46073 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46074 // selectNode - might want to handle IE?
46076 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46077 ev.target && ev.target.tagName == 'IMG') {
46078 // they have click on an image...
46079 // let's see if we can change the selection...
46082 var nodeRange = sel.ownerDocument.createRange();
46084 nodeRange.selectNode(sel);
46086 nodeRange.selectNodeContents(sel);
46088 //nodeRange.collapse(true);
46089 var s = this.editorcore.win.getSelection();
46090 s.removeAllRanges();
46091 s.addRange(nodeRange);
46095 var updateFooter = sel ? false : true;
46098 var ans = this.editorcore.getAllAncestors();
46101 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46104 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46105 sel = sel ? sel : this.editorcore.doc.body;
46106 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46109 // pick a menu that exists..
46110 var tn = sel.tagName.toUpperCase();
46111 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46113 tn = sel.tagName.toUpperCase();
46115 var lastSel = this.tb.selectedNode;
46117 this.tb.selectedNode = sel;
46119 // if current menu does not match..
46121 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46124 ///console.log("show: " + tn);
46125 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46128 this.tb.items.first().el.innerHTML = tn + ': ';
46131 // update attributes
46132 if (this.tb.fields) {
46133 this.tb.fields.each(function(e) {
46135 e.setValue(sel.style[e.stylename]);
46138 e.setValue(sel.getAttribute(e.attrname));
46142 var hasStyles = false;
46143 for(var i in this.styles) {
46150 var st = this.tb.fields.item(0);
46152 st.store.removeAll();
46155 var cn = sel.className.split(/\s+/);
46158 if (this.styles['*']) {
46160 Roo.each(this.styles['*'], function(v) {
46161 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46164 if (this.styles[tn]) {
46165 Roo.each(this.styles[tn], function(v) {
46166 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46170 st.store.loadData(avs);
46174 // flag our selected Node.
46175 this.tb.selectedNode = sel;
46178 Roo.menu.MenuMgr.hideAll();
46182 if (!updateFooter) {
46183 //this.footDisp.dom.innerHTML = '';
46186 // update the footer
46190 this.footerEls = ans.reverse();
46191 Roo.each(this.footerEls, function(a,i) {
46192 if (!a) { return; }
46193 html += html.length ? ' > ' : '';
46195 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46200 var sz = this.footDisp.up('td').getSize();
46201 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46202 this.footDisp.dom.style.marginLeft = '5px';
46204 this.footDisp.dom.style.overflow = 'hidden';
46206 this.footDisp.dom.innerHTML = html;
46208 //this.editorsyncValue();
46215 onDestroy : function(){
46218 this.tb.items.each(function(item){
46220 item.menu.removeAll();
46222 item.menu.el.destroy();
46230 onFirstFocus: function() {
46231 // need to do this for all the toolbars..
46232 this.tb.items.each(function(item){
46236 buildToolbar: function(tlist, nm)
46238 var editor = this.editor;
46239 var editorcore = this.editorcore;
46240 // create a new element.
46241 var wdiv = editor.wrap.createChild({
46243 }, editor.wrap.dom.firstChild.nextSibling, true);
46246 var tb = new Roo.Toolbar(wdiv);
46249 tb.add(nm+ ": ");
46252 for(var i in this.styles) {
46257 if (styles && styles.length) {
46259 // this needs a multi-select checkbox...
46260 tb.addField( new Roo.form.ComboBox({
46261 store: new Roo.data.SimpleStore({
46263 fields: ['val', 'selected'],
46266 name : '-roo-edit-className',
46267 attrname : 'className',
46268 displayField: 'val',
46272 triggerAction: 'all',
46273 emptyText:'Select Style',
46274 selectOnFocus:true,
46277 'select': function(c, r, i) {
46278 // initial support only for on class per el..
46279 tb.selectedNode.className = r ? r.get('val') : '';
46280 editorcore.syncValue();
46287 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46288 var tbops = tbc.options;
46290 for (var i in tlist) {
46292 var item = tlist[i];
46293 tb.add(item.title + ": ");
46296 //optname == used so you can configure the options available..
46297 var opts = item.opts ? item.opts : false;
46298 if (item.optname) {
46299 opts = tbops[item.optname];
46304 // opts == pulldown..
46305 tb.addField( new Roo.form.ComboBox({
46306 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46308 fields: ['val', 'display'],
46311 name : '-roo-edit-' + i,
46313 stylename : item.style ? item.style : false,
46314 displayField: item.displayField ? item.displayField : 'val',
46315 valueField : 'val',
46317 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46319 triggerAction: 'all',
46320 emptyText:'Select',
46321 selectOnFocus:true,
46322 width: item.width ? item.width : 130,
46324 'select': function(c, r, i) {
46326 tb.selectedNode.style[c.stylename] = r.get('val');
46329 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46338 tb.addField( new Roo.form.TextField({
46341 //allowBlank:false,
46346 tb.addField( new Roo.form.TextField({
46347 name: '-roo-edit-' + i,
46354 'change' : function(f, nv, ov) {
46355 tb.selectedNode.setAttribute(f.attrname, nv);
46356 editorcore.syncValue();
46369 text: 'Stylesheets',
46372 click : function ()
46374 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46382 text: 'Remove Tag',
46385 click : function ()
46388 // undo does not work.
46390 var sn = tb.selectedNode;
46392 var pn = sn.parentNode;
46394 var stn = sn.childNodes[0];
46395 var en = sn.childNodes[sn.childNodes.length - 1 ];
46396 while (sn.childNodes.length) {
46397 var node = sn.childNodes[0];
46398 sn.removeChild(node);
46400 pn.insertBefore(node, sn);
46403 pn.removeChild(sn);
46404 var range = editorcore.createRange();
46406 range.setStart(stn,0);
46407 range.setEnd(en,0); //????
46408 //range.selectNode(sel);
46411 var selection = editorcore.getSelection();
46412 selection.removeAllRanges();
46413 selection.addRange(range);
46417 //_this.updateToolbar(null, null, pn);
46418 _this.updateToolbar(null, null, null);
46419 _this.footDisp.dom.innerHTML = '';
46429 tb.el.on('click', function(e){
46430 e.preventDefault(); // what does this do?
46432 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46435 // dont need to disable them... as they will get hidden
46440 buildFooter : function()
46443 var fel = this.editor.wrap.createChild();
46444 this.footer = new Roo.Toolbar(fel);
46445 // toolbar has scrolly on left / right?
46446 var footDisp= new Roo.Toolbar.Fill();
46452 handler : function() {
46453 _t.footDisp.scrollTo('left',0,true)
46457 this.footer.add( footDisp );
46462 handler : function() {
46464 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46468 var fel = Roo.get(footDisp.el);
46469 fel.addClass('x-editor-context');
46470 this.footDispWrap = fel;
46471 this.footDispWrap.overflow = 'hidden';
46473 this.footDisp = fel.createChild();
46474 this.footDispWrap.on('click', this.onContextClick, this)
46478 onContextClick : function (ev,dom)
46480 ev.preventDefault();
46481 var cn = dom.className;
46483 if (!cn.match(/x-ed-loc-/)) {
46486 var n = cn.split('-').pop();
46487 var ans = this.footerEls;
46491 var range = this.editorcore.createRange();
46493 range.selectNodeContents(sel);
46494 //range.selectNode(sel);
46497 var selection = this.editorcore.getSelection();
46498 selection.removeAllRanges();
46499 selection.addRange(range);
46503 this.updateToolbar(null, null, sel);
46520 * Ext JS Library 1.1.1
46521 * Copyright(c) 2006-2007, Ext JS, LLC.
46523 * Originally Released Under LGPL - original licence link has changed is not relivant.
46526 * <script type="text/javascript">
46530 * @class Roo.form.BasicForm
46531 * @extends Roo.util.Observable
46532 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46534 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46535 * @param {Object} config Configuration options
46537 Roo.form.BasicForm = function(el, config){
46538 this.allItems = [];
46539 this.childForms = [];
46540 Roo.apply(this, config);
46542 * The Roo.form.Field items in this form.
46543 * @type MixedCollection
46547 this.items = new Roo.util.MixedCollection(false, function(o){
46548 return o.id || (o.id = Roo.id());
46552 * @event beforeaction
46553 * Fires before any action is performed. Return false to cancel the action.
46554 * @param {Form} this
46555 * @param {Action} action The action to be performed
46557 beforeaction: true,
46559 * @event actionfailed
46560 * Fires when an action fails.
46561 * @param {Form} this
46562 * @param {Action} action The action that failed
46564 actionfailed : true,
46566 * @event actioncomplete
46567 * Fires when an action is completed.
46568 * @param {Form} this
46569 * @param {Action} action The action that completed
46571 actioncomplete : true
46576 Roo.form.BasicForm.superclass.constructor.call(this);
46579 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46581 * @cfg {String} method
46582 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46585 * @cfg {DataReader} reader
46586 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46587 * This is optional as there is built-in support for processing JSON.
46590 * @cfg {DataReader} errorReader
46591 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46592 * This is completely optional as there is built-in support for processing JSON.
46595 * @cfg {String} url
46596 * The URL to use for form actions if one isn't supplied in the action options.
46599 * @cfg {Boolean} fileUpload
46600 * Set to true if this form is a file upload.
46604 * @cfg {Object} baseParams
46605 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46610 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46615 activeAction : null,
46618 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46619 * or setValues() data instead of when the form was first created.
46621 trackResetOnLoad : false,
46625 * childForms - used for multi-tab forms
46628 childForms : false,
46631 * allItems - full list of fields.
46637 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46638 * element by passing it or its id or mask the form itself by passing in true.
46641 waitMsgTarget : false,
46644 initEl : function(el){
46645 this.el = Roo.get(el);
46646 this.id = this.el.id || Roo.id();
46647 this.el.on('submit', this.onSubmit, this);
46648 this.el.addClass('x-form');
46652 onSubmit : function(e){
46657 * Returns true if client-side validation on the form is successful.
46660 isValid : function(){
46662 this.items.each(function(f){
46671 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46674 isDirty : function(){
46676 this.items.each(function(f){
46686 * Returns true if any fields in this form have changed since their original load. (New version)
46690 hasChanged : function()
46693 this.items.each(function(f){
46694 if(f.hasChanged()){
46703 * Resets all hasChanged to 'false' -
46704 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46705 * So hasChanged storage is only to be used for this purpose
46708 resetHasChanged : function()
46710 this.items.each(function(f){
46711 f.resetHasChanged();
46718 * Performs a predefined action (submit or load) or custom actions you define on this form.
46719 * @param {String} actionName The name of the action type
46720 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46721 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46722 * accept other config options):
46724 Property Type Description
46725 ---------------- --------------- ----------------------------------------------------------------------------------
46726 url String The url for the action (defaults to the form's url)
46727 method String The form method to use (defaults to the form's method, or POST if not defined)
46728 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46729 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46730 validate the form on the client (defaults to false)
46732 * @return {BasicForm} this
46734 doAction : function(action, options){
46735 if(typeof action == 'string'){
46736 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46738 if(this.fireEvent('beforeaction', this, action) !== false){
46739 this.beforeAction(action);
46740 action.run.defer(100, action);
46746 * Shortcut to do a submit action.
46747 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46748 * @return {BasicForm} this
46750 submit : function(options){
46751 this.doAction('submit', options);
46756 * Shortcut to do a load action.
46757 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46758 * @return {BasicForm} this
46760 load : function(options){
46761 this.doAction('load', options);
46766 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46767 * @param {Record} record The record to edit
46768 * @return {BasicForm} this
46770 updateRecord : function(record){
46771 record.beginEdit();
46772 var fs = record.fields;
46773 fs.each(function(f){
46774 var field = this.findField(f.name);
46776 record.set(f.name, field.getValue());
46784 * Loads an Roo.data.Record into this form.
46785 * @param {Record} record The record to load
46786 * @return {BasicForm} this
46788 loadRecord : function(record){
46789 this.setValues(record.data);
46794 beforeAction : function(action){
46795 var o = action.options;
46798 if(this.waitMsgTarget === true){
46799 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46800 }else if(this.waitMsgTarget){
46801 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46802 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46804 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46810 afterAction : function(action, success){
46811 this.activeAction = null;
46812 var o = action.options;
46814 if(this.waitMsgTarget === true){
46816 }else if(this.waitMsgTarget){
46817 this.waitMsgTarget.unmask();
46819 Roo.MessageBox.updateProgress(1);
46820 Roo.MessageBox.hide();
46827 Roo.callback(o.success, o.scope, [this, action]);
46828 this.fireEvent('actioncomplete', this, action);
46832 // failure condition..
46833 // we have a scenario where updates need confirming.
46834 // eg. if a locking scenario exists..
46835 // we look for { errors : { needs_confirm : true }} in the response.
46837 (typeof(action.result) != 'undefined') &&
46838 (typeof(action.result.errors) != 'undefined') &&
46839 (typeof(action.result.errors.needs_confirm) != 'undefined')
46842 Roo.MessageBox.confirm(
46843 "Change requires confirmation",
46844 action.result.errorMsg,
46849 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46859 Roo.callback(o.failure, o.scope, [this, action]);
46860 // show an error message if no failed handler is set..
46861 if (!this.hasListener('actionfailed')) {
46862 Roo.MessageBox.alert("Error",
46863 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46864 action.result.errorMsg :
46865 "Saving Failed, please check your entries or try again"
46869 this.fireEvent('actionfailed', this, action);
46875 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46876 * @param {String} id The value to search for
46879 findField : function(id){
46880 var field = this.items.get(id);
46882 this.items.each(function(f){
46883 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
46889 return field || null;
46893 * Add a secondary form to this one,
46894 * Used to provide tabbed forms. One form is primary, with hidden values
46895 * which mirror the elements from the other forms.
46897 * @param {Roo.form.Form} form to add.
46900 addForm : function(form)
46903 if (this.childForms.indexOf(form) > -1) {
46907 this.childForms.push(form);
46909 Roo.each(form.allItems, function (fe) {
46911 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
46912 if (this.findField(n)) { // already added..
46915 var add = new Roo.form.Hidden({
46918 add.render(this.el);
46925 * Mark fields in this form invalid in bulk.
46926 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
46927 * @return {BasicForm} this
46929 markInvalid : function(errors){
46930 if(errors instanceof Array){
46931 for(var i = 0, len = errors.length; i < len; i++){
46932 var fieldError = errors[i];
46933 var f = this.findField(fieldError.id);
46935 f.markInvalid(fieldError.msg);
46941 if(typeof errors[id] != 'function' && (field = this.findField(id))){
46942 field.markInvalid(errors[id]);
46946 Roo.each(this.childForms || [], function (f) {
46947 f.markInvalid(errors);
46954 * Set values for fields in this form in bulk.
46955 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
46956 * @return {BasicForm} this
46958 setValues : function(values){
46959 if(values instanceof Array){ // array of objects
46960 for(var i = 0, len = values.length; i < len; i++){
46962 var f = this.findField(v.id);
46964 f.setValue(v.value);
46965 if(this.trackResetOnLoad){
46966 f.originalValue = f.getValue();
46970 }else{ // object hash
46973 if(typeof values[id] != 'function' && (field = this.findField(id))){
46975 if (field.setFromData &&
46976 field.valueField &&
46977 field.displayField &&
46978 // combos' with local stores can
46979 // be queried via setValue()
46980 // to set their value..
46981 (field.store && !field.store.isLocal)
46985 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
46986 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
46987 field.setFromData(sd);
46990 field.setValue(values[id]);
46994 if(this.trackResetOnLoad){
46995 field.originalValue = field.getValue();
47000 this.resetHasChanged();
47003 Roo.each(this.childForms || [], function (f) {
47004 f.setValues(values);
47005 f.resetHasChanged();
47012 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47013 * they are returned as an array.
47014 * @param {Boolean} asString
47017 getValues : function(asString){
47018 if (this.childForms) {
47019 // copy values from the child forms
47020 Roo.each(this.childForms, function (f) {
47021 this.setValues(f.getValues());
47027 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47028 if(asString === true){
47031 return Roo.urlDecode(fs);
47035 * Returns the fields in this form as an object with key/value pairs.
47036 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47039 getFieldValues : function(with_hidden)
47041 if (this.childForms) {
47042 // copy values from the child forms
47043 // should this call getFieldValues - probably not as we do not currently copy
47044 // hidden fields when we generate..
47045 Roo.each(this.childForms, function (f) {
47046 this.setValues(f.getValues());
47051 this.items.each(function(f){
47052 if (!f.getName()) {
47055 var v = f.getValue();
47056 if (f.inputType =='radio') {
47057 if (typeof(ret[f.getName()]) == 'undefined') {
47058 ret[f.getName()] = ''; // empty..
47061 if (!f.el.dom.checked) {
47065 v = f.el.dom.value;
47069 // not sure if this supported any more..
47070 if ((typeof(v) == 'object') && f.getRawValue) {
47071 v = f.getRawValue() ; // dates..
47073 // combo boxes where name != hiddenName...
47074 if (f.name != f.getName()) {
47075 ret[f.name] = f.getRawValue();
47077 ret[f.getName()] = v;
47084 * Clears all invalid messages in this form.
47085 * @return {BasicForm} this
47087 clearInvalid : function(){
47088 this.items.each(function(f){
47092 Roo.each(this.childForms || [], function (f) {
47101 * Resets this form.
47102 * @return {BasicForm} this
47104 reset : function(){
47105 this.items.each(function(f){
47109 Roo.each(this.childForms || [], function (f) {
47112 this.resetHasChanged();
47118 * Add Roo.form components to this form.
47119 * @param {Field} field1
47120 * @param {Field} field2 (optional)
47121 * @param {Field} etc (optional)
47122 * @return {BasicForm} this
47125 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47131 * Removes a field from the items collection (does NOT remove its markup).
47132 * @param {Field} field
47133 * @return {BasicForm} this
47135 remove : function(field){
47136 this.items.remove(field);
47141 * Looks at the fields in this form, checks them for an id attribute,
47142 * and calls applyTo on the existing dom element with that id.
47143 * @return {BasicForm} this
47145 render : function(){
47146 this.items.each(function(f){
47147 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47155 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47156 * @param {Object} values
47157 * @return {BasicForm} this
47159 applyToFields : function(o){
47160 this.items.each(function(f){
47167 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47168 * @param {Object} values
47169 * @return {BasicForm} this
47171 applyIfToFields : function(o){
47172 this.items.each(function(f){
47180 Roo.BasicForm = Roo.form.BasicForm;/*
47182 * Ext JS Library 1.1.1
47183 * Copyright(c) 2006-2007, Ext JS, LLC.
47185 * Originally Released Under LGPL - original licence link has changed is not relivant.
47188 * <script type="text/javascript">
47192 * @class Roo.form.Form
47193 * @extends Roo.form.BasicForm
47194 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47196 * @param {Object} config Configuration options
47198 Roo.form.Form = function(config){
47200 if (config.items) {
47201 xitems = config.items;
47202 delete config.items;
47206 Roo.form.Form.superclass.constructor.call(this, null, config);
47207 this.url = this.url || this.action;
47209 this.root = new Roo.form.Layout(Roo.applyIf({
47213 this.active = this.root;
47215 * Array of all the buttons that have been added to this form via {@link addButton}
47219 this.allItems = [];
47222 * @event clientvalidation
47223 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47224 * @param {Form} this
47225 * @param {Boolean} valid true if the form has passed client-side validation
47227 clientvalidation: true,
47230 * Fires when the form is rendered
47231 * @param {Roo.form.Form} form
47236 if (this.progressUrl) {
47237 // push a hidden field onto the list of fields..
47241 name : 'UPLOAD_IDENTIFIER'
47246 Roo.each(xitems, this.addxtype, this);
47252 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47254 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47257 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47260 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47262 buttonAlign:'center',
47265 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47270 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47271 * This property cascades to child containers if not set.
47276 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47277 * fires a looping event with that state. This is required to bind buttons to the valid
47278 * state using the config value formBind:true on the button.
47280 monitorValid : false,
47283 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47288 * @cfg {String} progressUrl - Url to return progress data
47291 progressUrl : false,
47294 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47295 * fields are added and the column is closed. If no fields are passed the column remains open
47296 * until end() is called.
47297 * @param {Object} config The config to pass to the column
47298 * @param {Field} field1 (optional)
47299 * @param {Field} field2 (optional)
47300 * @param {Field} etc (optional)
47301 * @return Column The column container object
47303 column : function(c){
47304 var col = new Roo.form.Column(c);
47306 if(arguments.length > 1){ // duplicate code required because of Opera
47307 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47314 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47315 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47316 * until end() is called.
47317 * @param {Object} config The config to pass to the fieldset
47318 * @param {Field} field1 (optional)
47319 * @param {Field} field2 (optional)
47320 * @param {Field} etc (optional)
47321 * @return FieldSet The fieldset container object
47323 fieldset : function(c){
47324 var fs = new Roo.form.FieldSet(c);
47326 if(arguments.length > 1){ // duplicate code required because of Opera
47327 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47334 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47335 * fields are added and the container is closed. If no fields are passed the container remains open
47336 * until end() is called.
47337 * @param {Object} config The config to pass to the Layout
47338 * @param {Field} field1 (optional)
47339 * @param {Field} field2 (optional)
47340 * @param {Field} etc (optional)
47341 * @return Layout The container object
47343 container : function(c){
47344 var l = new Roo.form.Layout(c);
47346 if(arguments.length > 1){ // duplicate code required because of Opera
47347 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47354 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47355 * @param {Object} container A Roo.form.Layout or subclass of Layout
47356 * @return {Form} this
47358 start : function(c){
47359 // cascade label info
47360 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47361 this.active.stack.push(c);
47362 c.ownerCt = this.active;
47368 * Closes the current open container
47369 * @return {Form} this
47372 if(this.active == this.root){
47375 this.active = this.active.ownerCt;
47380 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47381 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47382 * as the label of the field.
47383 * @param {Field} field1
47384 * @param {Field} field2 (optional)
47385 * @param {Field} etc. (optional)
47386 * @return {Form} this
47389 this.active.stack.push.apply(this.active.stack, arguments);
47390 this.allItems.push.apply(this.allItems,arguments);
47392 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47393 if(a[i].isFormField){
47398 Roo.form.Form.superclass.add.apply(this, r);
47408 * Find any element that has been added to a form, using it's ID or name
47409 * This can include framesets, columns etc. along with regular fields..
47410 * @param {String} id - id or name to find.
47412 * @return {Element} e - or false if nothing found.
47414 findbyId : function(id)
47420 Roo.each(this.allItems, function(f){
47421 if (f.id == id || f.name == id ){
47432 * Render this form into the passed container. This should only be called once!
47433 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47434 * @return {Form} this
47436 render : function(ct)
47442 var o = this.autoCreate || {
47444 method : this.method || 'POST',
47445 id : this.id || Roo.id()
47447 this.initEl(ct.createChild(o));
47449 this.root.render(this.el);
47453 this.items.each(function(f){
47454 f.render('x-form-el-'+f.id);
47457 if(this.buttons.length > 0){
47458 // tables are required to maintain order and for correct IE layout
47459 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47460 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47461 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47463 var tr = tb.getElementsByTagName('tr')[0];
47464 for(var i = 0, len = this.buttons.length; i < len; i++) {
47465 var b = this.buttons[i];
47466 var td = document.createElement('td');
47467 td.className = 'x-form-btn-td';
47468 b.render(tr.appendChild(td));
47471 if(this.monitorValid){ // initialize after render
47472 this.startMonitoring();
47474 this.fireEvent('rendered', this);
47479 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47480 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47481 * object or a valid Roo.DomHelper element config
47482 * @param {Function} handler The function called when the button is clicked
47483 * @param {Object} scope (optional) The scope of the handler function
47484 * @return {Roo.Button}
47486 addButton : function(config, handler, scope){
47490 minWidth: this.minButtonWidth,
47493 if(typeof config == "string"){
47496 Roo.apply(bc, config);
47498 var btn = new Roo.Button(null, bc);
47499 this.buttons.push(btn);
47504 * Adds a series of form elements (using the xtype property as the factory method.
47505 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47506 * @param {Object} config
47509 addxtype : function()
47511 var ar = Array.prototype.slice.call(arguments, 0);
47513 for(var i = 0; i < ar.length; i++) {
47515 continue; // skip -- if this happends something invalid got sent, we
47516 // should ignore it, as basically that interface element will not show up
47517 // and that should be pretty obvious!!
47520 if (Roo.form[ar[i].xtype]) {
47522 var fe = Roo.factory(ar[i], Roo.form);
47528 fe.store.form = this;
47533 this.allItems.push(fe);
47534 if (fe.items && fe.addxtype) {
47535 fe.addxtype.apply(fe, fe.items);
47545 // console.log('adding ' + ar[i].xtype);
47547 if (ar[i].xtype == 'Button') {
47548 //console.log('adding button');
47549 //console.log(ar[i]);
47550 this.addButton(ar[i]);
47551 this.allItems.push(fe);
47555 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47556 alert('end is not supported on xtype any more, use items');
47558 // //console.log('adding end');
47566 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47567 * option "monitorValid"
47569 startMonitoring : function(){
47572 Roo.TaskMgr.start({
47573 run : this.bindHandler,
47574 interval : this.monitorPoll || 200,
47581 * Stops monitoring of the valid state of this form
47583 stopMonitoring : function(){
47584 this.bound = false;
47588 bindHandler : function(){
47590 return false; // stops binding
47593 this.items.each(function(f){
47594 if(!f.isValid(true)){
47599 for(var i = 0, len = this.buttons.length; i < len; i++){
47600 var btn = this.buttons[i];
47601 if(btn.formBind === true && btn.disabled === valid){
47602 btn.setDisabled(!valid);
47605 this.fireEvent('clientvalidation', this, valid);
47619 Roo.Form = Roo.form.Form;
47622 * Ext JS Library 1.1.1
47623 * Copyright(c) 2006-2007, Ext JS, LLC.
47625 * Originally Released Under LGPL - original licence link has changed is not relivant.
47628 * <script type="text/javascript">
47631 // as we use this in bootstrap.
47632 Roo.namespace('Roo.form');
47634 * @class Roo.form.Action
47635 * Internal Class used to handle form actions
47637 * @param {Roo.form.BasicForm} el The form element or its id
47638 * @param {Object} config Configuration options
47643 // define the action interface
47644 Roo.form.Action = function(form, options){
47646 this.options = options || {};
47649 * Client Validation Failed
47652 Roo.form.Action.CLIENT_INVALID = 'client';
47654 * Server Validation Failed
47657 Roo.form.Action.SERVER_INVALID = 'server';
47659 * Connect to Server Failed
47662 Roo.form.Action.CONNECT_FAILURE = 'connect';
47664 * Reading Data from Server Failed
47667 Roo.form.Action.LOAD_FAILURE = 'load';
47669 Roo.form.Action.prototype = {
47671 failureType : undefined,
47672 response : undefined,
47673 result : undefined,
47675 // interface method
47676 run : function(options){
47680 // interface method
47681 success : function(response){
47685 // interface method
47686 handleResponse : function(response){
47690 // default connection failure
47691 failure : function(response){
47693 this.response = response;
47694 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47695 this.form.afterAction(this, false);
47698 processResponse : function(response){
47699 this.response = response;
47700 if(!response.responseText){
47703 this.result = this.handleResponse(response);
47704 return this.result;
47707 // utility functions used internally
47708 getUrl : function(appendParams){
47709 var url = this.options.url || this.form.url || this.form.el.dom.action;
47711 var p = this.getParams();
47713 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47719 getMethod : function(){
47720 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47723 getParams : function(){
47724 var bp = this.form.baseParams;
47725 var p = this.options.params;
47727 if(typeof p == "object"){
47728 p = Roo.urlEncode(Roo.applyIf(p, bp));
47729 }else if(typeof p == 'string' && bp){
47730 p += '&' + Roo.urlEncode(bp);
47733 p = Roo.urlEncode(bp);
47738 createCallback : function(){
47740 success: this.success,
47741 failure: this.failure,
47743 timeout: (this.form.timeout*1000),
47744 upload: this.form.fileUpload ? this.success : undefined
47749 Roo.form.Action.Submit = function(form, options){
47750 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47753 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47756 haveProgress : false,
47757 uploadComplete : false,
47759 // uploadProgress indicator.
47760 uploadProgress : function()
47762 if (!this.form.progressUrl) {
47766 if (!this.haveProgress) {
47767 Roo.MessageBox.progress("Uploading", "Uploading");
47769 if (this.uploadComplete) {
47770 Roo.MessageBox.hide();
47774 this.haveProgress = true;
47776 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47778 var c = new Roo.data.Connection();
47780 url : this.form.progressUrl,
47785 success : function(req){
47786 //console.log(data);
47790 rdata = Roo.decode(req.responseText)
47792 Roo.log("Invalid data from server..");
47796 if (!rdata || !rdata.success) {
47798 Roo.MessageBox.alert(Roo.encode(rdata));
47801 var data = rdata.data;
47803 if (this.uploadComplete) {
47804 Roo.MessageBox.hide();
47809 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47810 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47813 this.uploadProgress.defer(2000,this);
47816 failure: function(data) {
47817 Roo.log('progress url failed ');
47828 // run get Values on the form, so it syncs any secondary forms.
47829 this.form.getValues();
47831 var o = this.options;
47832 var method = this.getMethod();
47833 var isPost = method == 'POST';
47834 if(o.clientValidation === false || this.form.isValid()){
47836 if (this.form.progressUrl) {
47837 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47838 (new Date() * 1) + '' + Math.random());
47843 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47844 form:this.form.el.dom,
47845 url:this.getUrl(!isPost),
47847 params:isPost ? this.getParams() : null,
47848 isUpload: this.form.fileUpload
47851 this.uploadProgress();
47853 }else if (o.clientValidation !== false){ // client validation failed
47854 this.failureType = Roo.form.Action.CLIENT_INVALID;
47855 this.form.afterAction(this, false);
47859 success : function(response)
47861 this.uploadComplete= true;
47862 if (this.haveProgress) {
47863 Roo.MessageBox.hide();
47867 var result = this.processResponse(response);
47868 if(result === true || result.success){
47869 this.form.afterAction(this, true);
47873 this.form.markInvalid(result.errors);
47874 this.failureType = Roo.form.Action.SERVER_INVALID;
47876 this.form.afterAction(this, false);
47878 failure : function(response)
47880 this.uploadComplete= true;
47881 if (this.haveProgress) {
47882 Roo.MessageBox.hide();
47885 this.response = response;
47886 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47887 this.form.afterAction(this, false);
47890 handleResponse : function(response){
47891 if(this.form.errorReader){
47892 var rs = this.form.errorReader.read(response);
47895 for(var i = 0, len = rs.records.length; i < len; i++) {
47896 var r = rs.records[i];
47897 errors[i] = r.data;
47900 if(errors.length < 1){
47904 success : rs.success,
47910 ret = Roo.decode(response.responseText);
47914 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
47924 Roo.form.Action.Load = function(form, options){
47925 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
47926 this.reader = this.form.reader;
47929 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
47934 Roo.Ajax.request(Roo.apply(
47935 this.createCallback(), {
47936 method:this.getMethod(),
47937 url:this.getUrl(false),
47938 params:this.getParams()
47942 success : function(response){
47944 var result = this.processResponse(response);
47945 if(result === true || !result.success || !result.data){
47946 this.failureType = Roo.form.Action.LOAD_FAILURE;
47947 this.form.afterAction(this, false);
47950 this.form.clearInvalid();
47951 this.form.setValues(result.data);
47952 this.form.afterAction(this, true);
47955 handleResponse : function(response){
47956 if(this.form.reader){
47957 var rs = this.form.reader.read(response);
47958 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
47960 success : rs.success,
47964 return Roo.decode(response.responseText);
47968 Roo.form.Action.ACTION_TYPES = {
47969 'load' : Roo.form.Action.Load,
47970 'submit' : Roo.form.Action.Submit
47973 * Ext JS Library 1.1.1
47974 * Copyright(c) 2006-2007, Ext JS, LLC.
47976 * Originally Released Under LGPL - original licence link has changed is not relivant.
47979 * <script type="text/javascript">
47983 * @class Roo.form.Layout
47984 * @extends Roo.Component
47985 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
47987 * @param {Object} config Configuration options
47989 Roo.form.Layout = function(config){
47991 if (config.items) {
47992 xitems = config.items;
47993 delete config.items;
47995 Roo.form.Layout.superclass.constructor.call(this, config);
47997 Roo.each(xitems, this.addxtype, this);
48001 Roo.extend(Roo.form.Layout, Roo.Component, {
48003 * @cfg {String/Object} autoCreate
48004 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
48007 * @cfg {String/Object/Function} style
48008 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
48009 * a function which returns such a specification.
48012 * @cfg {String} labelAlign
48013 * Valid values are "left," "top" and "right" (defaults to "left")
48016 * @cfg {Number} labelWidth
48017 * Fixed width in pixels of all field labels (defaults to undefined)
48020 * @cfg {Boolean} clear
48021 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
48025 * @cfg {String} labelSeparator
48026 * The separator to use after field labels (defaults to ':')
48028 labelSeparator : ':',
48030 * @cfg {Boolean} hideLabels
48031 * True to suppress the display of field labels in this layout (defaults to false)
48033 hideLabels : false,
48036 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48041 onRender : function(ct, position){
48042 if(this.el){ // from markup
48043 this.el = Roo.get(this.el);
48044 }else { // generate
48045 var cfg = this.getAutoCreate();
48046 this.el = ct.createChild(cfg, position);
48049 this.el.applyStyles(this.style);
48051 if(this.labelAlign){
48052 this.el.addClass('x-form-label-'+this.labelAlign);
48054 if(this.hideLabels){
48055 this.labelStyle = "display:none";
48056 this.elementStyle = "padding-left:0;";
48058 if(typeof this.labelWidth == 'number'){
48059 this.labelStyle = "width:"+this.labelWidth+"px;";
48060 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48062 if(this.labelAlign == 'top'){
48063 this.labelStyle = "width:auto;";
48064 this.elementStyle = "padding-left:0;";
48067 var stack = this.stack;
48068 var slen = stack.length;
48070 if(!this.fieldTpl){
48071 var t = new Roo.Template(
48072 '<div class="x-form-item {5}">',
48073 '<label for="{0}" style="{2}">{1}{4}</label>',
48074 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48076 '</div><div class="x-form-clear-left"></div>'
48078 t.disableFormats = true;
48080 Roo.form.Layout.prototype.fieldTpl = t;
48082 for(var i = 0; i < slen; i++) {
48083 if(stack[i].isFormField){
48084 this.renderField(stack[i]);
48086 this.renderComponent(stack[i]);
48091 this.el.createChild({cls:'x-form-clear'});
48096 renderField : function(f){
48097 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48100 f.labelStyle||this.labelStyle||'', //2
48101 this.elementStyle||'', //3
48102 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48103 f.itemCls||this.itemCls||'' //5
48104 ], true).getPrevSibling());
48108 renderComponent : function(c){
48109 c.render(c.isLayout ? this.el : this.el.createChild());
48112 * Adds a object form elements (using the xtype property as the factory method.)
48113 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48114 * @param {Object} config
48116 addxtype : function(o)
48118 // create the lement.
48119 o.form = this.form;
48120 var fe = Roo.factory(o, Roo.form);
48121 this.form.allItems.push(fe);
48122 this.stack.push(fe);
48124 if (fe.isFormField) {
48125 this.form.items.add(fe);
48133 * @class Roo.form.Column
48134 * @extends Roo.form.Layout
48135 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48137 * @param {Object} config Configuration options
48139 Roo.form.Column = function(config){
48140 Roo.form.Column.superclass.constructor.call(this, config);
48143 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48145 * @cfg {Number/String} width
48146 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48149 * @cfg {String/Object} autoCreate
48150 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48154 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48157 onRender : function(ct, position){
48158 Roo.form.Column.superclass.onRender.call(this, ct, position);
48160 this.el.setWidth(this.width);
48167 * @class Roo.form.Row
48168 * @extends Roo.form.Layout
48169 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48171 * @param {Object} config Configuration options
48175 Roo.form.Row = function(config){
48176 Roo.form.Row.superclass.constructor.call(this, config);
48179 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48181 * @cfg {Number/String} width
48182 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48185 * @cfg {Number/String} height
48186 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48188 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48192 onRender : function(ct, position){
48193 //console.log('row render');
48195 var t = new Roo.Template(
48196 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48197 '<label for="{0}" style="{2}">{1}{4}</label>',
48198 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48202 t.disableFormats = true;
48204 Roo.form.Layout.prototype.rowTpl = t;
48206 this.fieldTpl = this.rowTpl;
48208 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48209 var labelWidth = 100;
48211 if ((this.labelAlign != 'top')) {
48212 if (typeof this.labelWidth == 'number') {
48213 labelWidth = this.labelWidth
48215 this.padWidth = 20 + labelWidth;
48219 Roo.form.Column.superclass.onRender.call(this, ct, position);
48221 this.el.setWidth(this.width);
48224 this.el.setHeight(this.height);
48229 renderField : function(f){
48230 f.fieldEl = this.fieldTpl.append(this.el, [
48231 f.id, f.fieldLabel,
48232 f.labelStyle||this.labelStyle||'',
48233 this.elementStyle||'',
48234 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48235 f.itemCls||this.itemCls||'',
48236 f.width ? f.width + this.padWidth : 160 + this.padWidth
48243 * @class Roo.form.FieldSet
48244 * @extends Roo.form.Layout
48245 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48247 * @param {Object} config Configuration options
48249 Roo.form.FieldSet = function(config){
48250 Roo.form.FieldSet.superclass.constructor.call(this, config);
48253 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48255 * @cfg {String} legend
48256 * The text to display as the legend for the FieldSet (defaults to '')
48259 * @cfg {String/Object} autoCreate
48260 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48264 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48267 onRender : function(ct, position){
48268 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48270 this.setLegend(this.legend);
48275 setLegend : function(text){
48277 this.el.child('legend').update(text);
48282 * Ext JS Library 1.1.1
48283 * Copyright(c) 2006-2007, Ext JS, LLC.
48285 * Originally Released Under LGPL - original licence link has changed is not relivant.
48288 * <script type="text/javascript">
48291 * @class Roo.form.VTypes
48292 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48295 Roo.form.VTypes = function(){
48296 // closure these in so they are only created once.
48297 var alpha = /^[a-zA-Z_]+$/;
48298 var alphanum = /^[a-zA-Z0-9_]+$/;
48299 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48300 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48302 // All these messages and functions are configurable
48305 * The function used to validate email addresses
48306 * @param {String} value The email address
48308 'email' : function(v){
48309 return email.test(v);
48312 * The error text to display when the email validation function returns false
48315 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48317 * The keystroke filter mask to be applied on email input
48320 'emailMask' : /[a-z0-9_\.\-@]/i,
48323 * The function used to validate URLs
48324 * @param {String} value The URL
48326 'url' : function(v){
48327 return url.test(v);
48330 * The error text to display when the url validation function returns false
48333 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48336 * The function used to validate alpha values
48337 * @param {String} value The value
48339 'alpha' : function(v){
48340 return alpha.test(v);
48343 * The error text to display when the alpha validation function returns false
48346 'alphaText' : 'This field should only contain letters and _',
48348 * The keystroke filter mask to be applied on alpha input
48351 'alphaMask' : /[a-z_]/i,
48354 * The function used to validate alphanumeric values
48355 * @param {String} value The value
48357 'alphanum' : function(v){
48358 return alphanum.test(v);
48361 * The error text to display when the alphanumeric validation function returns false
48364 'alphanumText' : 'This field should only contain letters, numbers and _',
48366 * The keystroke filter mask to be applied on alphanumeric input
48369 'alphanumMask' : /[a-z0-9_]/i
48371 }();//<script type="text/javascript">
48374 * @class Roo.form.FCKeditor
48375 * @extends Roo.form.TextArea
48376 * Wrapper around the FCKEditor http://www.fckeditor.net
48378 * Creates a new FCKeditor
48379 * @param {Object} config Configuration options
48381 Roo.form.FCKeditor = function(config){
48382 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48385 * @event editorinit
48386 * Fired when the editor is initialized - you can add extra handlers here..
48387 * @param {FCKeditor} this
48388 * @param {Object} the FCK object.
48395 Roo.form.FCKeditor.editors = { };
48396 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48398 //defaultAutoCreate : {
48399 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48403 * @cfg {Object} fck options - see fck manual for details.
48408 * @cfg {Object} fck toolbar set (Basic or Default)
48410 toolbarSet : 'Basic',
48412 * @cfg {Object} fck BasePath
48414 basePath : '/fckeditor/',
48422 onRender : function(ct, position)
48425 this.defaultAutoCreate = {
48427 style:"width:300px;height:60px;",
48428 autocomplete: "new-password"
48431 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48434 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48435 if(this.preventScrollbars){
48436 this.el.setStyle("overflow", "hidden");
48438 this.el.setHeight(this.growMin);
48441 //console.log('onrender' + this.getId() );
48442 Roo.form.FCKeditor.editors[this.getId()] = this;
48445 this.replaceTextarea() ;
48449 getEditor : function() {
48450 return this.fckEditor;
48453 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48454 * @param {Mixed} value The value to set
48458 setValue : function(value)
48460 //console.log('setValue: ' + value);
48462 if(typeof(value) == 'undefined') { // not sure why this is happending...
48465 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48467 //if(!this.el || !this.getEditor()) {
48468 // this.value = value;
48469 //this.setValue.defer(100,this,[value]);
48473 if(!this.getEditor()) {
48477 this.getEditor().SetData(value);
48484 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48485 * @return {Mixed} value The field value
48487 getValue : function()
48490 if (this.frame && this.frame.dom.style.display == 'none') {
48491 return Roo.form.FCKeditor.superclass.getValue.call(this);
48494 if(!this.el || !this.getEditor()) {
48496 // this.getValue.defer(100,this);
48501 var value=this.getEditor().GetData();
48502 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48503 return Roo.form.FCKeditor.superclass.getValue.call(this);
48509 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48510 * @return {Mixed} value The field value
48512 getRawValue : function()
48514 if (this.frame && this.frame.dom.style.display == 'none') {
48515 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48518 if(!this.el || !this.getEditor()) {
48519 //this.getRawValue.defer(100,this);
48526 var value=this.getEditor().GetData();
48527 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48528 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48532 setSize : function(w,h) {
48536 //if (this.frame && this.frame.dom.style.display == 'none') {
48537 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48540 //if(!this.el || !this.getEditor()) {
48541 // this.setSize.defer(100,this, [w,h]);
48547 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48549 this.frame.dom.setAttribute('width', w);
48550 this.frame.dom.setAttribute('height', h);
48551 this.frame.setSize(w,h);
48555 toggleSourceEdit : function(value) {
48559 this.el.dom.style.display = value ? '' : 'none';
48560 this.frame.dom.style.display = value ? 'none' : '';
48565 focus: function(tag)
48567 if (this.frame.dom.style.display == 'none') {
48568 return Roo.form.FCKeditor.superclass.focus.call(this);
48570 if(!this.el || !this.getEditor()) {
48571 this.focus.defer(100,this, [tag]);
48578 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48579 this.getEditor().Focus();
48581 if (!this.getEditor().Selection.GetSelection()) {
48582 this.focus.defer(100,this, [tag]);
48587 var r = this.getEditor().EditorDocument.createRange();
48588 r.setStart(tgs[0],0);
48589 r.setEnd(tgs[0],0);
48590 this.getEditor().Selection.GetSelection().removeAllRanges();
48591 this.getEditor().Selection.GetSelection().addRange(r);
48592 this.getEditor().Focus();
48599 replaceTextarea : function()
48601 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48604 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48606 // We must check the elements firstly using the Id and then the name.
48607 var oTextarea = document.getElementById( this.getId() );
48609 var colElementsByName = document.getElementsByName( this.getId() ) ;
48611 oTextarea.style.display = 'none' ;
48613 if ( oTextarea.tabIndex ) {
48614 this.TabIndex = oTextarea.tabIndex ;
48617 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48618 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48619 this.frame = Roo.get(this.getId() + '___Frame')
48622 _getConfigHtml : function()
48626 for ( var o in this.fckconfig ) {
48627 sConfig += sConfig.length > 0 ? '&' : '';
48628 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48631 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48635 _getIFrameHtml : function()
48637 var sFile = 'fckeditor.html' ;
48638 /* no idea what this is about..
48641 if ( (/fcksource=true/i).test( window.top.location.search ) )
48642 sFile = 'fckeditor.original.html' ;
48647 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48648 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48651 var html = '<iframe id="' + this.getId() +
48652 '___Frame" src="' + sLink +
48653 '" width="' + this.width +
48654 '" height="' + this.height + '"' +
48655 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48656 ' frameborder="0" scrolling="no"></iframe>' ;
48661 _insertHtmlBefore : function( html, element )
48663 if ( element.insertAdjacentHTML ) {
48665 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48667 var oRange = document.createRange() ;
48668 oRange.setStartBefore( element ) ;
48669 var oFragment = oRange.createContextualFragment( html );
48670 element.parentNode.insertBefore( oFragment, element ) ;
48683 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48685 function FCKeditor_OnComplete(editorInstance){
48686 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48687 f.fckEditor = editorInstance;
48688 //console.log("loaded");
48689 f.fireEvent('editorinit', f, editorInstance);
48709 //<script type="text/javascript">
48711 * @class Roo.form.GridField
48712 * @extends Roo.form.Field
48713 * Embed a grid (or editable grid into a form)
48716 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48718 * xgrid.store = Roo.data.Store
48719 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48720 * xgrid.store.reader = Roo.data.JsonReader
48724 * Creates a new GridField
48725 * @param {Object} config Configuration options
48727 Roo.form.GridField = function(config){
48728 Roo.form.GridField.superclass.constructor.call(this, config);
48732 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48734 * @cfg {Number} width - used to restrict width of grid..
48738 * @cfg {Number} height - used to restrict height of grid..
48742 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48748 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48749 * {tag: "input", type: "checkbox", autocomplete: "off"})
48751 // defaultAutoCreate : { tag: 'div' },
48752 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48754 * @cfg {String} addTitle Text to include for adding a title.
48758 onResize : function(){
48759 Roo.form.Field.superclass.onResize.apply(this, arguments);
48762 initEvents : function(){
48763 // Roo.form.Checkbox.superclass.initEvents.call(this);
48764 // has no events...
48769 getResizeEl : function(){
48773 getPositionEl : function(){
48778 onRender : function(ct, position){
48780 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48781 var style = this.style;
48784 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48785 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48786 this.viewEl = this.wrap.createChild({ tag: 'div' });
48788 this.viewEl.applyStyles(style);
48791 this.viewEl.setWidth(this.width);
48794 this.viewEl.setHeight(this.height);
48796 //if(this.inputValue !== undefined){
48797 //this.setValue(this.value);
48800 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48803 this.grid.render();
48804 this.grid.getDataSource().on('remove', this.refreshValue, this);
48805 this.grid.getDataSource().on('update', this.refreshValue, this);
48806 this.grid.on('afteredit', this.refreshValue, this);
48812 * Sets the value of the item.
48813 * @param {String} either an object or a string..
48815 setValue : function(v){
48817 v = v || []; // empty set..
48818 // this does not seem smart - it really only affects memoryproxy grids..
48819 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48820 var ds = this.grid.getDataSource();
48821 // assumes a json reader..
48823 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48824 ds.loadData( data);
48826 // clear selection so it does not get stale.
48827 if (this.grid.sm) {
48828 this.grid.sm.clearSelections();
48831 Roo.form.GridField.superclass.setValue.call(this, v);
48832 this.refreshValue();
48833 // should load data in the grid really....
48837 refreshValue: function() {
48839 this.grid.getDataSource().each(function(r) {
48842 this.el.dom.value = Roo.encode(val);
48850 * Ext JS Library 1.1.1
48851 * Copyright(c) 2006-2007, Ext JS, LLC.
48853 * Originally Released Under LGPL - original licence link has changed is not relivant.
48856 * <script type="text/javascript">
48859 * @class Roo.form.DisplayField
48860 * @extends Roo.form.Field
48861 * A generic Field to display non-editable data.
48862 * @cfg {Boolean} closable (true|false) default false
48864 * Creates a new Display Field item.
48865 * @param {Object} config Configuration options
48867 Roo.form.DisplayField = function(config){
48868 Roo.form.DisplayField.superclass.constructor.call(this, config);
48873 * Fires after the click the close btn
48874 * @param {Roo.form.DisplayField} this
48880 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
48881 inputType: 'hidden',
48887 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48889 focusClass : undefined,
48891 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48893 fieldClass: 'x-form-field',
48896 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
48898 valueRenderer: undefined,
48902 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48903 * {tag: "input", type: "checkbox", autocomplete: "off"})
48906 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
48910 onResize : function(){
48911 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
48915 initEvents : function(){
48916 // Roo.form.Checkbox.superclass.initEvents.call(this);
48917 // has no events...
48920 this.closeEl.on('click', this.onClose, this);
48926 getResizeEl : function(){
48930 getPositionEl : function(){
48935 onRender : function(ct, position){
48937 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
48938 //if(this.inputValue !== undefined){
48939 this.wrap = this.el.wrap();
48941 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
48944 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
48947 if (this.bodyStyle) {
48948 this.viewEl.applyStyles(this.bodyStyle);
48950 //this.viewEl.setStyle('padding', '2px');
48952 this.setValue(this.value);
48957 initValue : Roo.emptyFn,
48962 onClick : function(){
48967 * Sets the checked state of the checkbox.
48968 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
48970 setValue : function(v){
48972 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
48973 // this might be called before we have a dom element..
48974 if (!this.viewEl) {
48977 this.viewEl.dom.innerHTML = html;
48978 Roo.form.DisplayField.superclass.setValue.call(this, v);
48982 onClose : function(e)
48984 e.preventDefault();
48986 this.fireEvent('close', this);
48995 * @class Roo.form.DayPicker
48996 * @extends Roo.form.Field
48997 * A Day picker show [M] [T] [W] ....
48999 * Creates a new Day Picker
49000 * @param {Object} config Configuration options
49002 Roo.form.DayPicker= function(config){
49003 Roo.form.DayPicker.superclass.constructor.call(this, config);
49007 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
49009 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49011 focusClass : undefined,
49013 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49015 fieldClass: "x-form-field",
49018 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49019 * {tag: "input", type: "checkbox", autocomplete: "off"})
49021 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
49024 actionMode : 'viewEl',
49028 inputType : 'hidden',
49031 inputElement: false, // real input element?
49032 basedOn: false, // ????
49034 isFormField: true, // not sure where this is needed!!!!
49036 onResize : function(){
49037 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49038 if(!this.boxLabel){
49039 this.el.alignTo(this.wrap, 'c-c');
49043 initEvents : function(){
49044 Roo.form.Checkbox.superclass.initEvents.call(this);
49045 this.el.on("click", this.onClick, this);
49046 this.el.on("change", this.onClick, this);
49050 getResizeEl : function(){
49054 getPositionEl : function(){
49060 onRender : function(ct, position){
49061 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49063 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49065 var r1 = '<table><tr>';
49066 var r2 = '<tr class="x-form-daypick-icons">';
49067 for (var i=0; i < 7; i++) {
49068 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49069 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49072 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49073 viewEl.select('img').on('click', this.onClick, this);
49074 this.viewEl = viewEl;
49077 // this will not work on Chrome!!!
49078 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49079 this.el.on('propertychange', this.setFromHidden, this); //ie
49087 initValue : Roo.emptyFn,
49090 * Returns the checked state of the checkbox.
49091 * @return {Boolean} True if checked, else false
49093 getValue : function(){
49094 return this.el.dom.value;
49099 onClick : function(e){
49100 //this.setChecked(!this.checked);
49101 Roo.get(e.target).toggleClass('x-menu-item-checked');
49102 this.refreshValue();
49103 //if(this.el.dom.checked != this.checked){
49104 // this.setValue(this.el.dom.checked);
49109 refreshValue : function()
49112 this.viewEl.select('img',true).each(function(e,i,n) {
49113 val += e.is(".x-menu-item-checked") ? String(n) : '';
49115 this.setValue(val, true);
49119 * Sets the checked state of the checkbox.
49120 * On is always based on a string comparison between inputValue and the param.
49121 * @param {Boolean/String} value - the value to set
49122 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49124 setValue : function(v,suppressEvent){
49125 if (!this.el.dom) {
49128 var old = this.el.dom.value ;
49129 this.el.dom.value = v;
49130 if (suppressEvent) {
49134 // update display..
49135 this.viewEl.select('img',true).each(function(e,i,n) {
49137 var on = e.is(".x-menu-item-checked");
49138 var newv = v.indexOf(String(n)) > -1;
49140 e.toggleClass('x-menu-item-checked');
49146 this.fireEvent('change', this, v, old);
49151 // handle setting of hidden value by some other method!!?!?
49152 setFromHidden: function()
49157 //console.log("SET FROM HIDDEN");
49158 //alert('setFrom hidden');
49159 this.setValue(this.el.dom.value);
49162 onDestroy : function()
49165 Roo.get(this.viewEl).remove();
49168 Roo.form.DayPicker.superclass.onDestroy.call(this);
49172 * RooJS Library 1.1.1
49173 * Copyright(c) 2008-2011 Alan Knowles
49180 * @class Roo.form.ComboCheck
49181 * @extends Roo.form.ComboBox
49182 * A combobox for multiple select items.
49184 * FIXME - could do with a reset button..
49187 * Create a new ComboCheck
49188 * @param {Object} config Configuration options
49190 Roo.form.ComboCheck = function(config){
49191 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49192 // should verify some data...
49194 // hiddenName = required..
49195 // displayField = required
49196 // valudField == required
49197 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49199 Roo.each(req, function(e) {
49200 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49201 throw "Roo.form.ComboCheck : missing value for: " + e;
49208 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49213 selectedClass: 'x-menu-item-checked',
49216 onRender : function(ct, position){
49222 var cls = 'x-combo-list';
49225 this.tpl = new Roo.Template({
49226 html : '<div class="'+cls+'-item x-menu-check-item">' +
49227 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49228 '<span>{' + this.displayField + '}</span>' +
49235 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49236 this.view.singleSelect = false;
49237 this.view.multiSelect = true;
49238 this.view.toggleSelect = true;
49239 this.pageTb.add(new Roo.Toolbar.Fill(), {
49242 handler: function()
49249 onViewOver : function(e, t){
49255 onViewClick : function(doFocus,index){
49259 select: function () {
49260 //Roo.log("SELECT CALLED");
49263 selectByValue : function(xv, scrollIntoView){
49264 var ar = this.getValueArray();
49267 Roo.each(ar, function(v) {
49268 if(v === undefined || v === null){
49271 var r = this.findRecord(this.valueField, v);
49273 sels.push(this.store.indexOf(r))
49277 this.view.select(sels);
49283 onSelect : function(record, index){
49284 // Roo.log("onselect Called");
49285 // this is only called by the clear button now..
49286 this.view.clearSelections();
49287 this.setValue('[]');
49288 if (this.value != this.valueBefore) {
49289 this.fireEvent('change', this, this.value, this.valueBefore);
49290 this.valueBefore = this.value;
49293 getValueArray : function()
49298 //Roo.log(this.value);
49299 if (typeof(this.value) == 'undefined') {
49302 var ar = Roo.decode(this.value);
49303 return ar instanceof Array ? ar : []; //?? valid?
49306 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49311 expand : function ()
49314 Roo.form.ComboCheck.superclass.expand.call(this);
49315 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49316 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49321 collapse : function(){
49322 Roo.form.ComboCheck.superclass.collapse.call(this);
49323 var sl = this.view.getSelectedIndexes();
49324 var st = this.store;
49328 Roo.each(sl, function(i) {
49330 nv.push(r.get(this.valueField));
49332 this.setValue(Roo.encode(nv));
49333 if (this.value != this.valueBefore) {
49335 this.fireEvent('change', this, this.value, this.valueBefore);
49336 this.valueBefore = this.value;
49341 setValue : function(v){
49345 var vals = this.getValueArray();
49347 Roo.each(vals, function(k) {
49348 var r = this.findRecord(this.valueField, k);
49350 tv.push(r.data[this.displayField]);
49351 }else if(this.valueNotFoundText !== undefined){
49352 tv.push( this.valueNotFoundText );
49357 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49358 this.hiddenField.value = v;
49364 * Ext JS Library 1.1.1
49365 * Copyright(c) 2006-2007, Ext JS, LLC.
49367 * Originally Released Under LGPL - original licence link has changed is not relivant.
49370 * <script type="text/javascript">
49374 * @class Roo.form.Signature
49375 * @extends Roo.form.Field
49379 * @param {Object} config Configuration options
49382 Roo.form.Signature = function(config){
49383 Roo.form.Signature.superclass.constructor.call(this, config);
49385 this.addEvents({// not in used??
49388 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49389 * @param {Roo.form.Signature} combo This combo box
49394 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49395 * @param {Roo.form.ComboBox} combo This combo box
49396 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49402 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49404 * @cfg {Object} labels Label to use when rendering a form.
49408 * confirm : "Confirm"
49413 confirm : "Confirm"
49416 * @cfg {Number} width The signature panel width (defaults to 300)
49420 * @cfg {Number} height The signature panel height (defaults to 100)
49424 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49426 allowBlank : false,
49429 // {Object} signPanel The signature SVG panel element (defaults to {})
49431 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49432 isMouseDown : false,
49433 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49434 isConfirmed : false,
49435 // {String} signatureTmp SVG mapping string (defaults to empty string)
49439 defaultAutoCreate : { // modified by initCompnoent..
49445 onRender : function(ct, position){
49447 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49449 this.wrap = this.el.wrap({
49450 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49453 this.createToolbar(this);
49454 this.signPanel = this.wrap.createChild({
49456 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49460 this.svgID = Roo.id();
49461 this.svgEl = this.signPanel.createChild({
49462 xmlns : 'http://www.w3.org/2000/svg',
49464 id : this.svgID + "-svg",
49466 height: this.height,
49467 viewBox: '0 0 '+this.width+' '+this.height,
49471 id: this.svgID + "-svg-r",
49473 height: this.height,
49478 id: this.svgID + "-svg-l",
49480 y1: (this.height*0.8), // start set the line in 80% of height
49481 x2: this.width, // end
49482 y2: (this.height*0.8), // end set the line in 80% of height
49484 'stroke-width': "1",
49485 'stroke-dasharray': "3",
49486 'shape-rendering': "crispEdges",
49487 'pointer-events': "none"
49491 id: this.svgID + "-svg-p",
49493 'stroke-width': "3",
49495 'pointer-events': 'none'
49500 this.svgBox = this.svgEl.dom.getScreenCTM();
49502 createSVG : function(){
49503 var svg = this.signPanel;
49504 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49507 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49508 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49509 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49510 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49511 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49512 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49513 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49516 isTouchEvent : function(e){
49517 return e.type.match(/^touch/);
49519 getCoords : function (e) {
49520 var pt = this.svgEl.dom.createSVGPoint();
49523 if (this.isTouchEvent(e)) {
49524 pt.x = e.targetTouches[0].clientX;
49525 pt.y = e.targetTouches[0].clientY;
49527 var a = this.svgEl.dom.getScreenCTM();
49528 var b = a.inverse();
49529 var mx = pt.matrixTransform(b);
49530 return mx.x + ',' + mx.y;
49532 //mouse event headler
49533 down : function (e) {
49534 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49535 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49537 this.isMouseDown = true;
49539 e.preventDefault();
49541 move : function (e) {
49542 if (this.isMouseDown) {
49543 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49544 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49547 e.preventDefault();
49549 up : function (e) {
49550 this.isMouseDown = false;
49551 var sp = this.signatureTmp.split(' ');
49554 if(!sp[sp.length-2].match(/^L/)){
49558 this.signatureTmp = sp.join(" ");
49561 if(this.getValue() != this.signatureTmp){
49562 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49563 this.isConfirmed = false;
49565 e.preventDefault();
49569 * Protected method that will not generally be called directly. It
49570 * is called when the editor creates its toolbar. Override this method if you need to
49571 * add custom toolbar buttons.
49572 * @param {HtmlEditor} editor
49574 createToolbar : function(editor){
49575 function btn(id, toggle, handler){
49576 var xid = fid + '-'+ id ;
49580 cls : 'x-btn-icon x-edit-'+id,
49581 enableToggle:toggle !== false,
49582 scope: editor, // was editor...
49583 handler:handler||editor.relayBtnCmd,
49584 clickEvent:'mousedown',
49585 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49591 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49595 cls : ' x-signature-btn x-signature-'+id,
49596 scope: editor, // was editor...
49597 handler: this.reset,
49598 clickEvent:'mousedown',
49599 text: this.labels.clear
49606 cls : ' x-signature-btn x-signature-'+id,
49607 scope: editor, // was editor...
49608 handler: this.confirmHandler,
49609 clickEvent:'mousedown',
49610 text: this.labels.confirm
49617 * when user is clicked confirm then show this image.....
49619 * @return {String} Image Data URI
49621 getImageDataURI : function(){
49622 var svg = this.svgEl.dom.parentNode.innerHTML;
49623 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49628 * @return {Boolean} this.isConfirmed
49630 getConfirmed : function(){
49631 return this.isConfirmed;
49635 * @return {Number} this.width
49637 getWidth : function(){
49642 * @return {Number} this.height
49644 getHeight : function(){
49645 return this.height;
49648 getSignature : function(){
49649 return this.signatureTmp;
49652 reset : function(){
49653 this.signatureTmp = '';
49654 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49655 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49656 this.isConfirmed = false;
49657 Roo.form.Signature.superclass.reset.call(this);
49659 setSignature : function(s){
49660 this.signatureTmp = s;
49661 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49662 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49664 this.isConfirmed = false;
49665 Roo.form.Signature.superclass.reset.call(this);
49668 // Roo.log(this.signPanel.dom.contentWindow.up())
49671 setConfirmed : function(){
49675 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49678 confirmHandler : function(){
49679 if(!this.getSignature()){
49683 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49684 this.setValue(this.getSignature());
49685 this.isConfirmed = true;
49687 this.fireEvent('confirm', this);
49690 // Subclasses should provide the validation implementation by overriding this
49691 validateValue : function(value){
49692 if(this.allowBlank){
49696 if(this.isConfirmed){
49703 * Ext JS Library 1.1.1
49704 * Copyright(c) 2006-2007, Ext JS, LLC.
49706 * Originally Released Under LGPL - original licence link has changed is not relivant.
49709 * <script type="text/javascript">
49714 * @class Roo.form.ComboBox
49715 * @extends Roo.form.TriggerField
49716 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49718 * Create a new ComboBox.
49719 * @param {Object} config Configuration options
49721 Roo.form.Select = function(config){
49722 Roo.form.Select.superclass.constructor.call(this, config);
49726 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49728 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49731 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49732 * rendering into an Roo.Editor, defaults to false)
49735 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49736 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49739 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49742 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49743 * the dropdown list (defaults to undefined, with no header element)
49747 * @cfg {String/Roo.Template} tpl The template to use to render the output
49751 defaultAutoCreate : {tag: "select" },
49753 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49755 listWidth: undefined,
49757 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49758 * mode = 'remote' or 'text' if mode = 'local')
49760 displayField: undefined,
49762 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49763 * mode = 'remote' or 'value' if mode = 'local').
49764 * Note: use of a valueField requires the user make a selection
49765 * in order for a value to be mapped.
49767 valueField: undefined,
49771 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49772 * field's data value (defaults to the underlying DOM element's name)
49774 hiddenName: undefined,
49776 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49780 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49782 selectedClass: 'x-combo-selected',
49784 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49785 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49786 * which displays a downward arrow icon).
49788 triggerClass : 'x-form-arrow-trigger',
49790 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49794 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49795 * anchor positions (defaults to 'tl-bl')
49797 listAlign: 'tl-bl?',
49799 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49803 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49804 * query specified by the allQuery config option (defaults to 'query')
49806 triggerAction: 'query',
49808 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49809 * (defaults to 4, does not apply if editable = false)
49813 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49814 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49818 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49819 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49823 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49824 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49828 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49829 * when editable = true (defaults to false)
49831 selectOnFocus:false,
49833 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49835 queryParam: 'query',
49837 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49838 * when mode = 'remote' (defaults to 'Loading...')
49840 loadingText: 'Loading...',
49842 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49846 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49850 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49851 * traditional select (defaults to true)
49855 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49859 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49863 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49864 * listWidth has a higher value)
49868 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49869 * allow the user to set arbitrary text into the field (defaults to false)
49871 forceSelection:false,
49873 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49874 * if typeAhead = true (defaults to 250)
49876 typeAheadDelay : 250,
49878 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
49879 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
49881 valueNotFoundText : undefined,
49884 * @cfg {String} defaultValue The value displayed after loading the store.
49889 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
49891 blockFocus : false,
49894 * @cfg {Boolean} disableClear Disable showing of clear button.
49896 disableClear : false,
49898 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
49900 alwaysQuery : false,
49906 // element that contains real text value.. (when hidden is used..)
49909 onRender : function(ct, position){
49910 Roo.form.Field.prototype.onRender.call(this, ct, position);
49913 this.store.on('beforeload', this.onBeforeLoad, this);
49914 this.store.on('load', this.onLoad, this);
49915 this.store.on('loadexception', this.onLoadException, this);
49916 this.store.load({});
49924 initEvents : function(){
49925 //Roo.form.ComboBox.superclass.initEvents.call(this);
49929 onDestroy : function(){
49932 this.store.un('beforeload', this.onBeforeLoad, this);
49933 this.store.un('load', this.onLoad, this);
49934 this.store.un('loadexception', this.onLoadException, this);
49936 //Roo.form.ComboBox.superclass.onDestroy.call(this);
49940 fireKey : function(e){
49941 if(e.isNavKeyPress() && !this.list.isVisible()){
49942 this.fireEvent("specialkey", this, e);
49947 onResize: function(w, h){
49955 * Allow or prevent the user from directly editing the field text. If false is passed,
49956 * the user will only be able to select from the items defined in the dropdown list. This method
49957 * is the runtime equivalent of setting the 'editable' config option at config time.
49958 * @param {Boolean} value True to allow the user to directly edit the field text
49960 setEditable : function(value){
49965 onBeforeLoad : function(){
49967 Roo.log("Select before load");
49970 this.innerList.update(this.loadingText ?
49971 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
49972 //this.restrictHeight();
49973 this.selectedIndex = -1;
49977 onLoad : function(){
49980 var dom = this.el.dom;
49981 dom.innerHTML = '';
49982 var od = dom.ownerDocument;
49984 if (this.emptyText) {
49985 var op = od.createElement('option');
49986 op.setAttribute('value', '');
49987 op.innerHTML = String.format('{0}', this.emptyText);
49988 dom.appendChild(op);
49990 if(this.store.getCount() > 0){
49992 var vf = this.valueField;
49993 var df = this.displayField;
49994 this.store.data.each(function(r) {
49995 // which colmsn to use... testing - cdoe / title..
49996 var op = od.createElement('option');
49997 op.setAttribute('value', r.data[vf]);
49998 op.innerHTML = String.format('{0}', r.data[df]);
49999 dom.appendChild(op);
50001 if (typeof(this.defaultValue != 'undefined')) {
50002 this.setValue(this.defaultValue);
50007 //this.onEmptyResults();
50012 onLoadException : function()
50014 dom.innerHTML = '';
50016 Roo.log("Select on load exception");
50020 Roo.log(this.store.reader.jsonData);
50021 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
50022 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50028 onTypeAhead : function(){
50033 onSelect : function(record, index){
50034 Roo.log('on select?');
50036 if(this.fireEvent('beforeselect', this, record, index) !== false){
50037 this.setFromData(index > -1 ? record.data : false);
50039 this.fireEvent('select', this, record, index);
50044 * Returns the currently selected field value or empty string if no value is set.
50045 * @return {String} value The selected value
50047 getValue : function(){
50048 var dom = this.el.dom;
50049 this.value = dom.options[dom.selectedIndex].value;
50055 * Clears any text/value currently set in the field
50057 clearValue : function(){
50059 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50064 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50065 * will be displayed in the field. If the value does not match the data value of an existing item,
50066 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50067 * Otherwise the field will be blank (although the value will still be set).
50068 * @param {String} value The value to match
50070 setValue : function(v){
50071 var d = this.el.dom;
50072 for (var i =0; i < d.options.length;i++) {
50073 if (v == d.options[i].value) {
50074 d.selectedIndex = i;
50082 * @property {Object} the last set data for the element
50087 * Sets the value of the field based on a object which is related to the record format for the store.
50088 * @param {Object} value the value to set as. or false on reset?
50090 setFromData : function(o){
50091 Roo.log('setfrom data?');
50097 reset : function(){
50101 findRecord : function(prop, value){
50106 if(this.store.getCount() > 0){
50107 this.store.each(function(r){
50108 if(r.data[prop] == value){
50118 getName: function()
50120 // returns hidden if it's set..
50121 if (!this.rendered) {return ''};
50122 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50130 onEmptyResults : function(){
50131 Roo.log('empty results');
50136 * Returns true if the dropdown list is expanded, else false.
50138 isExpanded : function(){
50143 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50144 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50145 * @param {String} value The data value of the item to select
50146 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50147 * selected item if it is not currently in view (defaults to true)
50148 * @return {Boolean} True if the value matched an item in the list, else false
50150 selectByValue : function(v, scrollIntoView){
50151 Roo.log('select By Value');
50154 if(v !== undefined && v !== null){
50155 var r = this.findRecord(this.valueField || this.displayField, v);
50157 this.select(this.store.indexOf(r), scrollIntoView);
50165 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50166 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50167 * @param {Number} index The zero-based index of the list item to select
50168 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50169 * selected item if it is not currently in view (defaults to true)
50171 select : function(index, scrollIntoView){
50172 Roo.log('select ');
50175 this.selectedIndex = index;
50176 this.view.select(index);
50177 if(scrollIntoView !== false){
50178 var el = this.view.getNode(index);
50180 this.innerList.scrollChildIntoView(el, false);
50188 validateBlur : function(){
50195 initQuery : function(){
50196 this.doQuery(this.getRawValue());
50200 doForce : function(){
50201 if(this.el.dom.value.length > 0){
50202 this.el.dom.value =
50203 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50209 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50210 * query allowing the query action to be canceled if needed.
50211 * @param {String} query The SQL query to execute
50212 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50213 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50214 * saved in the current store (defaults to false)
50216 doQuery : function(q, forceAll){
50218 Roo.log('doQuery?');
50219 if(q === undefined || q === null){
50224 forceAll: forceAll,
50228 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50232 forceAll = qe.forceAll;
50233 if(forceAll === true || (q.length >= this.minChars)){
50234 if(this.lastQuery != q || this.alwaysQuery){
50235 this.lastQuery = q;
50236 if(this.mode == 'local'){
50237 this.selectedIndex = -1;
50239 this.store.clearFilter();
50241 this.store.filter(this.displayField, q);
50245 this.store.baseParams[this.queryParam] = q;
50247 params: this.getParams(q)
50252 this.selectedIndex = -1;
50259 getParams : function(q){
50261 //p[this.queryParam] = q;
50264 p.limit = this.pageSize;
50270 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50272 collapse : function(){
50277 collapseIf : function(e){
50282 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50284 expand : function(){
50292 * @cfg {Boolean} grow
50296 * @cfg {Number} growMin
50300 * @cfg {Number} growMax
50308 setWidth : function()
50312 getResizeEl : function(){
50315 });//<script type="text/javasscript">
50319 * @class Roo.DDView
50320 * A DnD enabled version of Roo.View.
50321 * @param {Element/String} container The Element in which to create the View.
50322 * @param {String} tpl The template string used to create the markup for each element of the View
50323 * @param {Object} config The configuration properties. These include all the config options of
50324 * {@link Roo.View} plus some specific to this class.<br>
50326 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50327 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50329 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50330 .x-view-drag-insert-above {
50331 border-top:1px dotted #3366cc;
50333 .x-view-drag-insert-below {
50334 border-bottom:1px dotted #3366cc;
50340 Roo.DDView = function(container, tpl, config) {
50341 Roo.DDView.superclass.constructor.apply(this, arguments);
50342 this.getEl().setStyle("outline", "0px none");
50343 this.getEl().unselectable();
50344 if (this.dragGroup) {
50345 this.setDraggable(this.dragGroup.split(","));
50347 if (this.dropGroup) {
50348 this.setDroppable(this.dropGroup.split(","));
50350 if (this.deletable) {
50351 this.setDeletable();
50353 this.isDirtyFlag = false;
50359 Roo.extend(Roo.DDView, Roo.View, {
50360 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50361 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50362 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50363 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50367 reset: Roo.emptyFn,
50369 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50371 validate: function() {
50375 destroy: function() {
50376 this.purgeListeners();
50377 this.getEl.removeAllListeners();
50378 this.getEl().remove();
50379 if (this.dragZone) {
50380 if (this.dragZone.destroy) {
50381 this.dragZone.destroy();
50384 if (this.dropZone) {
50385 if (this.dropZone.destroy) {
50386 this.dropZone.destroy();
50391 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50392 getName: function() {
50396 /** Loads the View from a JSON string representing the Records to put into the Store. */
50397 setValue: function(v) {
50399 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50402 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50403 this.store.proxy = new Roo.data.MemoryProxy(data);
50407 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50408 getValue: function() {
50410 this.store.each(function(rec) {
50411 result += rec.id + ',';
50413 return result.substr(0, result.length - 1) + ')';
50416 getIds: function() {
50417 var i = 0, result = new Array(this.store.getCount());
50418 this.store.each(function(rec) {
50419 result[i++] = rec.id;
50424 isDirty: function() {
50425 return this.isDirtyFlag;
50429 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50430 * whole Element becomes the target, and this causes the drop gesture to append.
50432 getTargetFromEvent : function(e) {
50433 var target = e.getTarget();
50434 while ((target !== null) && (target.parentNode != this.el.dom)) {
50435 target = target.parentNode;
50438 target = this.el.dom.lastChild || this.el.dom;
50444 * Create the drag data which consists of an object which has the property "ddel" as
50445 * the drag proxy element.
50447 getDragData : function(e) {
50448 var target = this.findItemFromChild(e.getTarget());
50450 this.handleSelection(e);
50451 var selNodes = this.getSelectedNodes();
50454 copy: this.copy || (this.allowCopy && e.ctrlKey),
50458 var selectedIndices = this.getSelectedIndexes();
50459 for (var i = 0; i < selectedIndices.length; i++) {
50460 dragData.records.push(this.store.getAt(selectedIndices[i]));
50462 if (selNodes.length == 1) {
50463 dragData.ddel = target.cloneNode(true); // the div element
50465 var div = document.createElement('div'); // create the multi element drag "ghost"
50466 div.className = 'multi-proxy';
50467 for (var i = 0, len = selNodes.length; i < len; i++) {
50468 div.appendChild(selNodes[i].cloneNode(true));
50470 dragData.ddel = div;
50472 //console.log(dragData)
50473 //console.log(dragData.ddel.innerHTML)
50476 //console.log('nodragData')
50480 /** Specify to which ddGroup items in this DDView may be dragged. */
50481 setDraggable: function(ddGroup) {
50482 if (ddGroup instanceof Array) {
50483 Roo.each(ddGroup, this.setDraggable, this);
50486 if (this.dragZone) {
50487 this.dragZone.addToGroup(ddGroup);
50489 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50490 containerScroll: true,
50494 // Draggability implies selection. DragZone's mousedown selects the element.
50495 if (!this.multiSelect) { this.singleSelect = true; }
50497 // Wire the DragZone's handlers up to methods in *this*
50498 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50502 /** Specify from which ddGroup this DDView accepts drops. */
50503 setDroppable: function(ddGroup) {
50504 if (ddGroup instanceof Array) {
50505 Roo.each(ddGroup, this.setDroppable, this);
50508 if (this.dropZone) {
50509 this.dropZone.addToGroup(ddGroup);
50511 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50512 containerScroll: true,
50516 // Wire the DropZone's handlers up to methods in *this*
50517 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50518 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50519 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50520 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50521 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50525 /** Decide whether to drop above or below a View node. */
50526 getDropPoint : function(e, n, dd){
50527 if (n == this.el.dom) { return "above"; }
50528 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50529 var c = t + (b - t) / 2;
50530 var y = Roo.lib.Event.getPageY(e);
50538 onNodeEnter : function(n, dd, e, data){
50542 onNodeOver : function(n, dd, e, data){
50543 var pt = this.getDropPoint(e, n, dd);
50544 // set the insert point style on the target node
50545 var dragElClass = this.dropNotAllowed;
50548 if (pt == "above"){
50549 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50550 targetElClass = "x-view-drag-insert-above";
50552 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50553 targetElClass = "x-view-drag-insert-below";
50555 if (this.lastInsertClass != targetElClass){
50556 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50557 this.lastInsertClass = targetElClass;
50560 return dragElClass;
50563 onNodeOut : function(n, dd, e, data){
50564 this.removeDropIndicators(n);
50567 onNodeDrop : function(n, dd, e, data){
50568 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50571 var pt = this.getDropPoint(e, n, dd);
50572 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50573 if (pt == "below") { insertAt++; }
50574 for (var i = 0; i < data.records.length; i++) {
50575 var r = data.records[i];
50576 var dup = this.store.getById(r.id);
50577 if (dup && (dd != this.dragZone)) {
50578 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50581 this.store.insert(insertAt++, r.copy());
50583 data.source.isDirtyFlag = true;
50585 this.store.insert(insertAt++, r);
50587 this.isDirtyFlag = true;
50590 this.dragZone.cachedTarget = null;
50594 removeDropIndicators : function(n){
50596 Roo.fly(n).removeClass([
50597 "x-view-drag-insert-above",
50598 "x-view-drag-insert-below"]);
50599 this.lastInsertClass = "_noclass";
50604 * Utility method. Add a delete option to the DDView's context menu.
50605 * @param {String} imageUrl The URL of the "delete" icon image.
50607 setDeletable: function(imageUrl) {
50608 if (!this.singleSelect && !this.multiSelect) {
50609 this.singleSelect = true;
50611 var c = this.getContextMenu();
50612 this.contextMenu.on("itemclick", function(item) {
50615 this.remove(this.getSelectedIndexes());
50619 this.contextMenu.add({
50626 /** Return the context menu for this DDView. */
50627 getContextMenu: function() {
50628 if (!this.contextMenu) {
50629 // Create the View's context menu
50630 this.contextMenu = new Roo.menu.Menu({
50631 id: this.id + "-contextmenu"
50633 this.el.on("contextmenu", this.showContextMenu, this);
50635 return this.contextMenu;
50638 disableContextMenu: function() {
50639 if (this.contextMenu) {
50640 this.el.un("contextmenu", this.showContextMenu, this);
50644 showContextMenu: function(e, item) {
50645 item = this.findItemFromChild(e.getTarget());
50648 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50649 this.contextMenu.showAt(e.getXY());
50654 * Remove {@link Roo.data.Record}s at the specified indices.
50655 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50657 remove: function(selectedIndices) {
50658 selectedIndices = [].concat(selectedIndices);
50659 for (var i = 0; i < selectedIndices.length; i++) {
50660 var rec = this.store.getAt(selectedIndices[i]);
50661 this.store.remove(rec);
50666 * Double click fires the event, but also, if this is draggable, and there is only one other
50667 * related DropZone, it transfers the selected node.
50669 onDblClick : function(e){
50670 var item = this.findItemFromChild(e.getTarget());
50672 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50675 if (this.dragGroup) {
50676 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50677 while (targets.indexOf(this.dropZone) > -1) {
50678 targets.remove(this.dropZone);
50680 if (targets.length == 1) {
50681 this.dragZone.cachedTarget = null;
50682 var el = Roo.get(targets[0].getEl());
50683 var box = el.getBox(true);
50684 targets[0].onNodeDrop(el.dom, {
50686 xy: [box.x, box.y + box.height - 1]
50687 }, null, this.getDragData(e));
50693 handleSelection: function(e) {
50694 this.dragZone.cachedTarget = null;
50695 var item = this.findItemFromChild(e.getTarget());
50697 this.clearSelections(true);
50700 if (item && (this.multiSelect || this.singleSelect)){
50701 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50702 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50703 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50704 this.unselect(item);
50706 this.select(item, this.multiSelect && e.ctrlKey);
50707 this.lastSelection = item;
50712 onItemClick : function(item, index, e){
50713 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50719 unselect : function(nodeInfo, suppressEvent){
50720 var node = this.getNode(nodeInfo);
50721 if(node && this.isSelected(node)){
50722 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50723 Roo.fly(node).removeClass(this.selectedClass);
50724 this.selections.remove(node);
50725 if(!suppressEvent){
50726 this.fireEvent("selectionchange", this, this.selections);
50734 * Ext JS Library 1.1.1
50735 * Copyright(c) 2006-2007, Ext JS, LLC.
50737 * Originally Released Under LGPL - original licence link has changed is not relivant.
50740 * <script type="text/javascript">
50744 * @class Roo.LayoutManager
50745 * @extends Roo.util.Observable
50746 * Base class for layout managers.
50748 Roo.LayoutManager = function(container, config){
50749 Roo.LayoutManager.superclass.constructor.call(this);
50750 this.el = Roo.get(container);
50751 // ie scrollbar fix
50752 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50753 document.body.scroll = "no";
50754 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50755 this.el.position('relative');
50757 this.id = this.el.id;
50758 this.el.addClass("x-layout-container");
50759 /** false to disable window resize monitoring @type Boolean */
50760 this.monitorWindowResize = true;
50765 * Fires when a layout is performed.
50766 * @param {Roo.LayoutManager} this
50770 * @event regionresized
50771 * Fires when the user resizes a region.
50772 * @param {Roo.LayoutRegion} region The resized region
50773 * @param {Number} newSize The new size (width for east/west, height for north/south)
50775 "regionresized" : true,
50777 * @event regioncollapsed
50778 * Fires when a region is collapsed.
50779 * @param {Roo.LayoutRegion} region The collapsed region
50781 "regioncollapsed" : true,
50783 * @event regionexpanded
50784 * Fires when a region is expanded.
50785 * @param {Roo.LayoutRegion} region The expanded region
50787 "regionexpanded" : true
50789 this.updating = false;
50790 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50793 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50795 * Returns true if this layout is currently being updated
50796 * @return {Boolean}
50798 isUpdating : function(){
50799 return this.updating;
50803 * Suspend the LayoutManager from doing auto-layouts while
50804 * making multiple add or remove calls
50806 beginUpdate : function(){
50807 this.updating = true;
50811 * Restore auto-layouts and optionally disable the manager from performing a layout
50812 * @param {Boolean} noLayout true to disable a layout update
50814 endUpdate : function(noLayout){
50815 this.updating = false;
50821 layout: function(){
50825 onRegionResized : function(region, newSize){
50826 this.fireEvent("regionresized", region, newSize);
50830 onRegionCollapsed : function(region){
50831 this.fireEvent("regioncollapsed", region);
50834 onRegionExpanded : function(region){
50835 this.fireEvent("regionexpanded", region);
50839 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50840 * performs box-model adjustments.
50841 * @return {Object} The size as an object {width: (the width), height: (the height)}
50843 getViewSize : function(){
50845 if(this.el.dom != document.body){
50846 size = this.el.getSize();
50848 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50850 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50851 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50856 * Returns the Element this layout is bound to.
50857 * @return {Roo.Element}
50859 getEl : function(){
50864 * Returns the specified region.
50865 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50866 * @return {Roo.LayoutRegion}
50868 getRegion : function(target){
50869 return this.regions[target.toLowerCase()];
50872 onWindowResize : function(){
50873 if(this.monitorWindowResize){
50879 * Ext JS Library 1.1.1
50880 * Copyright(c) 2006-2007, Ext JS, LLC.
50882 * Originally Released Under LGPL - original licence link has changed is not relivant.
50885 * <script type="text/javascript">
50888 * @class Roo.BorderLayout
50889 * @extends Roo.LayoutManager
50890 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
50891 * please see: <br><br>
50892 * <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>
50893 * <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>
50896 var layout = new Roo.BorderLayout(document.body, {
50930 preferredTabWidth: 150
50935 var CP = Roo.ContentPanel;
50937 layout.beginUpdate();
50938 layout.add("north", new CP("north", "North"));
50939 layout.add("south", new CP("south", {title: "South", closable: true}));
50940 layout.add("west", new CP("west", {title: "West"}));
50941 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
50942 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
50943 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
50944 layout.getRegion("center").showPanel("center1");
50945 layout.endUpdate();
50948 <b>The container the layout is rendered into can be either the body element or any other element.
50949 If it is not the body element, the container needs to either be an absolute positioned element,
50950 or you will need to add "position:relative" to the css of the container. You will also need to specify
50951 the container size if it is not the body element.</b>
50954 * Create a new BorderLayout
50955 * @param {String/HTMLElement/Element} container The container this layout is bound to
50956 * @param {Object} config Configuration options
50958 Roo.BorderLayout = function(container, config){
50959 config = config || {};
50960 Roo.BorderLayout.superclass.constructor.call(this, container, config);
50961 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
50962 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
50963 var target = this.factory.validRegions[i];
50964 if(config[target]){
50965 this.addRegion(target, config[target]);
50970 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
50972 * Creates and adds a new region if it doesn't already exist.
50973 * @param {String} target The target region key (north, south, east, west or center).
50974 * @param {Object} config The regions config object
50975 * @return {BorderLayoutRegion} The new region
50977 addRegion : function(target, config){
50978 if(!this.regions[target]){
50979 var r = this.factory.create(target, this, config);
50980 this.bindRegion(target, r);
50982 return this.regions[target];
50986 bindRegion : function(name, r){
50987 this.regions[name] = r;
50988 r.on("visibilitychange", this.layout, this);
50989 r.on("paneladded", this.layout, this);
50990 r.on("panelremoved", this.layout, this);
50991 r.on("invalidated", this.layout, this);
50992 r.on("resized", this.onRegionResized, this);
50993 r.on("collapsed", this.onRegionCollapsed, this);
50994 r.on("expanded", this.onRegionExpanded, this);
50998 * Performs a layout update.
51000 layout : function(){
51001 if(this.updating) {
51004 var size = this.getViewSize();
51005 var w = size.width;
51006 var h = size.height;
51011 //var x = 0, y = 0;
51013 var rs = this.regions;
51014 var north = rs["north"];
51015 var south = rs["south"];
51016 var west = rs["west"];
51017 var east = rs["east"];
51018 var center = rs["center"];
51019 //if(this.hideOnLayout){ // not supported anymore
51020 //c.el.setStyle("display", "none");
51022 if(north && north.isVisible()){
51023 var b = north.getBox();
51024 var m = north.getMargins();
51025 b.width = w - (m.left+m.right);
51028 centerY = b.height + b.y + m.bottom;
51029 centerH -= centerY;
51030 north.updateBox(this.safeBox(b));
51032 if(south && south.isVisible()){
51033 var b = south.getBox();
51034 var m = south.getMargins();
51035 b.width = w - (m.left+m.right);
51037 var totalHeight = (b.height + m.top + m.bottom);
51038 b.y = h - totalHeight + m.top;
51039 centerH -= totalHeight;
51040 south.updateBox(this.safeBox(b));
51042 if(west && west.isVisible()){
51043 var b = west.getBox();
51044 var m = west.getMargins();
51045 b.height = centerH - (m.top+m.bottom);
51047 b.y = centerY + m.top;
51048 var totalWidth = (b.width + m.left + m.right);
51049 centerX += totalWidth;
51050 centerW -= totalWidth;
51051 west.updateBox(this.safeBox(b));
51053 if(east && east.isVisible()){
51054 var b = east.getBox();
51055 var m = east.getMargins();
51056 b.height = centerH - (m.top+m.bottom);
51057 var totalWidth = (b.width + m.left + m.right);
51058 b.x = w - totalWidth + m.left;
51059 b.y = centerY + m.top;
51060 centerW -= totalWidth;
51061 east.updateBox(this.safeBox(b));
51064 var m = center.getMargins();
51066 x: centerX + m.left,
51067 y: centerY + m.top,
51068 width: centerW - (m.left+m.right),
51069 height: centerH - (m.top+m.bottom)
51071 //if(this.hideOnLayout){
51072 //center.el.setStyle("display", "block");
51074 center.updateBox(this.safeBox(centerBox));
51077 this.fireEvent("layout", this);
51081 safeBox : function(box){
51082 box.width = Math.max(0, box.width);
51083 box.height = Math.max(0, box.height);
51088 * Adds a ContentPanel (or subclass) to this layout.
51089 * @param {String} target The target region key (north, south, east, west or center).
51090 * @param {Roo.ContentPanel} panel The panel to add
51091 * @return {Roo.ContentPanel} The added panel
51093 add : function(target, panel){
51095 target = target.toLowerCase();
51096 return this.regions[target].add(panel);
51100 * Remove a ContentPanel (or subclass) to this layout.
51101 * @param {String} target The target region key (north, south, east, west or center).
51102 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51103 * @return {Roo.ContentPanel} The removed panel
51105 remove : function(target, panel){
51106 target = target.toLowerCase();
51107 return this.regions[target].remove(panel);
51111 * Searches all regions for a panel with the specified id
51112 * @param {String} panelId
51113 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51115 findPanel : function(panelId){
51116 var rs = this.regions;
51117 for(var target in rs){
51118 if(typeof rs[target] != "function"){
51119 var p = rs[target].getPanel(panelId);
51129 * Searches all regions for a panel with the specified id and activates (shows) it.
51130 * @param {String/ContentPanel} panelId The panels id or the panel itself
51131 * @return {Roo.ContentPanel} The shown panel or null
51133 showPanel : function(panelId) {
51134 var rs = this.regions;
51135 for(var target in rs){
51136 var r = rs[target];
51137 if(typeof r != "function"){
51138 if(r.hasPanel(panelId)){
51139 return r.showPanel(panelId);
51147 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51148 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51150 restoreState : function(provider){
51152 provider = Roo.state.Manager;
51154 var sm = new Roo.LayoutStateManager();
51155 sm.init(this, provider);
51159 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51160 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51161 * a valid ContentPanel config object. Example:
51163 // Create the main layout
51164 var layout = new Roo.BorderLayout('main-ct', {
51175 // Create and add multiple ContentPanels at once via configs
51178 id: 'source-files',
51180 title:'Ext Source Files',
51193 * @param {Object} regions An object containing ContentPanel configs by region name
51195 batchAdd : function(regions){
51196 this.beginUpdate();
51197 for(var rname in regions){
51198 var lr = this.regions[rname];
51200 this.addTypedPanels(lr, regions[rname]);
51207 addTypedPanels : function(lr, ps){
51208 if(typeof ps == 'string'){
51209 lr.add(new Roo.ContentPanel(ps));
51211 else if(ps instanceof Array){
51212 for(var i =0, len = ps.length; i < len; i++){
51213 this.addTypedPanels(lr, ps[i]);
51216 else if(!ps.events){ // raw config?
51218 delete ps.el; // prevent conflict
51219 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51221 else { // panel object assumed!
51226 * Adds a xtype elements to the layout.
51230 xtype : 'ContentPanel',
51237 xtype : 'NestedLayoutPanel',
51243 items : [ ... list of content panels or nested layout panels.. ]
51247 * @param {Object} cfg Xtype definition of item to add.
51249 addxtype : function(cfg)
51251 // basically accepts a pannel...
51252 // can accept a layout region..!?!?
51253 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51255 if (!cfg.xtype.match(/Panel$/)) {
51260 if (typeof(cfg.region) == 'undefined') {
51261 Roo.log("Failed to add Panel, region was not set");
51265 var region = cfg.region;
51271 xitems = cfg.items;
51278 case 'ContentPanel': // ContentPanel (el, cfg)
51279 case 'ScrollPanel': // ContentPanel (el, cfg)
51281 if(cfg.autoCreate) {
51282 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51284 var el = this.el.createChild();
51285 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51288 this.add(region, ret);
51292 case 'TreePanel': // our new panel!
51293 cfg.el = this.el.createChild();
51294 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51295 this.add(region, ret);
51298 case 'NestedLayoutPanel':
51299 // create a new Layout (which is a Border Layout...
51300 var el = this.el.createChild();
51301 var clayout = cfg.layout;
51303 clayout.items = clayout.items || [];
51304 // replace this exitems with the clayout ones..
51305 xitems = clayout.items;
51308 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51309 cfg.background = false;
51311 var layout = new Roo.BorderLayout(el, clayout);
51313 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51314 //console.log('adding nested layout panel ' + cfg.toSource());
51315 this.add(region, ret);
51316 nb = {}; /// find first...
51321 // needs grid and region
51323 //var el = this.getRegion(region).el.createChild();
51324 var el = this.el.createChild();
51325 // create the grid first...
51327 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51329 if (region == 'center' && this.active ) {
51330 cfg.background = false;
51332 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51334 this.add(region, ret);
51335 if (cfg.background) {
51336 ret.on('activate', function(gp) {
51337 if (!gp.grid.rendered) {
51352 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51354 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51355 this.add(region, ret);
51358 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51362 // GridPanel (grid, cfg)
51365 this.beginUpdate();
51369 Roo.each(xitems, function(i) {
51370 region = nb && i.region ? i.region : false;
51372 var add = ret.addxtype(i);
51375 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51376 if (!i.background) {
51377 abn[region] = nb[region] ;
51384 // make the last non-background panel active..
51385 //if (nb) { Roo.log(abn); }
51388 for(var r in abn) {
51389 region = this.getRegion(r);
51391 // tried using nb[r], but it does not work..
51393 region.showPanel(abn[r]);
51404 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51405 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51406 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51407 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51410 var CP = Roo.ContentPanel;
51412 var layout = Roo.BorderLayout.create({
51416 panels: [new CP("north", "North")]
51425 panels: [new CP("west", {title: "West"})]
51434 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51443 panels: [new CP("south", {title: "South", closable: true})]
51450 preferredTabWidth: 150,
51452 new CP("center1", {title: "Close Me", closable: true}),
51453 new CP("center2", {title: "Center Panel", closable: false})
51458 layout.getRegion("center").showPanel("center1");
51463 Roo.BorderLayout.create = function(config, targetEl){
51464 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51465 layout.beginUpdate();
51466 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51467 for(var j = 0, jlen = regions.length; j < jlen; j++){
51468 var lr = regions[j];
51469 if(layout.regions[lr] && config[lr].panels){
51470 var r = layout.regions[lr];
51471 var ps = config[lr].panels;
51472 layout.addTypedPanels(r, ps);
51475 layout.endUpdate();
51480 Roo.BorderLayout.RegionFactory = {
51482 validRegions : ["north","south","east","west","center"],
51485 create : function(target, mgr, config){
51486 target = target.toLowerCase();
51487 if(config.lightweight || config.basic){
51488 return new Roo.BasicLayoutRegion(mgr, config, target);
51492 return new Roo.NorthLayoutRegion(mgr, config);
51494 return new Roo.SouthLayoutRegion(mgr, config);
51496 return new Roo.EastLayoutRegion(mgr, config);
51498 return new Roo.WestLayoutRegion(mgr, config);
51500 return new Roo.CenterLayoutRegion(mgr, config);
51502 throw 'Layout region "'+target+'" not supported.';
51506 * Ext JS Library 1.1.1
51507 * Copyright(c) 2006-2007, Ext JS, LLC.
51509 * Originally Released Under LGPL - original licence link has changed is not relivant.
51512 * <script type="text/javascript">
51516 * @class Roo.BasicLayoutRegion
51517 * @extends Roo.util.Observable
51518 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51519 * and does not have a titlebar, tabs or any other features. All it does is size and position
51520 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51522 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51524 this.position = pos;
51527 * @scope Roo.BasicLayoutRegion
51531 * @event beforeremove
51532 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51533 * @param {Roo.LayoutRegion} this
51534 * @param {Roo.ContentPanel} panel The panel
51535 * @param {Object} e The cancel event object
51537 "beforeremove" : true,
51539 * @event invalidated
51540 * Fires when the layout for this region is changed.
51541 * @param {Roo.LayoutRegion} this
51543 "invalidated" : true,
51545 * @event visibilitychange
51546 * Fires when this region is shown or hidden
51547 * @param {Roo.LayoutRegion} this
51548 * @param {Boolean} visibility true or false
51550 "visibilitychange" : true,
51552 * @event paneladded
51553 * Fires when a panel is added.
51554 * @param {Roo.LayoutRegion} this
51555 * @param {Roo.ContentPanel} panel The panel
51557 "paneladded" : true,
51559 * @event panelremoved
51560 * Fires when a panel is removed.
51561 * @param {Roo.LayoutRegion} this
51562 * @param {Roo.ContentPanel} panel The panel
51564 "panelremoved" : true,
51566 * @event beforecollapse
51567 * Fires when this region before collapse.
51568 * @param {Roo.LayoutRegion} this
51570 "beforecollapse" : true,
51573 * Fires when this region is collapsed.
51574 * @param {Roo.LayoutRegion} this
51576 "collapsed" : true,
51579 * Fires when this region is expanded.
51580 * @param {Roo.LayoutRegion} this
51585 * Fires when this region is slid into view.
51586 * @param {Roo.LayoutRegion} this
51588 "slideshow" : true,
51591 * Fires when this region slides out of view.
51592 * @param {Roo.LayoutRegion} this
51594 "slidehide" : true,
51596 * @event panelactivated
51597 * Fires when a panel is activated.
51598 * @param {Roo.LayoutRegion} this
51599 * @param {Roo.ContentPanel} panel The activated panel
51601 "panelactivated" : true,
51604 * Fires when the user resizes this region.
51605 * @param {Roo.LayoutRegion} this
51606 * @param {Number} newSize The new size (width for east/west, height for north/south)
51610 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51611 this.panels = new Roo.util.MixedCollection();
51612 this.panels.getKey = this.getPanelId.createDelegate(this);
51614 this.activePanel = null;
51615 // ensure listeners are added...
51617 if (config.listeners || config.events) {
51618 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51619 listeners : config.listeners || {},
51620 events : config.events || {}
51624 if(skipConfig !== true){
51625 this.applyConfig(config);
51629 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51630 getPanelId : function(p){
51634 applyConfig : function(config){
51635 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51636 this.config = config;
51641 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51642 * the width, for horizontal (north, south) the height.
51643 * @param {Number} newSize The new width or height
51645 resizeTo : function(newSize){
51646 var el = this.el ? this.el :
51647 (this.activePanel ? this.activePanel.getEl() : null);
51649 switch(this.position){
51652 el.setWidth(newSize);
51653 this.fireEvent("resized", this, newSize);
51657 el.setHeight(newSize);
51658 this.fireEvent("resized", this, newSize);
51664 getBox : function(){
51665 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51668 getMargins : function(){
51669 return this.margins;
51672 updateBox : function(box){
51674 var el = this.activePanel.getEl();
51675 el.dom.style.left = box.x + "px";
51676 el.dom.style.top = box.y + "px";
51677 this.activePanel.setSize(box.width, box.height);
51681 * Returns the container element for this region.
51682 * @return {Roo.Element}
51684 getEl : function(){
51685 return this.activePanel;
51689 * Returns true if this region is currently visible.
51690 * @return {Boolean}
51692 isVisible : function(){
51693 return this.activePanel ? true : false;
51696 setActivePanel : function(panel){
51697 panel = this.getPanel(panel);
51698 if(this.activePanel && this.activePanel != panel){
51699 this.activePanel.setActiveState(false);
51700 this.activePanel.getEl().setLeftTop(-10000,-10000);
51702 this.activePanel = panel;
51703 panel.setActiveState(true);
51705 panel.setSize(this.box.width, this.box.height);
51707 this.fireEvent("panelactivated", this, panel);
51708 this.fireEvent("invalidated");
51712 * Show the specified panel.
51713 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51714 * @return {Roo.ContentPanel} The shown panel or null
51716 showPanel : function(panel){
51717 if(panel = this.getPanel(panel)){
51718 this.setActivePanel(panel);
51724 * Get the active panel for this region.
51725 * @return {Roo.ContentPanel} The active panel or null
51727 getActivePanel : function(){
51728 return this.activePanel;
51732 * Add the passed ContentPanel(s)
51733 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51734 * @return {Roo.ContentPanel} The panel added (if only one was added)
51736 add : function(panel){
51737 if(arguments.length > 1){
51738 for(var i = 0, len = arguments.length; i < len; i++) {
51739 this.add(arguments[i]);
51743 if(this.hasPanel(panel)){
51744 this.showPanel(panel);
51747 var el = panel.getEl();
51748 if(el.dom.parentNode != this.mgr.el.dom){
51749 this.mgr.el.dom.appendChild(el.dom);
51751 if(panel.setRegion){
51752 panel.setRegion(this);
51754 this.panels.add(panel);
51755 el.setStyle("position", "absolute");
51756 if(!panel.background){
51757 this.setActivePanel(panel);
51758 if(this.config.initialSize && this.panels.getCount()==1){
51759 this.resizeTo(this.config.initialSize);
51762 this.fireEvent("paneladded", this, panel);
51767 * Returns true if the panel is in this region.
51768 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51769 * @return {Boolean}
51771 hasPanel : function(panel){
51772 if(typeof panel == "object"){ // must be panel obj
51773 panel = panel.getId();
51775 return this.getPanel(panel) ? true : false;
51779 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51780 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51781 * @param {Boolean} preservePanel Overrides the config preservePanel option
51782 * @return {Roo.ContentPanel} The panel that was removed
51784 remove : function(panel, preservePanel){
51785 panel = this.getPanel(panel);
51790 this.fireEvent("beforeremove", this, panel, e);
51791 if(e.cancel === true){
51794 var panelId = panel.getId();
51795 this.panels.removeKey(panelId);
51800 * Returns the panel specified or null if it's not in this region.
51801 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51802 * @return {Roo.ContentPanel}
51804 getPanel : function(id){
51805 if(typeof id == "object"){ // must be panel obj
51808 return this.panels.get(id);
51812 * Returns this regions position (north/south/east/west/center).
51815 getPosition: function(){
51816 return this.position;
51820 * Ext JS Library 1.1.1
51821 * Copyright(c) 2006-2007, Ext JS, LLC.
51823 * Originally Released Under LGPL - original licence link has changed is not relivant.
51826 * <script type="text/javascript">
51830 * @class Roo.LayoutRegion
51831 * @extends Roo.BasicLayoutRegion
51832 * This class represents a region in a layout manager.
51833 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51834 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51835 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51836 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51837 * @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})
51838 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51839 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51840 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51841 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51842 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51843 * @cfg {String} title The title for the region (overrides panel titles)
51844 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51845 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51846 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51847 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51848 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51849 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51850 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51851 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51852 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51853 * @cfg {Boolean} showPin True to show a pin button
51854 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51855 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51856 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51857 * @cfg {Number} width For East/West panels
51858 * @cfg {Number} height For North/South panels
51859 * @cfg {Boolean} split To show the splitter
51860 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51862 Roo.LayoutRegion = function(mgr, config, pos){
51863 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51864 var dh = Roo.DomHelper;
51865 /** This region's container element
51866 * @type Roo.Element */
51867 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51868 /** This region's title element
51869 * @type Roo.Element */
51871 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51872 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51873 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51875 this.titleEl.enableDisplayMode();
51876 /** This region's title text element
51877 * @type HTMLElement */
51878 this.titleTextEl = this.titleEl.dom.firstChild;
51879 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
51880 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
51881 this.closeBtn.enableDisplayMode();
51882 this.closeBtn.on("click", this.closeClicked, this);
51883 this.closeBtn.hide();
51885 this.createBody(config);
51886 this.visible = true;
51887 this.collapsed = false;
51889 if(config.hideWhenEmpty){
51891 this.on("paneladded", this.validateVisibility, this);
51892 this.on("panelremoved", this.validateVisibility, this);
51894 this.applyConfig(config);
51897 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
51899 createBody : function(){
51900 /** This region's body element
51901 * @type Roo.Element */
51902 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
51905 applyConfig : function(c){
51906 if(c.collapsible && this.position != "center" && !this.collapsedEl){
51907 var dh = Roo.DomHelper;
51908 if(c.titlebar !== false){
51909 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
51910 this.collapseBtn.on("click", this.collapse, this);
51911 this.collapseBtn.enableDisplayMode();
51913 if(c.showPin === true || this.showPin){
51914 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
51915 this.stickBtn.enableDisplayMode();
51916 this.stickBtn.on("click", this.expand, this);
51917 this.stickBtn.hide();
51920 /** This region's collapsed element
51921 * @type Roo.Element */
51922 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
51923 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
51925 if(c.floatable !== false){
51926 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
51927 this.collapsedEl.on("click", this.collapseClick, this);
51930 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
51931 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
51932 id: "message", unselectable: "on", style:{"float":"left"}});
51933 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
51935 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
51936 this.expandBtn.on("click", this.expand, this);
51938 if(this.collapseBtn){
51939 this.collapseBtn.setVisible(c.collapsible == true);
51941 this.cmargins = c.cmargins || this.cmargins ||
51942 (this.position == "west" || this.position == "east" ?
51943 {top: 0, left: 2, right:2, bottom: 0} :
51944 {top: 2, left: 0, right:0, bottom: 2});
51945 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51946 this.bottomTabs = c.tabPosition != "top";
51947 this.autoScroll = c.autoScroll || false;
51948 if(this.autoScroll){
51949 this.bodyEl.setStyle("overflow", "auto");
51951 this.bodyEl.setStyle("overflow", "hidden");
51953 //if(c.titlebar !== false){
51954 if((!c.titlebar && !c.title) || c.titlebar === false){
51955 this.titleEl.hide();
51957 this.titleEl.show();
51959 this.titleTextEl.innerHTML = c.title;
51963 this.duration = c.duration || .30;
51964 this.slideDuration = c.slideDuration || .45;
51967 this.collapse(true);
51974 * Returns true if this region is currently visible.
51975 * @return {Boolean}
51977 isVisible : function(){
51978 return this.visible;
51982 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
51983 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
51985 setCollapsedTitle : function(title){
51986 title = title || " ";
51987 if(this.collapsedTitleTextEl){
51988 this.collapsedTitleTextEl.innerHTML = title;
51992 getBox : function(){
51994 if(!this.collapsed){
51995 b = this.el.getBox(false, true);
51997 b = this.collapsedEl.getBox(false, true);
52002 getMargins : function(){
52003 return this.collapsed ? this.cmargins : this.margins;
52006 highlight : function(){
52007 this.el.addClass("x-layout-panel-dragover");
52010 unhighlight : function(){
52011 this.el.removeClass("x-layout-panel-dragover");
52014 updateBox : function(box){
52016 if(!this.collapsed){
52017 this.el.dom.style.left = box.x + "px";
52018 this.el.dom.style.top = box.y + "px";
52019 this.updateBody(box.width, box.height);
52021 this.collapsedEl.dom.style.left = box.x + "px";
52022 this.collapsedEl.dom.style.top = box.y + "px";
52023 this.collapsedEl.setSize(box.width, box.height);
52026 this.tabs.autoSizeTabs();
52030 updateBody : function(w, h){
52032 this.el.setWidth(w);
52033 w -= this.el.getBorderWidth("rl");
52034 if(this.config.adjustments){
52035 w += this.config.adjustments[0];
52039 this.el.setHeight(h);
52040 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52041 h -= this.el.getBorderWidth("tb");
52042 if(this.config.adjustments){
52043 h += this.config.adjustments[1];
52045 this.bodyEl.setHeight(h);
52047 h = this.tabs.syncHeight(h);
52050 if(this.panelSize){
52051 w = w !== null ? w : this.panelSize.width;
52052 h = h !== null ? h : this.panelSize.height;
52054 if(this.activePanel){
52055 var el = this.activePanel.getEl();
52056 w = w !== null ? w : el.getWidth();
52057 h = h !== null ? h : el.getHeight();
52058 this.panelSize = {width: w, height: h};
52059 this.activePanel.setSize(w, h);
52061 if(Roo.isIE && this.tabs){
52062 this.tabs.el.repaint();
52067 * Returns the container element for this region.
52068 * @return {Roo.Element}
52070 getEl : function(){
52075 * Hides this region.
52078 if(!this.collapsed){
52079 this.el.dom.style.left = "-2000px";
52082 this.collapsedEl.dom.style.left = "-2000px";
52083 this.collapsedEl.hide();
52085 this.visible = false;
52086 this.fireEvent("visibilitychange", this, false);
52090 * Shows this region if it was previously hidden.
52093 if(!this.collapsed){
52096 this.collapsedEl.show();
52098 this.visible = true;
52099 this.fireEvent("visibilitychange", this, true);
52102 closeClicked : function(){
52103 if(this.activePanel){
52104 this.remove(this.activePanel);
52108 collapseClick : function(e){
52110 e.stopPropagation();
52113 e.stopPropagation();
52119 * Collapses this region.
52120 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52122 collapse : function(skipAnim, skipCheck = false){
52123 if(this.collapsed) {
52127 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52129 this.collapsed = true;
52131 this.split.el.hide();
52133 if(this.config.animate && skipAnim !== true){
52134 this.fireEvent("invalidated", this);
52135 this.animateCollapse();
52137 this.el.setLocation(-20000,-20000);
52139 this.collapsedEl.show();
52140 this.fireEvent("collapsed", this);
52141 this.fireEvent("invalidated", this);
52147 animateCollapse : function(){
52152 * Expands this region if it was previously collapsed.
52153 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52154 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52156 expand : function(e, skipAnim){
52158 e.stopPropagation();
52160 if(!this.collapsed || this.el.hasActiveFx()) {
52164 this.afterSlideIn();
52167 this.collapsed = false;
52168 if(this.config.animate && skipAnim !== true){
52169 this.animateExpand();
52173 this.split.el.show();
52175 this.collapsedEl.setLocation(-2000,-2000);
52176 this.collapsedEl.hide();
52177 this.fireEvent("invalidated", this);
52178 this.fireEvent("expanded", this);
52182 animateExpand : function(){
52186 initTabs : function()
52188 this.bodyEl.setStyle("overflow", "hidden");
52189 var ts = new Roo.TabPanel(
52192 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52193 disableTooltips: this.config.disableTabTips,
52194 toolbar : this.config.toolbar
52197 if(this.config.hideTabs){
52198 ts.stripWrap.setDisplayed(false);
52201 ts.resizeTabs = this.config.resizeTabs === true;
52202 ts.minTabWidth = this.config.minTabWidth || 40;
52203 ts.maxTabWidth = this.config.maxTabWidth || 250;
52204 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52205 ts.monitorResize = false;
52206 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52207 ts.bodyEl.addClass('x-layout-tabs-body');
52208 this.panels.each(this.initPanelAsTab, this);
52211 initPanelAsTab : function(panel){
52212 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52213 this.config.closeOnTab && panel.isClosable());
52214 if(panel.tabTip !== undefined){
52215 ti.setTooltip(panel.tabTip);
52217 ti.on("activate", function(){
52218 this.setActivePanel(panel);
52220 if(this.config.closeOnTab){
52221 ti.on("beforeclose", function(t, e){
52223 this.remove(panel);
52229 updatePanelTitle : function(panel, title){
52230 if(this.activePanel == panel){
52231 this.updateTitle(title);
52234 var ti = this.tabs.getTab(panel.getEl().id);
52236 if(panel.tabTip !== undefined){
52237 ti.setTooltip(panel.tabTip);
52242 updateTitle : function(title){
52243 if(this.titleTextEl && !this.config.title){
52244 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52248 setActivePanel : function(panel){
52249 panel = this.getPanel(panel);
52250 if(this.activePanel && this.activePanel != panel){
52251 this.activePanel.setActiveState(false);
52253 this.activePanel = panel;
52254 panel.setActiveState(true);
52255 if(this.panelSize){
52256 panel.setSize(this.panelSize.width, this.panelSize.height);
52259 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52261 this.updateTitle(panel.getTitle());
52263 this.fireEvent("invalidated", this);
52265 this.fireEvent("panelactivated", this, panel);
52269 * Shows the specified panel.
52270 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52271 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52273 showPanel : function(panel)
52275 panel = this.getPanel(panel);
52278 var tab = this.tabs.getTab(panel.getEl().id);
52279 if(tab.isHidden()){
52280 this.tabs.unhideTab(tab.id);
52284 this.setActivePanel(panel);
52291 * Get the active panel for this region.
52292 * @return {Roo.ContentPanel} The active panel or null
52294 getActivePanel : function(){
52295 return this.activePanel;
52298 validateVisibility : function(){
52299 if(this.panels.getCount() < 1){
52300 this.updateTitle(" ");
52301 this.closeBtn.hide();
52304 if(!this.isVisible()){
52311 * Adds the passed ContentPanel(s) to this region.
52312 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52313 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52315 add : function(panel){
52316 if(arguments.length > 1){
52317 for(var i = 0, len = arguments.length; i < len; i++) {
52318 this.add(arguments[i]);
52322 if(this.hasPanel(panel)){
52323 this.showPanel(panel);
52326 panel.setRegion(this);
52327 this.panels.add(panel);
52328 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52329 this.bodyEl.dom.appendChild(panel.getEl().dom);
52330 if(panel.background !== true){
52331 this.setActivePanel(panel);
52333 this.fireEvent("paneladded", this, panel);
52339 this.initPanelAsTab(panel);
52341 if(panel.background !== true){
52342 this.tabs.activate(panel.getEl().id);
52344 this.fireEvent("paneladded", this, panel);
52349 * Hides the tab for the specified panel.
52350 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52352 hidePanel : function(panel){
52353 if(this.tabs && (panel = this.getPanel(panel))){
52354 this.tabs.hideTab(panel.getEl().id);
52359 * Unhides the tab for a previously hidden panel.
52360 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52362 unhidePanel : function(panel){
52363 if(this.tabs && (panel = this.getPanel(panel))){
52364 this.tabs.unhideTab(panel.getEl().id);
52368 clearPanels : function(){
52369 while(this.panels.getCount() > 0){
52370 this.remove(this.panels.first());
52375 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52376 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52377 * @param {Boolean} preservePanel Overrides the config preservePanel option
52378 * @return {Roo.ContentPanel} The panel that was removed
52380 remove : function(panel, preservePanel){
52381 panel = this.getPanel(panel);
52386 this.fireEvent("beforeremove", this, panel, e);
52387 if(e.cancel === true){
52390 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52391 var panelId = panel.getId();
52392 this.panels.removeKey(panelId);
52394 document.body.appendChild(panel.getEl().dom);
52397 this.tabs.removeTab(panel.getEl().id);
52398 }else if (!preservePanel){
52399 this.bodyEl.dom.removeChild(panel.getEl().dom);
52401 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52402 var p = this.panels.first();
52403 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52404 tempEl.appendChild(p.getEl().dom);
52405 this.bodyEl.update("");
52406 this.bodyEl.dom.appendChild(p.getEl().dom);
52408 this.updateTitle(p.getTitle());
52410 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52411 this.setActivePanel(p);
52413 panel.setRegion(null);
52414 if(this.activePanel == panel){
52415 this.activePanel = null;
52417 if(this.config.autoDestroy !== false && preservePanel !== true){
52418 try{panel.destroy();}catch(e){}
52420 this.fireEvent("panelremoved", this, panel);
52425 * Returns the TabPanel component used by this region
52426 * @return {Roo.TabPanel}
52428 getTabs : function(){
52432 createTool : function(parentEl, className){
52433 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52434 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52435 btn.addClassOnOver("x-layout-tools-button-over");
52440 * Ext JS Library 1.1.1
52441 * Copyright(c) 2006-2007, Ext JS, LLC.
52443 * Originally Released Under LGPL - original licence link has changed is not relivant.
52446 * <script type="text/javascript">
52452 * @class Roo.SplitLayoutRegion
52453 * @extends Roo.LayoutRegion
52454 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52456 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52457 this.cursor = cursor;
52458 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52461 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52462 splitTip : "Drag to resize.",
52463 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52464 useSplitTips : false,
52466 applyConfig : function(config){
52467 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52470 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52471 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52472 /** The SplitBar for this region
52473 * @type Roo.SplitBar */
52474 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52475 this.split.on("moved", this.onSplitMove, this);
52476 this.split.useShim = config.useShim === true;
52477 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52478 if(this.useSplitTips){
52479 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52481 if(config.collapsible){
52482 this.split.el.on("dblclick", this.collapse, this);
52485 if(typeof config.minSize != "undefined"){
52486 this.split.minSize = config.minSize;
52488 if(typeof config.maxSize != "undefined"){
52489 this.split.maxSize = config.maxSize;
52491 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52492 this.hideSplitter();
52497 getHMaxSize : function(){
52498 var cmax = this.config.maxSize || 10000;
52499 var center = this.mgr.getRegion("center");
52500 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52503 getVMaxSize : function(){
52504 var cmax = this.config.maxSize || 10000;
52505 var center = this.mgr.getRegion("center");
52506 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52509 onSplitMove : function(split, newSize){
52510 this.fireEvent("resized", this, newSize);
52514 * Returns the {@link Roo.SplitBar} for this region.
52515 * @return {Roo.SplitBar}
52517 getSplitBar : function(){
52522 this.hideSplitter();
52523 Roo.SplitLayoutRegion.superclass.hide.call(this);
52526 hideSplitter : function(){
52528 this.split.el.setLocation(-2000,-2000);
52529 this.split.el.hide();
52535 this.split.el.show();
52537 Roo.SplitLayoutRegion.superclass.show.call(this);
52540 beforeSlide: function(){
52541 if(Roo.isGecko){// firefox overflow auto bug workaround
52542 this.bodyEl.clip();
52544 this.tabs.bodyEl.clip();
52546 if(this.activePanel){
52547 this.activePanel.getEl().clip();
52549 if(this.activePanel.beforeSlide){
52550 this.activePanel.beforeSlide();
52556 afterSlide : function(){
52557 if(Roo.isGecko){// firefox overflow auto bug workaround
52558 this.bodyEl.unclip();
52560 this.tabs.bodyEl.unclip();
52562 if(this.activePanel){
52563 this.activePanel.getEl().unclip();
52564 if(this.activePanel.afterSlide){
52565 this.activePanel.afterSlide();
52571 initAutoHide : function(){
52572 if(this.autoHide !== false){
52573 if(!this.autoHideHd){
52574 var st = new Roo.util.DelayedTask(this.slideIn, this);
52575 this.autoHideHd = {
52576 "mouseout": function(e){
52577 if(!e.within(this.el, true)){
52581 "mouseover" : function(e){
52587 this.el.on(this.autoHideHd);
52591 clearAutoHide : function(){
52592 if(this.autoHide !== false){
52593 this.el.un("mouseout", this.autoHideHd.mouseout);
52594 this.el.un("mouseover", this.autoHideHd.mouseover);
52598 clearMonitor : function(){
52599 Roo.get(document).un("click", this.slideInIf, this);
52602 // these names are backwards but not changed for compat
52603 slideOut : function(){
52604 if(this.isSlid || this.el.hasActiveFx()){
52607 this.isSlid = true;
52608 if(this.collapseBtn){
52609 this.collapseBtn.hide();
52611 this.closeBtnState = this.closeBtn.getStyle('display');
52612 this.closeBtn.hide();
52614 this.stickBtn.show();
52617 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52618 this.beforeSlide();
52619 this.el.setStyle("z-index", 10001);
52620 this.el.slideIn(this.getSlideAnchor(), {
52621 callback: function(){
52623 this.initAutoHide();
52624 Roo.get(document).on("click", this.slideInIf, this);
52625 this.fireEvent("slideshow", this);
52632 afterSlideIn : function(){
52633 this.clearAutoHide();
52634 this.isSlid = false;
52635 this.clearMonitor();
52636 this.el.setStyle("z-index", "");
52637 if(this.collapseBtn){
52638 this.collapseBtn.show();
52640 this.closeBtn.setStyle('display', this.closeBtnState);
52642 this.stickBtn.hide();
52644 this.fireEvent("slidehide", this);
52647 slideIn : function(cb){
52648 if(!this.isSlid || this.el.hasActiveFx()){
52652 this.isSlid = false;
52653 this.beforeSlide();
52654 this.el.slideOut(this.getSlideAnchor(), {
52655 callback: function(){
52656 this.el.setLeftTop(-10000, -10000);
52658 this.afterSlideIn();
52666 slideInIf : function(e){
52667 if(!e.within(this.el)){
52672 animateCollapse : function(){
52673 this.beforeSlide();
52674 this.el.setStyle("z-index", 20000);
52675 var anchor = this.getSlideAnchor();
52676 this.el.slideOut(anchor, {
52677 callback : function(){
52678 this.el.setStyle("z-index", "");
52679 this.collapsedEl.slideIn(anchor, {duration:.3});
52681 this.el.setLocation(-10000,-10000);
52683 this.fireEvent("collapsed", this);
52690 animateExpand : function(){
52691 this.beforeSlide();
52692 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52693 this.el.setStyle("z-index", 20000);
52694 this.collapsedEl.hide({
52697 this.el.slideIn(this.getSlideAnchor(), {
52698 callback : function(){
52699 this.el.setStyle("z-index", "");
52702 this.split.el.show();
52704 this.fireEvent("invalidated", this);
52705 this.fireEvent("expanded", this);
52733 getAnchor : function(){
52734 return this.anchors[this.position];
52737 getCollapseAnchor : function(){
52738 return this.canchors[this.position];
52741 getSlideAnchor : function(){
52742 return this.sanchors[this.position];
52745 getAlignAdj : function(){
52746 var cm = this.cmargins;
52747 switch(this.position){
52763 getExpandAdj : function(){
52764 var c = this.collapsedEl, cm = this.cmargins;
52765 switch(this.position){
52767 return [-(cm.right+c.getWidth()+cm.left), 0];
52770 return [cm.right+c.getWidth()+cm.left, 0];
52773 return [0, -(cm.top+cm.bottom+c.getHeight())];
52776 return [0, cm.top+cm.bottom+c.getHeight()];
52782 * Ext JS Library 1.1.1
52783 * Copyright(c) 2006-2007, Ext JS, LLC.
52785 * Originally Released Under LGPL - original licence link has changed is not relivant.
52788 * <script type="text/javascript">
52791 * These classes are private internal classes
52793 Roo.CenterLayoutRegion = function(mgr, config){
52794 Roo.LayoutRegion.call(this, mgr, config, "center");
52795 this.visible = true;
52796 this.minWidth = config.minWidth || 20;
52797 this.minHeight = config.minHeight || 20;
52800 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52802 // center panel can't be hidden
52806 // center panel can't be hidden
52809 getMinWidth: function(){
52810 return this.minWidth;
52813 getMinHeight: function(){
52814 return this.minHeight;
52819 Roo.NorthLayoutRegion = function(mgr, config){
52820 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52822 this.split.placement = Roo.SplitBar.TOP;
52823 this.split.orientation = Roo.SplitBar.VERTICAL;
52824 this.split.el.addClass("x-layout-split-v");
52826 var size = config.initialSize || config.height;
52827 if(typeof size != "undefined"){
52828 this.el.setHeight(size);
52831 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52832 orientation: Roo.SplitBar.VERTICAL,
52833 getBox : function(){
52834 if(this.collapsed){
52835 return this.collapsedEl.getBox();
52837 var box = this.el.getBox();
52839 box.height += this.split.el.getHeight();
52844 updateBox : function(box){
52845 if(this.split && !this.collapsed){
52846 box.height -= this.split.el.getHeight();
52847 this.split.el.setLeft(box.x);
52848 this.split.el.setTop(box.y+box.height);
52849 this.split.el.setWidth(box.width);
52851 if(this.collapsed){
52852 this.updateBody(box.width, null);
52854 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52858 Roo.SouthLayoutRegion = function(mgr, config){
52859 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52861 this.split.placement = Roo.SplitBar.BOTTOM;
52862 this.split.orientation = Roo.SplitBar.VERTICAL;
52863 this.split.el.addClass("x-layout-split-v");
52865 var size = config.initialSize || config.height;
52866 if(typeof size != "undefined"){
52867 this.el.setHeight(size);
52870 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52871 orientation: Roo.SplitBar.VERTICAL,
52872 getBox : function(){
52873 if(this.collapsed){
52874 return this.collapsedEl.getBox();
52876 var box = this.el.getBox();
52878 var sh = this.split.el.getHeight();
52885 updateBox : function(box){
52886 if(this.split && !this.collapsed){
52887 var sh = this.split.el.getHeight();
52890 this.split.el.setLeft(box.x);
52891 this.split.el.setTop(box.y-sh);
52892 this.split.el.setWidth(box.width);
52894 if(this.collapsed){
52895 this.updateBody(box.width, null);
52897 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52901 Roo.EastLayoutRegion = function(mgr, config){
52902 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
52904 this.split.placement = Roo.SplitBar.RIGHT;
52905 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52906 this.split.el.addClass("x-layout-split-h");
52908 var size = config.initialSize || config.width;
52909 if(typeof size != "undefined"){
52910 this.el.setWidth(size);
52913 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
52914 orientation: Roo.SplitBar.HORIZONTAL,
52915 getBox : function(){
52916 if(this.collapsed){
52917 return this.collapsedEl.getBox();
52919 var box = this.el.getBox();
52921 var sw = this.split.el.getWidth();
52928 updateBox : function(box){
52929 if(this.split && !this.collapsed){
52930 var sw = this.split.el.getWidth();
52932 this.split.el.setLeft(box.x);
52933 this.split.el.setTop(box.y);
52934 this.split.el.setHeight(box.height);
52937 if(this.collapsed){
52938 this.updateBody(null, box.height);
52940 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52944 Roo.WestLayoutRegion = function(mgr, config){
52945 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
52947 this.split.placement = Roo.SplitBar.LEFT;
52948 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52949 this.split.el.addClass("x-layout-split-h");
52951 var size = config.initialSize || config.width;
52952 if(typeof size != "undefined"){
52953 this.el.setWidth(size);
52956 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
52957 orientation: Roo.SplitBar.HORIZONTAL,
52958 getBox : function(){
52959 if(this.collapsed){
52960 return this.collapsedEl.getBox();
52962 var box = this.el.getBox();
52964 box.width += this.split.el.getWidth();
52969 updateBox : function(box){
52970 if(this.split && !this.collapsed){
52971 var sw = this.split.el.getWidth();
52973 this.split.el.setLeft(box.x+box.width);
52974 this.split.el.setTop(box.y);
52975 this.split.el.setHeight(box.height);
52977 if(this.collapsed){
52978 this.updateBody(null, box.height);
52980 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52985 * Ext JS Library 1.1.1
52986 * Copyright(c) 2006-2007, Ext JS, LLC.
52988 * Originally Released Under LGPL - original licence link has changed is not relivant.
52991 * <script type="text/javascript">
52996 * Private internal class for reading and applying state
52998 Roo.LayoutStateManager = function(layout){
52999 // default empty state
53008 Roo.LayoutStateManager.prototype = {
53009 init : function(layout, provider){
53010 this.provider = provider;
53011 var state = provider.get(layout.id+"-layout-state");
53013 var wasUpdating = layout.isUpdating();
53015 layout.beginUpdate();
53017 for(var key in state){
53018 if(typeof state[key] != "function"){
53019 var rstate = state[key];
53020 var r = layout.getRegion(key);
53023 r.resizeTo(rstate.size);
53025 if(rstate.collapsed == true){
53028 r.expand(null, true);
53034 layout.endUpdate();
53036 this.state = state;
53038 this.layout = layout;
53039 layout.on("regionresized", this.onRegionResized, this);
53040 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53041 layout.on("regionexpanded", this.onRegionExpanded, this);
53044 storeState : function(){
53045 this.provider.set(this.layout.id+"-layout-state", this.state);
53048 onRegionResized : function(region, newSize){
53049 this.state[region.getPosition()].size = newSize;
53053 onRegionCollapsed : function(region){
53054 this.state[region.getPosition()].collapsed = true;
53058 onRegionExpanded : function(region){
53059 this.state[region.getPosition()].collapsed = false;
53064 * Ext JS Library 1.1.1
53065 * Copyright(c) 2006-2007, Ext JS, LLC.
53067 * Originally Released Under LGPL - original licence link has changed is not relivant.
53070 * <script type="text/javascript">
53073 * @class Roo.ContentPanel
53074 * @extends Roo.util.Observable
53075 * A basic ContentPanel element.
53076 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53077 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53078 * @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
53079 * @cfg {Boolean} closable True if the panel can be closed/removed
53080 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53081 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53082 * @cfg {Toolbar} toolbar A toolbar for this panel
53083 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53084 * @cfg {String} title The title for this panel
53085 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53086 * @cfg {String} url Calls {@link #setUrl} with this value
53087 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53088 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53089 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53090 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53093 * Create a new ContentPanel.
53094 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53095 * @param {String/Object} config A string to set only the title or a config object
53096 * @param {String} content (optional) Set the HTML content for this panel
53097 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53099 Roo.ContentPanel = function(el, config, content){
53103 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53107 if (config && config.parentLayout) {
53108 el = config.parentLayout.el.createChild();
53111 if(el.autoCreate){ // xtype is available if this is called from factory
53115 this.el = Roo.get(el);
53116 if(!this.el && config && config.autoCreate){
53117 if(typeof config.autoCreate == "object"){
53118 if(!config.autoCreate.id){
53119 config.autoCreate.id = config.id||el;
53121 this.el = Roo.DomHelper.append(document.body,
53122 config.autoCreate, true);
53124 this.el = Roo.DomHelper.append(document.body,
53125 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53128 this.closable = false;
53129 this.loaded = false;
53130 this.active = false;
53131 if(typeof config == "string"){
53132 this.title = config;
53134 Roo.apply(this, config);
53137 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53138 this.wrapEl = this.el.wrap();
53139 this.toolbar.container = this.el.insertSibling(false, 'before');
53140 this.toolbar = new Roo.Toolbar(this.toolbar);
53143 // xtype created footer. - not sure if will work as we normally have to render first..
53144 if (this.footer && !this.footer.el && this.footer.xtype) {
53145 if (!this.wrapEl) {
53146 this.wrapEl = this.el.wrap();
53149 this.footer.container = this.wrapEl.createChild();
53151 this.footer = Roo.factory(this.footer, Roo);
53156 this.resizeEl = Roo.get(this.resizeEl, true);
53158 this.resizeEl = this.el;
53160 // handle view.xtype
53168 * Fires when this panel is activated.
53169 * @param {Roo.ContentPanel} this
53173 * @event deactivate
53174 * Fires when this panel is activated.
53175 * @param {Roo.ContentPanel} this
53177 "deactivate" : true,
53181 * Fires when this panel is resized if fitToFrame is true.
53182 * @param {Roo.ContentPanel} this
53183 * @param {Number} width The width after any component adjustments
53184 * @param {Number} height The height after any component adjustments
53190 * Fires when this tab is created
53191 * @param {Roo.ContentPanel} this
53202 if(this.autoScroll){
53203 this.resizeEl.setStyle("overflow", "auto");
53205 // fix randome scrolling
53206 this.el.on('scroll', function() {
53207 Roo.log('fix random scolling');
53208 this.scrollTo('top',0);
53211 content = content || this.content;
53213 this.setContent(content);
53215 if(config && config.url){
53216 this.setUrl(this.url, this.params, this.loadOnce);
53221 Roo.ContentPanel.superclass.constructor.call(this);
53223 if (this.view && typeof(this.view.xtype) != 'undefined') {
53224 this.view.el = this.el.appendChild(document.createElement("div"));
53225 this.view = Roo.factory(this.view);
53226 this.view.render && this.view.render(false, '');
53230 this.fireEvent('render', this);
53233 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53235 setRegion : function(region){
53236 this.region = region;
53238 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53240 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53245 * Returns the toolbar for this Panel if one was configured.
53246 * @return {Roo.Toolbar}
53248 getToolbar : function(){
53249 return this.toolbar;
53252 setActiveState : function(active){
53253 this.active = active;
53255 this.fireEvent("deactivate", this);
53257 this.fireEvent("activate", this);
53261 * Updates this panel's element
53262 * @param {String} content The new content
53263 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53265 setContent : function(content, loadScripts){
53266 this.el.update(content, loadScripts);
53269 ignoreResize : function(w, h){
53270 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53273 this.lastSize = {width: w, height: h};
53278 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53279 * @return {Roo.UpdateManager} The UpdateManager
53281 getUpdateManager : function(){
53282 return this.el.getUpdateManager();
53285 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53286 * @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:
53289 url: "your-url.php",
53290 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53291 callback: yourFunction,
53292 scope: yourObject, //(optional scope)
53295 text: "Loading...",
53300 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53301 * 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.
53302 * @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}
53303 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53304 * @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.
53305 * @return {Roo.ContentPanel} this
53308 var um = this.el.getUpdateManager();
53309 um.update.apply(um, arguments);
53315 * 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.
53316 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53317 * @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)
53318 * @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)
53319 * @return {Roo.UpdateManager} The UpdateManager
53321 setUrl : function(url, params, loadOnce){
53322 if(this.refreshDelegate){
53323 this.removeListener("activate", this.refreshDelegate);
53325 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53326 this.on("activate", this.refreshDelegate);
53327 return this.el.getUpdateManager();
53330 _handleRefresh : function(url, params, loadOnce){
53331 if(!loadOnce || !this.loaded){
53332 var updater = this.el.getUpdateManager();
53333 updater.update(url, params, this._setLoaded.createDelegate(this));
53337 _setLoaded : function(){
53338 this.loaded = true;
53342 * Returns this panel's id
53345 getId : function(){
53350 * Returns this panel's element - used by regiosn to add.
53351 * @return {Roo.Element}
53353 getEl : function(){
53354 return this.wrapEl || this.el;
53357 adjustForComponents : function(width, height)
53359 //Roo.log('adjustForComponents ');
53360 if(this.resizeEl != this.el){
53361 width -= this.el.getFrameWidth('lr');
53362 height -= this.el.getFrameWidth('tb');
53365 var te = this.toolbar.getEl();
53366 height -= te.getHeight();
53367 te.setWidth(width);
53370 var te = this.footer.getEl();
53371 Roo.log("footer:" + te.getHeight());
53373 height -= te.getHeight();
53374 te.setWidth(width);
53378 if(this.adjustments){
53379 width += this.adjustments[0];
53380 height += this.adjustments[1];
53382 return {"width": width, "height": height};
53385 setSize : function(width, height){
53386 if(this.fitToFrame && !this.ignoreResize(width, height)){
53387 if(this.fitContainer && this.resizeEl != this.el){
53388 this.el.setSize(width, height);
53390 var size = this.adjustForComponents(width, height);
53391 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53392 this.fireEvent('resize', this, size.width, size.height);
53397 * Returns this panel's title
53400 getTitle : function(){
53405 * Set this panel's title
53406 * @param {String} title
53408 setTitle : function(title){
53409 this.title = title;
53411 this.region.updatePanelTitle(this, title);
53416 * Returns true is this panel was configured to be closable
53417 * @return {Boolean}
53419 isClosable : function(){
53420 return this.closable;
53423 beforeSlide : function(){
53425 this.resizeEl.clip();
53428 afterSlide : function(){
53430 this.resizeEl.unclip();
53434 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53435 * Will fail silently if the {@link #setUrl} method has not been called.
53436 * This does not activate the panel, just updates its content.
53438 refresh : function(){
53439 if(this.refreshDelegate){
53440 this.loaded = false;
53441 this.refreshDelegate();
53446 * Destroys this panel
53448 destroy : function(){
53449 this.el.removeAllListeners();
53450 var tempEl = document.createElement("span");
53451 tempEl.appendChild(this.el.dom);
53452 tempEl.innerHTML = "";
53458 * form - if the content panel contains a form - this is a reference to it.
53459 * @type {Roo.form.Form}
53463 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53464 * This contains a reference to it.
53470 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53480 * @param {Object} cfg Xtype definition of item to add.
53483 addxtype : function(cfg) {
53485 if (cfg.xtype.match(/^Form$/)) {
53488 //if (this.footer) {
53489 // el = this.footer.container.insertSibling(false, 'before');
53491 el = this.el.createChild();
53494 this.form = new Roo.form.Form(cfg);
53497 if ( this.form.allItems.length) {
53498 this.form.render(el.dom);
53502 // should only have one of theses..
53503 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53504 // views.. should not be just added - used named prop 'view''
53506 cfg.el = this.el.appendChild(document.createElement("div"));
53509 var ret = new Roo.factory(cfg);
53511 ret.render && ret.render(false, ''); // render blank..
53520 * @class Roo.GridPanel
53521 * @extends Roo.ContentPanel
53523 * Create a new GridPanel.
53524 * @param {Roo.grid.Grid} grid The grid for this panel
53525 * @param {String/Object} config A string to set only the panel's title, or a config object
53527 Roo.GridPanel = function(grid, config){
53530 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53531 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53533 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53535 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53538 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53540 // xtype created footer. - not sure if will work as we normally have to render first..
53541 if (this.footer && !this.footer.el && this.footer.xtype) {
53543 this.footer.container = this.grid.getView().getFooterPanel(true);
53544 this.footer.dataSource = this.grid.dataSource;
53545 this.footer = Roo.factory(this.footer, Roo);
53549 grid.monitorWindowResize = false; // turn off autosizing
53550 grid.autoHeight = false;
53551 grid.autoWidth = false;
53553 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53556 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53557 getId : function(){
53558 return this.grid.id;
53562 * Returns the grid for this panel
53563 * @return {Roo.grid.Grid}
53565 getGrid : function(){
53569 setSize : function(width, height){
53570 if(!this.ignoreResize(width, height)){
53571 var grid = this.grid;
53572 var size = this.adjustForComponents(width, height);
53573 grid.getGridEl().setSize(size.width, size.height);
53578 beforeSlide : function(){
53579 this.grid.getView().scroller.clip();
53582 afterSlide : function(){
53583 this.grid.getView().scroller.unclip();
53586 destroy : function(){
53587 this.grid.destroy();
53589 Roo.GridPanel.superclass.destroy.call(this);
53595 * @class Roo.NestedLayoutPanel
53596 * @extends Roo.ContentPanel
53598 * Create a new NestedLayoutPanel.
53601 * @param {Roo.BorderLayout} layout The layout for this panel
53602 * @param {String/Object} config A string to set only the title or a config object
53604 Roo.NestedLayoutPanel = function(layout, config)
53606 // construct with only one argument..
53607 /* FIXME - implement nicer consturctors
53608 if (layout.layout) {
53610 layout = config.layout;
53611 delete config.layout;
53613 if (layout.xtype && !layout.getEl) {
53614 // then layout needs constructing..
53615 layout = Roo.factory(layout, Roo);
53620 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53622 layout.monitorWindowResize = false; // turn off autosizing
53623 this.layout = layout;
53624 this.layout.getEl().addClass("x-layout-nested-layout");
53631 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53633 setSize : function(width, height){
53634 if(!this.ignoreResize(width, height)){
53635 var size = this.adjustForComponents(width, height);
53636 var el = this.layout.getEl();
53637 el.setSize(size.width, size.height);
53638 var touch = el.dom.offsetWidth;
53639 this.layout.layout();
53640 // ie requires a double layout on the first pass
53641 if(Roo.isIE && !this.initialized){
53642 this.initialized = true;
53643 this.layout.layout();
53648 // activate all subpanels if not currently active..
53650 setActiveState : function(active){
53651 this.active = active;
53653 this.fireEvent("deactivate", this);
53657 this.fireEvent("activate", this);
53658 // not sure if this should happen before or after..
53659 if (!this.layout) {
53660 return; // should not happen..
53663 for (var r in this.layout.regions) {
53664 reg = this.layout.getRegion(r);
53665 if (reg.getActivePanel()) {
53666 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53667 reg.setActivePanel(reg.getActivePanel());
53670 if (!reg.panels.length) {
53673 reg.showPanel(reg.getPanel(0));
53682 * Returns the nested BorderLayout for this panel
53683 * @return {Roo.BorderLayout}
53685 getLayout : function(){
53686 return this.layout;
53690 * Adds a xtype elements to the layout of the nested panel
53694 xtype : 'ContentPanel',
53701 xtype : 'NestedLayoutPanel',
53707 items : [ ... list of content panels or nested layout panels.. ]
53711 * @param {Object} cfg Xtype definition of item to add.
53713 addxtype : function(cfg) {
53714 return this.layout.addxtype(cfg);
53719 Roo.ScrollPanel = function(el, config, content){
53720 config = config || {};
53721 config.fitToFrame = true;
53722 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53724 this.el.dom.style.overflow = "hidden";
53725 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53726 this.el.removeClass("x-layout-inactive-content");
53727 this.el.on("mousewheel", this.onWheel, this);
53729 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53730 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53731 up.unselectable(); down.unselectable();
53732 up.on("click", this.scrollUp, this);
53733 down.on("click", this.scrollDown, this);
53734 up.addClassOnOver("x-scroller-btn-over");
53735 down.addClassOnOver("x-scroller-btn-over");
53736 up.addClassOnClick("x-scroller-btn-click");
53737 down.addClassOnClick("x-scroller-btn-click");
53738 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53740 this.resizeEl = this.el;
53741 this.el = wrap; this.up = up; this.down = down;
53744 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53746 wheelIncrement : 5,
53747 scrollUp : function(){
53748 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53751 scrollDown : function(){
53752 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53755 afterScroll : function(){
53756 var el = this.resizeEl;
53757 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53758 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53759 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53762 setSize : function(){
53763 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53764 this.afterScroll();
53767 onWheel : function(e){
53768 var d = e.getWheelDelta();
53769 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53770 this.afterScroll();
53774 setContent : function(content, loadScripts){
53775 this.resizeEl.update(content, loadScripts);
53789 * @class Roo.TreePanel
53790 * @extends Roo.ContentPanel
53792 * Create a new TreePanel. - defaults to fit/scoll contents.
53793 * @param {String/Object} config A string to set only the panel's title, or a config object
53794 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53796 Roo.TreePanel = function(config){
53797 var el = config.el;
53798 var tree = config.tree;
53799 delete config.tree;
53800 delete config.el; // hopefull!
53802 // wrapper for IE7 strict & safari scroll issue
53804 var treeEl = el.createChild();
53805 config.resizeEl = treeEl;
53809 Roo.TreePanel.superclass.constructor.call(this, el, config);
53812 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53813 //console.log(tree);
53814 this.on('activate', function()
53816 if (this.tree.rendered) {
53819 //console.log('render tree');
53820 this.tree.render();
53822 // this should not be needed.. - it's actually the 'el' that resizes?
53823 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53825 //this.on('resize', function (cp, w, h) {
53826 // this.tree.innerCt.setWidth(w);
53827 // this.tree.innerCt.setHeight(h);
53828 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53835 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53852 * Ext JS Library 1.1.1
53853 * Copyright(c) 2006-2007, Ext JS, LLC.
53855 * Originally Released Under LGPL - original licence link has changed is not relivant.
53858 * <script type="text/javascript">
53863 * @class Roo.ReaderLayout
53864 * @extends Roo.BorderLayout
53865 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53866 * center region containing two nested regions (a top one for a list view and one for item preview below),
53867 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53868 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53869 * expedites the setup of the overall layout and regions for this common application style.
53872 var reader = new Roo.ReaderLayout();
53873 var CP = Roo.ContentPanel; // shortcut for adding
53875 reader.beginUpdate();
53876 reader.add("north", new CP("north", "North"));
53877 reader.add("west", new CP("west", {title: "West"}));
53878 reader.add("east", new CP("east", {title: "East"}));
53880 reader.regions.listView.add(new CP("listView", "List"));
53881 reader.regions.preview.add(new CP("preview", "Preview"));
53882 reader.endUpdate();
53885 * Create a new ReaderLayout
53886 * @param {Object} config Configuration options
53887 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
53888 * document.body if omitted)
53890 Roo.ReaderLayout = function(config, renderTo){
53891 var c = config || {size:{}};
53892 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
53893 north: c.north !== false ? Roo.apply({
53897 }, c.north) : false,
53898 west: c.west !== false ? Roo.apply({
53906 margins:{left:5,right:0,bottom:5,top:5},
53907 cmargins:{left:5,right:5,bottom:5,top:5}
53908 }, c.west) : false,
53909 east: c.east !== false ? Roo.apply({
53917 margins:{left:0,right:5,bottom:5,top:5},
53918 cmargins:{left:5,right:5,bottom:5,top:5}
53919 }, c.east) : false,
53920 center: Roo.apply({
53921 tabPosition: 'top',
53925 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
53929 this.el.addClass('x-reader');
53931 this.beginUpdate();
53933 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
53934 south: c.preview !== false ? Roo.apply({
53941 cmargins:{top:5,left:0, right:0, bottom:0}
53942 }, c.preview) : false,
53943 center: Roo.apply({
53949 this.add('center', new Roo.NestedLayoutPanel(inner,
53950 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
53954 this.regions.preview = inner.getRegion('south');
53955 this.regions.listView = inner.getRegion('center');
53958 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
53960 * Ext JS Library 1.1.1
53961 * Copyright(c) 2006-2007, Ext JS, LLC.
53963 * Originally Released Under LGPL - original licence link has changed is not relivant.
53966 * <script type="text/javascript">
53970 * @class Roo.grid.Grid
53971 * @extends Roo.util.Observable
53972 * This class represents the primary interface of a component based grid control.
53973 * <br><br>Usage:<pre><code>
53974 var grid = new Roo.grid.Grid("my-container-id", {
53977 selModel: mySelectionModel,
53978 autoSizeColumns: true,
53979 monitorWindowResize: false,
53980 trackMouseOver: true
53985 * <b>Common Problems:</b><br/>
53986 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
53987 * element will correct this<br/>
53988 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
53989 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
53990 * are unpredictable.<br/>
53991 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
53992 * grid to calculate dimensions/offsets.<br/>
53994 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53995 * The container MUST have some type of size defined for the grid to fill. The container will be
53996 * automatically set to position relative if it isn't already.
53997 * @param {Object} config A config object that sets properties on this grid.
53999 Roo.grid.Grid = function(container, config){
54000 // initialize the container
54001 this.container = Roo.get(container);
54002 this.container.update("");
54003 this.container.setStyle("overflow", "hidden");
54004 this.container.addClass('x-grid-container');
54006 this.id = this.container.id;
54008 Roo.apply(this, config);
54009 // check and correct shorthanded configs
54011 this.dataSource = this.ds;
54015 this.colModel = this.cm;
54019 this.selModel = this.sm;
54023 if (this.selModel) {
54024 this.selModel = Roo.factory(this.selModel, Roo.grid);
54025 this.sm = this.selModel;
54026 this.sm.xmodule = this.xmodule || false;
54028 if (typeof(this.colModel.config) == 'undefined') {
54029 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54030 this.cm = this.colModel;
54031 this.cm.xmodule = this.xmodule || false;
54033 if (this.dataSource) {
54034 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54035 this.ds = this.dataSource;
54036 this.ds.xmodule = this.xmodule || false;
54043 this.container.setWidth(this.width);
54047 this.container.setHeight(this.height);
54054 * The raw click event for the entire grid.
54055 * @param {Roo.EventObject} e
54060 * The raw dblclick event for the entire grid.
54061 * @param {Roo.EventObject} e
54065 * @event contextmenu
54066 * The raw contextmenu event for the entire grid.
54067 * @param {Roo.EventObject} e
54069 "contextmenu" : true,
54072 * The raw mousedown event for the entire grid.
54073 * @param {Roo.EventObject} e
54075 "mousedown" : true,
54078 * The raw mouseup event for the entire grid.
54079 * @param {Roo.EventObject} e
54084 * The raw mouseover event for the entire grid.
54085 * @param {Roo.EventObject} e
54087 "mouseover" : true,
54090 * The raw mouseout event for the entire grid.
54091 * @param {Roo.EventObject} e
54096 * The raw keypress event for the entire grid.
54097 * @param {Roo.EventObject} e
54102 * The raw keydown event for the entire grid.
54103 * @param {Roo.EventObject} e
54111 * Fires when a cell is clicked
54112 * @param {Grid} this
54113 * @param {Number} rowIndex
54114 * @param {Number} columnIndex
54115 * @param {Roo.EventObject} e
54117 "cellclick" : true,
54119 * @event celldblclick
54120 * Fires when a cell is double clicked
54121 * @param {Grid} this
54122 * @param {Number} rowIndex
54123 * @param {Number} columnIndex
54124 * @param {Roo.EventObject} e
54126 "celldblclick" : true,
54129 * Fires when a row is clicked
54130 * @param {Grid} this
54131 * @param {Number} rowIndex
54132 * @param {Roo.EventObject} e
54136 * @event rowdblclick
54137 * Fires when a row is double clicked
54138 * @param {Grid} this
54139 * @param {Number} rowIndex
54140 * @param {Roo.EventObject} e
54142 "rowdblclick" : true,
54144 * @event headerclick
54145 * Fires when a header is clicked
54146 * @param {Grid} this
54147 * @param {Number} columnIndex
54148 * @param {Roo.EventObject} e
54150 "headerclick" : true,
54152 * @event headerdblclick
54153 * Fires when a header cell is double clicked
54154 * @param {Grid} this
54155 * @param {Number} columnIndex
54156 * @param {Roo.EventObject} e
54158 "headerdblclick" : true,
54160 * @event rowcontextmenu
54161 * Fires when a row is right clicked
54162 * @param {Grid} this
54163 * @param {Number} rowIndex
54164 * @param {Roo.EventObject} e
54166 "rowcontextmenu" : true,
54168 * @event cellcontextmenu
54169 * Fires when a cell is right clicked
54170 * @param {Grid} this
54171 * @param {Number} rowIndex
54172 * @param {Number} cellIndex
54173 * @param {Roo.EventObject} e
54175 "cellcontextmenu" : true,
54177 * @event headercontextmenu
54178 * Fires when a header is right clicked
54179 * @param {Grid} this
54180 * @param {Number} columnIndex
54181 * @param {Roo.EventObject} e
54183 "headercontextmenu" : true,
54185 * @event bodyscroll
54186 * Fires when the body element is scrolled
54187 * @param {Number} scrollLeft
54188 * @param {Number} scrollTop
54190 "bodyscroll" : true,
54192 * @event columnresize
54193 * Fires when the user resizes a column
54194 * @param {Number} columnIndex
54195 * @param {Number} newSize
54197 "columnresize" : true,
54199 * @event columnmove
54200 * Fires when the user moves a column
54201 * @param {Number} oldIndex
54202 * @param {Number} newIndex
54204 "columnmove" : true,
54207 * Fires when row(s) start being dragged
54208 * @param {Grid} this
54209 * @param {Roo.GridDD} dd The drag drop object
54210 * @param {event} e The raw browser event
54212 "startdrag" : true,
54215 * Fires when a drag operation is complete
54216 * @param {Grid} this
54217 * @param {Roo.GridDD} dd The drag drop object
54218 * @param {event} e The raw browser event
54223 * Fires when dragged row(s) are dropped on a valid DD target
54224 * @param {Grid} this
54225 * @param {Roo.GridDD} dd The drag drop object
54226 * @param {String} targetId The target drag drop object
54227 * @param {event} e The raw browser event
54232 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54233 * @param {Grid} this
54234 * @param {Roo.GridDD} dd The drag drop object
54235 * @param {String} targetId The target drag drop object
54236 * @param {event} e The raw browser event
54241 * Fires when the dragged row(s) first cross another DD target while being dragged
54242 * @param {Grid} this
54243 * @param {Roo.GridDD} dd The drag drop object
54244 * @param {String} targetId The target drag drop object
54245 * @param {event} e The raw browser event
54247 "dragenter" : true,
54250 * Fires when the dragged row(s) leave another DD target while being dragged
54251 * @param {Grid} this
54252 * @param {Roo.GridDD} dd The drag drop object
54253 * @param {String} targetId The target drag drop object
54254 * @param {event} e The raw browser event
54259 * Fires when a row is rendered, so you can change add a style to it.
54260 * @param {GridView} gridview The grid view
54261 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54267 * Fires when the grid is rendered
54268 * @param {Grid} grid
54273 Roo.grid.Grid.superclass.constructor.call(this);
54275 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54278 * @cfg {String} ddGroup - drag drop group.
54282 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54284 minColumnWidth : 25,
54287 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54288 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54289 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54291 autoSizeColumns : false,
54294 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54296 autoSizeHeaders : true,
54299 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54301 monitorWindowResize : true,
54304 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54305 * rows measured to get a columns size. Default is 0 (all rows).
54307 maxRowsToMeasure : 0,
54310 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54312 trackMouseOver : true,
54315 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54319 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54321 enableDragDrop : false,
54324 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54326 enableColumnMove : true,
54329 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54331 enableColumnHide : true,
54334 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54336 enableRowHeightSync : false,
54339 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54344 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54346 autoHeight : false,
54349 * @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.
54351 autoExpandColumn : false,
54354 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54357 autoExpandMin : 50,
54360 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54362 autoExpandMax : 1000,
54365 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54370 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54374 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54384 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54385 * of a fixed width. Default is false.
54388 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54391 * Called once after all setup has been completed and the grid is ready to be rendered.
54392 * @return {Roo.grid.Grid} this
54394 render : function()
54396 var c = this.container;
54397 // try to detect autoHeight/width mode
54398 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54399 this.autoHeight = true;
54401 var view = this.getView();
54404 c.on("click", this.onClick, this);
54405 c.on("dblclick", this.onDblClick, this);
54406 c.on("contextmenu", this.onContextMenu, this);
54407 c.on("keydown", this.onKeyDown, this);
54409 c.on("touchstart", this.onTouchStart, this);
54412 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54414 this.getSelectionModel().init(this);
54419 this.loadMask = new Roo.LoadMask(this.container,
54420 Roo.apply({store:this.dataSource}, this.loadMask));
54424 if (this.toolbar && this.toolbar.xtype) {
54425 this.toolbar.container = this.getView().getHeaderPanel(true);
54426 this.toolbar = new Roo.Toolbar(this.toolbar);
54428 if (this.footer && this.footer.xtype) {
54429 this.footer.dataSource = this.getDataSource();
54430 this.footer.container = this.getView().getFooterPanel(true);
54431 this.footer = Roo.factory(this.footer, Roo);
54433 if (this.dropTarget && this.dropTarget.xtype) {
54434 delete this.dropTarget.xtype;
54435 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54439 this.rendered = true;
54440 this.fireEvent('render', this);
54445 * Reconfigures the grid to use a different Store and Column Model.
54446 * The View will be bound to the new objects and refreshed.
54447 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54448 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54450 reconfigure : function(dataSource, colModel){
54452 this.loadMask.destroy();
54453 this.loadMask = new Roo.LoadMask(this.container,
54454 Roo.apply({store:dataSource}, this.loadMask));
54456 this.view.bind(dataSource, colModel);
54457 this.dataSource = dataSource;
54458 this.colModel = colModel;
54459 this.view.refresh(true);
54463 onKeyDown : function(e){
54464 this.fireEvent("keydown", e);
54468 * Destroy this grid.
54469 * @param {Boolean} removeEl True to remove the element
54471 destroy : function(removeEl, keepListeners){
54473 this.loadMask.destroy();
54475 var c = this.container;
54476 c.removeAllListeners();
54477 this.view.destroy();
54478 this.colModel.purgeListeners();
54479 if(!keepListeners){
54480 this.purgeListeners();
54483 if(removeEl === true){
54489 processEvent : function(name, e){
54490 // does this fire select???
54491 //Roo.log('grid:processEvent ' + name);
54493 if (name != 'touchstart' ) {
54494 this.fireEvent(name, e);
54497 var t = e.getTarget();
54499 var header = v.findHeaderIndex(t);
54500 if(header !== false){
54501 var ename = name == 'touchstart' ? 'click' : name;
54503 this.fireEvent("header" + ename, this, header, e);
54505 var row = v.findRowIndex(t);
54506 var cell = v.findCellIndex(t);
54507 if (name == 'touchstart') {
54508 // first touch is always a click.
54509 // hopefull this happens after selection is updated.?
54512 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54513 var cs = this.selModel.getSelectedCell();
54514 if (row == cs[0] && cell == cs[1]){
54518 if (typeof(this.selModel.getSelections) != 'undefined') {
54519 var cs = this.selModel.getSelections();
54520 var ds = this.dataSource;
54521 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54532 this.fireEvent("row" + name, this, row, e);
54533 if(cell !== false){
54534 this.fireEvent("cell" + name, this, row, cell, e);
54541 onClick : function(e){
54542 this.processEvent("click", e);
54545 onTouchStart : function(e){
54546 this.processEvent("touchstart", e);
54550 onContextMenu : function(e, t){
54551 this.processEvent("contextmenu", e);
54555 onDblClick : function(e){
54556 this.processEvent("dblclick", e);
54560 walkCells : function(row, col, step, fn, scope){
54561 var cm = this.colModel, clen = cm.getColumnCount();
54562 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54574 if(fn.call(scope || this, row, col, cm) === true){
54592 if(fn.call(scope || this, row, col, cm) === true){
54604 getSelections : function(){
54605 return this.selModel.getSelections();
54609 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54610 * but if manual update is required this method will initiate it.
54612 autoSize : function(){
54614 this.view.layout();
54615 if(this.view.adjustForScroll){
54616 this.view.adjustForScroll();
54622 * Returns the grid's underlying element.
54623 * @return {Element} The element
54625 getGridEl : function(){
54626 return this.container;
54629 // private for compatibility, overridden by editor grid
54630 stopEditing : function(){},
54633 * Returns the grid's SelectionModel.
54634 * @return {SelectionModel}
54636 getSelectionModel : function(){
54637 if(!this.selModel){
54638 this.selModel = new Roo.grid.RowSelectionModel();
54640 return this.selModel;
54644 * Returns the grid's DataSource.
54645 * @return {DataSource}
54647 getDataSource : function(){
54648 return this.dataSource;
54652 * Returns the grid's ColumnModel.
54653 * @return {ColumnModel}
54655 getColumnModel : function(){
54656 return this.colModel;
54660 * Returns the grid's GridView object.
54661 * @return {GridView}
54663 getView : function(){
54665 this.view = new Roo.grid.GridView(this.viewConfig);
54670 * Called to get grid's drag proxy text, by default returns this.ddText.
54673 getDragDropText : function(){
54674 var count = this.selModel.getCount();
54675 return String.format(this.ddText, count, count == 1 ? '' : 's');
54679 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54680 * %0 is replaced with the number of selected rows.
54683 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54685 * Ext JS Library 1.1.1
54686 * Copyright(c) 2006-2007, Ext JS, LLC.
54688 * Originally Released Under LGPL - original licence link has changed is not relivant.
54691 * <script type="text/javascript">
54694 Roo.grid.AbstractGridView = function(){
54698 "beforerowremoved" : true,
54699 "beforerowsinserted" : true,
54700 "beforerefresh" : true,
54701 "rowremoved" : true,
54702 "rowsinserted" : true,
54703 "rowupdated" : true,
54706 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54709 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54710 rowClass : "x-grid-row",
54711 cellClass : "x-grid-cell",
54712 tdClass : "x-grid-td",
54713 hdClass : "x-grid-hd",
54714 splitClass : "x-grid-hd-split",
54716 init: function(grid){
54718 var cid = this.grid.getGridEl().id;
54719 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54720 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54721 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54722 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54725 getColumnRenderers : function(){
54726 var renderers = [];
54727 var cm = this.grid.colModel;
54728 var colCount = cm.getColumnCount();
54729 for(var i = 0; i < colCount; i++){
54730 renderers[i] = cm.getRenderer(i);
54735 getColumnIds : function(){
54737 var cm = this.grid.colModel;
54738 var colCount = cm.getColumnCount();
54739 for(var i = 0; i < colCount; i++){
54740 ids[i] = cm.getColumnId(i);
54745 getDataIndexes : function(){
54746 if(!this.indexMap){
54747 this.indexMap = this.buildIndexMap();
54749 return this.indexMap.colToData;
54752 getColumnIndexByDataIndex : function(dataIndex){
54753 if(!this.indexMap){
54754 this.indexMap = this.buildIndexMap();
54756 return this.indexMap.dataToCol[dataIndex];
54760 * Set a css style for a column dynamically.
54761 * @param {Number} colIndex The index of the column
54762 * @param {String} name The css property name
54763 * @param {String} value The css value
54765 setCSSStyle : function(colIndex, name, value){
54766 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54767 Roo.util.CSS.updateRule(selector, name, value);
54770 generateRules : function(cm){
54771 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54772 Roo.util.CSS.removeStyleSheet(rulesId);
54773 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54774 var cid = cm.getColumnId(i);
54775 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54776 this.tdSelector, cid, " {\n}\n",
54777 this.hdSelector, cid, " {\n}\n",
54778 this.splitSelector, cid, " {\n}\n");
54780 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54784 * Ext JS Library 1.1.1
54785 * Copyright(c) 2006-2007, Ext JS, LLC.
54787 * Originally Released Under LGPL - original licence link has changed is not relivant.
54790 * <script type="text/javascript">
54794 // This is a support class used internally by the Grid components
54795 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54797 this.view = grid.getView();
54798 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54799 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54801 this.setHandleElId(Roo.id(hd));
54802 this.setOuterHandleElId(Roo.id(hd2));
54804 this.scroll = false;
54806 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54808 getDragData : function(e){
54809 var t = Roo.lib.Event.getTarget(e);
54810 var h = this.view.findHeaderCell(t);
54812 return {ddel: h.firstChild, header:h};
54817 onInitDrag : function(e){
54818 this.view.headersDisabled = true;
54819 var clone = this.dragData.ddel.cloneNode(true);
54820 clone.id = Roo.id();
54821 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54822 this.proxy.update(clone);
54826 afterValidDrop : function(){
54828 setTimeout(function(){
54829 v.headersDisabled = false;
54833 afterInvalidDrop : function(){
54835 setTimeout(function(){
54836 v.headersDisabled = false;
54842 * Ext JS Library 1.1.1
54843 * Copyright(c) 2006-2007, Ext JS, LLC.
54845 * Originally Released Under LGPL - original licence link has changed is not relivant.
54848 * <script type="text/javascript">
54851 // This is a support class used internally by the Grid components
54852 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54854 this.view = grid.getView();
54855 // split the proxies so they don't interfere with mouse events
54856 this.proxyTop = Roo.DomHelper.append(document.body, {
54857 cls:"col-move-top", html:" "
54859 this.proxyBottom = Roo.DomHelper.append(document.body, {
54860 cls:"col-move-bottom", html:" "
54862 this.proxyTop.hide = this.proxyBottom.hide = function(){
54863 this.setLeftTop(-100,-100);
54864 this.setStyle("visibility", "hidden");
54866 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54867 // temporarily disabled
54868 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54869 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54871 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54872 proxyOffsets : [-4, -9],
54873 fly: Roo.Element.fly,
54875 getTargetFromEvent : function(e){
54876 var t = Roo.lib.Event.getTarget(e);
54877 var cindex = this.view.findCellIndex(t);
54878 if(cindex !== false){
54879 return this.view.getHeaderCell(cindex);
54884 nextVisible : function(h){
54885 var v = this.view, cm = this.grid.colModel;
54888 if(!cm.isHidden(v.getCellIndex(h))){
54896 prevVisible : function(h){
54897 var v = this.view, cm = this.grid.colModel;
54900 if(!cm.isHidden(v.getCellIndex(h))){
54908 positionIndicator : function(h, n, e){
54909 var x = Roo.lib.Event.getPageX(e);
54910 var r = Roo.lib.Dom.getRegion(n.firstChild);
54911 var px, pt, py = r.top + this.proxyOffsets[1];
54912 if((r.right - x) <= (r.right-r.left)/2){
54913 px = r.right+this.view.borderWidth;
54919 var oldIndex = this.view.getCellIndex(h);
54920 var newIndex = this.view.getCellIndex(n);
54922 if(this.grid.colModel.isFixed(newIndex)){
54926 var locked = this.grid.colModel.isLocked(newIndex);
54931 if(oldIndex < newIndex){
54934 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
54937 px += this.proxyOffsets[0];
54938 this.proxyTop.setLeftTop(px, py);
54939 this.proxyTop.show();
54940 if(!this.bottomOffset){
54941 this.bottomOffset = this.view.mainHd.getHeight();
54943 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
54944 this.proxyBottom.show();
54948 onNodeEnter : function(n, dd, e, data){
54949 if(data.header != n){
54950 this.positionIndicator(data.header, n, e);
54954 onNodeOver : function(n, dd, e, data){
54955 var result = false;
54956 if(data.header != n){
54957 result = this.positionIndicator(data.header, n, e);
54960 this.proxyTop.hide();
54961 this.proxyBottom.hide();
54963 return result ? this.dropAllowed : this.dropNotAllowed;
54966 onNodeOut : function(n, dd, e, data){
54967 this.proxyTop.hide();
54968 this.proxyBottom.hide();
54971 onNodeDrop : function(n, dd, e, data){
54972 var h = data.header;
54974 var cm = this.grid.colModel;
54975 var x = Roo.lib.Event.getPageX(e);
54976 var r = Roo.lib.Dom.getRegion(n.firstChild);
54977 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
54978 var oldIndex = this.view.getCellIndex(h);
54979 var newIndex = this.view.getCellIndex(n);
54980 var locked = cm.isLocked(newIndex);
54984 if(oldIndex < newIndex){
54987 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
54990 cm.setLocked(oldIndex, locked, true);
54991 cm.moveColumn(oldIndex, newIndex);
54992 this.grid.fireEvent("columnmove", oldIndex, newIndex);
55000 * Ext JS Library 1.1.1
55001 * Copyright(c) 2006-2007, Ext JS, LLC.
55003 * Originally Released Under LGPL - original licence link has changed is not relivant.
55006 * <script type="text/javascript">
55010 * @class Roo.grid.GridView
55011 * @extends Roo.util.Observable
55014 * @param {Object} config
55016 Roo.grid.GridView = function(config){
55017 Roo.grid.GridView.superclass.constructor.call(this);
55020 Roo.apply(this, config);
55023 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
55025 unselectable : 'unselectable="on"',
55026 unselectableCls : 'x-unselectable',
55029 rowClass : "x-grid-row",
55031 cellClass : "x-grid-col",
55033 tdClass : "x-grid-td",
55035 hdClass : "x-grid-hd",
55037 splitClass : "x-grid-split",
55039 sortClasses : ["sort-asc", "sort-desc"],
55041 enableMoveAnim : false,
55045 dh : Roo.DomHelper,
55047 fly : Roo.Element.fly,
55049 css : Roo.util.CSS,
55055 scrollIncrement : 22,
55057 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55059 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55061 bind : function(ds, cm){
55063 this.ds.un("load", this.onLoad, this);
55064 this.ds.un("datachanged", this.onDataChange, this);
55065 this.ds.un("add", this.onAdd, this);
55066 this.ds.un("remove", this.onRemove, this);
55067 this.ds.un("update", this.onUpdate, this);
55068 this.ds.un("clear", this.onClear, this);
55071 ds.on("load", this.onLoad, this);
55072 ds.on("datachanged", this.onDataChange, this);
55073 ds.on("add", this.onAdd, this);
55074 ds.on("remove", this.onRemove, this);
55075 ds.on("update", this.onUpdate, this);
55076 ds.on("clear", this.onClear, this);
55081 this.cm.un("widthchange", this.onColWidthChange, this);
55082 this.cm.un("headerchange", this.onHeaderChange, this);
55083 this.cm.un("hiddenchange", this.onHiddenChange, this);
55084 this.cm.un("columnmoved", this.onColumnMove, this);
55085 this.cm.un("columnlockchange", this.onColumnLock, this);
55088 this.generateRules(cm);
55089 cm.on("widthchange", this.onColWidthChange, this);
55090 cm.on("headerchange", this.onHeaderChange, this);
55091 cm.on("hiddenchange", this.onHiddenChange, this);
55092 cm.on("columnmoved", this.onColumnMove, this);
55093 cm.on("columnlockchange", this.onColumnLock, this);
55098 init: function(grid){
55099 Roo.grid.GridView.superclass.init.call(this, grid);
55101 this.bind(grid.dataSource, grid.colModel);
55103 grid.on("headerclick", this.handleHeaderClick, this);
55105 if(grid.trackMouseOver){
55106 grid.on("mouseover", this.onRowOver, this);
55107 grid.on("mouseout", this.onRowOut, this);
55109 grid.cancelTextSelection = function(){};
55110 this.gridId = grid.id;
55112 var tpls = this.templates || {};
55115 tpls.master = new Roo.Template(
55116 '<div class="x-grid" hidefocus="true">',
55117 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55118 '<div class="x-grid-topbar"></div>',
55119 '<div class="x-grid-scroller"><div></div></div>',
55120 '<div class="x-grid-locked">',
55121 '<div class="x-grid-header">{lockedHeader}</div>',
55122 '<div class="x-grid-body">{lockedBody}</div>',
55124 '<div class="x-grid-viewport">',
55125 '<div class="x-grid-header">{header}</div>',
55126 '<div class="x-grid-body">{body}</div>',
55128 '<div class="x-grid-bottombar"></div>',
55130 '<div class="x-grid-resize-proxy"> </div>',
55133 tpls.master.disableformats = true;
55137 tpls.header = new Roo.Template(
55138 '<table border="0" cellspacing="0" cellpadding="0">',
55139 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55142 tpls.header.disableformats = true;
55144 tpls.header.compile();
55147 tpls.hcell = new Roo.Template(
55148 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55149 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55152 tpls.hcell.disableFormats = true;
55154 tpls.hcell.compile();
55157 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55158 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55159 tpls.hsplit.disableFormats = true;
55161 tpls.hsplit.compile();
55164 tpls.body = new Roo.Template(
55165 '<table border="0" cellspacing="0" cellpadding="0">',
55166 "<tbody>{rows}</tbody>",
55169 tpls.body.disableFormats = true;
55171 tpls.body.compile();
55174 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55175 tpls.row.disableFormats = true;
55177 tpls.row.compile();
55180 tpls.cell = new Roo.Template(
55181 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55182 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55183 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55186 tpls.cell.disableFormats = true;
55188 tpls.cell.compile();
55190 this.templates = tpls;
55193 // remap these for backwards compat
55194 onColWidthChange : function(){
55195 this.updateColumns.apply(this, arguments);
55197 onHeaderChange : function(){
55198 this.updateHeaders.apply(this, arguments);
55200 onHiddenChange : function(){
55201 this.handleHiddenChange.apply(this, arguments);
55203 onColumnMove : function(){
55204 this.handleColumnMove.apply(this, arguments);
55206 onColumnLock : function(){
55207 this.handleLockChange.apply(this, arguments);
55210 onDataChange : function(){
55212 this.updateHeaderSortState();
55215 onClear : function(){
55219 onUpdate : function(ds, record){
55220 this.refreshRow(record);
55223 refreshRow : function(record){
55224 var ds = this.ds, index;
55225 if(typeof record == 'number'){
55227 record = ds.getAt(index);
55229 index = ds.indexOf(record);
55231 this.insertRows(ds, index, index, true);
55232 this.onRemove(ds, record, index+1, true);
55233 this.syncRowHeights(index, index);
55235 this.fireEvent("rowupdated", this, index, record);
55238 onAdd : function(ds, records, index){
55239 this.insertRows(ds, index, index + (records.length-1));
55242 onRemove : function(ds, record, index, isUpdate){
55243 if(isUpdate !== true){
55244 this.fireEvent("beforerowremoved", this, index, record);
55246 var bt = this.getBodyTable(), lt = this.getLockedTable();
55247 if(bt.rows[index]){
55248 bt.firstChild.removeChild(bt.rows[index]);
55250 if(lt.rows[index]){
55251 lt.firstChild.removeChild(lt.rows[index]);
55253 if(isUpdate !== true){
55254 this.stripeRows(index);
55255 this.syncRowHeights(index, index);
55257 this.fireEvent("rowremoved", this, index, record);
55261 onLoad : function(){
55262 this.scrollToTop();
55266 * Scrolls the grid to the top
55268 scrollToTop : function(){
55270 this.scroller.dom.scrollTop = 0;
55276 * Gets a panel in the header of the grid that can be used for toolbars etc.
55277 * After modifying the contents of this panel a call to grid.autoSize() may be
55278 * required to register any changes in size.
55279 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55280 * @return Roo.Element
55282 getHeaderPanel : function(doShow){
55284 this.headerPanel.show();
55286 return this.headerPanel;
55290 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55291 * After modifying the contents of this panel a call to grid.autoSize() may be
55292 * required to register any changes in size.
55293 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55294 * @return Roo.Element
55296 getFooterPanel : function(doShow){
55298 this.footerPanel.show();
55300 return this.footerPanel;
55303 initElements : function(){
55304 var E = Roo.Element;
55305 var el = this.grid.getGridEl().dom.firstChild;
55306 var cs = el.childNodes;
55308 this.el = new E(el);
55310 this.focusEl = new E(el.firstChild);
55311 this.focusEl.swallowEvent("click", true);
55313 this.headerPanel = new E(cs[1]);
55314 this.headerPanel.enableDisplayMode("block");
55316 this.scroller = new E(cs[2]);
55317 this.scrollSizer = new E(this.scroller.dom.firstChild);
55319 this.lockedWrap = new E(cs[3]);
55320 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55321 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55323 this.mainWrap = new E(cs[4]);
55324 this.mainHd = new E(this.mainWrap.dom.firstChild);
55325 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55327 this.footerPanel = new E(cs[5]);
55328 this.footerPanel.enableDisplayMode("block");
55330 this.resizeProxy = new E(cs[6]);
55332 this.headerSelector = String.format(
55333 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55334 this.lockedHd.id, this.mainHd.id
55337 this.splitterSelector = String.format(
55338 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55339 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55342 idToCssName : function(s)
55344 return s.replace(/[^a-z0-9]+/ig, '-');
55347 getHeaderCell : function(index){
55348 return Roo.DomQuery.select(this.headerSelector)[index];
55351 getHeaderCellMeasure : function(index){
55352 return this.getHeaderCell(index).firstChild;
55355 getHeaderCellText : function(index){
55356 return this.getHeaderCell(index).firstChild.firstChild;
55359 getLockedTable : function(){
55360 return this.lockedBody.dom.firstChild;
55363 getBodyTable : function(){
55364 return this.mainBody.dom.firstChild;
55367 getLockedRow : function(index){
55368 return this.getLockedTable().rows[index];
55371 getRow : function(index){
55372 return this.getBodyTable().rows[index];
55375 getRowComposite : function(index){
55377 this.rowEl = new Roo.CompositeElementLite();
55379 var els = [], lrow, mrow;
55380 if(lrow = this.getLockedRow(index)){
55383 if(mrow = this.getRow(index)){
55386 this.rowEl.elements = els;
55390 * Gets the 'td' of the cell
55392 * @param {Integer} rowIndex row to select
55393 * @param {Integer} colIndex column to select
55397 getCell : function(rowIndex, colIndex){
55398 var locked = this.cm.getLockedCount();
55400 if(colIndex < locked){
55401 source = this.lockedBody.dom.firstChild;
55403 source = this.mainBody.dom.firstChild;
55404 colIndex -= locked;
55406 return source.rows[rowIndex].childNodes[colIndex];
55409 getCellText : function(rowIndex, colIndex){
55410 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55413 getCellBox : function(cell){
55414 var b = this.fly(cell).getBox();
55415 if(Roo.isOpera){ // opera fails to report the Y
55416 b.y = cell.offsetTop + this.mainBody.getY();
55421 getCellIndex : function(cell){
55422 var id = String(cell.className).match(this.cellRE);
55424 return parseInt(id[1], 10);
55429 findHeaderIndex : function(n){
55430 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55431 return r ? this.getCellIndex(r) : false;
55434 findHeaderCell : function(n){
55435 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55436 return r ? r : false;
55439 findRowIndex : function(n){
55443 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55444 return r ? r.rowIndex : false;
55447 findCellIndex : function(node){
55448 var stop = this.el.dom;
55449 while(node && node != stop){
55450 if(this.findRE.test(node.className)){
55451 return this.getCellIndex(node);
55453 node = node.parentNode;
55458 getColumnId : function(index){
55459 return this.cm.getColumnId(index);
55462 getSplitters : function()
55464 if(this.splitterSelector){
55465 return Roo.DomQuery.select(this.splitterSelector);
55471 getSplitter : function(index){
55472 return this.getSplitters()[index];
55475 onRowOver : function(e, t){
55477 if((row = this.findRowIndex(t)) !== false){
55478 this.getRowComposite(row).addClass("x-grid-row-over");
55482 onRowOut : function(e, t){
55484 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55485 this.getRowComposite(row).removeClass("x-grid-row-over");
55489 renderHeaders : function(){
55491 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55492 var cb = [], lb = [], sb = [], lsb = [], p = {};
55493 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55494 p.cellId = "x-grid-hd-0-" + i;
55495 p.splitId = "x-grid-csplit-0-" + i;
55496 p.id = cm.getColumnId(i);
55497 p.value = cm.getColumnHeader(i) || "";
55498 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55499 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55500 if(!cm.isLocked(i)){
55501 cb[cb.length] = ct.apply(p);
55502 sb[sb.length] = st.apply(p);
55504 lb[lb.length] = ct.apply(p);
55505 lsb[lsb.length] = st.apply(p);
55508 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55509 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55512 updateHeaders : function(){
55513 var html = this.renderHeaders();
55514 this.lockedHd.update(html[0]);
55515 this.mainHd.update(html[1]);
55519 * Focuses the specified row.
55520 * @param {Number} row The row index
55522 focusRow : function(row)
55524 //Roo.log('GridView.focusRow');
55525 var x = this.scroller.dom.scrollLeft;
55526 this.focusCell(row, 0, false);
55527 this.scroller.dom.scrollLeft = x;
55531 * Focuses the specified cell.
55532 * @param {Number} row The row index
55533 * @param {Number} col The column index
55534 * @param {Boolean} hscroll false to disable horizontal scrolling
55536 focusCell : function(row, col, hscroll)
55538 //Roo.log('GridView.focusCell');
55539 var el = this.ensureVisible(row, col, hscroll);
55540 this.focusEl.alignTo(el, "tl-tl");
55542 this.focusEl.focus();
55544 this.focusEl.focus.defer(1, this.focusEl);
55549 * Scrolls the specified cell into view
55550 * @param {Number} row The row index
55551 * @param {Number} col The column index
55552 * @param {Boolean} hscroll false to disable horizontal scrolling
55554 ensureVisible : function(row, col, hscroll)
55556 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55557 //return null; //disable for testing.
55558 if(typeof row != "number"){
55559 row = row.rowIndex;
55561 if(row < 0 && row >= this.ds.getCount()){
55564 col = (col !== undefined ? col : 0);
55565 var cm = this.grid.colModel;
55566 while(cm.isHidden(col)){
55570 var el = this.getCell(row, col);
55574 var c = this.scroller.dom;
55576 var ctop = parseInt(el.offsetTop, 10);
55577 var cleft = parseInt(el.offsetLeft, 10);
55578 var cbot = ctop + el.offsetHeight;
55579 var cright = cleft + el.offsetWidth;
55581 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55582 var stop = parseInt(c.scrollTop, 10);
55583 var sleft = parseInt(c.scrollLeft, 10);
55584 var sbot = stop + ch;
55585 var sright = sleft + c.clientWidth;
55587 Roo.log('GridView.ensureVisible:' +
55589 ' c.clientHeight:' + c.clientHeight +
55590 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55598 c.scrollTop = ctop;
55599 //Roo.log("set scrolltop to ctop DISABLE?");
55600 }else if(cbot > sbot){
55601 //Roo.log("set scrolltop to cbot-ch");
55602 c.scrollTop = cbot-ch;
55605 if(hscroll !== false){
55607 c.scrollLeft = cleft;
55608 }else if(cright > sright){
55609 c.scrollLeft = cright-c.clientWidth;
55616 updateColumns : function(){
55617 this.grid.stopEditing();
55618 var cm = this.grid.colModel, colIds = this.getColumnIds();
55619 //var totalWidth = cm.getTotalWidth();
55621 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55622 //if(cm.isHidden(i)) continue;
55623 var w = cm.getColumnWidth(i);
55624 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55625 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55627 this.updateSplitters();
55630 generateRules : function(cm){
55631 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55632 Roo.util.CSS.removeStyleSheet(rulesId);
55633 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55634 var cid = cm.getColumnId(i);
55636 if(cm.config[i].align){
55637 align = 'text-align:'+cm.config[i].align+';';
55640 if(cm.isHidden(i)){
55641 hidden = 'display:none;';
55643 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55645 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55646 this.hdSelector, cid, " {\n", align, width, "}\n",
55647 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55648 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55650 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55653 updateSplitters : function(){
55654 var cm = this.cm, s = this.getSplitters();
55655 if(s){ // splitters not created yet
55656 var pos = 0, locked = true;
55657 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55658 if(cm.isHidden(i)) {
55661 var w = cm.getColumnWidth(i); // make sure it's a number
55662 if(!cm.isLocked(i) && locked){
55667 s[i].style.left = (pos-this.splitOffset) + "px";
55672 handleHiddenChange : function(colModel, colIndex, hidden){
55674 this.hideColumn(colIndex);
55676 this.unhideColumn(colIndex);
55680 hideColumn : function(colIndex){
55681 var cid = this.getColumnId(colIndex);
55682 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55683 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55685 this.updateHeaders();
55687 this.updateSplitters();
55691 unhideColumn : function(colIndex){
55692 var cid = this.getColumnId(colIndex);
55693 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55694 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55697 this.updateHeaders();
55699 this.updateSplitters();
55703 insertRows : function(dm, firstRow, lastRow, isUpdate){
55704 if(firstRow == 0 && lastRow == dm.getCount()-1){
55708 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55710 var s = this.getScrollState();
55711 var markup = this.renderRows(firstRow, lastRow);
55712 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55713 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55714 this.restoreScroll(s);
55716 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55717 this.syncRowHeights(firstRow, lastRow);
55718 this.stripeRows(firstRow);
55724 bufferRows : function(markup, target, index){
55725 var before = null, trows = target.rows, tbody = target.tBodies[0];
55726 if(index < trows.length){
55727 before = trows[index];
55729 var b = document.createElement("div");
55730 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55731 var rows = b.firstChild.rows;
55732 for(var i = 0, len = rows.length; i < len; i++){
55734 tbody.insertBefore(rows[0], before);
55736 tbody.appendChild(rows[0]);
55743 deleteRows : function(dm, firstRow, lastRow){
55744 if(dm.getRowCount()<1){
55745 this.fireEvent("beforerefresh", this);
55746 this.mainBody.update("");
55747 this.lockedBody.update("");
55748 this.fireEvent("refresh", this);
55750 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55751 var bt = this.getBodyTable();
55752 var tbody = bt.firstChild;
55753 var rows = bt.rows;
55754 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55755 tbody.removeChild(rows[firstRow]);
55757 this.stripeRows(firstRow);
55758 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55762 updateRows : function(dataSource, firstRow, lastRow){
55763 var s = this.getScrollState();
55765 this.restoreScroll(s);
55768 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55772 this.updateHeaderSortState();
55775 getScrollState : function(){
55777 var sb = this.scroller.dom;
55778 return {left: sb.scrollLeft, top: sb.scrollTop};
55781 stripeRows : function(startRow){
55782 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55785 startRow = startRow || 0;
55786 var rows = this.getBodyTable().rows;
55787 var lrows = this.getLockedTable().rows;
55788 var cls = ' x-grid-row-alt ';
55789 for(var i = startRow, len = rows.length; i < len; i++){
55790 var row = rows[i], lrow = lrows[i];
55791 var isAlt = ((i+1) % 2 == 0);
55792 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55793 if(isAlt == hasAlt){
55797 row.className += " x-grid-row-alt";
55799 row.className = row.className.replace("x-grid-row-alt", "");
55802 lrow.className = row.className;
55807 restoreScroll : function(state){
55808 //Roo.log('GridView.restoreScroll');
55809 var sb = this.scroller.dom;
55810 sb.scrollLeft = state.left;
55811 sb.scrollTop = state.top;
55815 syncScroll : function(){
55816 //Roo.log('GridView.syncScroll');
55817 var sb = this.scroller.dom;
55818 var sh = this.mainHd.dom;
55819 var bs = this.mainBody.dom;
55820 var lv = this.lockedBody.dom;
55821 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55822 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55825 handleScroll : function(e){
55827 var sb = this.scroller.dom;
55828 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55832 handleWheel : function(e){
55833 var d = e.getWheelDelta();
55834 this.scroller.dom.scrollTop -= d*22;
55835 // set this here to prevent jumpy scrolling on large tables
55836 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55840 renderRows : function(startRow, endRow){
55841 // pull in all the crap needed to render rows
55842 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55843 var colCount = cm.getColumnCount();
55845 if(ds.getCount() < 1){
55849 // build a map for all the columns
55851 for(var i = 0; i < colCount; i++){
55852 var name = cm.getDataIndex(i);
55854 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55855 renderer : cm.getRenderer(i),
55856 id : cm.getColumnId(i),
55857 locked : cm.isLocked(i),
55858 has_editor : cm.isCellEditable(i)
55862 startRow = startRow || 0;
55863 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55865 // records to render
55866 var rs = ds.getRange(startRow, endRow);
55868 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55871 // As much as I hate to duplicate code, this was branched because FireFox really hates
55872 // [].join("") on strings. The performance difference was substantial enough to
55873 // branch this function
55874 doRender : Roo.isGecko ?
55875 function(cs, rs, ds, startRow, colCount, stripe){
55876 var ts = this.templates, ct = ts.cell, rt = ts.row;
55878 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55880 var hasListener = this.grid.hasListener('rowclass');
55882 for(var j = 0, len = rs.length; j < len; j++){
55883 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
55884 for(var i = 0; i < colCount; i++){
55886 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55888 p.css = p.attr = "";
55889 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55890 if(p.value == undefined || p.value === "") {
55891 p.value = " ";
55894 p.css += ' x-grid-editable-cell';
55896 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
55897 p.css += ' x-grid-dirty-cell';
55899 var markup = ct.apply(p);
55907 if(stripe && ((rowIndex+1) % 2 == 0)){
55908 alt.push("x-grid-row-alt")
55911 alt.push( " x-grid-dirty-row");
55914 if(this.getRowClass){
55915 alt.push(this.getRowClass(r, rowIndex));
55921 rowIndex : rowIndex,
55924 this.grid.fireEvent('rowclass', this, rowcfg);
55925 alt.push(rowcfg.rowClass);
55927 rp.alt = alt.join(" ");
55928 lbuf+= rt.apply(rp);
55930 buf+= rt.apply(rp);
55932 return [lbuf, buf];
55934 function(cs, rs, ds, startRow, colCount, stripe){
55935 var ts = this.templates, ct = ts.cell, rt = ts.row;
55937 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55938 var hasListener = this.grid.hasListener('rowclass');
55941 for(var j = 0, len = rs.length; j < len; j++){
55942 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
55943 for(var i = 0; i < colCount; i++){
55945 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55947 p.css = p.attr = "";
55948 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55949 if(p.value == undefined || p.value === "") {
55950 p.value = " ";
55954 p.css += ' x-grid-editable-cell';
55956 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
55957 p.css += ' x-grid-dirty-cell'
55960 var markup = ct.apply(p);
55962 cb[cb.length] = markup;
55964 lcb[lcb.length] = markup;
55968 if(stripe && ((rowIndex+1) % 2 == 0)){
55969 alt.push( "x-grid-row-alt");
55972 alt.push(" x-grid-dirty-row");
55975 if(this.getRowClass){
55976 alt.push( this.getRowClass(r, rowIndex));
55982 rowIndex : rowIndex,
55985 this.grid.fireEvent('rowclass', this, rowcfg);
55986 alt.push(rowcfg.rowClass);
55989 rp.alt = alt.join(" ");
55990 rp.cells = lcb.join("");
55991 lbuf[lbuf.length] = rt.apply(rp);
55992 rp.cells = cb.join("");
55993 buf[buf.length] = rt.apply(rp);
55995 return [lbuf.join(""), buf.join("")];
55998 renderBody : function(){
55999 var markup = this.renderRows();
56000 var bt = this.templates.body;
56001 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
56005 * Refreshes the grid
56006 * @param {Boolean} headersToo
56008 refresh : function(headersToo){
56009 this.fireEvent("beforerefresh", this);
56010 this.grid.stopEditing();
56011 var result = this.renderBody();
56012 this.lockedBody.update(result[0]);
56013 this.mainBody.update(result[1]);
56014 if(headersToo === true){
56015 this.updateHeaders();
56016 this.updateColumns();
56017 this.updateSplitters();
56018 this.updateHeaderSortState();
56020 this.syncRowHeights();
56022 this.fireEvent("refresh", this);
56025 handleColumnMove : function(cm, oldIndex, newIndex){
56026 this.indexMap = null;
56027 var s = this.getScrollState();
56028 this.refresh(true);
56029 this.restoreScroll(s);
56030 this.afterMove(newIndex);
56033 afterMove : function(colIndex){
56034 if(this.enableMoveAnim && Roo.enableFx){
56035 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56037 // if multisort - fix sortOrder, and reload..
56038 if (this.grid.dataSource.multiSort) {
56039 // the we can call sort again..
56040 var dm = this.grid.dataSource;
56041 var cm = this.grid.colModel;
56043 for(var i = 0; i < cm.config.length; i++ ) {
56045 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56046 continue; // dont' bother, it's not in sort list or being set.
56049 so.push(cm.config[i].dataIndex);
56052 dm.load(dm.lastOptions);
56059 updateCell : function(dm, rowIndex, dataIndex){
56060 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56061 if(typeof colIndex == "undefined"){ // not present in grid
56064 var cm = this.grid.colModel;
56065 var cell = this.getCell(rowIndex, colIndex);
56066 var cellText = this.getCellText(rowIndex, colIndex);
56069 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56070 id : cm.getColumnId(colIndex),
56071 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56073 var renderer = cm.getRenderer(colIndex);
56074 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56075 if(typeof val == "undefined" || val === "") {
56078 cellText.innerHTML = val;
56079 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56080 this.syncRowHeights(rowIndex, rowIndex);
56083 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56085 if(this.grid.autoSizeHeaders){
56086 var h = this.getHeaderCellMeasure(colIndex);
56087 maxWidth = Math.max(maxWidth, h.scrollWidth);
56090 if(this.cm.isLocked(colIndex)){
56091 tb = this.getLockedTable();
56094 tb = this.getBodyTable();
56095 index = colIndex - this.cm.getLockedCount();
56098 var rows = tb.rows;
56099 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56100 for(var i = 0; i < stopIndex; i++){
56101 var cell = rows[i].childNodes[index].firstChild;
56102 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56105 return maxWidth + /*margin for error in IE*/ 5;
56108 * Autofit a column to its content.
56109 * @param {Number} colIndex
56110 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56112 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56113 if(this.cm.isHidden(colIndex)){
56114 return; // can't calc a hidden column
56117 var cid = this.cm.getColumnId(colIndex);
56118 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56119 if(this.grid.autoSizeHeaders){
56120 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56123 var newWidth = this.calcColumnWidth(colIndex);
56124 this.cm.setColumnWidth(colIndex,
56125 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56126 if(!suppressEvent){
56127 this.grid.fireEvent("columnresize", colIndex, newWidth);
56132 * Autofits all columns to their content and then expands to fit any extra space in the grid
56134 autoSizeColumns : function(){
56135 var cm = this.grid.colModel;
56136 var colCount = cm.getColumnCount();
56137 for(var i = 0; i < colCount; i++){
56138 this.autoSizeColumn(i, true, true);
56140 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56143 this.updateColumns();
56149 * Autofits all columns to the grid's width proportionate with their current size
56150 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56152 fitColumns : function(reserveScrollSpace){
56153 var cm = this.grid.colModel;
56154 var colCount = cm.getColumnCount();
56158 for (i = 0; i < colCount; i++){
56159 if(!cm.isHidden(i) && !cm.isFixed(i)){
56160 w = cm.getColumnWidth(i);
56166 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56167 if(reserveScrollSpace){
56170 var frac = (avail - cm.getTotalWidth())/width;
56171 while (cols.length){
56174 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56176 this.updateColumns();
56180 onRowSelect : function(rowIndex){
56181 var row = this.getRowComposite(rowIndex);
56182 row.addClass("x-grid-row-selected");
56185 onRowDeselect : function(rowIndex){
56186 var row = this.getRowComposite(rowIndex);
56187 row.removeClass("x-grid-row-selected");
56190 onCellSelect : function(row, col){
56191 var cell = this.getCell(row, col);
56193 Roo.fly(cell).addClass("x-grid-cell-selected");
56197 onCellDeselect : function(row, col){
56198 var cell = this.getCell(row, col);
56200 Roo.fly(cell).removeClass("x-grid-cell-selected");
56204 updateHeaderSortState : function(){
56206 // sort state can be single { field: xxx, direction : yyy}
56207 // or { xxx=>ASC , yyy : DESC ..... }
56210 if (!this.ds.multiSort) {
56211 var state = this.ds.getSortState();
56215 mstate[state.field] = state.direction;
56216 // FIXME... - this is not used here.. but might be elsewhere..
56217 this.sortState = state;
56220 mstate = this.ds.sortToggle;
56222 //remove existing sort classes..
56224 var sc = this.sortClasses;
56225 var hds = this.el.select(this.headerSelector).removeClass(sc);
56227 for(var f in mstate) {
56229 var sortColumn = this.cm.findColumnIndex(f);
56231 if(sortColumn != -1){
56232 var sortDir = mstate[f];
56233 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56242 handleHeaderClick : function(g, index,e){
56244 Roo.log("header click");
56247 // touch events on header are handled by context
56248 this.handleHdCtx(g,index,e);
56253 if(this.headersDisabled){
56256 var dm = g.dataSource, cm = g.colModel;
56257 if(!cm.isSortable(index)){
56262 if (dm.multiSort) {
56263 // update the sortOrder
56265 for(var i = 0; i < cm.config.length; i++ ) {
56267 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56268 continue; // dont' bother, it's not in sort list or being set.
56271 so.push(cm.config[i].dataIndex);
56277 dm.sort(cm.getDataIndex(index));
56281 destroy : function(){
56283 this.colMenu.removeAll();
56284 Roo.menu.MenuMgr.unregister(this.colMenu);
56285 this.colMenu.getEl().remove();
56286 delete this.colMenu;
56289 this.hmenu.removeAll();
56290 Roo.menu.MenuMgr.unregister(this.hmenu);
56291 this.hmenu.getEl().remove();
56294 if(this.grid.enableColumnMove){
56295 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56297 for(var dd in dds){
56298 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56299 var elid = dds[dd].dragElId;
56301 Roo.get(elid).remove();
56302 } else if(dds[dd].config.isTarget){
56303 dds[dd].proxyTop.remove();
56304 dds[dd].proxyBottom.remove();
56307 if(Roo.dd.DDM.locationCache[dd]){
56308 delete Roo.dd.DDM.locationCache[dd];
56311 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56314 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56315 this.bind(null, null);
56316 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56319 handleLockChange : function(){
56320 this.refresh(true);
56323 onDenyColumnLock : function(){
56327 onDenyColumnHide : function(){
56331 handleHdMenuClick : function(item){
56332 var index = this.hdCtxIndex;
56333 var cm = this.cm, ds = this.ds;
56336 ds.sort(cm.getDataIndex(index), "ASC");
56339 ds.sort(cm.getDataIndex(index), "DESC");
56342 var lc = cm.getLockedCount();
56343 if(cm.getColumnCount(true) <= lc+1){
56344 this.onDenyColumnLock();
56348 cm.setLocked(index, true, true);
56349 cm.moveColumn(index, lc);
56350 this.grid.fireEvent("columnmove", index, lc);
56352 cm.setLocked(index, true);
56356 var lc = cm.getLockedCount();
56357 if((lc-1) != index){
56358 cm.setLocked(index, false, true);
56359 cm.moveColumn(index, lc-1);
56360 this.grid.fireEvent("columnmove", index, lc-1);
56362 cm.setLocked(index, false);
56365 case 'wider': // used to expand cols on touch..
56367 var cw = cm.getColumnWidth(index);
56368 cw += (item.id == 'wider' ? 1 : -1) * 50;
56369 cw = Math.max(0, cw);
56370 cw = Math.min(cw,4000);
56371 cm.setColumnWidth(index, cw);
56375 index = cm.getIndexById(item.id.substr(4));
56377 if(item.checked && cm.getColumnCount(true) <= 1){
56378 this.onDenyColumnHide();
56381 cm.setHidden(index, item.checked);
56387 beforeColMenuShow : function(){
56388 var cm = this.cm, colCount = cm.getColumnCount();
56389 this.colMenu.removeAll();
56390 for(var i = 0; i < colCount; i++){
56391 this.colMenu.add(new Roo.menu.CheckItem({
56392 id: "col-"+cm.getColumnId(i),
56393 text: cm.getColumnHeader(i),
56394 checked: !cm.isHidden(i),
56400 handleHdCtx : function(g, index, e){
56402 var hd = this.getHeaderCell(index);
56403 this.hdCtxIndex = index;
56404 var ms = this.hmenu.items, cm = this.cm;
56405 ms.get("asc").setDisabled(!cm.isSortable(index));
56406 ms.get("desc").setDisabled(!cm.isSortable(index));
56407 if(this.grid.enableColLock !== false){
56408 ms.get("lock").setDisabled(cm.isLocked(index));
56409 ms.get("unlock").setDisabled(!cm.isLocked(index));
56411 this.hmenu.show(hd, "tl-bl");
56414 handleHdOver : function(e){
56415 var hd = this.findHeaderCell(e.getTarget());
56416 if(hd && !this.headersDisabled){
56417 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56418 this.fly(hd).addClass("x-grid-hd-over");
56423 handleHdOut : function(e){
56424 var hd = this.findHeaderCell(e.getTarget());
56426 this.fly(hd).removeClass("x-grid-hd-over");
56430 handleSplitDblClick : function(e, t){
56431 var i = this.getCellIndex(t);
56432 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56433 this.autoSizeColumn(i, true);
56438 render : function(){
56441 var colCount = cm.getColumnCount();
56443 if(this.grid.monitorWindowResize === true){
56444 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56446 var header = this.renderHeaders();
56447 var body = this.templates.body.apply({rows:""});
56448 var html = this.templates.master.apply({
56451 lockedHeader: header[0],
56455 //this.updateColumns();
56457 this.grid.getGridEl().dom.innerHTML = html;
56459 this.initElements();
56461 // a kludge to fix the random scolling effect in webkit
56462 this.el.on("scroll", function() {
56463 this.el.dom.scrollTop=0; // hopefully not recursive..
56466 this.scroller.on("scroll", this.handleScroll, this);
56467 this.lockedBody.on("mousewheel", this.handleWheel, this);
56468 this.mainBody.on("mousewheel", this.handleWheel, this);
56470 this.mainHd.on("mouseover", this.handleHdOver, this);
56471 this.mainHd.on("mouseout", this.handleHdOut, this);
56472 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56473 {delegate: "."+this.splitClass});
56475 this.lockedHd.on("mouseover", this.handleHdOver, this);
56476 this.lockedHd.on("mouseout", this.handleHdOut, this);
56477 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56478 {delegate: "."+this.splitClass});
56480 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56481 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56484 this.updateSplitters();
56486 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56487 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56488 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56491 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56492 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56494 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56495 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56497 if(this.grid.enableColLock !== false){
56498 this.hmenu.add('-',
56499 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56500 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56504 this.hmenu.add('-',
56505 {id:"wider", text: this.columnsWiderText},
56506 {id:"narrow", text: this.columnsNarrowText }
56512 if(this.grid.enableColumnHide !== false){
56514 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56515 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56516 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56518 this.hmenu.add('-',
56519 {id:"columns", text: this.columnsText, menu: this.colMenu}
56522 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56524 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56527 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56528 this.dd = new Roo.grid.GridDragZone(this.grid, {
56529 ddGroup : this.grid.ddGroup || 'GridDD'
56535 for(var i = 0; i < colCount; i++){
56536 if(cm.isHidden(i)){
56537 this.hideColumn(i);
56539 if(cm.config[i].align){
56540 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56541 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56545 this.updateHeaderSortState();
56547 this.beforeInitialResize();
56550 // two part rendering gives faster view to the user
56551 this.renderPhase2.defer(1, this);
56554 renderPhase2 : function(){
56555 // render the rows now
56557 if(this.grid.autoSizeColumns){
56558 this.autoSizeColumns();
56562 beforeInitialResize : function(){
56566 onColumnSplitterMoved : function(i, w){
56567 this.userResized = true;
56568 var cm = this.grid.colModel;
56569 cm.setColumnWidth(i, w, true);
56570 var cid = cm.getColumnId(i);
56571 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56572 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56573 this.updateSplitters();
56575 this.grid.fireEvent("columnresize", i, w);
56578 syncRowHeights : function(startIndex, endIndex){
56579 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56580 startIndex = startIndex || 0;
56581 var mrows = this.getBodyTable().rows;
56582 var lrows = this.getLockedTable().rows;
56583 var len = mrows.length-1;
56584 endIndex = Math.min(endIndex || len, len);
56585 for(var i = startIndex; i <= endIndex; i++){
56586 var m = mrows[i], l = lrows[i];
56587 var h = Math.max(m.offsetHeight, l.offsetHeight);
56588 m.style.height = l.style.height = h + "px";
56593 layout : function(initialRender, is2ndPass){
56595 var auto = g.autoHeight;
56596 var scrollOffset = 16;
56597 var c = g.getGridEl(), cm = this.cm,
56598 expandCol = g.autoExpandColumn,
56600 //c.beginMeasure();
56602 if(!c.dom.offsetWidth){ // display:none?
56604 this.lockedWrap.show();
56605 this.mainWrap.show();
56610 var hasLock = this.cm.isLocked(0);
56612 var tbh = this.headerPanel.getHeight();
56613 var bbh = this.footerPanel.getHeight();
56616 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56617 var newHeight = ch + c.getBorderWidth("tb");
56619 newHeight = Math.min(g.maxHeight, newHeight);
56621 c.setHeight(newHeight);
56625 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56628 var s = this.scroller;
56630 var csize = c.getSize(true);
56632 this.el.setSize(csize.width, csize.height);
56634 this.headerPanel.setWidth(csize.width);
56635 this.footerPanel.setWidth(csize.width);
56637 var hdHeight = this.mainHd.getHeight();
56638 var vw = csize.width;
56639 var vh = csize.height - (tbh + bbh);
56643 var bt = this.getBodyTable();
56645 if(cm.getLockedCount() == cm.config.length){
56646 bt = this.getLockedTable();
56649 var ltWidth = hasLock ?
56650 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56652 var scrollHeight = bt.offsetHeight;
56653 var scrollWidth = ltWidth + bt.offsetWidth;
56654 var vscroll = false, hscroll = false;
56656 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56658 var lw = this.lockedWrap, mw = this.mainWrap;
56659 var lb = this.lockedBody, mb = this.mainBody;
56661 setTimeout(function(){
56662 var t = s.dom.offsetTop;
56663 var w = s.dom.clientWidth,
56664 h = s.dom.clientHeight;
56667 lw.setSize(ltWidth, h);
56669 mw.setLeftTop(ltWidth, t);
56670 mw.setSize(w-ltWidth, h);
56672 lb.setHeight(h-hdHeight);
56673 mb.setHeight(h-hdHeight);
56675 if(is2ndPass !== true && !gv.userResized && expandCol){
56676 // high speed resize without full column calculation
56678 var ci = cm.getIndexById(expandCol);
56680 ci = cm.findColumnIndex(expandCol);
56682 ci = Math.max(0, ci); // make sure it's got at least the first col.
56683 var expandId = cm.getColumnId(ci);
56684 var tw = cm.getTotalWidth(false);
56685 var currentWidth = cm.getColumnWidth(ci);
56686 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56687 if(currentWidth != cw){
56688 cm.setColumnWidth(ci, cw, true);
56689 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56690 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56691 gv.updateSplitters();
56692 gv.layout(false, true);
56704 onWindowResize : function(){
56705 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56711 appendFooter : function(parentEl){
56715 sortAscText : "Sort Ascending",
56716 sortDescText : "Sort Descending",
56717 lockText : "Lock Column",
56718 unlockText : "Unlock Column",
56719 columnsText : "Columns",
56721 columnsWiderText : "Wider",
56722 columnsNarrowText : "Thinner"
56726 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56727 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56728 this.proxy.el.addClass('x-grid3-col-dd');
56731 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56732 handleMouseDown : function(e){
56736 callHandleMouseDown : function(e){
56737 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56742 * Ext JS Library 1.1.1
56743 * Copyright(c) 2006-2007, Ext JS, LLC.
56745 * Originally Released Under LGPL - original licence link has changed is not relivant.
56748 * <script type="text/javascript">
56752 // This is a support class used internally by the Grid components
56753 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56755 this.view = grid.getView();
56756 this.proxy = this.view.resizeProxy;
56757 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56758 "gridSplitters" + this.grid.getGridEl().id, {
56759 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56761 this.setHandleElId(Roo.id(hd));
56762 this.setOuterHandleElId(Roo.id(hd2));
56763 this.scroll = false;
56765 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56766 fly: Roo.Element.fly,
56768 b4StartDrag : function(x, y){
56769 this.view.headersDisabled = true;
56770 this.proxy.setHeight(this.view.mainWrap.getHeight());
56771 var w = this.cm.getColumnWidth(this.cellIndex);
56772 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56773 this.resetConstraints();
56774 this.setXConstraint(minw, 1000);
56775 this.setYConstraint(0, 0);
56776 this.minX = x - minw;
56777 this.maxX = x + 1000;
56779 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56783 handleMouseDown : function(e){
56784 ev = Roo.EventObject.setEvent(e);
56785 var t = this.fly(ev.getTarget());
56786 if(t.hasClass("x-grid-split")){
56787 this.cellIndex = this.view.getCellIndex(t.dom);
56788 this.split = t.dom;
56789 this.cm = this.grid.colModel;
56790 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56791 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56796 endDrag : function(e){
56797 this.view.headersDisabled = false;
56798 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56799 var diff = endX - this.startPos;
56800 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56803 autoOffset : function(){
56804 this.setDelta(0,0);
56808 * Ext JS Library 1.1.1
56809 * Copyright(c) 2006-2007, Ext JS, LLC.
56811 * Originally Released Under LGPL - original licence link has changed is not relivant.
56814 * <script type="text/javascript">
56818 // This is a support class used internally by the Grid components
56819 Roo.grid.GridDragZone = function(grid, config){
56820 this.view = grid.getView();
56821 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56822 if(this.view.lockedBody){
56823 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56824 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56826 this.scroll = false;
56828 this.ddel = document.createElement('div');
56829 this.ddel.className = 'x-grid-dd-wrap';
56832 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56833 ddGroup : "GridDD",
56835 getDragData : function(e){
56836 var t = Roo.lib.Event.getTarget(e);
56837 var rowIndex = this.view.findRowIndex(t);
56838 var sm = this.grid.selModel;
56840 //Roo.log(rowIndex);
56842 if (sm.getSelectedCell) {
56843 // cell selection..
56844 if (!sm.getSelectedCell()) {
56847 if (rowIndex != sm.getSelectedCell()[0]) {
56853 if(rowIndex !== false){
56858 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56860 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56863 if (e.hasModifier()){
56864 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56867 Roo.log("getDragData");
56872 rowIndex: rowIndex,
56873 selections:sm.getSelections ? sm.getSelections() : (
56874 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
56881 onInitDrag : function(e){
56882 var data = this.dragData;
56883 this.ddel.innerHTML = this.grid.getDragDropText();
56884 this.proxy.update(this.ddel);
56885 // fire start drag?
56888 afterRepair : function(){
56889 this.dragging = false;
56892 getRepairXY : function(e, data){
56896 onEndDrag : function(data, e){
56900 onValidDrop : function(dd, e, id){
56905 beforeInvalidDrop : function(e, id){
56910 * Ext JS Library 1.1.1
56911 * Copyright(c) 2006-2007, Ext JS, LLC.
56913 * Originally Released Under LGPL - original licence link has changed is not relivant.
56916 * <script type="text/javascript">
56921 * @class Roo.grid.ColumnModel
56922 * @extends Roo.util.Observable
56923 * This is the default implementation of a ColumnModel used by the Grid. It defines
56924 * the columns in the grid.
56927 var colModel = new Roo.grid.ColumnModel([
56928 {header: "Ticker", width: 60, sortable: true, locked: true},
56929 {header: "Company Name", width: 150, sortable: true},
56930 {header: "Market Cap.", width: 100, sortable: true},
56931 {header: "$ Sales", width: 100, sortable: true, renderer: money},
56932 {header: "Employees", width: 100, sortable: true, resizable: false}
56937 * The config options listed for this class are options which may appear in each
56938 * individual column definition.
56939 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
56941 * @param {Object} config An Array of column config objects. See this class's
56942 * config objects for details.
56944 Roo.grid.ColumnModel = function(config){
56946 * The config passed into the constructor
56948 this.config = config;
56951 // if no id, create one
56952 // if the column does not have a dataIndex mapping,
56953 // map it to the order it is in the config
56954 for(var i = 0, len = config.length; i < len; i++){
56956 if(typeof c.dataIndex == "undefined"){
56959 if(typeof c.renderer == "string"){
56960 c.renderer = Roo.util.Format[c.renderer];
56962 if(typeof c.id == "undefined"){
56965 if(c.editor && c.editor.xtype){
56966 c.editor = Roo.factory(c.editor, Roo.grid);
56968 if(c.editor && c.editor.isFormField){
56969 c.editor = new Roo.grid.GridEditor(c.editor);
56971 this.lookup[c.id] = c;
56975 * The width of columns which have no width specified (defaults to 100)
56978 this.defaultWidth = 100;
56981 * Default sortable of columns which have no sortable specified (defaults to false)
56984 this.defaultSortable = false;
56988 * @event widthchange
56989 * Fires when the width of a column changes.
56990 * @param {ColumnModel} this
56991 * @param {Number} columnIndex The column index
56992 * @param {Number} newWidth The new width
56994 "widthchange": true,
56996 * @event headerchange
56997 * Fires when the text of a header changes.
56998 * @param {ColumnModel} this
56999 * @param {Number} columnIndex The column index
57000 * @param {Number} newText The new header text
57002 "headerchange": true,
57004 * @event hiddenchange
57005 * Fires when a column is hidden or "unhidden".
57006 * @param {ColumnModel} this
57007 * @param {Number} columnIndex The column index
57008 * @param {Boolean} hidden true if hidden, false otherwise
57010 "hiddenchange": true,
57012 * @event columnmoved
57013 * Fires when a column is moved.
57014 * @param {ColumnModel} this
57015 * @param {Number} oldIndex
57016 * @param {Number} newIndex
57018 "columnmoved" : true,
57020 * @event columlockchange
57021 * Fires when a column's locked state is changed
57022 * @param {ColumnModel} this
57023 * @param {Number} colIndex
57024 * @param {Boolean} locked true if locked
57026 "columnlockchange" : true
57028 Roo.grid.ColumnModel.superclass.constructor.call(this);
57030 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57032 * @cfg {String} header The header text to display in the Grid view.
57035 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57036 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57037 * specified, the column's index is used as an index into the Record's data Array.
57040 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57041 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57044 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57045 * Defaults to the value of the {@link #defaultSortable} property.
57046 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57049 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57052 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57055 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57058 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57061 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57062 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57063 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57064 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57067 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57070 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57073 * @cfg {String} cursor (Optional)
57076 * @cfg {String} tooltip (Optional)
57079 * @cfg {Number} xs (Optional)
57082 * @cfg {Number} sm (Optional)
57085 * @cfg {Number} md (Optional)
57088 * @cfg {Number} lg (Optional)
57091 * Returns the id of the column at the specified index.
57092 * @param {Number} index The column index
57093 * @return {String} the id
57095 getColumnId : function(index){
57096 return this.config[index].id;
57100 * Returns the column for a specified id.
57101 * @param {String} id The column id
57102 * @return {Object} the column
57104 getColumnById : function(id){
57105 return this.lookup[id];
57110 * Returns the column for a specified dataIndex.
57111 * @param {String} dataIndex The column dataIndex
57112 * @return {Object|Boolean} the column or false if not found
57114 getColumnByDataIndex: function(dataIndex){
57115 var index = this.findColumnIndex(dataIndex);
57116 return index > -1 ? this.config[index] : false;
57120 * Returns the index for a specified column id.
57121 * @param {String} id The column id
57122 * @return {Number} the index, or -1 if not found
57124 getIndexById : function(id){
57125 for(var i = 0, len = this.config.length; i < len; i++){
57126 if(this.config[i].id == id){
57134 * Returns the index for a specified column dataIndex.
57135 * @param {String} dataIndex The column dataIndex
57136 * @return {Number} the index, or -1 if not found
57139 findColumnIndex : function(dataIndex){
57140 for(var i = 0, len = this.config.length; i < len; i++){
57141 if(this.config[i].dataIndex == dataIndex){
57149 moveColumn : function(oldIndex, newIndex){
57150 var c = this.config[oldIndex];
57151 this.config.splice(oldIndex, 1);
57152 this.config.splice(newIndex, 0, c);
57153 this.dataMap = null;
57154 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57157 isLocked : function(colIndex){
57158 return this.config[colIndex].locked === true;
57161 setLocked : function(colIndex, value, suppressEvent){
57162 if(this.isLocked(colIndex) == value){
57165 this.config[colIndex].locked = value;
57166 if(!suppressEvent){
57167 this.fireEvent("columnlockchange", this, colIndex, value);
57171 getTotalLockedWidth : function(){
57172 var totalWidth = 0;
57173 for(var i = 0; i < this.config.length; i++){
57174 if(this.isLocked(i) && !this.isHidden(i)){
57175 this.totalWidth += this.getColumnWidth(i);
57181 getLockedCount : function(){
57182 for(var i = 0, len = this.config.length; i < len; i++){
57183 if(!this.isLocked(i)){
57188 return this.config.length;
57192 * Returns the number of columns.
57195 getColumnCount : function(visibleOnly){
57196 if(visibleOnly === true){
57198 for(var i = 0, len = this.config.length; i < len; i++){
57199 if(!this.isHidden(i)){
57205 return this.config.length;
57209 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57210 * @param {Function} fn
57211 * @param {Object} scope (optional)
57212 * @return {Array} result
57214 getColumnsBy : function(fn, scope){
57216 for(var i = 0, len = this.config.length; i < len; i++){
57217 var c = this.config[i];
57218 if(fn.call(scope||this, c, i) === true){
57226 * Returns true if the specified column is sortable.
57227 * @param {Number} col The column index
57228 * @return {Boolean}
57230 isSortable : function(col){
57231 if(typeof this.config[col].sortable == "undefined"){
57232 return this.defaultSortable;
57234 return this.config[col].sortable;
57238 * Returns the rendering (formatting) function defined for the column.
57239 * @param {Number} col The column index.
57240 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57242 getRenderer : function(col){
57243 if(!this.config[col].renderer){
57244 return Roo.grid.ColumnModel.defaultRenderer;
57246 return this.config[col].renderer;
57250 * Sets the rendering (formatting) function for a column.
57251 * @param {Number} col The column index
57252 * @param {Function} fn The function to use to process the cell's raw data
57253 * to return HTML markup for the grid view. The render function is called with
57254 * the following parameters:<ul>
57255 * <li>Data value.</li>
57256 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57257 * <li>css A CSS style string to apply to the table cell.</li>
57258 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57259 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57260 * <li>Row index</li>
57261 * <li>Column index</li>
57262 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57264 setRenderer : function(col, fn){
57265 this.config[col].renderer = fn;
57269 * Returns the width for the specified column.
57270 * @param {Number} col The column index
57273 getColumnWidth : function(col){
57274 return this.config[col].width * 1 || this.defaultWidth;
57278 * Sets the width for a column.
57279 * @param {Number} col The column index
57280 * @param {Number} width The new width
57282 setColumnWidth : function(col, width, suppressEvent){
57283 this.config[col].width = width;
57284 this.totalWidth = null;
57285 if(!suppressEvent){
57286 this.fireEvent("widthchange", this, col, width);
57291 * Returns the total width of all columns.
57292 * @param {Boolean} includeHidden True to include hidden column widths
57295 getTotalWidth : function(includeHidden){
57296 if(!this.totalWidth){
57297 this.totalWidth = 0;
57298 for(var i = 0, len = this.config.length; i < len; i++){
57299 if(includeHidden || !this.isHidden(i)){
57300 this.totalWidth += this.getColumnWidth(i);
57304 return this.totalWidth;
57308 * Returns the header for the specified column.
57309 * @param {Number} col The column index
57312 getColumnHeader : function(col){
57313 return this.config[col].header;
57317 * Sets the header for a column.
57318 * @param {Number} col The column index
57319 * @param {String} header The new header
57321 setColumnHeader : function(col, header){
57322 this.config[col].header = header;
57323 this.fireEvent("headerchange", this, col, header);
57327 * Returns the tooltip for the specified column.
57328 * @param {Number} col The column index
57331 getColumnTooltip : function(col){
57332 return this.config[col].tooltip;
57335 * Sets the tooltip for a column.
57336 * @param {Number} col The column index
57337 * @param {String} tooltip The new tooltip
57339 setColumnTooltip : function(col, tooltip){
57340 this.config[col].tooltip = tooltip;
57344 * Returns the dataIndex for the specified column.
57345 * @param {Number} col The column index
57348 getDataIndex : function(col){
57349 return this.config[col].dataIndex;
57353 * Sets the dataIndex for a column.
57354 * @param {Number} col The column index
57355 * @param {Number} dataIndex The new dataIndex
57357 setDataIndex : function(col, dataIndex){
57358 this.config[col].dataIndex = dataIndex;
57364 * Returns true if the cell is editable.
57365 * @param {Number} colIndex The column index
57366 * @param {Number} rowIndex The row index - this is nto actually used..?
57367 * @return {Boolean}
57369 isCellEditable : function(colIndex, rowIndex){
57370 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57374 * Returns the editor defined for the cell/column.
57375 * return false or null to disable editing.
57376 * @param {Number} colIndex The column index
57377 * @param {Number} rowIndex The row index
57380 getCellEditor : function(colIndex, rowIndex){
57381 return this.config[colIndex].editor;
57385 * Sets if a column is editable.
57386 * @param {Number} col The column index
57387 * @param {Boolean} editable True if the column is editable
57389 setEditable : function(col, editable){
57390 this.config[col].editable = editable;
57395 * Returns true if the column is hidden.
57396 * @param {Number} colIndex The column index
57397 * @return {Boolean}
57399 isHidden : function(colIndex){
57400 return this.config[colIndex].hidden;
57405 * Returns true if the column width cannot be changed
57407 isFixed : function(colIndex){
57408 return this.config[colIndex].fixed;
57412 * Returns true if the column can be resized
57413 * @return {Boolean}
57415 isResizable : function(colIndex){
57416 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57419 * Sets if a column is hidden.
57420 * @param {Number} colIndex The column index
57421 * @param {Boolean} hidden True if the column is hidden
57423 setHidden : function(colIndex, hidden){
57424 this.config[colIndex].hidden = hidden;
57425 this.totalWidth = null;
57426 this.fireEvent("hiddenchange", this, colIndex, hidden);
57430 * Sets the editor for a column.
57431 * @param {Number} col The column index
57432 * @param {Object} editor The editor object
57434 setEditor : function(col, editor){
57435 this.config[col].editor = editor;
57439 Roo.grid.ColumnModel.defaultRenderer = function(value)
57441 if(typeof value == "object") {
57444 if(typeof value == "string" && value.length < 1){
57448 return String.format("{0}", value);
57451 // Alias for backwards compatibility
57452 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57455 * Ext JS Library 1.1.1
57456 * Copyright(c) 2006-2007, Ext JS, LLC.
57458 * Originally Released Under LGPL - original licence link has changed is not relivant.
57461 * <script type="text/javascript">
57465 * @class Roo.grid.AbstractSelectionModel
57466 * @extends Roo.util.Observable
57467 * Abstract base class for grid SelectionModels. It provides the interface that should be
57468 * implemented by descendant classes. This class should not be directly instantiated.
57471 Roo.grid.AbstractSelectionModel = function(){
57472 this.locked = false;
57473 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57476 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57477 /** @ignore Called by the grid automatically. Do not call directly. */
57478 init : function(grid){
57484 * Locks the selections.
57487 this.locked = true;
57491 * Unlocks the selections.
57493 unlock : function(){
57494 this.locked = false;
57498 * Returns true if the selections are locked.
57499 * @return {Boolean}
57501 isLocked : function(){
57502 return this.locked;
57506 * Ext JS Library 1.1.1
57507 * Copyright(c) 2006-2007, Ext JS, LLC.
57509 * Originally Released Under LGPL - original licence link has changed is not relivant.
57512 * <script type="text/javascript">
57515 * @extends Roo.grid.AbstractSelectionModel
57516 * @class Roo.grid.RowSelectionModel
57517 * The default SelectionModel used by {@link Roo.grid.Grid}.
57518 * It supports multiple selections and keyboard selection/navigation.
57520 * @param {Object} config
57522 Roo.grid.RowSelectionModel = function(config){
57523 Roo.apply(this, config);
57524 this.selections = new Roo.util.MixedCollection(false, function(o){
57529 this.lastActive = false;
57533 * @event selectionchange
57534 * Fires when the selection changes
57535 * @param {SelectionModel} this
57537 "selectionchange" : true,
57539 * @event afterselectionchange
57540 * Fires after the selection changes (eg. by key press or clicking)
57541 * @param {SelectionModel} this
57543 "afterselectionchange" : true,
57545 * @event beforerowselect
57546 * Fires when a row is selected being selected, return false to cancel.
57547 * @param {SelectionModel} this
57548 * @param {Number} rowIndex The selected index
57549 * @param {Boolean} keepExisting False if other selections will be cleared
57551 "beforerowselect" : true,
57554 * Fires when a row is selected.
57555 * @param {SelectionModel} this
57556 * @param {Number} rowIndex The selected index
57557 * @param {Roo.data.Record} r The record
57559 "rowselect" : true,
57561 * @event rowdeselect
57562 * Fires when a row is deselected.
57563 * @param {SelectionModel} this
57564 * @param {Number} rowIndex The selected index
57566 "rowdeselect" : true
57568 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57569 this.locked = false;
57572 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57574 * @cfg {Boolean} singleSelect
57575 * True to allow selection of only one row at a time (defaults to false)
57577 singleSelect : false,
57580 initEvents : function(){
57582 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57583 this.grid.on("mousedown", this.handleMouseDown, this);
57584 }else{ // allow click to work like normal
57585 this.grid.on("rowclick", this.handleDragableRowClick, this);
57588 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57589 "up" : function(e){
57591 this.selectPrevious(e.shiftKey);
57592 }else if(this.last !== false && this.lastActive !== false){
57593 var last = this.last;
57594 this.selectRange(this.last, this.lastActive-1);
57595 this.grid.getView().focusRow(this.lastActive);
57596 if(last !== false){
57600 this.selectFirstRow();
57602 this.fireEvent("afterselectionchange", this);
57604 "down" : function(e){
57606 this.selectNext(e.shiftKey);
57607 }else if(this.last !== false && this.lastActive !== false){
57608 var last = this.last;
57609 this.selectRange(this.last, this.lastActive+1);
57610 this.grid.getView().focusRow(this.lastActive);
57611 if(last !== false){
57615 this.selectFirstRow();
57617 this.fireEvent("afterselectionchange", this);
57622 var view = this.grid.view;
57623 view.on("refresh", this.onRefresh, this);
57624 view.on("rowupdated", this.onRowUpdated, this);
57625 view.on("rowremoved", this.onRemove, this);
57629 onRefresh : function(){
57630 var ds = this.grid.dataSource, i, v = this.grid.view;
57631 var s = this.selections;
57632 s.each(function(r){
57633 if((i = ds.indexOfId(r.id)) != -1){
57635 s.add(ds.getAt(i)); // updating the selection relate data
57643 onRemove : function(v, index, r){
57644 this.selections.remove(r);
57648 onRowUpdated : function(v, index, r){
57649 if(this.isSelected(r)){
57650 v.onRowSelect(index);
57656 * @param {Array} records The records to select
57657 * @param {Boolean} keepExisting (optional) True to keep existing selections
57659 selectRecords : function(records, keepExisting){
57661 this.clearSelections();
57663 var ds = this.grid.dataSource;
57664 for(var i = 0, len = records.length; i < len; i++){
57665 this.selectRow(ds.indexOf(records[i]), true);
57670 * Gets the number of selected rows.
57673 getCount : function(){
57674 return this.selections.length;
57678 * Selects the first row in the grid.
57680 selectFirstRow : function(){
57685 * Select the last row.
57686 * @param {Boolean} keepExisting (optional) True to keep existing selections
57688 selectLastRow : function(keepExisting){
57689 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57693 * Selects the row immediately following the last selected row.
57694 * @param {Boolean} keepExisting (optional) True to keep existing selections
57696 selectNext : function(keepExisting){
57697 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57698 this.selectRow(this.last+1, keepExisting);
57699 this.grid.getView().focusRow(this.last);
57704 * Selects the row that precedes the last selected row.
57705 * @param {Boolean} keepExisting (optional) True to keep existing selections
57707 selectPrevious : function(keepExisting){
57709 this.selectRow(this.last-1, keepExisting);
57710 this.grid.getView().focusRow(this.last);
57715 * Returns the selected records
57716 * @return {Array} Array of selected records
57718 getSelections : function(){
57719 return [].concat(this.selections.items);
57723 * Returns the first selected record.
57726 getSelected : function(){
57727 return this.selections.itemAt(0);
57732 * Clears all selections.
57734 clearSelections : function(fast){
57739 var ds = this.grid.dataSource;
57740 var s = this.selections;
57741 s.each(function(r){
57742 this.deselectRow(ds.indexOfId(r.id));
57746 this.selections.clear();
57753 * Selects all rows.
57755 selectAll : function(){
57759 this.selections.clear();
57760 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57761 this.selectRow(i, true);
57766 * Returns True if there is a selection.
57767 * @return {Boolean}
57769 hasSelection : function(){
57770 return this.selections.length > 0;
57774 * Returns True if the specified row is selected.
57775 * @param {Number/Record} record The record or index of the record to check
57776 * @return {Boolean}
57778 isSelected : function(index){
57779 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57780 return (r && this.selections.key(r.id) ? true : false);
57784 * Returns True if the specified record id is selected.
57785 * @param {String} id The id of record to check
57786 * @return {Boolean}
57788 isIdSelected : function(id){
57789 return (this.selections.key(id) ? true : false);
57793 handleMouseDown : function(e, t){
57794 var view = this.grid.getView(), rowIndex;
57795 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57798 if(e.shiftKey && this.last !== false){
57799 var last = this.last;
57800 this.selectRange(last, rowIndex, e.ctrlKey);
57801 this.last = last; // reset the last
57802 view.focusRow(rowIndex);
57804 var isSelected = this.isSelected(rowIndex);
57805 if(e.button !== 0 && isSelected){
57806 view.focusRow(rowIndex);
57807 }else if(e.ctrlKey && isSelected){
57808 this.deselectRow(rowIndex);
57809 }else if(!isSelected){
57810 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57811 view.focusRow(rowIndex);
57814 this.fireEvent("afterselectionchange", this);
57817 handleDragableRowClick : function(grid, rowIndex, e)
57819 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57820 this.selectRow(rowIndex, false);
57821 grid.view.focusRow(rowIndex);
57822 this.fireEvent("afterselectionchange", this);
57827 * Selects multiple rows.
57828 * @param {Array} rows Array of the indexes of the row to select
57829 * @param {Boolean} keepExisting (optional) True to keep existing selections
57831 selectRows : function(rows, keepExisting){
57833 this.clearSelections();
57835 for(var i = 0, len = rows.length; i < len; i++){
57836 this.selectRow(rows[i], true);
57841 * Selects a range of rows. All rows in between startRow and endRow are also selected.
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
57844 * @param {Boolean} keepExisting (optional) True to retain existing selections
57846 selectRange : function(startRow, endRow, keepExisting){
57851 this.clearSelections();
57853 if(startRow <= endRow){
57854 for(var i = startRow; i <= endRow; i++){
57855 this.selectRow(i, true);
57858 for(var i = startRow; i >= endRow; i--){
57859 this.selectRow(i, true);
57865 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57866 * @param {Number} startRow The index of the first row in the range
57867 * @param {Number} endRow The index of the last row in the range
57869 deselectRange : function(startRow, endRow, preventViewNotify){
57873 for(var i = startRow; i <= endRow; i++){
57874 this.deselectRow(i, preventViewNotify);
57880 * @param {Number} row The index of the row to select
57881 * @param {Boolean} keepExisting (optional) True to keep existing selections
57883 selectRow : function(index, keepExisting, preventViewNotify){
57884 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
57887 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
57888 if(!keepExisting || this.singleSelect){
57889 this.clearSelections();
57891 var r = this.grid.dataSource.getAt(index);
57892 this.selections.add(r);
57893 this.last = this.lastActive = index;
57894 if(!preventViewNotify){
57895 this.grid.getView().onRowSelect(index);
57897 this.fireEvent("rowselect", this, index, r);
57898 this.fireEvent("selectionchange", this);
57904 * @param {Number} row The index of the row to deselect
57906 deselectRow : function(index, preventViewNotify){
57910 if(this.last == index){
57913 if(this.lastActive == index){
57914 this.lastActive = false;
57916 var r = this.grid.dataSource.getAt(index);
57917 this.selections.remove(r);
57918 if(!preventViewNotify){
57919 this.grid.getView().onRowDeselect(index);
57921 this.fireEvent("rowdeselect", this, index);
57922 this.fireEvent("selectionchange", this);
57926 restoreLast : function(){
57928 this.last = this._last;
57933 acceptsNav : function(row, col, cm){
57934 return !cm.isHidden(col) && cm.isCellEditable(col, row);
57938 onEditorKey : function(field, e){
57939 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
57944 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
57946 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
57948 }else if(k == e.ENTER && !e.ctrlKey){
57952 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
57954 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
57956 }else if(k == e.ESC){
57960 g.startEditing(newCell[0], newCell[1]);
57965 * Ext JS Library 1.1.1
57966 * Copyright(c) 2006-2007, Ext JS, LLC.
57968 * Originally Released Under LGPL - original licence link has changed is not relivant.
57971 * <script type="text/javascript">
57974 * @class Roo.grid.CellSelectionModel
57975 * @extends Roo.grid.AbstractSelectionModel
57976 * This class provides the basic implementation for cell selection in a grid.
57978 * @param {Object} config The object containing the configuration of this model.
57979 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
57981 Roo.grid.CellSelectionModel = function(config){
57982 Roo.apply(this, config);
57984 this.selection = null;
57988 * @event beforerowselect
57989 * Fires before a cell is selected.
57990 * @param {SelectionModel} this
57991 * @param {Number} rowIndex The selected row index
57992 * @param {Number} colIndex The selected cell index
57994 "beforecellselect" : true,
57996 * @event cellselect
57997 * Fires when a cell is selected.
57998 * @param {SelectionModel} this
57999 * @param {Number} rowIndex The selected row index
58000 * @param {Number} colIndex The selected cell index
58002 "cellselect" : true,
58004 * @event selectionchange
58005 * Fires when the active selection changes.
58006 * @param {SelectionModel} this
58007 * @param {Object} selection null for no selection or an object (o) with two properties
58009 <li>o.record: the record object for the row the selection is in</li>
58010 <li>o.cell: An array of [rowIndex, columnIndex]</li>
58013 "selectionchange" : true,
58016 * Fires when the tab (or enter) was pressed on the last editable cell
58017 * You can use this to trigger add new row.
58018 * @param {SelectionModel} this
58022 * @event beforeeditnext
58023 * Fires before the next editable sell is made active
58024 * You can use this to skip to another cell or fire the tabend
58025 * if you set cell to false
58026 * @param {Object} eventdata object : { cell : [ row, col ] }
58028 "beforeeditnext" : true
58030 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58033 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58035 enter_is_tab: false,
58038 initEvents : function(){
58039 this.grid.on("mousedown", this.handleMouseDown, this);
58040 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58041 var view = this.grid.view;
58042 view.on("refresh", this.onViewChange, this);
58043 view.on("rowupdated", this.onRowUpdated, this);
58044 view.on("beforerowremoved", this.clearSelections, this);
58045 view.on("beforerowsinserted", this.clearSelections, this);
58046 if(this.grid.isEditor){
58047 this.grid.on("beforeedit", this.beforeEdit, this);
58052 beforeEdit : function(e){
58053 this.select(e.row, e.column, false, true, e.record);
58057 onRowUpdated : function(v, index, r){
58058 if(this.selection && this.selection.record == r){
58059 v.onCellSelect(index, this.selection.cell[1]);
58064 onViewChange : function(){
58065 this.clearSelections(true);
58069 * Returns the currently selected cell,.
58070 * @return {Array} The selected cell (row, column) or null if none selected.
58072 getSelectedCell : function(){
58073 return this.selection ? this.selection.cell : null;
58077 * Clears all selections.
58078 * @param {Boolean} true to prevent the gridview from being notified about the change.
58080 clearSelections : function(preventNotify){
58081 var s = this.selection;
58083 if(preventNotify !== true){
58084 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58086 this.selection = null;
58087 this.fireEvent("selectionchange", this, null);
58092 * Returns true if there is a selection.
58093 * @return {Boolean}
58095 hasSelection : function(){
58096 return this.selection ? true : false;
58100 handleMouseDown : function(e, t){
58101 var v = this.grid.getView();
58102 if(this.isLocked()){
58105 var row = v.findRowIndex(t);
58106 var cell = v.findCellIndex(t);
58107 if(row !== false && cell !== false){
58108 this.select(row, cell);
58114 * @param {Number} rowIndex
58115 * @param {Number} collIndex
58117 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58118 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58119 this.clearSelections();
58120 r = r || this.grid.dataSource.getAt(rowIndex);
58123 cell : [rowIndex, colIndex]
58125 if(!preventViewNotify){
58126 var v = this.grid.getView();
58127 v.onCellSelect(rowIndex, colIndex);
58128 if(preventFocus !== true){
58129 v.focusCell(rowIndex, colIndex);
58132 this.fireEvent("cellselect", this, rowIndex, colIndex);
58133 this.fireEvent("selectionchange", this, this.selection);
58138 isSelectable : function(rowIndex, colIndex, cm){
58139 return !cm.isHidden(colIndex);
58143 handleKeyDown : function(e){
58144 //Roo.log('Cell Sel Model handleKeyDown');
58145 if(!e.isNavKeyPress()){
58148 var g = this.grid, s = this.selection;
58151 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58153 this.select(cell[0], cell[1]);
58158 var walk = function(row, col, step){
58159 return g.walkCells(row, col, step, sm.isSelectable, sm);
58161 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58168 // handled by onEditorKey
58169 if (g.isEditor && g.editing) {
58173 newCell = walk(r, c-1, -1);
58175 newCell = walk(r, c+1, 1);
58180 newCell = walk(r+1, c, 1);
58184 newCell = walk(r-1, c, -1);
58188 newCell = walk(r, c+1, 1);
58192 newCell = walk(r, c-1, -1);
58197 if(g.isEditor && !g.editing){
58198 g.startEditing(r, c);
58207 this.select(newCell[0], newCell[1]);
58213 acceptsNav : function(row, col, cm){
58214 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58218 * @param {Number} field (not used) - as it's normally used as a listener
58219 * @param {Number} e - event - fake it by using
58221 * var e = Roo.EventObjectImpl.prototype;
58222 * e.keyCode = e.TAB
58226 onEditorKey : function(field, e){
58228 var k = e.getKey(),
58231 ed = g.activeEditor,
58233 ///Roo.log('onEditorKey' + k);
58236 if (this.enter_is_tab && k == e.ENTER) {
58242 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58244 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58250 } else if(k == e.ENTER && !e.ctrlKey){
58253 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58255 } else if(k == e.ESC){
58260 var ecall = { cell : newCell, forward : forward };
58261 this.fireEvent('beforeeditnext', ecall );
58262 newCell = ecall.cell;
58263 forward = ecall.forward;
58267 //Roo.log('next cell after edit');
58268 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58269 } else if (forward) {
58270 // tabbed past last
58271 this.fireEvent.defer(100, this, ['tabend',this]);
58276 * Ext JS Library 1.1.1
58277 * Copyright(c) 2006-2007, Ext JS, LLC.
58279 * Originally Released Under LGPL - original licence link has changed is not relivant.
58282 * <script type="text/javascript">
58286 * @class Roo.grid.EditorGrid
58287 * @extends Roo.grid.Grid
58288 * Class for creating and editable grid.
58289 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58290 * The container MUST have some type of size defined for the grid to fill. The container will be
58291 * automatically set to position relative if it isn't already.
58292 * @param {Object} dataSource The data model to bind to
58293 * @param {Object} colModel The column model with info about this grid's columns
58295 Roo.grid.EditorGrid = function(container, config){
58296 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58297 this.getGridEl().addClass("xedit-grid");
58299 if(!this.selModel){
58300 this.selModel = new Roo.grid.CellSelectionModel();
58303 this.activeEditor = null;
58307 * @event beforeedit
58308 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58309 * <ul style="padding:5px;padding-left:16px;">
58310 * <li>grid - This grid</li>
58311 * <li>record - The record being edited</li>
58312 * <li>field - The field name being edited</li>
58313 * <li>value - The value for the field being edited.</li>
58314 * <li>row - The grid row index</li>
58315 * <li>column - The grid column index</li>
58316 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58318 * @param {Object} e An edit event (see above for description)
58320 "beforeedit" : true,
58323 * Fires after a cell is edited. <br />
58324 * <ul style="padding:5px;padding-left:16px;">
58325 * <li>grid - This grid</li>
58326 * <li>record - The record being edited</li>
58327 * <li>field - The field name being edited</li>
58328 * <li>value - The value being set</li>
58329 * <li>originalValue - The original value for the field, before the edit.</li>
58330 * <li>row - The grid row index</li>
58331 * <li>column - The grid column index</li>
58333 * @param {Object} e An edit event (see above for description)
58335 "afteredit" : true,
58337 * @event validateedit
58338 * Fires after a cell is edited, but before the value is set in the record.
58339 * You can use this to modify the value being set in the field, Return false
58340 * to cancel the change. The edit event object has the following properties <br />
58341 * <ul style="padding:5px;padding-left:16px;">
58342 * <li>editor - This editor</li>
58343 * <li>grid - This grid</li>
58344 * <li>record - The record being edited</li>
58345 * <li>field - The field name being edited</li>
58346 * <li>value - The value being set</li>
58347 * <li>originalValue - The original value for the field, before the edit.</li>
58348 * <li>row - The grid row index</li>
58349 * <li>column - The grid column index</li>
58350 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58352 * @param {Object} e An edit event (see above for description)
58354 "validateedit" : true
58356 this.on("bodyscroll", this.stopEditing, this);
58357 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58360 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58362 * @cfg {Number} clicksToEdit
58363 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58370 trackMouseOver: false, // causes very odd FF errors
58372 onCellDblClick : function(g, row, col){
58373 this.startEditing(row, col);
58376 onEditComplete : function(ed, value, startValue){
58377 this.editing = false;
58378 this.activeEditor = null;
58379 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58381 var field = this.colModel.getDataIndex(ed.col);
58386 originalValue: startValue,
58393 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58396 if(String(value) !== String(startValue)){
58398 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58399 r.set(field, e.value);
58400 // if we are dealing with a combo box..
58401 // then we also set the 'name' colum to be the displayField
58402 if (ed.field.displayField && ed.field.name) {
58403 r.set(ed.field.name, ed.field.el.dom.value);
58406 delete e.cancel; //?? why!!!
58407 this.fireEvent("afteredit", e);
58410 this.fireEvent("afteredit", e); // always fire it!
58412 this.view.focusCell(ed.row, ed.col);
58416 * Starts editing the specified for the specified row/column
58417 * @param {Number} rowIndex
58418 * @param {Number} colIndex
58420 startEditing : function(row, col){
58421 this.stopEditing();
58422 if(this.colModel.isCellEditable(col, row)){
58423 this.view.ensureVisible(row, col, true);
58425 var r = this.dataSource.getAt(row);
58426 var field = this.colModel.getDataIndex(col);
58427 var cell = Roo.get(this.view.getCell(row,col));
58432 value: r.data[field],
58437 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58438 this.editing = true;
58439 var ed = this.colModel.getCellEditor(col, row);
58445 ed.render(ed.parentEl || document.body);
58451 (function(){ // complex but required for focus issues in safari, ie and opera
58455 ed.on("complete", this.onEditComplete, this, {single: true});
58456 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58457 this.activeEditor = ed;
58458 var v = r.data[field];
58459 ed.startEdit(this.view.getCell(row, col), v);
58460 // combo's with 'displayField and name set
58461 if (ed.field.displayField && ed.field.name) {
58462 ed.field.el.dom.value = r.data[ed.field.name];
58466 }).defer(50, this);
58472 * Stops any active editing
58474 stopEditing : function(){
58475 if(this.activeEditor){
58476 this.activeEditor.completeEdit();
58478 this.activeEditor = null;
58482 * Called to get grid's drag proxy text, by default returns this.ddText.
58485 getDragDropText : function(){
58486 var count = this.selModel.getSelectedCell() ? 1 : 0;
58487 return String.format(this.ddText, count, count == 1 ? '' : 's');
58492 * Ext JS Library 1.1.1
58493 * Copyright(c) 2006-2007, Ext JS, LLC.
58495 * Originally Released Under LGPL - original licence link has changed is not relivant.
58498 * <script type="text/javascript">
58501 // private - not really -- you end up using it !
58502 // This is a support class used internally by the Grid components
58505 * @class Roo.grid.GridEditor
58506 * @extends Roo.Editor
58507 * Class for creating and editable grid elements.
58508 * @param {Object} config any settings (must include field)
58510 Roo.grid.GridEditor = function(field, config){
58511 if (!config && field.field) {
58513 field = Roo.factory(config.field, Roo.form);
58515 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58516 field.monitorTab = false;
58519 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58522 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58525 alignment: "tl-tl",
58528 cls: "x-small-editor x-grid-editor",
58533 * Ext JS Library 1.1.1
58534 * Copyright(c) 2006-2007, Ext JS, LLC.
58536 * Originally Released Under LGPL - original licence link has changed is not relivant.
58539 * <script type="text/javascript">
58544 Roo.grid.PropertyRecord = Roo.data.Record.create([
58545 {name:'name',type:'string'}, 'value'
58549 Roo.grid.PropertyStore = function(grid, source){
58551 this.store = new Roo.data.Store({
58552 recordType : Roo.grid.PropertyRecord
58554 this.store.on('update', this.onUpdate, this);
58556 this.setSource(source);
58558 Roo.grid.PropertyStore.superclass.constructor.call(this);
58563 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58564 setSource : function(o){
58566 this.store.removeAll();
58569 if(this.isEditableValue(o[k])){
58570 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58573 this.store.loadRecords({records: data}, {}, true);
58576 onUpdate : function(ds, record, type){
58577 if(type == Roo.data.Record.EDIT){
58578 var v = record.data['value'];
58579 var oldValue = record.modified['value'];
58580 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58581 this.source[record.id] = v;
58583 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58590 getProperty : function(row){
58591 return this.store.getAt(row);
58594 isEditableValue: function(val){
58595 if(val && val instanceof Date){
58597 }else if(typeof val == 'object' || typeof val == 'function'){
58603 setValue : function(prop, value){
58604 this.source[prop] = value;
58605 this.store.getById(prop).set('value', value);
58608 getSource : function(){
58609 return this.source;
58613 Roo.grid.PropertyColumnModel = function(grid, store){
58616 g.PropertyColumnModel.superclass.constructor.call(this, [
58617 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58618 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58620 this.store = store;
58621 this.bselect = Roo.DomHelper.append(document.body, {
58622 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58623 {tag: 'option', value: 'true', html: 'true'},
58624 {tag: 'option', value: 'false', html: 'false'}
58627 Roo.id(this.bselect);
58630 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58631 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58632 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58633 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58634 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58636 this.renderCellDelegate = this.renderCell.createDelegate(this);
58637 this.renderPropDelegate = this.renderProp.createDelegate(this);
58640 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58644 valueText : 'Value',
58646 dateFormat : 'm/j/Y',
58649 renderDate : function(dateVal){
58650 return dateVal.dateFormat(this.dateFormat);
58653 renderBool : function(bVal){
58654 return bVal ? 'true' : 'false';
58657 isCellEditable : function(colIndex, rowIndex){
58658 return colIndex == 1;
58661 getRenderer : function(col){
58663 this.renderCellDelegate : this.renderPropDelegate;
58666 renderProp : function(v){
58667 return this.getPropertyName(v);
58670 renderCell : function(val){
58672 if(val instanceof Date){
58673 rv = this.renderDate(val);
58674 }else if(typeof val == 'boolean'){
58675 rv = this.renderBool(val);
58677 return Roo.util.Format.htmlEncode(rv);
58680 getPropertyName : function(name){
58681 var pn = this.grid.propertyNames;
58682 return pn && pn[name] ? pn[name] : name;
58685 getCellEditor : function(colIndex, rowIndex){
58686 var p = this.store.getProperty(rowIndex);
58687 var n = p.data['name'], val = p.data['value'];
58689 if(typeof(this.grid.customEditors[n]) == 'string'){
58690 return this.editors[this.grid.customEditors[n]];
58692 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58693 return this.grid.customEditors[n];
58695 if(val instanceof Date){
58696 return this.editors['date'];
58697 }else if(typeof val == 'number'){
58698 return this.editors['number'];
58699 }else if(typeof val == 'boolean'){
58700 return this.editors['boolean'];
58702 return this.editors['string'];
58708 * @class Roo.grid.PropertyGrid
58709 * @extends Roo.grid.EditorGrid
58710 * This class represents the interface of a component based property grid control.
58711 * <br><br>Usage:<pre><code>
58712 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58720 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58721 * The container MUST have some type of size defined for the grid to fill. The container will be
58722 * automatically set to position relative if it isn't already.
58723 * @param {Object} config A config object that sets properties on this grid.
58725 Roo.grid.PropertyGrid = function(container, config){
58726 config = config || {};
58727 var store = new Roo.grid.PropertyStore(this);
58728 this.store = store;
58729 var cm = new Roo.grid.PropertyColumnModel(this, store);
58730 store.store.sort('name', 'ASC');
58731 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58734 enableColLock:false,
58735 enableColumnMove:false,
58737 trackMouseOver: false,
58740 this.getGridEl().addClass('x-props-grid');
58741 this.lastEditRow = null;
58742 this.on('columnresize', this.onColumnResize, this);
58745 * @event beforepropertychange
58746 * Fires before a property changes (return false to stop?)
58747 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58748 * @param {String} id Record Id
58749 * @param {String} newval New Value
58750 * @param {String} oldval Old Value
58752 "beforepropertychange": true,
58754 * @event propertychange
58755 * Fires after a property changes
58756 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58757 * @param {String} id Record Id
58758 * @param {String} newval New Value
58759 * @param {String} oldval Old Value
58761 "propertychange": true
58763 this.customEditors = this.customEditors || {};
58765 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58768 * @cfg {Object} customEditors map of colnames=> custom editors.
58769 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58770 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58771 * false disables editing of the field.
58775 * @cfg {Object} propertyNames map of property Names to their displayed value
58778 render : function(){
58779 Roo.grid.PropertyGrid.superclass.render.call(this);
58780 this.autoSize.defer(100, this);
58783 autoSize : function(){
58784 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58786 this.view.fitColumns();
58790 onColumnResize : function(){
58791 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58795 * Sets the data for the Grid
58796 * accepts a Key => Value object of all the elements avaiable.
58797 * @param {Object} data to appear in grid.
58799 setSource : function(source){
58800 this.store.setSource(source);
58804 * Gets all the data from the grid.
58805 * @return {Object} data data stored in grid
58807 getSource : function(){
58808 return this.store.getSource();
58817 * @class Roo.grid.Calendar
58818 * @extends Roo.util.Grid
58819 * This class extends the Grid to provide a calendar widget
58820 * <br><br>Usage:<pre><code>
58821 var grid = new Roo.grid.Calendar("my-container-id", {
58824 selModel: mySelectionModel,
58825 autoSizeColumns: true,
58826 monitorWindowResize: false,
58827 trackMouseOver: true
58828 eventstore : real data store..
58834 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58835 * The container MUST have some type of size defined for the grid to fill. The container will be
58836 * automatically set to position relative if it isn't already.
58837 * @param {Object} config A config object that sets properties on this grid.
58839 Roo.grid.Calendar = function(container, config){
58840 // initialize the container
58841 this.container = Roo.get(container);
58842 this.container.update("");
58843 this.container.setStyle("overflow", "hidden");
58844 this.container.addClass('x-grid-container');
58846 this.id = this.container.id;
58848 Roo.apply(this, config);
58849 // check and correct shorthanded configs
58853 for (var r = 0;r < 6;r++) {
58856 for (var c =0;c < 7;c++) {
58860 if (this.eventStore) {
58861 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58862 this.eventStore.on('load',this.onLoad, this);
58863 this.eventStore.on('beforeload',this.clearEvents, this);
58867 this.dataSource = new Roo.data.Store({
58868 proxy: new Roo.data.MemoryProxy(rows),
58869 reader: new Roo.data.ArrayReader({}, [
58870 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58873 this.dataSource.load();
58874 this.ds = this.dataSource;
58875 this.ds.xmodule = this.xmodule || false;
58878 var cellRender = function(v,x,r)
58880 return String.format(
58881 '<div class="fc-day fc-widget-content"><div>' +
58882 '<div class="fc-event-container"></div>' +
58883 '<div class="fc-day-number">{0}</div>'+
58885 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
58886 '</div></div>', v);
58891 this.colModel = new Roo.grid.ColumnModel( [
58893 xtype: 'ColumnModel',
58895 dataIndex : 'weekday0',
58897 renderer : cellRender
58900 xtype: 'ColumnModel',
58902 dataIndex : 'weekday1',
58904 renderer : cellRender
58907 xtype: 'ColumnModel',
58909 dataIndex : 'weekday2',
58910 header : 'Tuesday',
58911 renderer : cellRender
58914 xtype: 'ColumnModel',
58916 dataIndex : 'weekday3',
58917 header : 'Wednesday',
58918 renderer : cellRender
58921 xtype: 'ColumnModel',
58923 dataIndex : 'weekday4',
58924 header : 'Thursday',
58925 renderer : cellRender
58928 xtype: 'ColumnModel',
58930 dataIndex : 'weekday5',
58932 renderer : cellRender
58935 xtype: 'ColumnModel',
58937 dataIndex : 'weekday6',
58938 header : 'Saturday',
58939 renderer : cellRender
58942 this.cm = this.colModel;
58943 this.cm.xmodule = this.xmodule || false;
58947 //this.selModel = new Roo.grid.CellSelectionModel();
58948 //this.sm = this.selModel;
58949 //this.selModel.init(this);
58953 this.container.setWidth(this.width);
58957 this.container.setHeight(this.height);
58964 * The raw click event for the entire grid.
58965 * @param {Roo.EventObject} e
58970 * The raw dblclick event for the entire grid.
58971 * @param {Roo.EventObject} e
58975 * @event contextmenu
58976 * The raw contextmenu event for the entire grid.
58977 * @param {Roo.EventObject} e
58979 "contextmenu" : true,
58982 * The raw mousedown event for the entire grid.
58983 * @param {Roo.EventObject} e
58985 "mousedown" : true,
58988 * The raw mouseup event for the entire grid.
58989 * @param {Roo.EventObject} e
58994 * The raw mouseover event for the entire grid.
58995 * @param {Roo.EventObject} e
58997 "mouseover" : true,
59000 * The raw mouseout event for the entire grid.
59001 * @param {Roo.EventObject} e
59006 * The raw keypress event for the entire grid.
59007 * @param {Roo.EventObject} e
59012 * The raw keydown event for the entire grid.
59013 * @param {Roo.EventObject} e
59021 * Fires when a cell is clicked
59022 * @param {Grid} this
59023 * @param {Number} rowIndex
59024 * @param {Number} columnIndex
59025 * @param {Roo.EventObject} e
59027 "cellclick" : true,
59029 * @event celldblclick
59030 * Fires when a cell is double clicked
59031 * @param {Grid} this
59032 * @param {Number} rowIndex
59033 * @param {Number} columnIndex
59034 * @param {Roo.EventObject} e
59036 "celldblclick" : true,
59039 * Fires when a row is clicked
59040 * @param {Grid} this
59041 * @param {Number} rowIndex
59042 * @param {Roo.EventObject} e
59046 * @event rowdblclick
59047 * Fires when a row is double clicked
59048 * @param {Grid} this
59049 * @param {Number} rowIndex
59050 * @param {Roo.EventObject} e
59052 "rowdblclick" : true,
59054 * @event headerclick
59055 * Fires when a header is clicked
59056 * @param {Grid} this
59057 * @param {Number} columnIndex
59058 * @param {Roo.EventObject} e
59060 "headerclick" : true,
59062 * @event headerdblclick
59063 * Fires when a header cell is double clicked
59064 * @param {Grid} this
59065 * @param {Number} columnIndex
59066 * @param {Roo.EventObject} e
59068 "headerdblclick" : true,
59070 * @event rowcontextmenu
59071 * Fires when a row is right clicked
59072 * @param {Grid} this
59073 * @param {Number} rowIndex
59074 * @param {Roo.EventObject} e
59076 "rowcontextmenu" : true,
59078 * @event cellcontextmenu
59079 * Fires when a cell is right clicked
59080 * @param {Grid} this
59081 * @param {Number} rowIndex
59082 * @param {Number} cellIndex
59083 * @param {Roo.EventObject} e
59085 "cellcontextmenu" : true,
59087 * @event headercontextmenu
59088 * Fires when a header is right clicked
59089 * @param {Grid} this
59090 * @param {Number} columnIndex
59091 * @param {Roo.EventObject} e
59093 "headercontextmenu" : true,
59095 * @event bodyscroll
59096 * Fires when the body element is scrolled
59097 * @param {Number} scrollLeft
59098 * @param {Number} scrollTop
59100 "bodyscroll" : true,
59102 * @event columnresize
59103 * Fires when the user resizes a column
59104 * @param {Number} columnIndex
59105 * @param {Number} newSize
59107 "columnresize" : true,
59109 * @event columnmove
59110 * Fires when the user moves a column
59111 * @param {Number} oldIndex
59112 * @param {Number} newIndex
59114 "columnmove" : true,
59117 * Fires when row(s) start being dragged
59118 * @param {Grid} this
59119 * @param {Roo.GridDD} dd The drag drop object
59120 * @param {event} e The raw browser event
59122 "startdrag" : true,
59125 * Fires when a drag operation is complete
59126 * @param {Grid} this
59127 * @param {Roo.GridDD} dd The drag drop object
59128 * @param {event} e The raw browser event
59133 * Fires when dragged row(s) are dropped on a valid DD target
59134 * @param {Grid} this
59135 * @param {Roo.GridDD} dd The drag drop object
59136 * @param {String} targetId The target drag drop object
59137 * @param {event} e The raw browser event
59142 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59143 * @param {Grid} this
59144 * @param {Roo.GridDD} dd The drag drop object
59145 * @param {String} targetId The target drag drop object
59146 * @param {event} e The raw browser event
59151 * Fires when the dragged row(s) first cross another DD target while being dragged
59152 * @param {Grid} this
59153 * @param {Roo.GridDD} dd The drag drop object
59154 * @param {String} targetId The target drag drop object
59155 * @param {event} e The raw browser event
59157 "dragenter" : true,
59160 * Fires when the dragged row(s) leave another DD target while being dragged
59161 * @param {Grid} this
59162 * @param {Roo.GridDD} dd The drag drop object
59163 * @param {String} targetId The target drag drop object
59164 * @param {event} e The raw browser event
59169 * Fires when a row is rendered, so you can change add a style to it.
59170 * @param {GridView} gridview The grid view
59171 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59177 * Fires when the grid is rendered
59178 * @param {Grid} grid
59183 * Fires when a date is selected
59184 * @param {DatePicker} this
59185 * @param {Date} date The selected date
59189 * @event monthchange
59190 * Fires when the displayed month changes
59191 * @param {DatePicker} this
59192 * @param {Date} date The selected month
59194 'monthchange': true,
59196 * @event evententer
59197 * Fires when mouse over an event
59198 * @param {Calendar} this
59199 * @param {event} Event
59201 'evententer': true,
59203 * @event eventleave
59204 * Fires when the mouse leaves an
59205 * @param {Calendar} this
59208 'eventleave': true,
59210 * @event eventclick
59211 * Fires when the mouse click an
59212 * @param {Calendar} this
59215 'eventclick': true,
59217 * @event eventrender
59218 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59219 * @param {Calendar} this
59220 * @param {data} data to be modified
59222 'eventrender': true
59226 Roo.grid.Grid.superclass.constructor.call(this);
59227 this.on('render', function() {
59228 this.view.el.addClass('x-grid-cal');
59230 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59234 if (!Roo.grid.Calendar.style) {
59235 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59238 '.x-grid-cal .x-grid-col' : {
59239 height: 'auto !important',
59240 'vertical-align': 'top'
59242 '.x-grid-cal .fc-event-hori' : {
59253 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59255 * @cfg {Store} eventStore The store that loads events.
59260 activeDate : false,
59263 monitorWindowResize : false,
59266 resizeColumns : function() {
59267 var col = (this.view.el.getWidth() / 7) - 3;
59268 // loop through cols, and setWidth
59269 for(var i =0 ; i < 7 ; i++){
59270 this.cm.setColumnWidth(i, col);
59273 setDate :function(date) {
59275 Roo.log('setDate?');
59277 this.resizeColumns();
59278 var vd = this.activeDate;
59279 this.activeDate = date;
59280 // if(vd && this.el){
59281 // var t = date.getTime();
59282 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59283 // Roo.log('using add remove');
59285 // this.fireEvent('monthchange', this, date);
59287 // this.cells.removeClass("fc-state-highlight");
59288 // this.cells.each(function(c){
59289 // if(c.dateValue == t){
59290 // c.addClass("fc-state-highlight");
59291 // setTimeout(function(){
59292 // try{c.dom.firstChild.focus();}catch(e){}
59302 var days = date.getDaysInMonth();
59304 var firstOfMonth = date.getFirstDateOfMonth();
59305 var startingPos = firstOfMonth.getDay()-this.startDay;
59307 if(startingPos < this.startDay){
59311 var pm = date.add(Date.MONTH, -1);
59312 var prevStart = pm.getDaysInMonth()-startingPos;
59316 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59318 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59319 //this.cells.addClassOnOver('fc-state-hover');
59321 var cells = this.cells.elements;
59322 var textEls = this.textNodes;
59324 //Roo.each(cells, function(cell){
59325 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59328 days += startingPos;
59330 // convert everything to numbers so it's fast
59331 var day = 86400000;
59332 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59335 //Roo.log(prevStart);
59337 var today = new Date().clearTime().getTime();
59338 var sel = date.clearTime().getTime();
59339 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59340 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59341 var ddMatch = this.disabledDatesRE;
59342 var ddText = this.disabledDatesText;
59343 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59344 var ddaysText = this.disabledDaysText;
59345 var format = this.format;
59347 var setCellClass = function(cal, cell){
59349 //Roo.log('set Cell Class');
59351 var t = d.getTime();
59356 cell.dateValue = t;
59358 cell.className += " fc-today";
59359 cell.className += " fc-state-highlight";
59360 cell.title = cal.todayText;
59363 // disable highlight in other month..
59364 cell.className += " fc-state-highlight";
59369 //cell.className = " fc-state-disabled";
59370 cell.title = cal.minText;
59374 //cell.className = " fc-state-disabled";
59375 cell.title = cal.maxText;
59379 if(ddays.indexOf(d.getDay()) != -1){
59380 // cell.title = ddaysText;
59381 // cell.className = " fc-state-disabled";
59384 if(ddMatch && format){
59385 var fvalue = d.dateFormat(format);
59386 if(ddMatch.test(fvalue)){
59387 cell.title = ddText.replace("%0", fvalue);
59388 cell.className = " fc-state-disabled";
59392 if (!cell.initialClassName) {
59393 cell.initialClassName = cell.dom.className;
59396 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59401 for(; i < startingPos; i++) {
59402 cells[i].dayName = (++prevStart);
59403 Roo.log(textEls[i]);
59404 d.setDate(d.getDate()+1);
59406 //cells[i].className = "fc-past fc-other-month";
59407 setCellClass(this, cells[i]);
59412 for(; i < days; i++){
59413 intDay = i - startingPos + 1;
59414 cells[i].dayName = (intDay);
59415 d.setDate(d.getDate()+1);
59417 cells[i].className = ''; // "x-date-active";
59418 setCellClass(this, cells[i]);
59422 for(; i < 42; i++) {
59423 //textEls[i].innerHTML = (++extraDays);
59425 d.setDate(d.getDate()+1);
59426 cells[i].dayName = (++extraDays);
59427 cells[i].className = "fc-future fc-other-month";
59428 setCellClass(this, cells[i]);
59431 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59433 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59435 // this will cause all the cells to mis
59438 for (var r = 0;r < 6;r++) {
59439 for (var c =0;c < 7;c++) {
59440 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59444 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59445 for(i=0;i<cells.length;i++) {
59447 this.cells.elements[i].dayName = cells[i].dayName ;
59448 this.cells.elements[i].className = cells[i].className;
59449 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59450 this.cells.elements[i].title = cells[i].title ;
59451 this.cells.elements[i].dateValue = cells[i].dateValue ;
59457 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59458 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59460 ////if(totalRows != 6){
59461 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59462 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59465 this.fireEvent('monthchange', this, date);
59470 * Returns the grid's SelectionModel.
59471 * @return {SelectionModel}
59473 getSelectionModel : function(){
59474 if(!this.selModel){
59475 this.selModel = new Roo.grid.CellSelectionModel();
59477 return this.selModel;
59481 this.eventStore.load()
59487 findCell : function(dt) {
59488 dt = dt.clearTime().getTime();
59490 this.cells.each(function(c){
59491 //Roo.log("check " +c.dateValue + '?=' + dt);
59492 if(c.dateValue == dt){
59502 findCells : function(rec) {
59503 var s = rec.data.start_dt.clone().clearTime().getTime();
59505 var e= rec.data.end_dt.clone().clearTime().getTime();
59508 this.cells.each(function(c){
59509 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59511 if(c.dateValue > e){
59514 if(c.dateValue < s){
59523 findBestRow: function(cells)
59527 for (var i =0 ; i < cells.length;i++) {
59528 ret = Math.max(cells[i].rows || 0,ret);
59535 addItem : function(rec)
59537 // look for vertical location slot in
59538 var cells = this.findCells(rec);
59540 rec.row = this.findBestRow(cells);
59542 // work out the location.
59546 for(var i =0; i < cells.length; i++) {
59554 if (crow.start.getY() == cells[i].getY()) {
59556 crow.end = cells[i];
59572 for (var i = 0; i < cells.length;i++) {
59573 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59580 clearEvents: function() {
59582 if (!this.eventStore.getCount()) {
59585 // reset number of rows in cells.
59586 Roo.each(this.cells.elements, function(c){
59590 this.eventStore.each(function(e) {
59591 this.clearEvent(e);
59596 clearEvent : function(ev)
59599 Roo.each(ev.els, function(el) {
59600 el.un('mouseenter' ,this.onEventEnter, this);
59601 el.un('mouseleave' ,this.onEventLeave, this);
59609 renderEvent : function(ev,ctr) {
59611 ctr = this.view.el.select('.fc-event-container',true).first();
59615 this.clearEvent(ev);
59621 var cells = ev.cells;
59622 var rows = ev.rows;
59623 this.fireEvent('eventrender', this, ev);
59625 for(var i =0; i < rows.length; i++) {
59629 cls += ' fc-event-start';
59631 if ((i+1) == rows.length) {
59632 cls += ' fc-event-end';
59635 //Roo.log(ev.data);
59636 // how many rows should it span..
59637 var cg = this.eventTmpl.append(ctr,Roo.apply({
59640 }, ev.data) , true);
59643 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59644 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59645 cg.on('click', this.onEventClick, this, ev);
59649 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59650 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59653 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59654 cg.setWidth(ebox.right - sbox.x -2);
59658 renderEvents: function()
59660 // first make sure there is enough space..
59662 if (!this.eventTmpl) {
59663 this.eventTmpl = new Roo.Template(
59664 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59665 '<div class="fc-event-inner">' +
59666 '<span class="fc-event-time">{time}</span>' +
59667 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59669 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59677 this.cells.each(function(c) {
59678 //Roo.log(c.select('.fc-day-content div',true).first());
59679 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59682 var ctr = this.view.el.select('.fc-event-container',true).first();
59685 this.eventStore.each(function(ev){
59687 this.renderEvent(ev);
59691 this.view.layout();
59695 onEventEnter: function (e, el,event,d) {
59696 this.fireEvent('evententer', this, el, event);
59699 onEventLeave: function (e, el,event,d) {
59700 this.fireEvent('eventleave', this, el, event);
59703 onEventClick: function (e, el,event,d) {
59704 this.fireEvent('eventclick', this, el, event);
59707 onMonthChange: function () {
59711 onLoad: function () {
59713 //Roo.log('calendar onload');
59715 if(this.eventStore.getCount() > 0){
59719 this.eventStore.each(function(d){
59724 if (typeof(add.end_dt) == 'undefined') {
59725 Roo.log("Missing End time in calendar data: ");
59729 if (typeof(add.start_dt) == 'undefined') {
59730 Roo.log("Missing Start time in calendar data: ");
59734 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59735 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59736 add.id = add.id || d.id;
59737 add.title = add.title || '??';
59745 this.renderEvents();
59755 render : function ()
59759 if (!this.view.el.hasClass('course-timesheet')) {
59760 this.view.el.addClass('course-timesheet');
59762 if (this.tsStyle) {
59767 Roo.log(_this.grid.view.el.getWidth());
59770 this.tsStyle = Roo.util.CSS.createStyleSheet({
59771 '.course-timesheet .x-grid-row' : {
59774 '.x-grid-row td' : {
59775 'vertical-align' : 0
59777 '.course-edit-link' : {
59779 'text-overflow' : 'ellipsis',
59780 'overflow' : 'hidden',
59781 'white-space' : 'nowrap',
59782 'cursor' : 'pointer'
59787 '.de-act-sup-link' : {
59788 'color' : 'purple',
59789 'text-decoration' : 'line-through'
59793 'text-decoration' : 'line-through'
59795 '.course-timesheet .course-highlight' : {
59796 'border-top-style': 'dashed !important',
59797 'border-bottom-bottom': 'dashed !important'
59799 '.course-timesheet .course-item' : {
59800 'font-family' : 'tahoma, arial, helvetica',
59801 'font-size' : '11px',
59802 'overflow' : 'hidden',
59803 'padding-left' : '10px',
59804 'padding-right' : '10px',
59805 'padding-top' : '10px'
59813 monitorWindowResize : false,
59814 cellrenderer : function(v,x,r)
59819 xtype: 'CellSelectionModel',
59826 beforeload : function (_self, options)
59828 options.params = options.params || {};
59829 options.params._month = _this.monthField.getValue();
59830 options.params.limit = 9999;
59831 options.params['sort'] = 'when_dt';
59832 options.params['dir'] = 'ASC';
59833 this.proxy.loadResponse = this.loadResponse;
59835 //this.addColumns();
59837 load : function (_self, records, options)
59839 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59840 // if you click on the translation.. you can edit it...
59841 var el = Roo.get(this);
59842 var id = el.dom.getAttribute('data-id');
59843 var d = el.dom.getAttribute('data-date');
59844 var t = el.dom.getAttribute('data-time');
59845 //var id = this.child('span').dom.textContent;
59848 Pman.Dialog.CourseCalendar.show({
59852 productitem_active : id ? 1 : 0
59854 _this.grid.ds.load({});
59859 _this.panel.fireEvent('resize', [ '', '' ]);
59862 loadResponse : function(o, success, response){
59863 // this is overridden on before load..
59865 Roo.log("our code?");
59866 //Roo.log(success);
59867 //Roo.log(response)
59868 delete this.activeRequest;
59870 this.fireEvent("loadexception", this, o, response);
59871 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59876 result = o.reader.read(response);
59878 Roo.log("load exception?");
59879 this.fireEvent("loadexception", this, o, response, e);
59880 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59883 Roo.log("ready...");
59884 // loop through result.records;
59885 // and set this.tdate[date] = [] << array of records..
59887 Roo.each(result.records, function(r){
59889 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
59890 _this.tdata[r.data.when_dt.format('j')] = [];
59892 _this.tdata[r.data.when_dt.format('j')].push(r.data);
59895 //Roo.log(_this.tdata);
59897 result.records = [];
59898 result.totalRecords = 6;
59900 // let's generate some duumy records for the rows.
59901 //var st = _this.dateField.getValue();
59903 // work out monday..
59904 //st = st.add(Date.DAY, -1 * st.format('w'));
59906 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59908 var firstOfMonth = date.getFirstDayOfMonth();
59909 var days = date.getDaysInMonth();
59911 var firstAdded = false;
59912 for (var i = 0; i < result.totalRecords ; i++) {
59913 //var d= st.add(Date.DAY, i);
59916 for(var w = 0 ; w < 7 ; w++){
59917 if(!firstAdded && firstOfMonth != w){
59924 var dd = (d > 0 && d < 10) ? "0"+d : d;
59925 row['weekday'+w] = String.format(
59926 '<span style="font-size: 16px;"><b>{0}</b></span>'+
59927 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
59929 date.format('Y-m-')+dd
59932 if(typeof(_this.tdata[d]) != 'undefined'){
59933 Roo.each(_this.tdata[d], function(r){
59937 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
59938 if(r.parent_id*1>0){
59939 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
59942 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
59943 deactive = 'de-act-link';
59946 row['weekday'+w] += String.format(
59947 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
59949 r.product_id_name, //1
59950 r.when_dt.format('h:ia'), //2
59960 // only do this if something added..
59962 result.records.push(_this.grid.dataSource.reader.newRow(row));
59966 // push it twice. (second one with an hour..
59970 this.fireEvent("load", this, o, o.request.arg);
59971 o.request.callback.call(o.request.scope, result, o.request.arg, true);
59973 sortInfo : {field: 'when_dt', direction : 'ASC' },
59975 xtype: 'HttpProxy',
59978 url : baseURL + '/Roo/Shop_course.php'
59981 xtype: 'JsonReader',
59998 'name': 'parent_id',
60002 'name': 'product_id',
60006 'name': 'productitem_id',
60024 click : function (_self, e)
60026 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60027 sd.setMonth(sd.getMonth()-1);
60028 _this.monthField.setValue(sd.format('Y-m-d'));
60029 _this.grid.ds.load({});
60035 xtype: 'Separator',
60039 xtype: 'MonthField',
60042 render : function (_self)
60044 _this.monthField = _self;
60045 // _this.monthField.set today
60047 select : function (combo, date)
60049 _this.grid.ds.load({});
60052 value : (function() { return new Date(); })()
60055 xtype: 'Separator',
60061 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60071 click : function (_self, e)
60073 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60074 sd.setMonth(sd.getMonth()+1);
60075 _this.monthField.setValue(sd.format('Y-m-d'));
60076 _this.grid.ds.load({});
60089 * Ext JS Library 1.1.1
60090 * Copyright(c) 2006-2007, Ext JS, LLC.
60092 * Originally Released Under LGPL - original licence link has changed is not relivant.
60095 * <script type="text/javascript">
60099 * @class Roo.LoadMask
60100 * A simple utility class for generically masking elements while loading data. If the element being masked has
60101 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60102 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60103 * element's UpdateManager load indicator and will be destroyed after the initial load.
60105 * Create a new LoadMask
60106 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60107 * @param {Object} config The config object
60109 Roo.LoadMask = function(el, config){
60110 this.el = Roo.get(el);
60111 Roo.apply(this, config);
60113 this.store.on('beforeload', this.onBeforeLoad, this);
60114 this.store.on('load', this.onLoad, this);
60115 this.store.on('loadexception', this.onLoadException, this);
60116 this.removeMask = false;
60118 var um = this.el.getUpdateManager();
60119 um.showLoadIndicator = false; // disable the default indicator
60120 um.on('beforeupdate', this.onBeforeLoad, this);
60121 um.on('update', this.onLoad, this);
60122 um.on('failure', this.onLoad, this);
60123 this.removeMask = true;
60127 Roo.LoadMask.prototype = {
60129 * @cfg {Boolean} removeMask
60130 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60131 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60134 * @cfg {String} msg
60135 * The text to display in a centered loading message box (defaults to 'Loading...')
60137 msg : 'Loading...',
60139 * @cfg {String} msgCls
60140 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60142 msgCls : 'x-mask-loading',
60145 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60151 * Disables the mask to prevent it from being displayed
60153 disable : function(){
60154 this.disabled = true;
60158 * Enables the mask so that it can be displayed
60160 enable : function(){
60161 this.disabled = false;
60164 onLoadException : function()
60166 Roo.log(arguments);
60168 if (typeof(arguments[3]) != 'undefined') {
60169 Roo.MessageBox.alert("Error loading",arguments[3]);
60173 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60174 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60183 this.el.unmask(this.removeMask);
60186 onLoad : function()
60188 this.el.unmask(this.removeMask);
60192 onBeforeLoad : function(){
60193 if(!this.disabled){
60194 this.el.mask(this.msg, this.msgCls);
60199 destroy : function(){
60201 this.store.un('beforeload', this.onBeforeLoad, this);
60202 this.store.un('load', this.onLoad, this);
60203 this.store.un('loadexception', this.onLoadException, this);
60205 var um = this.el.getUpdateManager();
60206 um.un('beforeupdate', this.onBeforeLoad, this);
60207 um.un('update', this.onLoad, this);
60208 um.un('failure', this.onLoad, this);
60213 * Ext JS Library 1.1.1
60214 * Copyright(c) 2006-2007, Ext JS, LLC.
60216 * Originally Released Under LGPL - original licence link has changed is not relivant.
60219 * <script type="text/javascript">
60224 * @class Roo.XTemplate
60225 * @extends Roo.Template
60226 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60228 var t = new Roo.XTemplate(
60229 '<select name="{name}">',
60230 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60234 // then append, applying the master template values
60237 * Supported features:
60242 {a_variable} - output encoded.
60243 {a_variable.format:("Y-m-d")} - call a method on the variable
60244 {a_variable:raw} - unencoded output
60245 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60246 {a_variable:this.method_on_template(...)} - call a method on the template object.
60251 <tpl for="a_variable or condition.."></tpl>
60252 <tpl if="a_variable or condition"></tpl>
60253 <tpl exec="some javascript"></tpl>
60254 <tpl name="named_template"></tpl> (experimental)
60256 <tpl for="."></tpl> - just iterate the property..
60257 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60261 Roo.XTemplate = function()
60263 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60270 Roo.extend(Roo.XTemplate, Roo.Template, {
60273 * The various sub templates
60278 * basic tag replacing syntax
60281 * // you can fake an object call by doing this
60285 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60288 * compile the template
60290 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60293 compile: function()
60297 s = ['<tpl>', s, '</tpl>'].join('');
60299 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60300 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60301 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60302 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60303 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60308 while(true == !!(m = s.match(re))){
60309 var forMatch = m[0].match(nameRe),
60310 ifMatch = m[0].match(ifRe),
60311 execMatch = m[0].match(execRe),
60312 namedMatch = m[0].match(namedRe),
60317 name = forMatch && forMatch[1] ? forMatch[1] : '';
60320 // if - puts fn into test..
60321 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60323 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60328 // exec - calls a function... returns empty if true is returned.
60329 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60331 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60339 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60340 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60341 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60344 var uid = namedMatch ? namedMatch[1] : id;
60348 id: namedMatch ? namedMatch[1] : id,
60355 s = s.replace(m[0], '');
60357 s = s.replace(m[0], '{xtpl'+ id + '}');
60362 for(var i = tpls.length-1; i >= 0; --i){
60363 this.compileTpl(tpls[i]);
60364 this.tpls[tpls[i].id] = tpls[i];
60366 this.master = tpls[tpls.length-1];
60370 * same as applyTemplate, except it's done to one of the subTemplates
60371 * when using named templates, you can do:
60373 * var str = pl.applySubTemplate('your-name', values);
60376 * @param {Number} id of the template
60377 * @param {Object} values to apply to template
60378 * @param {Object} parent (normaly the instance of this object)
60380 applySubTemplate : function(id, values, parent)
60384 var t = this.tpls[id];
60388 if(t.test && !t.test.call(this, values, parent)){
60392 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60393 Roo.log(e.toString());
60399 if(t.exec && t.exec.call(this, values, parent)){
60403 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60404 Roo.log(e.toString());
60409 var vs = t.target ? t.target.call(this, values, parent) : values;
60410 parent = t.target ? values : parent;
60411 if(t.target && vs instanceof Array){
60413 for(var i = 0, len = vs.length; i < len; i++){
60414 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60416 return buf.join('');
60418 return t.compiled.call(this, vs, parent);
60420 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60421 Roo.log(e.toString());
60422 Roo.log(t.compiled);
60427 compileTpl : function(tpl)
60429 var fm = Roo.util.Format;
60430 var useF = this.disableFormats !== true;
60431 var sep = Roo.isGecko ? "+" : ",";
60432 var undef = function(str) {
60433 Roo.log("Property not found :" + str);
60437 var fn = function(m, name, format, args)
60439 //Roo.log(arguments);
60440 args = args ? args.replace(/\\'/g,"'") : args;
60441 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60442 if (typeof(format) == 'undefined') {
60443 format= 'htmlEncode';
60445 if (format == 'raw' ) {
60449 if(name.substr(0, 4) == 'xtpl'){
60450 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60453 // build an array of options to determine if value is undefined..
60455 // basically get 'xxxx.yyyy' then do
60456 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60457 // (function () { Roo.log("Property not found"); return ''; })() :
60462 Roo.each(name.split('.'), function(st) {
60463 lookfor += (lookfor.length ? '.': '') + st;
60464 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60467 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60470 if(format && useF){
60472 args = args ? ',' + args : "";
60474 if(format.substr(0, 5) != "this."){
60475 format = "fm." + format + '(';
60477 format = 'this.call("'+ format.substr(5) + '", ';
60481 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60485 // called with xxyx.yuu:(test,test)
60487 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60489 // raw.. - :raw modifier..
60490 return "'"+ sep + udef_st + name + ")"+sep+"'";
60494 // branched to use + in gecko and [].join() in others
60496 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60497 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60500 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60501 body.push(tpl.body.replace(/(\r\n|\n)/g,
60502 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60503 body.push("'].join('');};};");
60504 body = body.join('');
60507 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60509 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60515 applyTemplate : function(values){
60516 return this.master.compiled.call(this, values, {});
60517 //var s = this.subs;
60520 apply : function(){
60521 return this.applyTemplate.apply(this, arguments);
60526 Roo.XTemplate.from = function(el){
60527 el = Roo.getDom(el);
60528 return new Roo.XTemplate(el.value || el.innerHTML);