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") {
7186 parent.dom.nodeName.toLowerCase() == 'body' ||
7187 overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))
7193 return Roo.get(document.body);
7197 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7198 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7199 * @param {String} selector The simple selector to test
7200 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7201 search as a number or element (defaults to 10 || document.body)
7202 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7204 up : function(simpleSelector, maxDepth){
7205 return this.findParentNode(simpleSelector, maxDepth, true);
7211 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7212 * @param {String} selector The simple selector to test
7213 * @return {Boolean} True if this element matches the selector, else false
7215 is : function(simpleSelector){
7216 return Roo.DomQuery.is(this.dom, simpleSelector);
7220 * Perform animation on this element.
7221 * @param {Object} args The YUI animation control args
7222 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7223 * @param {Function} onComplete (optional) Function to call when animation completes
7224 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7225 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7226 * @return {Roo.Element} this
7228 animate : function(args, duration, onComplete, easing, animType){
7229 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7234 * @private Internal animation call
7236 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7237 animType = animType || 'run';
7239 var anim = Roo.lib.Anim[animType](
7241 (opt.duration || defaultDur) || .35,
7242 (opt.easing || defaultEase) || 'easeOut',
7244 Roo.callback(cb, this);
7245 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7253 // private legacy anim prep
7254 preanim : function(a, i){
7255 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7259 * Removes worthless text nodes
7260 * @param {Boolean} forceReclean (optional) By default the element
7261 * keeps track if it has been cleaned already so
7262 * you can call this over and over. However, if you update the element and
7263 * need to force a reclean, you can pass true.
7265 clean : function(forceReclean){
7266 if(this.isCleaned && forceReclean !== true){
7270 var d = this.dom, n = d.firstChild, ni = -1;
7272 var nx = n.nextSibling;
7273 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7280 this.isCleaned = true;
7285 calcOffsetsTo : function(el){
7288 var restorePos = false;
7289 if(el.getStyle('position') == 'static'){
7290 el.position('relative');
7295 while(op && op != d && op.tagName != 'HTML'){
7298 op = op.offsetParent;
7301 el.position('static');
7307 * Scrolls this element into view within the passed container.
7308 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7309 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7310 * @return {Roo.Element} this
7312 scrollIntoView : function(container, hscroll){
7313 var c = Roo.getDom(container) || document.body;
7316 var o = this.calcOffsetsTo(c),
7319 b = t+el.offsetHeight,
7320 r = l+el.offsetWidth;
7322 var ch = c.clientHeight;
7323 var ct = parseInt(c.scrollTop, 10);
7324 var cl = parseInt(c.scrollLeft, 10);
7326 var cr = cl + c.clientWidth;
7334 if(hscroll !== false){
7338 c.scrollLeft = r-c.clientWidth;
7345 scrollChildIntoView : function(child, hscroll){
7346 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7350 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7351 * the new height may not be available immediately.
7352 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7353 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7354 * @param {Function} onComplete (optional) Function to call when animation completes
7355 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7356 * @return {Roo.Element} this
7358 autoHeight : function(animate, duration, onComplete, easing){
7359 var oldHeight = this.getHeight();
7361 this.setHeight(1); // force clipping
7362 setTimeout(function(){
7363 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7365 this.setHeight(height);
7367 if(typeof onComplete == "function"){
7371 this.setHeight(oldHeight); // restore original height
7372 this.setHeight(height, animate, duration, function(){
7374 if(typeof onComplete == "function") { onComplete(); }
7375 }.createDelegate(this), easing);
7377 }.createDelegate(this), 0);
7382 * Returns true if this element is an ancestor of the passed element
7383 * @param {HTMLElement/String} el The element to check
7384 * @return {Boolean} True if this element is an ancestor of el, else false
7386 contains : function(el){
7387 if(!el){return false;}
7388 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7392 * Checks whether the element is currently visible using both visibility and display properties.
7393 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7394 * @return {Boolean} True if the element is currently visible, else false
7396 isVisible : function(deep) {
7397 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7398 if(deep !== true || !vis){
7401 var p = this.dom.parentNode;
7402 while(p && p.tagName.toLowerCase() != "body"){
7403 if(!Roo.fly(p, '_isVisible').isVisible()){
7412 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7413 * @param {String} selector The CSS selector
7414 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7415 * @return {CompositeElement/CompositeElementLite} The composite element
7417 select : function(selector, unique){
7418 return El.select(selector, unique, this.dom);
7422 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7423 * @param {String} selector The CSS selector
7424 * @return {Array} An array of the matched nodes
7426 query : function(selector, unique){
7427 return Roo.DomQuery.select(selector, this.dom);
7431 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7432 * @param {String} selector The CSS selector
7433 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7434 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7436 child : function(selector, returnDom){
7437 var n = Roo.DomQuery.selectNode(selector, this.dom);
7438 return returnDom ? n : Roo.get(n);
7442 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7443 * @param {String} selector The CSS selector
7444 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7445 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7447 down : function(selector, returnDom){
7448 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7449 return returnDom ? n : Roo.get(n);
7453 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7454 * @param {String} group The group the DD object is member of
7455 * @param {Object} config The DD config object
7456 * @param {Object} overrides An object containing methods to override/implement on the DD object
7457 * @return {Roo.dd.DD} The DD object
7459 initDD : function(group, config, overrides){
7460 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7461 return Roo.apply(dd, overrides);
7465 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7466 * @param {String} group The group the DDProxy object is member of
7467 * @param {Object} config The DDProxy config object
7468 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7469 * @return {Roo.dd.DDProxy} The DDProxy object
7471 initDDProxy : function(group, config, overrides){
7472 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7473 return Roo.apply(dd, overrides);
7477 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7478 * @param {String} group The group the DDTarget object is member of
7479 * @param {Object} config The DDTarget config object
7480 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7481 * @return {Roo.dd.DDTarget} The DDTarget object
7483 initDDTarget : function(group, config, overrides){
7484 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7485 return Roo.apply(dd, overrides);
7489 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7490 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7491 * @param {Boolean} visible Whether the element is visible
7492 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7493 * @return {Roo.Element} this
7495 setVisible : function(visible, animate){
7497 if(this.visibilityMode == El.DISPLAY){
7498 this.setDisplayed(visible);
7501 this.dom.style.visibility = visible ? "visible" : "hidden";
7504 // closure for composites
7506 var visMode = this.visibilityMode;
7508 this.setOpacity(.01);
7509 this.setVisible(true);
7511 this.anim({opacity: { to: (visible?1:0) }},
7512 this.preanim(arguments, 1),
7513 null, .35, 'easeIn', function(){
7515 if(visMode == El.DISPLAY){
7516 dom.style.display = "none";
7518 dom.style.visibility = "hidden";
7520 Roo.get(dom).setOpacity(1);
7528 * Returns true if display is not "none"
7531 isDisplayed : function() {
7532 return this.getStyle("display") != "none";
7536 * Toggles the element's visibility or display, depending on visibility mode.
7537 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7538 * @return {Roo.Element} this
7540 toggle : function(animate){
7541 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7546 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7547 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7548 * @return {Roo.Element} this
7550 setDisplayed : function(value) {
7551 if(typeof value == "boolean"){
7552 value = value ? this.originalDisplay : "none";
7554 this.setStyle("display", value);
7559 * Tries to focus the element. Any exceptions are caught and ignored.
7560 * @return {Roo.Element} this
7562 focus : function() {
7570 * Tries to blur the element. Any exceptions are caught and ignored.
7571 * @return {Roo.Element} this
7581 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7582 * @param {String/Array} className The CSS class to add, or an array of classes
7583 * @return {Roo.Element} this
7585 addClass : function(className){
7586 if(className instanceof Array){
7587 for(var i = 0, len = className.length; i < len; i++) {
7588 this.addClass(className[i]);
7591 if(className && !this.hasClass(className)){
7592 this.dom.className = this.dom.className + " " + className;
7599 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7600 * @param {String/Array} className The CSS class to add, or an array of classes
7601 * @return {Roo.Element} this
7603 radioClass : function(className){
7604 var siblings = this.dom.parentNode.childNodes;
7605 for(var i = 0; i < siblings.length; i++) {
7606 var s = siblings[i];
7607 if(s.nodeType == 1){
7608 Roo.get(s).removeClass(className);
7611 this.addClass(className);
7616 * Removes one or more CSS classes from the element.
7617 * @param {String/Array} className The CSS class to remove, or an array of classes
7618 * @return {Roo.Element} this
7620 removeClass : function(className){
7621 if(!className || !this.dom.className){
7624 if(className instanceof Array){
7625 for(var i = 0, len = className.length; i < len; i++) {
7626 this.removeClass(className[i]);
7629 if(this.hasClass(className)){
7630 var re = this.classReCache[className];
7632 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7633 this.classReCache[className] = re;
7635 this.dom.className =
7636 this.dom.className.replace(re, " ");
7646 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7647 * @param {String} className The CSS class to toggle
7648 * @return {Roo.Element} this
7650 toggleClass : function(className){
7651 if(this.hasClass(className)){
7652 this.removeClass(className);
7654 this.addClass(className);
7660 * Checks if the specified CSS class exists on this element's DOM node.
7661 * @param {String} className The CSS class to check for
7662 * @return {Boolean} True if the class exists, else false
7664 hasClass : function(className){
7665 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7669 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7670 * @param {String} oldClassName The CSS class to replace
7671 * @param {String} newClassName The replacement CSS class
7672 * @return {Roo.Element} this
7674 replaceClass : function(oldClassName, newClassName){
7675 this.removeClass(oldClassName);
7676 this.addClass(newClassName);
7681 * Returns an object with properties matching the styles requested.
7682 * For example, el.getStyles('color', 'font-size', 'width') might return
7683 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7684 * @param {String} style1 A style name
7685 * @param {String} style2 A style name
7686 * @param {String} etc.
7687 * @return {Object} The style object
7689 getStyles : function(){
7690 var a = arguments, len = a.length, r = {};
7691 for(var i = 0; i < len; i++){
7692 r[a[i]] = this.getStyle(a[i]);
7698 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7699 * @param {String} property The style property whose value is returned.
7700 * @return {String} The current value of the style property for this element.
7702 getStyle : function(){
7703 return view && view.getComputedStyle ?
7705 var el = this.dom, v, cs, camel;
7706 if(prop == 'float'){
7709 if(el.style && (v = el.style[prop])){
7712 if(cs = view.getComputedStyle(el, "")){
7713 if(!(camel = propCache[prop])){
7714 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7721 var el = this.dom, v, cs, camel;
7722 if(prop == 'opacity'){
7723 if(typeof el.style.filter == 'string'){
7724 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7726 var fv = parseFloat(m[1]);
7728 return fv ? fv / 100 : 0;
7733 }else if(prop == 'float'){
7734 prop = "styleFloat";
7736 if(!(camel = propCache[prop])){
7737 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7739 if(v = el.style[camel]){
7742 if(cs = el.currentStyle){
7750 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7751 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7752 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7753 * @return {Roo.Element} this
7755 setStyle : function(prop, value){
7756 if(typeof prop == "string"){
7758 if (prop == 'float') {
7759 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7764 if(!(camel = propCache[prop])){
7765 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7768 if(camel == 'opacity') {
7769 this.setOpacity(value);
7771 this.dom.style[camel] = value;
7774 for(var style in prop){
7775 if(typeof prop[style] != "function"){
7776 this.setStyle(style, prop[style]);
7784 * More flexible version of {@link #setStyle} for setting style properties.
7785 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7786 * a function which returns such a specification.
7787 * @return {Roo.Element} this
7789 applyStyles : function(style){
7790 Roo.DomHelper.applyStyles(this.dom, style);
7795 * 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).
7796 * @return {Number} The X position of the element
7799 return D.getX(this.dom);
7803 * 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).
7804 * @return {Number} The Y position of the element
7807 return D.getY(this.dom);
7811 * 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).
7812 * @return {Array} The XY position of the element
7815 return D.getXY(this.dom);
7819 * 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).
7820 * @param {Number} The X position of the element
7821 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7822 * @return {Roo.Element} this
7824 setX : function(x, animate){
7826 D.setX(this.dom, x);
7828 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7834 * 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).
7835 * @param {Number} The Y position of the element
7836 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7837 * @return {Roo.Element} this
7839 setY : function(y, animate){
7841 D.setY(this.dom, y);
7843 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7849 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7850 * @param {String} left The left CSS property value
7851 * @return {Roo.Element} this
7853 setLeft : function(left){
7854 this.setStyle("left", this.addUnits(left));
7859 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7860 * @param {String} top The top CSS property value
7861 * @return {Roo.Element} this
7863 setTop : function(top){
7864 this.setStyle("top", this.addUnits(top));
7869 * Sets the element's CSS right style.
7870 * @param {String} right The right CSS property value
7871 * @return {Roo.Element} this
7873 setRight : function(right){
7874 this.setStyle("right", this.addUnits(right));
7879 * Sets the element's CSS bottom style.
7880 * @param {String} bottom The bottom CSS property value
7881 * @return {Roo.Element} this
7883 setBottom : function(bottom){
7884 this.setStyle("bottom", this.addUnits(bottom));
7889 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7890 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7891 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7892 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7893 * @return {Roo.Element} this
7895 setXY : function(pos, animate){
7897 D.setXY(this.dom, pos);
7899 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7905 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7906 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7907 * @param {Number} x X value for new position (coordinates are page-based)
7908 * @param {Number} y Y value for new position (coordinates are page-based)
7909 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7910 * @return {Roo.Element} this
7912 setLocation : function(x, y, animate){
7913 this.setXY([x, y], this.preanim(arguments, 2));
7918 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7919 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7920 * @param {Number} x X value for new position (coordinates are page-based)
7921 * @param {Number} y Y value for new position (coordinates are page-based)
7922 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7923 * @return {Roo.Element} this
7925 moveTo : function(x, y, animate){
7926 this.setXY([x, y], this.preanim(arguments, 2));
7931 * Returns the region of the given element.
7932 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7933 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7935 getRegion : function(){
7936 return D.getRegion(this.dom);
7940 * Returns the offset height of the element
7941 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7942 * @return {Number} The element's height
7944 getHeight : function(contentHeight){
7945 var h = this.dom.offsetHeight || 0;
7946 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7950 * Returns the offset width of the element
7951 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7952 * @return {Number} The element's width
7954 getWidth : function(contentWidth){
7955 var w = this.dom.offsetWidth || 0;
7956 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7960 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7961 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7962 * if a height has not been set using CSS.
7965 getComputedHeight : function(){
7966 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7968 h = parseInt(this.getStyle('height'), 10) || 0;
7969 if(!this.isBorderBox()){
7970 h += this.getFrameWidth('tb');
7977 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7978 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7979 * if a width has not been set using CSS.
7982 getComputedWidth : function(){
7983 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7985 w = parseInt(this.getStyle('width'), 10) || 0;
7986 if(!this.isBorderBox()){
7987 w += this.getFrameWidth('lr');
7994 * Returns the size of the element.
7995 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7996 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7998 getSize : function(contentSize){
7999 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8003 * Returns the width and height of the viewport.
8004 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8006 getViewSize : function(){
8007 var d = this.dom, doc = document, aw = 0, ah = 0;
8008 if(d == doc || d == doc.body){
8009 return {width : D.getViewWidth(), height: D.getViewHeight()};
8012 width : d.clientWidth,
8013 height: d.clientHeight
8019 * Returns the value of the "value" attribute
8020 * @param {Boolean} asNumber true to parse the value as a number
8021 * @return {String/Number}
8023 getValue : function(asNumber){
8024 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8028 adjustWidth : function(width){
8029 if(typeof width == "number"){
8030 if(this.autoBoxAdjust && !this.isBorderBox()){
8031 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8041 adjustHeight : function(height){
8042 if(typeof height == "number"){
8043 if(this.autoBoxAdjust && !this.isBorderBox()){
8044 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8054 * Set the width of the element
8055 * @param {Number} width The new width
8056 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8057 * @return {Roo.Element} this
8059 setWidth : function(width, animate){
8060 width = this.adjustWidth(width);
8062 this.dom.style.width = this.addUnits(width);
8064 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8070 * Set the height of the element
8071 * @param {Number} height The new height
8072 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8073 * @return {Roo.Element} this
8075 setHeight : function(height, animate){
8076 height = this.adjustHeight(height);
8078 this.dom.style.height = this.addUnits(height);
8080 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8086 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8087 * @param {Number} width The new width
8088 * @param {Number} height The new height
8089 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8090 * @return {Roo.Element} this
8092 setSize : function(width, height, animate){
8093 if(typeof width == "object"){ // in case of object from getSize()
8094 height = width.height; width = width.width;
8096 width = this.adjustWidth(width); height = this.adjustHeight(height);
8098 this.dom.style.width = this.addUnits(width);
8099 this.dom.style.height = this.addUnits(height);
8101 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8107 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8108 * @param {Number} x X value for new position (coordinates are page-based)
8109 * @param {Number} y Y value for new position (coordinates are page-based)
8110 * @param {Number} width The new width
8111 * @param {Number} height The new height
8112 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8113 * @return {Roo.Element} this
8115 setBounds : function(x, y, width, height, animate){
8117 this.setSize(width, height);
8118 this.setLocation(x, y);
8120 width = this.adjustWidth(width); height = this.adjustHeight(height);
8121 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8122 this.preanim(arguments, 4), 'motion');
8128 * 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.
8129 * @param {Roo.lib.Region} region The region to fill
8130 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8131 * @return {Roo.Element} this
8133 setRegion : function(region, animate){
8134 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8139 * Appends an event handler
8141 * @param {String} eventName The type of event to append
8142 * @param {Function} fn The method the event invokes
8143 * @param {Object} scope (optional) The scope (this object) of the fn
8144 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8146 addListener : function(eventName, fn, scope, options){
8148 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8153 * Removes an event handler from this element
8154 * @param {String} eventName the type of event to remove
8155 * @param {Function} fn the method the event invokes
8156 * @return {Roo.Element} this
8158 removeListener : function(eventName, fn){
8159 Roo.EventManager.removeListener(this.dom, eventName, fn);
8164 * Removes all previous added listeners from this element
8165 * @return {Roo.Element} this
8167 removeAllListeners : function(){
8168 E.purgeElement(this.dom);
8172 relayEvent : function(eventName, observable){
8173 this.on(eventName, function(e){
8174 observable.fireEvent(eventName, e);
8179 * Set the opacity of the element
8180 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8181 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8182 * @return {Roo.Element} this
8184 setOpacity : function(opacity, animate){
8186 var s = this.dom.style;
8189 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8190 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8192 s.opacity = opacity;
8195 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8201 * Gets the left X coordinate
8202 * @param {Boolean} local True to get the local css position instead of page coordinate
8205 getLeft : function(local){
8209 return parseInt(this.getStyle("left"), 10) || 0;
8214 * Gets the right X coordinate of the element (element X position + element width)
8215 * @param {Boolean} local True to get the local css position instead of page coordinate
8218 getRight : function(local){
8220 return this.getX() + this.getWidth();
8222 return (this.getLeft(true) + this.getWidth()) || 0;
8227 * Gets the top Y coordinate
8228 * @param {Boolean} local True to get the local css position instead of page coordinate
8231 getTop : function(local) {
8235 return parseInt(this.getStyle("top"), 10) || 0;
8240 * Gets the bottom Y coordinate of the element (element Y position + element height)
8241 * @param {Boolean} local True to get the local css position instead of page coordinate
8244 getBottom : function(local){
8246 return this.getY() + this.getHeight();
8248 return (this.getTop(true) + this.getHeight()) || 0;
8253 * Initializes positioning on this element. If a desired position is not passed, it will make the
8254 * the element positioned relative IF it is not already positioned.
8255 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8256 * @param {Number} zIndex (optional) The zIndex to apply
8257 * @param {Number} x (optional) Set the page X position
8258 * @param {Number} y (optional) Set the page Y position
8260 position : function(pos, zIndex, x, y){
8262 if(this.getStyle('position') == 'static'){
8263 this.setStyle('position', 'relative');
8266 this.setStyle("position", pos);
8269 this.setStyle("z-index", zIndex);
8271 if(x !== undefined && y !== undefined){
8273 }else if(x !== undefined){
8275 }else if(y !== undefined){
8281 * Clear positioning back to the default when the document was loaded
8282 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8283 * @return {Roo.Element} this
8285 clearPositioning : function(value){
8293 "position" : "static"
8299 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8300 * snapshot before performing an update and then restoring the element.
8303 getPositioning : function(){
8304 var l = this.getStyle("left");
8305 var t = this.getStyle("top");
8307 "position" : this.getStyle("position"),
8309 "right" : l ? "" : this.getStyle("right"),
8311 "bottom" : t ? "" : this.getStyle("bottom"),
8312 "z-index" : this.getStyle("z-index")
8317 * Gets the width of the border(s) for the specified side(s)
8318 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8319 * passing lr would get the border (l)eft width + the border (r)ight width.
8320 * @return {Number} The width of the sides passed added together
8322 getBorderWidth : function(side){
8323 return this.addStyles(side, El.borders);
8327 * Gets the width of the padding(s) for the specified side(s)
8328 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8329 * passing lr would get the padding (l)eft + the padding (r)ight.
8330 * @return {Number} The padding of the sides passed added together
8332 getPadding : function(side){
8333 return this.addStyles(side, El.paddings);
8337 * Set positioning with an object returned by getPositioning().
8338 * @param {Object} posCfg
8339 * @return {Roo.Element} this
8341 setPositioning : function(pc){
8342 this.applyStyles(pc);
8343 if(pc.right == "auto"){
8344 this.dom.style.right = "";
8346 if(pc.bottom == "auto"){
8347 this.dom.style.bottom = "";
8353 fixDisplay : function(){
8354 if(this.getStyle("display") == "none"){
8355 this.setStyle("visibility", "hidden");
8356 this.setStyle("display", this.originalDisplay); // first try reverting to default
8357 if(this.getStyle("display") == "none"){ // if that fails, default to block
8358 this.setStyle("display", "block");
8364 * Quick set left and top adding default units
8365 * @param {String} left The left CSS property value
8366 * @param {String} top The top CSS property value
8367 * @return {Roo.Element} this
8369 setLeftTop : function(left, top){
8370 this.dom.style.left = this.addUnits(left);
8371 this.dom.style.top = this.addUnits(top);
8376 * Move this element relative to its current position.
8377 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8378 * @param {Number} distance How far to move the element in pixels
8379 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8380 * @return {Roo.Element} this
8382 move : function(direction, distance, animate){
8383 var xy = this.getXY();
8384 direction = direction.toLowerCase();
8388 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8392 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8397 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8402 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8409 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8410 * @return {Roo.Element} this
8413 if(!this.isClipped){
8414 this.isClipped = true;
8415 this.originalClip = {
8416 "o": this.getStyle("overflow"),
8417 "x": this.getStyle("overflow-x"),
8418 "y": this.getStyle("overflow-y")
8420 this.setStyle("overflow", "hidden");
8421 this.setStyle("overflow-x", "hidden");
8422 this.setStyle("overflow-y", "hidden");
8428 * Return clipping (overflow) to original clipping before clip() was called
8429 * @return {Roo.Element} this
8431 unclip : function(){
8433 this.isClipped = false;
8434 var o = this.originalClip;
8435 if(o.o){this.setStyle("overflow", o.o);}
8436 if(o.x){this.setStyle("overflow-x", o.x);}
8437 if(o.y){this.setStyle("overflow-y", o.y);}
8444 * Gets the x,y coordinates specified by the anchor position on the element.
8445 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8446 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8447 * {width: (target width), height: (target height)} (defaults to the element's current size)
8448 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8449 * @return {Array} [x, y] An array containing the element's x and y coordinates
8451 getAnchorXY : function(anchor, local, s){
8452 //Passing a different size is useful for pre-calculating anchors,
8453 //especially for anchored animations that change the el size.
8455 var w, h, vp = false;
8458 if(d == document.body || d == document){
8460 w = D.getViewWidth(); h = D.getViewHeight();
8462 w = this.getWidth(); h = this.getHeight();
8465 w = s.width; h = s.height;
8467 var x = 0, y = 0, r = Math.round;
8468 switch((anchor || "tl").toLowerCase()){
8510 var sc = this.getScroll();
8511 return [x + sc.left, y + sc.top];
8513 //Add the element's offset xy
8514 var o = this.getXY();
8515 return [x+o[0], y+o[1]];
8519 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8520 * supported position values.
8521 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8522 * @param {String} position The position to align to.
8523 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8524 * @return {Array} [x, y]
8526 getAlignToXY : function(el, p, o){
8530 throw "Element.alignTo with an element that doesn't exist";
8532 var c = false; //constrain to viewport
8533 var p1 = "", p2 = "";
8540 }else if(p.indexOf("-") == -1){
8543 p = p.toLowerCase();
8544 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8546 throw "Element.alignTo with an invalid alignment " + p;
8548 p1 = m[1]; p2 = m[2]; c = !!m[3];
8550 //Subtract the aligned el's internal xy from the target's offset xy
8551 //plus custom offset to get the aligned el's new offset xy
8552 var a1 = this.getAnchorXY(p1, true);
8553 var a2 = el.getAnchorXY(p2, false);
8554 var x = a2[0] - a1[0] + o[0];
8555 var y = a2[1] - a1[1] + o[1];
8557 //constrain the aligned el to viewport if necessary
8558 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8559 // 5px of margin for ie
8560 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8562 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8563 //perpendicular to the vp border, allow the aligned el to slide on that border,
8564 //otherwise swap the aligned el to the opposite border of the target.
8565 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8566 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8567 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8568 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8571 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8572 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8574 if((x+w) > dw + scrollX){
8575 x = swapX ? r.left-w : dw+scrollX-w;
8578 x = swapX ? r.right : scrollX;
8580 if((y+h) > dh + scrollY){
8581 y = swapY ? r.top-h : dh+scrollY-h;
8584 y = swapY ? r.bottom : scrollY;
8591 getConstrainToXY : function(){
8592 var os = {top:0, left:0, bottom:0, right: 0};
8594 return function(el, local, offsets, proposedXY){
8596 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8598 var vw, vh, vx = 0, vy = 0;
8599 if(el.dom == document.body || el.dom == document){
8600 vw = Roo.lib.Dom.getViewWidth();
8601 vh = Roo.lib.Dom.getViewHeight();
8603 vw = el.dom.clientWidth;
8604 vh = el.dom.clientHeight;
8606 var vxy = el.getXY();
8612 var s = el.getScroll();
8614 vx += offsets.left + s.left;
8615 vy += offsets.top + s.top;
8617 vw -= offsets.right;
8618 vh -= offsets.bottom;
8623 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8624 var x = xy[0], y = xy[1];
8625 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8627 // only move it if it needs it
8630 // first validate right/bottom
8639 // then make sure top/left isn't negative
8648 return moved ? [x, y] : false;
8653 adjustForConstraints : function(xy, parent, offsets){
8654 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8658 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8659 * document it aligns it to the viewport.
8660 * The position parameter is optional, and can be specified in any one of the following formats:
8662 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8663 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8664 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8665 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8666 * <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
8667 * element's anchor point, and the second value is used as the target's anchor point.</li>
8669 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8670 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8671 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8672 * that specified in order to enforce the viewport constraints.
8673 * Following are all of the supported anchor positions:
8676 ----- -----------------------------
8677 tl The top left corner (default)
8678 t The center of the top edge
8679 tr The top right corner
8680 l The center of the left edge
8681 c In the center of the element
8682 r The center of the right edge
8683 bl The bottom left corner
8684 b The center of the bottom edge
8685 br The bottom right corner
8689 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8690 el.alignTo("other-el");
8692 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8693 el.alignTo("other-el", "tr?");
8695 // align the bottom right corner of el with the center left edge of other-el
8696 el.alignTo("other-el", "br-l?");
8698 // align the center of el with the bottom left corner of other-el and
8699 // adjust the x position by -6 pixels (and the y position by 0)
8700 el.alignTo("other-el", "c-bl", [-6, 0]);
8702 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8703 * @param {String} position The position to align to.
8704 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8705 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8706 * @return {Roo.Element} this
8708 alignTo : function(element, position, offsets, animate){
8709 var xy = this.getAlignToXY(element, position, offsets);
8710 this.setXY(xy, this.preanim(arguments, 3));
8715 * Anchors an element to another element and realigns it when the window is resized.
8716 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8717 * @param {String} position The position to align to.
8718 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8719 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8720 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8721 * is a number, it is used as the buffer delay (defaults to 50ms).
8722 * @param {Function} callback The function to call after the animation finishes
8723 * @return {Roo.Element} this
8725 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8726 var action = function(){
8727 this.alignTo(el, alignment, offsets, animate);
8728 Roo.callback(callback, this);
8730 Roo.EventManager.onWindowResize(action, this);
8731 var tm = typeof monitorScroll;
8732 if(tm != 'undefined'){
8733 Roo.EventManager.on(window, 'scroll', action, this,
8734 {buffer: tm == 'number' ? monitorScroll : 50});
8736 action.call(this); // align immediately
8740 * Clears any opacity settings from this element. Required in some cases for IE.
8741 * @return {Roo.Element} this
8743 clearOpacity : function(){
8744 if (window.ActiveXObject) {
8745 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8746 this.dom.style.filter = "";
8749 this.dom.style.opacity = "";
8750 this.dom.style["-moz-opacity"] = "";
8751 this.dom.style["-khtml-opacity"] = "";
8757 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8758 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8759 * @return {Roo.Element} this
8761 hide : function(animate){
8762 this.setVisible(false, this.preanim(arguments, 0));
8767 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8768 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8769 * @return {Roo.Element} this
8771 show : function(animate){
8772 this.setVisible(true, this.preanim(arguments, 0));
8777 * @private Test if size has a unit, otherwise appends the default
8779 addUnits : function(size){
8780 return Roo.Element.addUnits(size, this.defaultUnit);
8784 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8785 * @return {Roo.Element} this
8787 beginMeasure : function(){
8789 if(el.offsetWidth || el.offsetHeight){
8790 return this; // offsets work already
8793 var p = this.dom, b = document.body; // start with this element
8794 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8795 var pe = Roo.get(p);
8796 if(pe.getStyle('display') == 'none'){
8797 changed.push({el: p, visibility: pe.getStyle("visibility")});
8798 p.style.visibility = "hidden";
8799 p.style.display = "block";
8803 this._measureChanged = changed;
8809 * Restores displays to before beginMeasure was called
8810 * @return {Roo.Element} this
8812 endMeasure : function(){
8813 var changed = this._measureChanged;
8815 for(var i = 0, len = changed.length; i < len; i++) {
8817 r.el.style.visibility = r.visibility;
8818 r.el.style.display = "none";
8820 this._measureChanged = null;
8826 * Update the innerHTML of this element, optionally searching for and processing scripts
8827 * @param {String} html The new HTML
8828 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8829 * @param {Function} callback For async script loading you can be noticed when the update completes
8830 * @return {Roo.Element} this
8832 update : function(html, loadScripts, callback){
8833 if(typeof html == "undefined"){
8836 if(loadScripts !== true){
8837 this.dom.innerHTML = html;
8838 if(typeof callback == "function"){
8846 html += '<span id="' + id + '"></span>';
8848 E.onAvailable(id, function(){
8849 var hd = document.getElementsByTagName("head")[0];
8850 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8851 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8852 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8855 while(match = re.exec(html)){
8856 var attrs = match[1];
8857 var srcMatch = attrs ? attrs.match(srcRe) : false;
8858 if(srcMatch && srcMatch[2]){
8859 var s = document.createElement("script");
8860 s.src = srcMatch[2];
8861 var typeMatch = attrs.match(typeRe);
8862 if(typeMatch && typeMatch[2]){
8863 s.type = typeMatch[2];
8866 }else if(match[2] && match[2].length > 0){
8867 if(window.execScript) {
8868 window.execScript(match[2]);
8876 window.eval(match[2]);
8880 var el = document.getElementById(id);
8881 if(el){el.parentNode.removeChild(el);}
8882 if(typeof callback == "function"){
8886 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8891 * Direct access to the UpdateManager update() method (takes the same parameters).
8892 * @param {String/Function} url The url for this request or a function to call to get the url
8893 * @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}
8894 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8895 * @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.
8896 * @return {Roo.Element} this
8899 var um = this.getUpdateManager();
8900 um.update.apply(um, arguments);
8905 * Gets this element's UpdateManager
8906 * @return {Roo.UpdateManager} The UpdateManager
8908 getUpdateManager : function(){
8909 if(!this.updateManager){
8910 this.updateManager = new Roo.UpdateManager(this);
8912 return this.updateManager;
8916 * Disables text selection for this element (normalized across browsers)
8917 * @return {Roo.Element} this
8919 unselectable : function(){
8920 this.dom.unselectable = "on";
8921 this.swallowEvent("selectstart", true);
8922 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8923 this.addClass("x-unselectable");
8928 * Calculates the x, y to center this element on the screen
8929 * @return {Array} The x, y values [x, y]
8931 getCenterXY : function(){
8932 return this.getAlignToXY(document, 'c-c');
8936 * Centers the Element in either the viewport, or another Element.
8937 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8939 center : function(centerIn){
8940 this.alignTo(centerIn || document, 'c-c');
8945 * Tests various css rules/browsers to determine if this element uses a border box
8948 isBorderBox : function(){
8949 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8953 * Return a box {x, y, width, height} that can be used to set another elements
8954 * size/location to match this element.
8955 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8956 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8957 * @return {Object} box An object in the format {x, y, width, height}
8959 getBox : function(contentBox, local){
8964 var left = parseInt(this.getStyle("left"), 10) || 0;
8965 var top = parseInt(this.getStyle("top"), 10) || 0;
8968 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8970 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8972 var l = this.getBorderWidth("l")+this.getPadding("l");
8973 var r = this.getBorderWidth("r")+this.getPadding("r");
8974 var t = this.getBorderWidth("t")+this.getPadding("t");
8975 var b = this.getBorderWidth("b")+this.getPadding("b");
8976 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)};
8978 bx.right = bx.x + bx.width;
8979 bx.bottom = bx.y + bx.height;
8984 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8985 for more information about the sides.
8986 * @param {String} sides
8989 getFrameWidth : function(sides, onlyContentBox){
8990 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8994 * 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.
8995 * @param {Object} box The box to fill {x, y, width, height}
8996 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8997 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8998 * @return {Roo.Element} this
9000 setBox : function(box, adjust, animate){
9001 var w = box.width, h = box.height;
9002 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9003 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9004 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9006 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9011 * Forces the browser to repaint this element
9012 * @return {Roo.Element} this
9014 repaint : function(){
9016 this.addClass("x-repaint");
9017 setTimeout(function(){
9018 Roo.get(dom).removeClass("x-repaint");
9024 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9025 * then it returns the calculated width of the sides (see getPadding)
9026 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9027 * @return {Object/Number}
9029 getMargins : function(side){
9032 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9033 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9034 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9035 right: parseInt(this.getStyle("margin-right"), 10) || 0
9038 return this.addStyles(side, El.margins);
9043 addStyles : function(sides, styles){
9045 for(var i = 0, len = sides.length; i < len; i++){
9046 v = this.getStyle(styles[sides.charAt(i)]);
9048 w = parseInt(v, 10);
9056 * Creates a proxy element of this element
9057 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9058 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9059 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9060 * @return {Roo.Element} The new proxy element
9062 createProxy : function(config, renderTo, matchBox){
9064 renderTo = Roo.getDom(renderTo);
9066 renderTo = document.body;
9068 config = typeof config == "object" ?
9069 config : {tag : "div", cls: config};
9070 var proxy = Roo.DomHelper.append(renderTo, config, true);
9072 proxy.setBox(this.getBox());
9078 * Puts a mask over this element to disable user interaction. Requires core.css.
9079 * This method can only be applied to elements which accept child nodes.
9080 * @param {String} msg (optional) A message to display in the mask
9081 * @param {String} msgCls (optional) A css class to apply to the msg element
9082 * @return {Element} The mask element
9084 mask : function(msg, msgCls)
9086 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9087 this.setStyle("position", "relative");
9090 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9092 this.addClass("x-masked");
9093 this._mask.setDisplayed(true);
9098 while (dom && dom.style) {
9099 if (!isNaN(parseInt(dom.style.zIndex))) {
9100 z = Math.max(z, parseInt(dom.style.zIndex));
9102 dom = dom.parentNode;
9104 // if we are masking the body - then it hides everything..
9105 if (this.dom == document.body) {
9107 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9108 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9111 if(typeof msg == 'string'){
9113 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9115 var mm = this._maskMsg;
9116 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9117 if (mm.dom.firstChild) { // weird IE issue?
9118 mm.dom.firstChild.innerHTML = msg;
9120 mm.setDisplayed(true);
9122 mm.setStyle('z-index', z + 102);
9124 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9125 this._mask.setHeight(this.getHeight());
9127 this._mask.setStyle('z-index', z + 100);
9133 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9134 * it is cached for reuse.
9136 unmask : function(removeEl){
9138 if(removeEl === true){
9139 this._mask.remove();
9142 this._maskMsg.remove();
9143 delete this._maskMsg;
9146 this._mask.setDisplayed(false);
9148 this._maskMsg.setDisplayed(false);
9152 this.removeClass("x-masked");
9156 * Returns true if this element is masked
9159 isMasked : function(){
9160 return this._mask && this._mask.isVisible();
9164 * Creates an iframe shim for this element to keep selects and other windowed objects from
9166 * @return {Roo.Element} The new shim element
9168 createShim : function(){
9169 var el = document.createElement('iframe');
9170 el.frameBorder = 'no';
9171 el.className = 'roo-shim';
9172 if(Roo.isIE && Roo.isSecure){
9173 el.src = Roo.SSL_SECURE_URL;
9175 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9176 shim.autoBoxAdjust = false;
9181 * Removes this element from the DOM and deletes it from the cache
9183 remove : function(){
9184 if(this.dom.parentNode){
9185 this.dom.parentNode.removeChild(this.dom);
9187 delete El.cache[this.dom.id];
9191 * Sets up event handlers to add and remove a css class when the mouse is over this element
9192 * @param {String} className
9193 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9194 * mouseout events for children elements
9195 * @return {Roo.Element} this
9197 addClassOnOver : function(className, preventFlicker){
9198 this.on("mouseover", function(){
9199 Roo.fly(this, '_internal').addClass(className);
9201 var removeFn = function(e){
9202 if(preventFlicker !== true || !e.within(this, true)){
9203 Roo.fly(this, '_internal').removeClass(className);
9206 this.on("mouseout", removeFn, this.dom);
9211 * Sets up event handlers to add and remove a css class when this element has the focus
9212 * @param {String} className
9213 * @return {Roo.Element} this
9215 addClassOnFocus : function(className){
9216 this.on("focus", function(){
9217 Roo.fly(this, '_internal').addClass(className);
9219 this.on("blur", function(){
9220 Roo.fly(this, '_internal').removeClass(className);
9225 * 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)
9226 * @param {String} className
9227 * @return {Roo.Element} this
9229 addClassOnClick : function(className){
9231 this.on("mousedown", function(){
9232 Roo.fly(dom, '_internal').addClass(className);
9233 var d = Roo.get(document);
9234 var fn = function(){
9235 Roo.fly(dom, '_internal').removeClass(className);
9236 d.removeListener("mouseup", fn);
9238 d.on("mouseup", fn);
9244 * Stops the specified event from bubbling and optionally prevents the default action
9245 * @param {String} eventName
9246 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9247 * @return {Roo.Element} this
9249 swallowEvent : function(eventName, preventDefault){
9250 var fn = function(e){
9251 e.stopPropagation();
9256 if(eventName instanceof Array){
9257 for(var i = 0, len = eventName.length; i < len; i++){
9258 this.on(eventName[i], fn);
9262 this.on(eventName, fn);
9269 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9272 * Sizes this element to its parent element's dimensions performing
9273 * neccessary box adjustments.
9274 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9275 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9276 * @return {Roo.Element} this
9278 fitToParent : function(monitorResize, targetParent) {
9279 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9280 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9281 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9284 var p = Roo.get(targetParent || this.dom.parentNode);
9285 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9286 if (monitorResize === true) {
9287 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9288 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9294 * Gets the next sibling, skipping text nodes
9295 * @return {HTMLElement} The next sibling or null
9297 getNextSibling : function(){
9298 var n = this.dom.nextSibling;
9299 while(n && n.nodeType != 1){
9306 * Gets the previous sibling, skipping text nodes
9307 * @return {HTMLElement} The previous sibling or null
9309 getPrevSibling : function(){
9310 var n = this.dom.previousSibling;
9311 while(n && n.nodeType != 1){
9312 n = n.previousSibling;
9319 * Appends the passed element(s) to this element
9320 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9321 * @return {Roo.Element} this
9323 appendChild: function(el){
9330 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9331 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9332 * automatically generated with the specified attributes.
9333 * @param {HTMLElement} insertBefore (optional) a child element of this element
9334 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9335 * @return {Roo.Element} The new child element
9337 createChild: function(config, insertBefore, returnDom){
9338 config = config || {tag:'div'};
9340 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9342 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9346 * Appends this element to the passed element
9347 * @param {String/HTMLElement/Element} el The new parent element
9348 * @return {Roo.Element} this
9350 appendTo: function(el){
9351 el = Roo.getDom(el);
9352 el.appendChild(this.dom);
9357 * Inserts this element before the passed element in the DOM
9358 * @param {String/HTMLElement/Element} el The element to insert before
9359 * @return {Roo.Element} this
9361 insertBefore: function(el){
9362 el = Roo.getDom(el);
9363 el.parentNode.insertBefore(this.dom, el);
9368 * Inserts this element after the passed element in the DOM
9369 * @param {String/HTMLElement/Element} el The element to insert after
9370 * @return {Roo.Element} this
9372 insertAfter: function(el){
9373 el = Roo.getDom(el);
9374 el.parentNode.insertBefore(this.dom, el.nextSibling);
9379 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9380 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9381 * @return {Roo.Element} The new child
9383 insertFirst: function(el, returnDom){
9385 if(typeof el == 'object' && !el.nodeType){ // dh config
9386 return this.createChild(el, this.dom.firstChild, returnDom);
9388 el = Roo.getDom(el);
9389 this.dom.insertBefore(el, this.dom.firstChild);
9390 return !returnDom ? Roo.get(el) : el;
9395 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9396 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9397 * @param {String} where (optional) 'before' or 'after' defaults to before
9398 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9399 * @return {Roo.Element} the inserted Element
9401 insertSibling: function(el, where, returnDom){
9402 where = where ? where.toLowerCase() : 'before';
9404 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9406 if(typeof el == 'object' && !el.nodeType){ // dh config
9407 if(where == 'after' && !this.dom.nextSibling){
9408 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9410 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9414 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9415 where == 'before' ? this.dom : this.dom.nextSibling);
9424 * Creates and wraps this element with another element
9425 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9426 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9427 * @return {HTMLElement/Element} The newly created wrapper element
9429 wrap: function(config, returnDom){
9431 config = {tag: "div"};
9433 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9434 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9439 * Replaces the passed element with this element
9440 * @param {String/HTMLElement/Element} el The element to replace
9441 * @return {Roo.Element} this
9443 replace: function(el){
9445 this.insertBefore(el);
9451 * Inserts an html fragment into this element
9452 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9453 * @param {String} html The HTML fragment
9454 * @param {Boolean} returnEl True to return an Roo.Element
9455 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9457 insertHtml : function(where, html, returnEl){
9458 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9459 return returnEl ? Roo.get(el) : el;
9463 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9464 * @param {Object} o The object with the attributes
9465 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9466 * @return {Roo.Element} this
9468 set : function(o, useSet){
9470 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9472 if(attr == "style" || typeof o[attr] == "function") { continue; }
9474 el.className = o["cls"];
9477 el.setAttribute(attr, o[attr]);
9484 Roo.DomHelper.applyStyles(el, o.style);
9490 * Convenience method for constructing a KeyMap
9491 * @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:
9492 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9493 * @param {Function} fn The function to call
9494 * @param {Object} scope (optional) The scope of the function
9495 * @return {Roo.KeyMap} The KeyMap created
9497 addKeyListener : function(key, fn, scope){
9499 if(typeof key != "object" || key instanceof Array){
9515 return new Roo.KeyMap(this, config);
9519 * Creates a KeyMap for this element
9520 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9521 * @return {Roo.KeyMap} The KeyMap created
9523 addKeyMap : function(config){
9524 return new Roo.KeyMap(this, config);
9528 * Returns true if this element is scrollable.
9531 isScrollable : function(){
9533 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9537 * 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().
9538 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9539 * @param {Number} value The new scroll value
9540 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9541 * @return {Element} this
9544 scrollTo : function(side, value, animate){
9545 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9547 this.dom[prop] = value;
9549 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9550 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9556 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9557 * within this element's scrollable range.
9558 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9559 * @param {Number} distance How far to scroll the element in pixels
9560 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9561 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9562 * was scrolled as far as it could go.
9564 scroll : function(direction, distance, animate){
9565 if(!this.isScrollable()){
9569 var l = el.scrollLeft, t = el.scrollTop;
9570 var w = el.scrollWidth, h = el.scrollHeight;
9571 var cw = el.clientWidth, ch = el.clientHeight;
9572 direction = direction.toLowerCase();
9573 var scrolled = false;
9574 var a = this.preanim(arguments, 2);
9579 var v = Math.min(l + distance, w-cw);
9580 this.scrollTo("left", v, a);
9587 var v = Math.max(l - distance, 0);
9588 this.scrollTo("left", v, a);
9596 var v = Math.max(t - distance, 0);
9597 this.scrollTo("top", v, a);
9605 var v = Math.min(t + distance, h-ch);
9606 this.scrollTo("top", v, a);
9615 * Translates the passed page coordinates into left/top css values for this element
9616 * @param {Number/Array} x The page x or an array containing [x, y]
9617 * @param {Number} y The page y
9618 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9620 translatePoints : function(x, y){
9621 if(typeof x == 'object' || x instanceof Array){
9624 var p = this.getStyle('position');
9625 var o = this.getXY();
9627 var l = parseInt(this.getStyle('left'), 10);
9628 var t = parseInt(this.getStyle('top'), 10);
9631 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9634 t = (p == "relative") ? 0 : this.dom.offsetTop;
9637 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9641 * Returns the current scroll position of the element.
9642 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9644 getScroll : function(){
9645 var d = this.dom, doc = document;
9646 if(d == doc || d == doc.body){
9647 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9648 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9649 return {left: l, top: t};
9651 return {left: d.scrollLeft, top: d.scrollTop};
9656 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9657 * are convert to standard 6 digit hex color.
9658 * @param {String} attr The css attribute
9659 * @param {String} defaultValue The default value to use when a valid color isn't found
9660 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9663 getColor : function(attr, defaultValue, prefix){
9664 var v = this.getStyle(attr);
9665 if(!v || v == "transparent" || v == "inherit") {
9666 return defaultValue;
9668 var color = typeof prefix == "undefined" ? "#" : prefix;
9669 if(v.substr(0, 4) == "rgb("){
9670 var rvs = v.slice(4, v.length -1).split(",");
9671 for(var i = 0; i < 3; i++){
9672 var h = parseInt(rvs[i]).toString(16);
9679 if(v.substr(0, 1) == "#"){
9681 for(var i = 1; i < 4; i++){
9682 var c = v.charAt(i);
9685 }else if(v.length == 7){
9686 color += v.substr(1);
9690 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9694 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9695 * gradient background, rounded corners and a 4-way shadow.
9696 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9697 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9698 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9699 * @return {Roo.Element} this
9701 boxWrap : function(cls){
9702 cls = cls || 'x-box';
9703 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9704 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9709 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9710 * @param {String} namespace The namespace in which to look for the attribute
9711 * @param {String} name The attribute name
9712 * @return {String} The attribute value
9714 getAttributeNS : Roo.isIE ? function(ns, name){
9716 var type = typeof d[ns+":"+name];
9717 if(type != 'undefined' && type != 'unknown'){
9718 return d[ns+":"+name];
9721 } : function(ns, name){
9723 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9728 * Sets or Returns the value the dom attribute value
9729 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9730 * @param {String} value (optional) The value to set the attribute to
9731 * @return {String} The attribute value
9733 attr : function(name){
9734 if (arguments.length > 1) {
9735 this.dom.setAttribute(name, arguments[1]);
9736 return arguments[1];
9738 if (typeof(name) == 'object') {
9739 for(var i in name) {
9740 this.attr(i, name[i]);
9746 if (!this.dom.hasAttribute(name)) {
9749 return this.dom.getAttribute(name);
9756 var ep = El.prototype;
9759 * Appends an event handler (Shorthand for addListener)
9760 * @param {String} eventName The type of event to append
9761 * @param {Function} fn The method the event invokes
9762 * @param {Object} scope (optional) The scope (this object) of the fn
9763 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9766 ep.on = ep.addListener;
9768 ep.mon = ep.addListener;
9771 * Removes an event handler from this element (shorthand for removeListener)
9772 * @param {String} eventName the type of event to remove
9773 * @param {Function} fn the method the event invokes
9774 * @return {Roo.Element} this
9777 ep.un = ep.removeListener;
9780 * true to automatically adjust width and height settings for box-model issues (default to true)
9782 ep.autoBoxAdjust = true;
9785 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9788 El.addUnits = function(v, defaultUnit){
9789 if(v === "" || v == "auto"){
9792 if(v === undefined){
9795 if(typeof v == "number" || !El.unitPattern.test(v)){
9796 return v + (defaultUnit || 'px');
9801 // special markup used throughout Roo when box wrapping elements
9802 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>';
9804 * Visibility mode constant - Use visibility to hide element
9810 * Visibility mode constant - Use display to hide element
9816 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9817 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9818 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9830 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9831 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9832 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9833 * @return {Element} The Element object
9836 El.get = function(el){
9838 if(!el){ return null; }
9839 if(typeof el == "string"){ // element id
9840 if(!(elm = document.getElementById(el))){
9843 if(ex = El.cache[el]){
9846 ex = El.cache[el] = new El(elm);
9849 }else if(el.tagName){ // dom element
9853 if(ex = El.cache[id]){
9856 ex = El.cache[id] = new El(el);
9859 }else if(el instanceof El){
9861 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9862 // catch case where it hasn't been appended
9863 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9866 }else if(el.isComposite){
9868 }else if(el instanceof Array){
9869 return El.select(el);
9870 }else if(el == document){
9871 // create a bogus element object representing the document object
9873 var f = function(){};
9874 f.prototype = El.prototype;
9876 docEl.dom = document;
9884 El.uncache = function(el){
9885 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9887 delete El.cache[a[i].id || a[i]];
9893 // Garbage collection - uncache elements/purge listeners on orphaned elements
9894 // so we don't hold a reference and cause the browser to retain them
9895 El.garbageCollect = function(){
9896 if(!Roo.enableGarbageCollector){
9897 clearInterval(El.collectorThread);
9900 for(var eid in El.cache){
9901 var el = El.cache[eid], d = el.dom;
9902 // -------------------------------------------------------
9903 // Determining what is garbage:
9904 // -------------------------------------------------------
9906 // dom node is null, definitely garbage
9907 // -------------------------------------------------------
9909 // no parentNode == direct orphan, definitely garbage
9910 // -------------------------------------------------------
9911 // !d.offsetParent && !document.getElementById(eid)
9912 // display none elements have no offsetParent so we will
9913 // also try to look it up by it's id. However, check
9914 // offsetParent first so we don't do unneeded lookups.
9915 // This enables collection of elements that are not orphans
9916 // directly, but somewhere up the line they have an orphan
9918 // -------------------------------------------------------
9919 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9920 delete El.cache[eid];
9921 if(d && Roo.enableListenerCollection){
9927 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9931 El.Flyweight = function(dom){
9934 El.Flyweight.prototype = El.prototype;
9936 El._flyweights = {};
9938 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9939 * the dom node can be overwritten by other code.
9940 * @param {String/HTMLElement} el The dom node or id
9941 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9942 * prevent conflicts (e.g. internally Roo uses "_internal")
9944 * @return {Element} The shared Element object
9946 El.fly = function(el, named){
9947 named = named || '_global';
9948 el = Roo.getDom(el);
9952 if(!El._flyweights[named]){
9953 El._flyweights[named] = new El.Flyweight();
9955 El._flyweights[named].dom = el;
9956 return El._flyweights[named];
9960 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9961 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9962 * Shorthand of {@link Roo.Element#get}
9963 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9964 * @return {Element} The Element object
9970 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9971 * the dom node can be overwritten by other code.
9972 * Shorthand of {@link Roo.Element#fly}
9973 * @param {String/HTMLElement} el The dom node or id
9974 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9975 * prevent conflicts (e.g. internally Roo uses "_internal")
9977 * @return {Element} The shared Element object
9983 // speedy lookup for elements never to box adjust
9984 var noBoxAdjust = Roo.isStrict ? {
9987 input:1, select:1, textarea:1
9989 if(Roo.isIE || Roo.isGecko){
9990 noBoxAdjust['button'] = 1;
9994 Roo.EventManager.on(window, 'unload', function(){
9996 delete El._flyweights;
10004 Roo.Element.selectorFunction = Roo.DomQuery.select;
10007 Roo.Element.select = function(selector, unique, root){
10009 if(typeof selector == "string"){
10010 els = Roo.Element.selectorFunction(selector, root);
10011 }else if(selector.length !== undefined){
10014 throw "Invalid selector";
10016 if(unique === true){
10017 return new Roo.CompositeElement(els);
10019 return new Roo.CompositeElementLite(els);
10023 * Selects elements based on the passed CSS selector to enable working on them as 1.
10024 * @param {String/Array} selector The CSS selector or an array of elements
10025 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10026 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10027 * @return {CompositeElementLite/CompositeElement}
10031 Roo.select = Roo.Element.select;
10048 * Ext JS Library 1.1.1
10049 * Copyright(c) 2006-2007, Ext JS, LLC.
10051 * Originally Released Under LGPL - original licence link has changed is not relivant.
10054 * <script type="text/javascript">
10059 //Notifies Element that fx methods are available
10060 Roo.enableFx = true;
10064 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10065 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10066 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10067 * Element effects to work.</p><br/>
10069 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10070 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10071 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10072 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10073 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10074 * expected results and should be done with care.</p><br/>
10076 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10077 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10080 ----- -----------------------------
10081 tl The top left corner
10082 t The center of the top edge
10083 tr The top right corner
10084 l The center of the left edge
10085 r The center of the right edge
10086 bl The bottom left corner
10087 b The center of the bottom edge
10088 br The bottom right corner
10090 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10091 * below are common options that can be passed to any Fx method.</b>
10092 * @cfg {Function} callback A function called when the effect is finished
10093 * @cfg {Object} scope The scope of the effect function
10094 * @cfg {String} easing A valid Easing value for the effect
10095 * @cfg {String} afterCls A css class to apply after the effect
10096 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10097 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10098 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10099 * effects that end with the element being visually hidden, ignored otherwise)
10100 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10101 * a function which returns such a specification that will be applied to the Element after the effect finishes
10102 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10103 * @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
10104 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10108 * Slides the element into view. An anchor point can be optionally passed to set the point of
10109 * origin for the slide effect. This function automatically handles wrapping the element with
10110 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10113 // default: slide the element in from the top
10116 // custom: slide the element in from the right with a 2-second duration
10117 el.slideIn('r', { duration: 2 });
10119 // common config options shown with default values
10125 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10126 * @param {Object} options (optional) Object literal with any of the Fx config options
10127 * @return {Roo.Element} The Element
10129 slideIn : function(anchor, o){
10130 var el = this.getFxEl();
10133 el.queueFx(o, function(){
10135 anchor = anchor || "t";
10137 // fix display to visibility
10140 // restore values after effect
10141 var r = this.getFxRestore();
10142 var b = this.getBox();
10143 // fixed size for slide
10147 var wrap = this.fxWrap(r.pos, o, "hidden");
10149 var st = this.dom.style;
10150 st.visibility = "visible";
10151 st.position = "absolute";
10153 // clear out temp styles after slide and unwrap
10154 var after = function(){
10155 el.fxUnwrap(wrap, r.pos, o);
10156 st.width = r.width;
10157 st.height = r.height;
10160 // time to calc the positions
10161 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10163 switch(anchor.toLowerCase()){
10165 wrap.setSize(b.width, 0);
10166 st.left = st.bottom = "0";
10170 wrap.setSize(0, b.height);
10171 st.right = st.top = "0";
10175 wrap.setSize(0, b.height);
10176 wrap.setX(b.right);
10177 st.left = st.top = "0";
10178 a = {width: bw, points: pt};
10181 wrap.setSize(b.width, 0);
10182 wrap.setY(b.bottom);
10183 st.left = st.top = "0";
10184 a = {height: bh, points: pt};
10187 wrap.setSize(0, 0);
10188 st.right = st.bottom = "0";
10189 a = {width: bw, height: bh};
10192 wrap.setSize(0, 0);
10193 wrap.setY(b.y+b.height);
10194 st.right = st.top = "0";
10195 a = {width: bw, height: bh, points: pt};
10198 wrap.setSize(0, 0);
10199 wrap.setXY([b.right, b.bottom]);
10200 st.left = st.top = "0";
10201 a = {width: bw, height: bh, points: pt};
10204 wrap.setSize(0, 0);
10205 wrap.setX(b.x+b.width);
10206 st.left = st.bottom = "0";
10207 a = {width: bw, height: bh, points: pt};
10210 this.dom.style.visibility = "visible";
10213 arguments.callee.anim = wrap.fxanim(a,
10223 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10224 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10225 * 'hidden') but block elements will still take up space in the document. The element must be removed
10226 * from the DOM using the 'remove' config option if desired. This function automatically handles
10227 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10230 // default: slide the element out to the top
10233 // custom: slide the element out to the right with a 2-second duration
10234 el.slideOut('r', { duration: 2 });
10236 // common config options shown with default values
10244 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10245 * @param {Object} options (optional) Object literal with any of the Fx config options
10246 * @return {Roo.Element} The Element
10248 slideOut : function(anchor, o){
10249 var el = this.getFxEl();
10252 el.queueFx(o, function(){
10254 anchor = anchor || "t";
10256 // restore values after effect
10257 var r = this.getFxRestore();
10259 var b = this.getBox();
10260 // fixed size for slide
10264 var wrap = this.fxWrap(r.pos, o, "visible");
10266 var st = this.dom.style;
10267 st.visibility = "visible";
10268 st.position = "absolute";
10272 var after = function(){
10274 el.setDisplayed(false);
10279 el.fxUnwrap(wrap, r.pos, o);
10281 st.width = r.width;
10282 st.height = r.height;
10287 var a, zero = {to: 0};
10288 switch(anchor.toLowerCase()){
10290 st.left = st.bottom = "0";
10291 a = {height: zero};
10294 st.right = st.top = "0";
10298 st.left = st.top = "0";
10299 a = {width: zero, points: {to:[b.right, b.y]}};
10302 st.left = st.top = "0";
10303 a = {height: zero, points: {to:[b.x, b.bottom]}};
10306 st.right = st.bottom = "0";
10307 a = {width: zero, height: zero};
10310 st.right = st.top = "0";
10311 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10314 st.left = st.top = "0";
10315 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10318 st.left = st.bottom = "0";
10319 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10323 arguments.callee.anim = wrap.fxanim(a,
10333 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10334 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10335 * The element must be removed from the DOM using the 'remove' config option if desired.
10341 // common config options shown with default values
10349 * @param {Object} options (optional) Object literal with any of the Fx config options
10350 * @return {Roo.Element} The Element
10352 puff : function(o){
10353 var el = this.getFxEl();
10356 el.queueFx(o, function(){
10357 this.clearOpacity();
10360 // restore values after effect
10361 var r = this.getFxRestore();
10362 var st = this.dom.style;
10364 var after = function(){
10366 el.setDisplayed(false);
10373 el.setPositioning(r.pos);
10374 st.width = r.width;
10375 st.height = r.height;
10380 var width = this.getWidth();
10381 var height = this.getHeight();
10383 arguments.callee.anim = this.fxanim({
10384 width : {to: this.adjustWidth(width * 2)},
10385 height : {to: this.adjustHeight(height * 2)},
10386 points : {by: [-(width * .5), -(height * .5)]},
10388 fontSize: {to:200, unit: "%"}
10399 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10400 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10401 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10407 // all config options shown with default values
10415 * @param {Object} options (optional) Object literal with any of the Fx config options
10416 * @return {Roo.Element} The Element
10418 switchOff : function(o){
10419 var el = this.getFxEl();
10422 el.queueFx(o, function(){
10423 this.clearOpacity();
10426 // restore values after effect
10427 var r = this.getFxRestore();
10428 var st = this.dom.style;
10430 var after = function(){
10432 el.setDisplayed(false);
10438 el.setPositioning(r.pos);
10439 st.width = r.width;
10440 st.height = r.height;
10445 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10446 this.clearOpacity();
10450 points:{by:[0, this.getHeight() * .5]}
10451 }, o, 'motion', 0.3, 'easeIn', after);
10452 }).defer(100, this);
10459 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10460 * changed using the "attr" config option) and then fading back to the original color. If no original
10461 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10464 // default: highlight background to yellow
10467 // custom: highlight foreground text to blue for 2 seconds
10468 el.highlight("0000ff", { attr: 'color', duration: 2 });
10470 // common config options shown with default values
10471 el.highlight("ffff9c", {
10472 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10473 endColor: (current color) or "ffffff",
10478 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10479 * @param {Object} options (optional) Object literal with any of the Fx config options
10480 * @return {Roo.Element} The Element
10482 highlight : function(color, o){
10483 var el = this.getFxEl();
10486 el.queueFx(o, function(){
10487 color = color || "ffff9c";
10488 attr = o.attr || "backgroundColor";
10490 this.clearOpacity();
10493 var origColor = this.getColor(attr);
10494 var restoreColor = this.dom.style[attr];
10495 endColor = (o.endColor || origColor) || "ffffff";
10497 var after = function(){
10498 el.dom.style[attr] = restoreColor;
10503 a[attr] = {from: color, to: endColor};
10504 arguments.callee.anim = this.fxanim(a,
10514 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10517 // default: a single light blue ripple
10520 // custom: 3 red ripples lasting 3 seconds total
10521 el.frame("ff0000", 3, { duration: 3 });
10523 // common config options shown with default values
10524 el.frame("C3DAF9", 1, {
10525 duration: 1 //duration of entire animation (not each individual ripple)
10526 // Note: Easing is not configurable and will be ignored if included
10529 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10530 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10531 * @param {Object} options (optional) Object literal with any of the Fx config options
10532 * @return {Roo.Element} The Element
10534 frame : function(color, count, o){
10535 var el = this.getFxEl();
10538 el.queueFx(o, function(){
10539 color = color || "#C3DAF9";
10540 if(color.length == 6){
10541 color = "#" + color;
10543 count = count || 1;
10544 duration = o.duration || 1;
10547 var b = this.getBox();
10548 var animFn = function(){
10549 var proxy = this.createProxy({
10552 visbility:"hidden",
10553 position:"absolute",
10554 "z-index":"35000", // yee haw
10555 border:"0px solid " + color
10558 var scale = Roo.isBorderBox ? 2 : 1;
10560 top:{from:b.y, to:b.y - 20},
10561 left:{from:b.x, to:b.x - 20},
10562 borderWidth:{from:0, to:10},
10563 opacity:{from:1, to:0},
10564 height:{from:b.height, to:(b.height + (20*scale))},
10565 width:{from:b.width, to:(b.width + (20*scale))}
10566 }, duration, function(){
10570 animFn.defer((duration/2)*1000, this);
10581 * Creates a pause before any subsequent queued effects begin. If there are
10582 * no effects queued after the pause it will have no effect.
10587 * @param {Number} seconds The length of time to pause (in seconds)
10588 * @return {Roo.Element} The Element
10590 pause : function(seconds){
10591 var el = this.getFxEl();
10594 el.queueFx(o, function(){
10595 setTimeout(function(){
10597 }, seconds * 1000);
10603 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10604 * using the "endOpacity" config option.
10607 // default: fade in from opacity 0 to 100%
10610 // custom: fade in from opacity 0 to 75% over 2 seconds
10611 el.fadeIn({ endOpacity: .75, duration: 2});
10613 // common config options shown with default values
10615 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10620 * @param {Object} options (optional) Object literal with any of the Fx config options
10621 * @return {Roo.Element} The Element
10623 fadeIn : function(o){
10624 var el = this.getFxEl();
10626 el.queueFx(o, function(){
10627 this.setOpacity(0);
10629 this.dom.style.visibility = 'visible';
10630 var to = o.endOpacity || 1;
10631 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10632 o, null, .5, "easeOut", function(){
10634 this.clearOpacity();
10643 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10644 * using the "endOpacity" config option.
10647 // default: fade out from the element's current opacity to 0
10650 // custom: fade out from the element's current opacity to 25% over 2 seconds
10651 el.fadeOut({ endOpacity: .25, duration: 2});
10653 // common config options shown with default values
10655 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10662 * @param {Object} options (optional) Object literal with any of the Fx config options
10663 * @return {Roo.Element} The Element
10665 fadeOut : function(o){
10666 var el = this.getFxEl();
10668 el.queueFx(o, function(){
10669 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10670 o, null, .5, "easeOut", function(){
10671 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10672 this.dom.style.display = "none";
10674 this.dom.style.visibility = "hidden";
10676 this.clearOpacity();
10684 * Animates the transition of an element's dimensions from a starting height/width
10685 * to an ending height/width.
10688 // change height and width to 100x100 pixels
10689 el.scale(100, 100);
10691 // common config options shown with default values. The height and width will default to
10692 // the element's existing values if passed as null.
10695 [element's height], {
10700 * @param {Number} width The new width (pass undefined to keep the original width)
10701 * @param {Number} height The new height (pass undefined to keep the original height)
10702 * @param {Object} options (optional) Object literal with any of the Fx config options
10703 * @return {Roo.Element} The Element
10705 scale : function(w, h, o){
10706 this.shift(Roo.apply({}, o, {
10714 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10715 * Any of these properties not specified in the config object will not be changed. This effect
10716 * requires that at least one new dimension, position or opacity setting must be passed in on
10717 * the config object in order for the function to have any effect.
10720 // slide the element horizontally to x position 200 while changing the height and opacity
10721 el.shift({ x: 200, height: 50, opacity: .8 });
10723 // common config options shown with default values.
10725 width: [element's width],
10726 height: [element's height],
10727 x: [element's x position],
10728 y: [element's y position],
10729 opacity: [element's opacity],
10734 * @param {Object} options Object literal with any of the Fx config options
10735 * @return {Roo.Element} The Element
10737 shift : function(o){
10738 var el = this.getFxEl();
10740 el.queueFx(o, function(){
10741 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10742 if(w !== undefined){
10743 a.width = {to: this.adjustWidth(w)};
10745 if(h !== undefined){
10746 a.height = {to: this.adjustHeight(h)};
10748 if(x !== undefined || y !== undefined){
10750 x !== undefined ? x : this.getX(),
10751 y !== undefined ? y : this.getY()
10754 if(op !== undefined){
10755 a.opacity = {to: op};
10757 if(o.xy !== undefined){
10758 a.points = {to: o.xy};
10760 arguments.callee.anim = this.fxanim(a,
10761 o, 'motion', .35, "easeOut", function(){
10769 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10770 * ending point of the effect.
10773 // default: slide the element downward while fading out
10776 // custom: slide the element out to the right with a 2-second duration
10777 el.ghost('r', { duration: 2 });
10779 // common config options shown with default values
10787 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10788 * @param {Object} options (optional) Object literal with any of the Fx config options
10789 * @return {Roo.Element} The Element
10791 ghost : function(anchor, o){
10792 var el = this.getFxEl();
10795 el.queueFx(o, function(){
10796 anchor = anchor || "b";
10798 // restore values after effect
10799 var r = this.getFxRestore();
10800 var w = this.getWidth(),
10801 h = this.getHeight();
10803 var st = this.dom.style;
10805 var after = function(){
10807 el.setDisplayed(false);
10813 el.setPositioning(r.pos);
10814 st.width = r.width;
10815 st.height = r.height;
10820 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10821 switch(anchor.toLowerCase()){
10848 arguments.callee.anim = this.fxanim(a,
10858 * Ensures that all effects queued after syncFx is called on the element are
10859 * run concurrently. This is the opposite of {@link #sequenceFx}.
10860 * @return {Roo.Element} The Element
10862 syncFx : function(){
10863 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10872 * Ensures that all effects queued after sequenceFx is called on the element are
10873 * run in sequence. This is the opposite of {@link #syncFx}.
10874 * @return {Roo.Element} The Element
10876 sequenceFx : function(){
10877 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10879 concurrent : false,
10886 nextFx : function(){
10887 var ef = this.fxQueue[0];
10894 * Returns true if the element has any effects actively running or queued, else returns false.
10895 * @return {Boolean} True if element has active effects, else false
10897 hasActiveFx : function(){
10898 return this.fxQueue && this.fxQueue[0];
10902 * Stops any running effects and clears the element's internal effects queue if it contains
10903 * any additional effects that haven't started yet.
10904 * @return {Roo.Element} The Element
10906 stopFx : function(){
10907 if(this.hasActiveFx()){
10908 var cur = this.fxQueue[0];
10909 if(cur && cur.anim && cur.anim.isAnimated()){
10910 this.fxQueue = [cur]; // clear out others
10911 cur.anim.stop(true);
10918 beforeFx : function(o){
10919 if(this.hasActiveFx() && !o.concurrent){
10930 * Returns true if the element is currently blocking so that no other effect can be queued
10931 * until this effect is finished, else returns false if blocking is not set. This is commonly
10932 * used to ensure that an effect initiated by a user action runs to completion prior to the
10933 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10934 * @return {Boolean} True if blocking, else false
10936 hasFxBlock : function(){
10937 var q = this.fxQueue;
10938 return q && q[0] && q[0].block;
10942 queueFx : function(o, fn){
10946 if(!this.hasFxBlock()){
10947 Roo.applyIf(o, this.fxDefaults);
10949 var run = this.beforeFx(o);
10950 fn.block = o.block;
10951 this.fxQueue.push(fn);
10963 fxWrap : function(pos, o, vis){
10965 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10968 wrapXY = this.getXY();
10970 var div = document.createElement("div");
10971 div.style.visibility = vis;
10972 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10973 wrap.setPositioning(pos);
10974 if(wrap.getStyle("position") == "static"){
10975 wrap.position("relative");
10977 this.clearPositioning('auto');
10979 wrap.dom.appendChild(this.dom);
10981 wrap.setXY(wrapXY);
10988 fxUnwrap : function(wrap, pos, o){
10989 this.clearPositioning();
10990 this.setPositioning(pos);
10992 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10998 getFxRestore : function(){
10999 var st = this.dom.style;
11000 return {pos: this.getPositioning(), width: st.width, height : st.height};
11004 afterFx : function(o){
11006 this.applyStyles(o.afterStyle);
11009 this.addClass(o.afterCls);
11011 if(o.remove === true){
11014 Roo.callback(o.callback, o.scope, [this]);
11016 this.fxQueue.shift();
11022 getFxEl : function(){ // support for composite element fx
11023 return Roo.get(this.dom);
11027 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11028 animType = animType || 'run';
11030 var anim = Roo.lib.Anim[animType](
11032 (opt.duration || defaultDur) || .35,
11033 (opt.easing || defaultEase) || 'easeOut',
11035 Roo.callback(cb, this);
11044 // backwords compat
11045 Roo.Fx.resize = Roo.Fx.scale;
11047 //When included, Roo.Fx is automatically applied to Element so that all basic
11048 //effects are available directly via the Element API
11049 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11051 * Ext JS Library 1.1.1
11052 * Copyright(c) 2006-2007, Ext JS, LLC.
11054 * Originally Released Under LGPL - original licence link has changed is not relivant.
11057 * <script type="text/javascript">
11062 * @class Roo.CompositeElement
11063 * Standard composite class. Creates a Roo.Element for every element in the collection.
11065 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11066 * actions will be performed on all the elements in this collection.</b>
11068 * All methods return <i>this</i> and can be chained.
11070 var els = Roo.select("#some-el div.some-class", true);
11071 // or select directly from an existing element
11072 var el = Roo.get('some-el');
11073 el.select('div.some-class', true);
11075 els.setWidth(100); // all elements become 100 width
11076 els.hide(true); // all elements fade out and hide
11078 els.setWidth(100).hide(true);
11081 Roo.CompositeElement = function(els){
11082 this.elements = [];
11083 this.addElements(els);
11085 Roo.CompositeElement.prototype = {
11087 addElements : function(els){
11091 if(typeof els == "string"){
11092 els = Roo.Element.selectorFunction(els);
11094 var yels = this.elements;
11095 var index = yels.length-1;
11096 for(var i = 0, len = els.length; i < len; i++) {
11097 yels[++index] = Roo.get(els[i]);
11103 * Clears this composite and adds the elements returned by the passed selector.
11104 * @param {String/Array} els A string CSS selector, an array of elements or an element
11105 * @return {CompositeElement} this
11107 fill : function(els){
11108 this.elements = [];
11114 * Filters this composite to only elements that match the passed selector.
11115 * @param {String} selector A string CSS selector
11116 * @param {Boolean} inverse return inverse filter (not matches)
11117 * @return {CompositeElement} this
11119 filter : function(selector, inverse){
11121 inverse = inverse || false;
11122 this.each(function(el){
11123 var match = inverse ? !el.is(selector) : el.is(selector);
11125 els[els.length] = el.dom;
11132 invoke : function(fn, args){
11133 var els = this.elements;
11134 for(var i = 0, len = els.length; i < len; i++) {
11135 Roo.Element.prototype[fn].apply(els[i], args);
11140 * Adds elements to this composite.
11141 * @param {String/Array} els A string CSS selector, an array of elements or an element
11142 * @return {CompositeElement} this
11144 add : function(els){
11145 if(typeof els == "string"){
11146 this.addElements(Roo.Element.selectorFunction(els));
11147 }else if(els.length !== undefined){
11148 this.addElements(els);
11150 this.addElements([els]);
11155 * Calls the passed function passing (el, this, index) for each element in this composite.
11156 * @param {Function} fn The function to call
11157 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11158 * @return {CompositeElement} this
11160 each : function(fn, scope){
11161 var els = this.elements;
11162 for(var i = 0, len = els.length; i < len; i++){
11163 if(fn.call(scope || els[i], els[i], this, i) === false) {
11171 * Returns the Element object at the specified index
11172 * @param {Number} index
11173 * @return {Roo.Element}
11175 item : function(index){
11176 return this.elements[index] || null;
11180 * Returns the first Element
11181 * @return {Roo.Element}
11183 first : function(){
11184 return this.item(0);
11188 * Returns the last Element
11189 * @return {Roo.Element}
11192 return this.item(this.elements.length-1);
11196 * Returns the number of elements in this composite
11199 getCount : function(){
11200 return this.elements.length;
11204 * Returns true if this composite contains the passed element
11207 contains : function(el){
11208 return this.indexOf(el) !== -1;
11212 * Returns true if this composite contains the passed element
11215 indexOf : function(el){
11216 return this.elements.indexOf(Roo.get(el));
11221 * Removes the specified element(s).
11222 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11223 * or an array of any of those.
11224 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11225 * @return {CompositeElement} this
11227 removeElement : function(el, removeDom){
11228 if(el instanceof Array){
11229 for(var i = 0, len = el.length; i < len; i++){
11230 this.removeElement(el[i]);
11234 var index = typeof el == 'number' ? el : this.indexOf(el);
11237 var d = this.elements[index];
11241 d.parentNode.removeChild(d);
11244 this.elements.splice(index, 1);
11250 * Replaces the specified element with the passed element.
11251 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11253 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11254 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11255 * @return {CompositeElement} this
11257 replaceElement : function(el, replacement, domReplace){
11258 var index = typeof el == 'number' ? el : this.indexOf(el);
11261 this.elements[index].replaceWith(replacement);
11263 this.elements.splice(index, 1, Roo.get(replacement))
11270 * Removes all elements.
11272 clear : function(){
11273 this.elements = [];
11277 Roo.CompositeElement.createCall = function(proto, fnName){
11278 if(!proto[fnName]){
11279 proto[fnName] = function(){
11280 return this.invoke(fnName, arguments);
11284 for(var fnName in Roo.Element.prototype){
11285 if(typeof Roo.Element.prototype[fnName] == "function"){
11286 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11292 * Ext JS Library 1.1.1
11293 * Copyright(c) 2006-2007, Ext JS, LLC.
11295 * Originally Released Under LGPL - original licence link has changed is not relivant.
11298 * <script type="text/javascript">
11302 * @class Roo.CompositeElementLite
11303 * @extends Roo.CompositeElement
11304 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11306 var els = Roo.select("#some-el div.some-class");
11307 // or select directly from an existing element
11308 var el = Roo.get('some-el');
11309 el.select('div.some-class');
11311 els.setWidth(100); // all elements become 100 width
11312 els.hide(true); // all elements fade out and hide
11314 els.setWidth(100).hide(true);
11315 </code></pre><br><br>
11316 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11317 * actions will be performed on all the elements in this collection.</b>
11319 Roo.CompositeElementLite = function(els){
11320 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11321 this.el = new Roo.Element.Flyweight();
11323 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11324 addElements : function(els){
11326 if(els instanceof Array){
11327 this.elements = this.elements.concat(els);
11329 var yels = this.elements;
11330 var index = yels.length-1;
11331 for(var i = 0, len = els.length; i < len; i++) {
11332 yels[++index] = els[i];
11338 invoke : function(fn, args){
11339 var els = this.elements;
11341 for(var i = 0, len = els.length; i < len; i++) {
11343 Roo.Element.prototype[fn].apply(el, args);
11348 * Returns a flyweight Element of the dom element object at the specified index
11349 * @param {Number} index
11350 * @return {Roo.Element}
11352 item : function(index){
11353 if(!this.elements[index]){
11356 this.el.dom = this.elements[index];
11360 // fixes scope with flyweight
11361 addListener : function(eventName, handler, scope, opt){
11362 var els = this.elements;
11363 for(var i = 0, len = els.length; i < len; i++) {
11364 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11370 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11371 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11372 * a reference to the dom node, use el.dom.</b>
11373 * @param {Function} fn The function to call
11374 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11375 * @return {CompositeElement} this
11377 each : function(fn, scope){
11378 var els = this.elements;
11380 for(var i = 0, len = els.length; i < len; i++){
11382 if(fn.call(scope || el, el, this, i) === false){
11389 indexOf : function(el){
11390 return this.elements.indexOf(Roo.getDom(el));
11393 replaceElement : function(el, replacement, domReplace){
11394 var index = typeof el == 'number' ? el : this.indexOf(el);
11396 replacement = Roo.getDom(replacement);
11398 var d = this.elements[index];
11399 d.parentNode.insertBefore(replacement, d);
11400 d.parentNode.removeChild(d);
11402 this.elements.splice(index, 1, replacement);
11407 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11411 * Ext JS Library 1.1.1
11412 * Copyright(c) 2006-2007, Ext JS, LLC.
11414 * Originally Released Under LGPL - original licence link has changed is not relivant.
11417 * <script type="text/javascript">
11423 * @class Roo.data.Connection
11424 * @extends Roo.util.Observable
11425 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11426 * either to a configured URL, or to a URL specified at request time.<br><br>
11428 * Requests made by this class are asynchronous, and will return immediately. No data from
11429 * the server will be available to the statement immediately following the {@link #request} call.
11430 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11432 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11433 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11434 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11435 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11436 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11437 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11438 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11439 * standard DOM methods.
11441 * @param {Object} config a configuration object.
11443 Roo.data.Connection = function(config){
11444 Roo.apply(this, config);
11447 * @event beforerequest
11448 * Fires before a network request is made to retrieve a data object.
11449 * @param {Connection} conn This Connection object.
11450 * @param {Object} options The options config object passed to the {@link #request} method.
11452 "beforerequest" : true,
11454 * @event requestcomplete
11455 * Fires if the request was successfully completed.
11456 * @param {Connection} conn This Connection object.
11457 * @param {Object} response The XHR object containing the response data.
11458 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11459 * @param {Object} options The options config object passed to the {@link #request} method.
11461 "requestcomplete" : true,
11463 * @event requestexception
11464 * Fires if an error HTTP status was returned from the server.
11465 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11466 * @param {Connection} conn This Connection object.
11467 * @param {Object} response The XHR object containing the response data.
11468 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11469 * @param {Object} options The options config object passed to the {@link #request} method.
11471 "requestexception" : true
11473 Roo.data.Connection.superclass.constructor.call(this);
11476 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11478 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11481 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11482 * extra parameters to each request made by this object. (defaults to undefined)
11485 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11486 * to each request made by this object. (defaults to undefined)
11489 * @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)
11492 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11496 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11502 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11505 disableCaching: true,
11508 * Sends an HTTP request to a remote server.
11509 * @param {Object} options An object which may contain the following properties:<ul>
11510 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11511 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11512 * request, a url encoded string or a function to call to get either.</li>
11513 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11514 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11515 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11516 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11517 * <li>options {Object} The parameter to the request call.</li>
11518 * <li>success {Boolean} True if the request succeeded.</li>
11519 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11521 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11522 * The callback is passed the following parameters:<ul>
11523 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11524 * <li>options {Object} The parameter to the request call.</li>
11526 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11527 * The callback is passed the following parameters:<ul>
11528 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11529 * <li>options {Object} The parameter to the request call.</li>
11531 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11532 * for the callback function. Defaults to the browser window.</li>
11533 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11534 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11535 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11536 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11537 * params for the post data. Any params will be appended to the URL.</li>
11538 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11540 * @return {Number} transactionId
11542 request : function(o){
11543 if(this.fireEvent("beforerequest", this, o) !== false){
11546 if(typeof p == "function"){
11547 p = p.call(o.scope||window, o);
11549 if(typeof p == "object"){
11550 p = Roo.urlEncode(o.params);
11552 if(this.extraParams){
11553 var extras = Roo.urlEncode(this.extraParams);
11554 p = p ? (p + '&' + extras) : extras;
11557 var url = o.url || this.url;
11558 if(typeof url == 'function'){
11559 url = url.call(o.scope||window, o);
11563 var form = Roo.getDom(o.form);
11564 url = url || form.action;
11566 var enctype = form.getAttribute("enctype");
11567 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11568 return this.doFormUpload(o, p, url);
11570 var f = Roo.lib.Ajax.serializeForm(form);
11571 p = p ? (p + '&' + f) : f;
11574 var hs = o.headers;
11575 if(this.defaultHeaders){
11576 hs = Roo.apply(hs || {}, this.defaultHeaders);
11583 success: this.handleResponse,
11584 failure: this.handleFailure,
11586 argument: {options: o},
11587 timeout : o.timeout || this.timeout
11590 var method = o.method||this.method||(p ? "POST" : "GET");
11592 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11593 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11596 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11600 }else if(this.autoAbort !== false){
11604 if((method == 'GET' && p) || o.xmlData){
11605 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11608 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11609 return this.transId;
11611 Roo.callback(o.callback, o.scope, [o, null, null]);
11617 * Determine whether this object has a request outstanding.
11618 * @param {Number} transactionId (Optional) defaults to the last transaction
11619 * @return {Boolean} True if there is an outstanding request.
11621 isLoading : function(transId){
11623 return Roo.lib.Ajax.isCallInProgress(transId);
11625 return this.transId ? true : false;
11630 * Aborts any outstanding request.
11631 * @param {Number} transactionId (Optional) defaults to the last transaction
11633 abort : function(transId){
11634 if(transId || this.isLoading()){
11635 Roo.lib.Ajax.abort(transId || this.transId);
11640 handleResponse : function(response){
11641 this.transId = false;
11642 var options = response.argument.options;
11643 response.argument = options ? options.argument : null;
11644 this.fireEvent("requestcomplete", this, response, options);
11645 Roo.callback(options.success, options.scope, [response, options]);
11646 Roo.callback(options.callback, options.scope, [options, true, response]);
11650 handleFailure : function(response, e){
11651 this.transId = false;
11652 var options = response.argument.options;
11653 response.argument = options ? options.argument : null;
11654 this.fireEvent("requestexception", this, response, options, e);
11655 Roo.callback(options.failure, options.scope, [response, options]);
11656 Roo.callback(options.callback, options.scope, [options, false, response]);
11660 doFormUpload : function(o, ps, url){
11662 var frame = document.createElement('iframe');
11665 frame.className = 'x-hidden';
11667 frame.src = Roo.SSL_SECURE_URL;
11669 document.body.appendChild(frame);
11672 document.frames[id].name = id;
11675 var form = Roo.getDom(o.form);
11677 form.method = 'POST';
11678 form.enctype = form.encoding = 'multipart/form-data';
11684 if(ps){ // add dynamic params
11686 ps = Roo.urlDecode(ps, false);
11688 if(ps.hasOwnProperty(k)){
11689 hd = document.createElement('input');
11690 hd.type = 'hidden';
11693 form.appendChild(hd);
11700 var r = { // bogus response object
11705 r.argument = o ? o.argument : null;
11710 doc = frame.contentWindow.document;
11712 doc = (frame.contentDocument || window.frames[id].document);
11714 if(doc && doc.body){
11715 r.responseText = doc.body.innerHTML;
11717 if(doc && doc.XMLDocument){
11718 r.responseXML = doc.XMLDocument;
11720 r.responseXML = doc;
11727 Roo.EventManager.removeListener(frame, 'load', cb, this);
11729 this.fireEvent("requestcomplete", this, r, o);
11730 Roo.callback(o.success, o.scope, [r, o]);
11731 Roo.callback(o.callback, o.scope, [o, true, r]);
11733 setTimeout(function(){document.body.removeChild(frame);}, 100);
11736 Roo.EventManager.on(frame, 'load', cb, this);
11739 if(hiddens){ // remove dynamic params
11740 for(var i = 0, len = hiddens.length; i < len; i++){
11741 form.removeChild(hiddens[i]);
11748 * Ext JS Library 1.1.1
11749 * Copyright(c) 2006-2007, Ext JS, LLC.
11751 * Originally Released Under LGPL - original licence link has changed is not relivant.
11754 * <script type="text/javascript">
11758 * Global Ajax request class.
11761 * @extends Roo.data.Connection
11764 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11765 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11766 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11767 * @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)
11768 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11769 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11770 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11772 Roo.Ajax = new Roo.data.Connection({
11781 * Serialize the passed form into a url encoded string
11783 * @param {String/HTMLElement} form
11786 serializeForm : function(form){
11787 return Roo.lib.Ajax.serializeForm(form);
11791 * Ext JS Library 1.1.1
11792 * Copyright(c) 2006-2007, Ext JS, LLC.
11794 * Originally Released Under LGPL - original licence link has changed is not relivant.
11797 * <script type="text/javascript">
11802 * @class Roo.UpdateManager
11803 * @extends Roo.util.Observable
11804 * Provides AJAX-style update for Element object.<br><br>
11807 * // Get it from a Roo.Element object
11808 * var el = Roo.get("foo");
11809 * var mgr = el.getUpdateManager();
11810 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11812 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11814 * // or directly (returns the same UpdateManager instance)
11815 * var mgr = new Roo.UpdateManager("myElementId");
11816 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11817 * mgr.on("update", myFcnNeedsToKnow);
11819 // short handed call directly from the element object
11820 Roo.get("foo").load({
11824 text: "Loading Foo..."
11828 * Create new UpdateManager directly.
11829 * @param {String/HTMLElement/Roo.Element} el The element to update
11830 * @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).
11832 Roo.UpdateManager = function(el, forceNew){
11834 if(!forceNew && el.updateManager){
11835 return el.updateManager;
11838 * The Element object
11839 * @type Roo.Element
11843 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11846 this.defaultUrl = null;
11850 * @event beforeupdate
11851 * Fired before an update is made, return false from your handler and the update is cancelled.
11852 * @param {Roo.Element} el
11853 * @param {String/Object/Function} url
11854 * @param {String/Object} params
11856 "beforeupdate": true,
11859 * Fired after successful update is made.
11860 * @param {Roo.Element} el
11861 * @param {Object} oResponseObject The response Object
11866 * Fired on update failure.
11867 * @param {Roo.Element} el
11868 * @param {Object} oResponseObject The response Object
11872 var d = Roo.UpdateManager.defaults;
11874 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11877 this.sslBlankUrl = d.sslBlankUrl;
11879 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11882 this.disableCaching = d.disableCaching;
11884 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11887 this.indicatorText = d.indicatorText;
11889 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11892 this.showLoadIndicator = d.showLoadIndicator;
11894 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11897 this.timeout = d.timeout;
11900 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11903 this.loadScripts = d.loadScripts;
11906 * Transaction object of current executing transaction
11908 this.transaction = null;
11913 this.autoRefreshProcId = null;
11915 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11918 this.refreshDelegate = this.refresh.createDelegate(this);
11920 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11923 this.updateDelegate = this.update.createDelegate(this);
11925 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11928 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11932 this.successDelegate = this.processSuccess.createDelegate(this);
11936 this.failureDelegate = this.processFailure.createDelegate(this);
11938 if(!this.renderer){
11940 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11942 this.renderer = new Roo.UpdateManager.BasicRenderer();
11945 Roo.UpdateManager.superclass.constructor.call(this);
11948 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11950 * Get the Element this UpdateManager is bound to
11951 * @return {Roo.Element} The element
11953 getEl : function(){
11957 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11958 * @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:
11961 url: "your-url.php",<br/>
11962 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11963 callback: yourFunction,<br/>
11964 scope: yourObject, //(optional scope) <br/>
11965 discardUrl: false, <br/>
11966 nocache: false,<br/>
11967 text: "Loading...",<br/>
11969 scripts: false<br/>
11972 * The only required property is url. The optional properties nocache, text and scripts
11973 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11974 * @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}
11975 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11976 * @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.
11978 update : function(url, params, callback, discardUrl){
11979 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11980 var method = this.method,
11982 if(typeof url == "object"){ // must be config object
11985 params = params || cfg.params;
11986 callback = callback || cfg.callback;
11987 discardUrl = discardUrl || cfg.discardUrl;
11988 if(callback && cfg.scope){
11989 callback = callback.createDelegate(cfg.scope);
11991 if(typeof cfg.method != "undefined"){method = cfg.method;};
11992 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11993 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11994 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11995 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11997 this.showLoading();
11999 this.defaultUrl = url;
12001 if(typeof url == "function"){
12002 url = url.call(this);
12005 method = method || (params ? "POST" : "GET");
12006 if(method == "GET"){
12007 url = this.prepareUrl(url);
12010 var o = Roo.apply(cfg ||{}, {
12013 success: this.successDelegate,
12014 failure: this.failureDelegate,
12015 callback: undefined,
12016 timeout: (this.timeout*1000),
12017 argument: {"url": url, "form": null, "callback": callback, "params": params}
12019 Roo.log("updated manager called with timeout of " + o.timeout);
12020 this.transaction = Roo.Ajax.request(o);
12025 * 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.
12026 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12027 * @param {String/HTMLElement} form The form Id or form element
12028 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12029 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12030 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12032 formUpdate : function(form, url, reset, callback){
12033 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12034 if(typeof url == "function"){
12035 url = url.call(this);
12037 form = Roo.getDom(form);
12038 this.transaction = Roo.Ajax.request({
12041 success: this.successDelegate,
12042 failure: this.failureDelegate,
12043 timeout: (this.timeout*1000),
12044 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12046 this.showLoading.defer(1, this);
12051 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12052 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12054 refresh : function(callback){
12055 if(this.defaultUrl == null){
12058 this.update(this.defaultUrl, null, callback, true);
12062 * Set this element to auto refresh.
12063 * @param {Number} interval How often to update (in seconds).
12064 * @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)
12065 * @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}
12066 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12067 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12069 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12071 this.update(url || this.defaultUrl, params, callback, true);
12073 if(this.autoRefreshProcId){
12074 clearInterval(this.autoRefreshProcId);
12076 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12080 * Stop auto refresh on this element.
12082 stopAutoRefresh : function(){
12083 if(this.autoRefreshProcId){
12084 clearInterval(this.autoRefreshProcId);
12085 delete this.autoRefreshProcId;
12089 isAutoRefreshing : function(){
12090 return this.autoRefreshProcId ? true : false;
12093 * Called to update the element to "Loading" state. Override to perform custom action.
12095 showLoading : function(){
12096 if(this.showLoadIndicator){
12097 this.el.update(this.indicatorText);
12102 * Adds unique parameter to query string if disableCaching = true
12105 prepareUrl : function(url){
12106 if(this.disableCaching){
12107 var append = "_dc=" + (new Date().getTime());
12108 if(url.indexOf("?") !== -1){
12109 url += "&" + append;
12111 url += "?" + append;
12120 processSuccess : function(response){
12121 this.transaction = null;
12122 if(response.argument.form && response.argument.reset){
12123 try{ // put in try/catch since some older FF releases had problems with this
12124 response.argument.form.reset();
12127 if(this.loadScripts){
12128 this.renderer.render(this.el, response, this,
12129 this.updateComplete.createDelegate(this, [response]));
12131 this.renderer.render(this.el, response, this);
12132 this.updateComplete(response);
12136 updateComplete : function(response){
12137 this.fireEvent("update", this.el, response);
12138 if(typeof response.argument.callback == "function"){
12139 response.argument.callback(this.el, true, response);
12146 processFailure : function(response){
12147 this.transaction = null;
12148 this.fireEvent("failure", this.el, response);
12149 if(typeof response.argument.callback == "function"){
12150 response.argument.callback(this.el, false, response);
12155 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12156 * @param {Object} renderer The object implementing the render() method
12158 setRenderer : function(renderer){
12159 this.renderer = renderer;
12162 getRenderer : function(){
12163 return this.renderer;
12167 * Set the defaultUrl used for updates
12168 * @param {String/Function} defaultUrl The url or a function to call to get the url
12170 setDefaultUrl : function(defaultUrl){
12171 this.defaultUrl = defaultUrl;
12175 * Aborts the executing transaction
12177 abort : function(){
12178 if(this.transaction){
12179 Roo.Ajax.abort(this.transaction);
12184 * Returns true if an update is in progress
12185 * @return {Boolean}
12187 isUpdating : function(){
12188 if(this.transaction){
12189 return Roo.Ajax.isLoading(this.transaction);
12196 * @class Roo.UpdateManager.defaults
12197 * @static (not really - but it helps the doc tool)
12198 * The defaults collection enables customizing the default properties of UpdateManager
12200 Roo.UpdateManager.defaults = {
12202 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12208 * True to process scripts by default (Defaults to false).
12211 loadScripts : false,
12214 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12217 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12219 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12222 disableCaching : false,
12224 * Whether to show indicatorText when loading (Defaults to true).
12227 showLoadIndicator : true,
12229 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12232 indicatorText : '<div class="loading-indicator">Loading...</div>'
12236 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12238 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12239 * @param {String/HTMLElement/Roo.Element} el The element to update
12240 * @param {String} url The url
12241 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12242 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12245 * @member Roo.UpdateManager
12247 Roo.UpdateManager.updateElement = function(el, url, params, options){
12248 var um = Roo.get(el, true).getUpdateManager();
12249 Roo.apply(um, options);
12250 um.update(url, params, options ? options.callback : null);
12252 // alias for backwards compat
12253 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12255 * @class Roo.UpdateManager.BasicRenderer
12256 * Default Content renderer. Updates the elements innerHTML with the responseText.
12258 Roo.UpdateManager.BasicRenderer = function(){};
12260 Roo.UpdateManager.BasicRenderer.prototype = {
12262 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12263 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12264 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12265 * @param {Roo.Element} el The element being rendered
12266 * @param {Object} response The YUI Connect response object
12267 * @param {UpdateManager} updateManager The calling update manager
12268 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12270 render : function(el, response, updateManager, callback){
12271 el.update(response.responseText, updateManager.loadScripts, callback);
12277 * (c)) Alan Knowles
12283 * @class Roo.DomTemplate
12284 * @extends Roo.Template
12285 * An effort at a dom based template engine..
12287 * Similar to XTemplate, except it uses dom parsing to create the template..
12289 * Supported features:
12294 {a_variable} - output encoded.
12295 {a_variable.format:("Y-m-d")} - call a method on the variable
12296 {a_variable:raw} - unencoded output
12297 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12298 {a_variable:this.method_on_template(...)} - call a method on the template object.
12303 <div roo-for="a_variable or condition.."></div>
12304 <div roo-if="a_variable or condition"></div>
12305 <div roo-exec="some javascript"></div>
12306 <div roo-name="named_template"></div>
12311 Roo.DomTemplate = function()
12313 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12320 Roo.extend(Roo.DomTemplate, Roo.Template, {
12322 * id counter for sub templates.
12326 * flag to indicate if dom parser is inside a pre,
12327 * it will strip whitespace if not.
12332 * The various sub templates
12340 * basic tag replacing syntax
12343 * // you can fake an object call by doing this
12347 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12348 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12350 iterChild : function (node, method) {
12352 var oldPre = this.inPre;
12353 if (node.tagName == 'PRE') {
12356 for( var i = 0; i < node.childNodes.length; i++) {
12357 method.call(this, node.childNodes[i]);
12359 this.inPre = oldPre;
12365 * compile the template
12367 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12370 compile: function()
12374 // covert the html into DOM...
12378 doc = document.implementation.createHTMLDocument("");
12379 doc.documentElement.innerHTML = this.html ;
12380 div = doc.documentElement;
12382 // old IE... - nasty -- it causes all sorts of issues.. with
12383 // images getting pulled from server..
12384 div = document.createElement('div');
12385 div.innerHTML = this.html;
12387 //doc.documentElement.innerHTML = htmlBody
12393 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12395 var tpls = this.tpls;
12397 // create a top level template from the snippet..
12399 //Roo.log(div.innerHTML);
12406 body : div.innerHTML,
12419 Roo.each(tpls, function(tp){
12420 this.compileTpl(tp);
12421 this.tpls[tp.id] = tp;
12424 this.master = tpls[0];
12430 compileNode : function(node, istop) {
12435 // skip anything not a tag..
12436 if (node.nodeType != 1) {
12437 if (node.nodeType == 3 && !this.inPre) {
12438 // reduce white space..
12439 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12462 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12463 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12464 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12465 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12471 // just itterate children..
12472 this.iterChild(node,this.compileNode);
12475 tpl.uid = this.id++;
12476 tpl.value = node.getAttribute('roo-' + tpl.attr);
12477 node.removeAttribute('roo-'+ tpl.attr);
12478 if (tpl.attr != 'name') {
12479 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12480 node.parentNode.replaceChild(placeholder, node);
12483 var placeholder = document.createElement('span');
12484 placeholder.className = 'roo-tpl-' + tpl.value;
12485 node.parentNode.replaceChild(placeholder, node);
12488 // parent now sees '{domtplXXXX}
12489 this.iterChild(node,this.compileNode);
12491 // we should now have node body...
12492 var div = document.createElement('div');
12493 div.appendChild(node);
12495 // this has the unfortunate side effect of converting tagged attributes
12496 // eg. href="{...}" into %7C...%7D
12497 // this has been fixed by searching for those combo's although it's a bit hacky..
12500 tpl.body = div.innerHTML;
12507 switch (tpl.value) {
12508 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12509 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12510 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12515 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12519 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12523 tpl.id = tpl.value; // replace non characters???
12529 this.tpls.push(tpl);
12539 * Compile a segment of the template into a 'sub-template'
12545 compileTpl : function(tpl)
12547 var fm = Roo.util.Format;
12548 var useF = this.disableFormats !== true;
12550 var sep = Roo.isGecko ? "+\n" : ",\n";
12552 var undef = function(str) {
12553 Roo.debug && Roo.log("Property not found :" + str);
12557 //Roo.log(tpl.body);
12561 var fn = function(m, lbrace, name, format, args)
12564 //Roo.log(arguments);
12565 args = args ? args.replace(/\\'/g,"'") : args;
12566 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12567 if (typeof(format) == 'undefined') {
12568 format = 'htmlEncode';
12570 if (format == 'raw' ) {
12574 if(name.substr(0, 6) == 'domtpl'){
12575 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12578 // build an array of options to determine if value is undefined..
12580 // basically get 'xxxx.yyyy' then do
12581 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12582 // (function () { Roo.log("Property not found"); return ''; })() :
12587 Roo.each(name.split('.'), function(st) {
12588 lookfor += (lookfor.length ? '.': '') + st;
12589 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12592 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12595 if(format && useF){
12597 args = args ? ',' + args : "";
12599 if(format.substr(0, 5) != "this."){
12600 format = "fm." + format + '(';
12602 format = 'this.call("'+ format.substr(5) + '", ';
12606 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12609 if (args && args.length) {
12610 // called with xxyx.yuu:(test,test)
12612 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12614 // raw.. - :raw modifier..
12615 return "'"+ sep + udef_st + name + ")"+sep+"'";
12619 // branched to use + in gecko and [].join() in others
12621 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12622 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12625 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12626 body.push(tpl.body.replace(/(\r\n|\n)/g,
12627 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12628 body.push("'].join('');};};");
12629 body = body.join('');
12632 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12634 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12641 * same as applyTemplate, except it's done to one of the subTemplates
12642 * when using named templates, you can do:
12644 * var str = pl.applySubTemplate('your-name', values);
12647 * @param {Number} id of the template
12648 * @param {Object} values to apply to template
12649 * @param {Object} parent (normaly the instance of this object)
12651 applySubTemplate : function(id, values, parent)
12655 var t = this.tpls[id];
12659 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12660 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12664 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12671 if(t.execCall && t.execCall.call(this, values, parent)){
12675 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12681 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12682 parent = t.target ? values : parent;
12683 if(t.forCall && vs instanceof Array){
12685 for(var i = 0, len = vs.length; i < len; i++){
12687 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12689 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12691 //Roo.log(t.compiled);
12695 return buf.join('');
12698 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12703 return t.compiled.call(this, vs, parent);
12705 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12707 //Roo.log(t.compiled);
12715 applyTemplate : function(values){
12716 return this.master.compiled.call(this, values, {});
12717 //var s = this.subs;
12720 apply : function(){
12721 return this.applyTemplate.apply(this, arguments);
12726 Roo.DomTemplate.from = function(el){
12727 el = Roo.getDom(el);
12728 return new Roo.Domtemplate(el.value || el.innerHTML);
12731 * Ext JS Library 1.1.1
12732 * Copyright(c) 2006-2007, Ext JS, LLC.
12734 * Originally Released Under LGPL - original licence link has changed is not relivant.
12737 * <script type="text/javascript">
12741 * @class Roo.util.DelayedTask
12742 * Provides a convenient method of performing setTimeout where a new
12743 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12744 * You can use this class to buffer
12745 * the keypress events for a certain number of milliseconds, and perform only if they stop
12746 * for that amount of time.
12747 * @constructor The parameters to this constructor serve as defaults and are not required.
12748 * @param {Function} fn (optional) The default function to timeout
12749 * @param {Object} scope (optional) The default scope of that timeout
12750 * @param {Array} args (optional) The default Array of arguments
12752 Roo.util.DelayedTask = function(fn, scope, args){
12753 var id = null, d, t;
12755 var call = function(){
12756 var now = new Date().getTime();
12760 fn.apply(scope, args || []);
12764 * Cancels any pending timeout and queues a new one
12765 * @param {Number} delay The milliseconds to delay
12766 * @param {Function} newFn (optional) Overrides function passed to constructor
12767 * @param {Object} newScope (optional) Overrides scope passed to constructor
12768 * @param {Array} newArgs (optional) Overrides args passed to constructor
12770 this.delay = function(delay, newFn, newScope, newArgs){
12771 if(id && delay != d){
12775 t = new Date().getTime();
12777 scope = newScope || scope;
12778 args = newArgs || args;
12780 id = setInterval(call, d);
12785 * Cancel the last queued timeout
12787 this.cancel = function(){
12795 * Ext JS Library 1.1.1
12796 * Copyright(c) 2006-2007, Ext JS, LLC.
12798 * Originally Released Under LGPL - original licence link has changed is not relivant.
12801 * <script type="text/javascript">
12805 Roo.util.TaskRunner = function(interval){
12806 interval = interval || 10;
12807 var tasks = [], removeQueue = [];
12809 var running = false;
12811 var stopThread = function(){
12817 var startThread = function(){
12820 id = setInterval(runTasks, interval);
12824 var removeTask = function(task){
12825 removeQueue.push(task);
12831 var runTasks = function(){
12832 if(removeQueue.length > 0){
12833 for(var i = 0, len = removeQueue.length; i < len; i++){
12834 tasks.remove(removeQueue[i]);
12837 if(tasks.length < 1){
12842 var now = new Date().getTime();
12843 for(var i = 0, len = tasks.length; i < len; ++i){
12845 var itime = now - t.taskRunTime;
12846 if(t.interval <= itime){
12847 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12848 t.taskRunTime = now;
12849 if(rt === false || t.taskRunCount === t.repeat){
12854 if(t.duration && t.duration <= (now - t.taskStartTime)){
12861 * Queues a new task.
12862 * @param {Object} task
12864 this.start = function(task){
12866 task.taskStartTime = new Date().getTime();
12867 task.taskRunTime = 0;
12868 task.taskRunCount = 0;
12873 this.stop = function(task){
12878 this.stopAll = function(){
12880 for(var i = 0, len = tasks.length; i < len; i++){
12881 if(tasks[i].onStop){
12890 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12892 * Ext JS Library 1.1.1
12893 * Copyright(c) 2006-2007, Ext JS, LLC.
12895 * Originally Released Under LGPL - original licence link has changed is not relivant.
12898 * <script type="text/javascript">
12903 * @class Roo.util.MixedCollection
12904 * @extends Roo.util.Observable
12905 * A Collection class that maintains both numeric indexes and keys and exposes events.
12907 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12908 * collection (defaults to false)
12909 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12910 * and return the key value for that item. This is used when available to look up the key on items that
12911 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12912 * equivalent to providing an implementation for the {@link #getKey} method.
12914 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12922 * Fires when the collection is cleared.
12927 * Fires when an item is added to the collection.
12928 * @param {Number} index The index at which the item was added.
12929 * @param {Object} o The item added.
12930 * @param {String} key The key associated with the added item.
12935 * Fires when an item is replaced in the collection.
12936 * @param {String} key he key associated with the new added.
12937 * @param {Object} old The item being replaced.
12938 * @param {Object} new The new item.
12943 * Fires when an item is removed from the collection.
12944 * @param {Object} o The item being removed.
12945 * @param {String} key (optional) The key associated with the removed item.
12950 this.allowFunctions = allowFunctions === true;
12952 this.getKey = keyFn;
12954 Roo.util.MixedCollection.superclass.constructor.call(this);
12957 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12958 allowFunctions : false,
12961 * Adds an item to the collection.
12962 * @param {String} key The key to associate with the item
12963 * @param {Object} o The item to add.
12964 * @return {Object} The item added.
12966 add : function(key, o){
12967 if(arguments.length == 1){
12969 key = this.getKey(o);
12971 if(typeof key == "undefined" || key === null){
12973 this.items.push(o);
12974 this.keys.push(null);
12976 var old = this.map[key];
12978 return this.replace(key, o);
12981 this.items.push(o);
12983 this.keys.push(key);
12985 this.fireEvent("add", this.length-1, o, key);
12990 * MixedCollection has a generic way to fetch keys if you implement getKey.
12993 var mc = new Roo.util.MixedCollection();
12994 mc.add(someEl.dom.id, someEl);
12995 mc.add(otherEl.dom.id, otherEl);
12999 var mc = new Roo.util.MixedCollection();
13000 mc.getKey = function(el){
13006 // or via the constructor
13007 var mc = new Roo.util.MixedCollection(false, function(el){
13013 * @param o {Object} The item for which to find the key.
13014 * @return {Object} The key for the passed item.
13016 getKey : function(o){
13021 * Replaces an item in the collection.
13022 * @param {String} key The key associated with the item to replace, or the item to replace.
13023 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13024 * @return {Object} The new item.
13026 replace : function(key, o){
13027 if(arguments.length == 1){
13029 key = this.getKey(o);
13031 var old = this.item(key);
13032 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13033 return this.add(key, o);
13035 var index = this.indexOfKey(key);
13036 this.items[index] = o;
13038 this.fireEvent("replace", key, old, o);
13043 * Adds all elements of an Array or an Object to the collection.
13044 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13045 * an Array of values, each of which are added to the collection.
13047 addAll : function(objs){
13048 if(arguments.length > 1 || objs instanceof Array){
13049 var args = arguments.length > 1 ? arguments : objs;
13050 for(var i = 0, len = args.length; i < len; i++){
13054 for(var key in objs){
13055 if(this.allowFunctions || typeof objs[key] != "function"){
13056 this.add(key, objs[key]);
13063 * Executes the specified function once for every item in the collection, passing each
13064 * item as the first and only parameter. returning false from the function will stop the iteration.
13065 * @param {Function} fn The function to execute for each item.
13066 * @param {Object} scope (optional) The scope in which to execute the function.
13068 each : function(fn, scope){
13069 var items = [].concat(this.items); // each safe for removal
13070 for(var i = 0, len = items.length; i < len; i++){
13071 if(fn.call(scope || items[i], items[i], i, len) === false){
13078 * Executes the specified function once for every key in the collection, passing each
13079 * key, and its associated item as the first two parameters.
13080 * @param {Function} fn The function to execute for each item.
13081 * @param {Object} scope (optional) The scope in which to execute the function.
13083 eachKey : function(fn, scope){
13084 for(var i = 0, len = this.keys.length; i < len; i++){
13085 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13090 * Returns the first item in the collection which elicits a true return value from the
13091 * passed selection function.
13092 * @param {Function} fn The selection function to execute for each item.
13093 * @param {Object} scope (optional) The scope in which to execute the function.
13094 * @return {Object} The first item in the collection which returned true from the selection function.
13096 find : function(fn, scope){
13097 for(var i = 0, len = this.items.length; i < len; i++){
13098 if(fn.call(scope || window, this.items[i], this.keys[i])){
13099 return this.items[i];
13106 * Inserts an item at the specified index in the collection.
13107 * @param {Number} index The index to insert the item at.
13108 * @param {String} key The key to associate with the new item, or the item itself.
13109 * @param {Object} o (optional) If the second parameter was a key, the new item.
13110 * @return {Object} The item inserted.
13112 insert : function(index, key, o){
13113 if(arguments.length == 2){
13115 key = this.getKey(o);
13117 if(index >= this.length){
13118 return this.add(key, o);
13121 this.items.splice(index, 0, o);
13122 if(typeof key != "undefined" && key != null){
13125 this.keys.splice(index, 0, key);
13126 this.fireEvent("add", index, o, key);
13131 * Removed an item from the collection.
13132 * @param {Object} o The item to remove.
13133 * @return {Object} The item removed.
13135 remove : function(o){
13136 return this.removeAt(this.indexOf(o));
13140 * Remove an item from a specified index in the collection.
13141 * @param {Number} index The index within the collection of the item to remove.
13143 removeAt : function(index){
13144 if(index < this.length && index >= 0){
13146 var o = this.items[index];
13147 this.items.splice(index, 1);
13148 var key = this.keys[index];
13149 if(typeof key != "undefined"){
13150 delete this.map[key];
13152 this.keys.splice(index, 1);
13153 this.fireEvent("remove", o, key);
13158 * Removed an item associated with the passed key fom the collection.
13159 * @param {String} key The key of the item to remove.
13161 removeKey : function(key){
13162 return this.removeAt(this.indexOfKey(key));
13166 * Returns the number of items in the collection.
13167 * @return {Number} the number of items in the collection.
13169 getCount : function(){
13170 return this.length;
13174 * Returns index within the collection of the passed Object.
13175 * @param {Object} o The item to find the index of.
13176 * @return {Number} index of the item.
13178 indexOf : function(o){
13179 if(!this.items.indexOf){
13180 for(var i = 0, len = this.items.length; i < len; i++){
13181 if(this.items[i] == o) {
13187 return this.items.indexOf(o);
13192 * Returns index within the collection of the passed key.
13193 * @param {String} key The key to find the index of.
13194 * @return {Number} index of the key.
13196 indexOfKey : function(key){
13197 if(!this.keys.indexOf){
13198 for(var i = 0, len = this.keys.length; i < len; i++){
13199 if(this.keys[i] == key) {
13205 return this.keys.indexOf(key);
13210 * Returns the item associated with the passed key OR index. Key has priority over index.
13211 * @param {String/Number} key The key or index of the item.
13212 * @return {Object} The item associated with the passed key.
13214 item : function(key){
13215 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13216 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13220 * Returns the item at the specified index.
13221 * @param {Number} index The index of the item.
13224 itemAt : function(index){
13225 return this.items[index];
13229 * Returns the item associated with the passed key.
13230 * @param {String/Number} key The key of the item.
13231 * @return {Object} The item associated with the passed key.
13233 key : function(key){
13234 return this.map[key];
13238 * Returns true if the collection contains the passed Object as an item.
13239 * @param {Object} o The Object to look for in the collection.
13240 * @return {Boolean} True if the collection contains the Object as an item.
13242 contains : function(o){
13243 return this.indexOf(o) != -1;
13247 * Returns true if the collection contains the passed Object as a key.
13248 * @param {String} key The key to look for in the collection.
13249 * @return {Boolean} True if the collection contains the Object as a key.
13251 containsKey : function(key){
13252 return typeof this.map[key] != "undefined";
13256 * Removes all items from the collection.
13258 clear : function(){
13263 this.fireEvent("clear");
13267 * Returns the first item in the collection.
13268 * @return {Object} the first item in the collection..
13270 first : function(){
13271 return this.items[0];
13275 * Returns the last item in the collection.
13276 * @return {Object} the last item in the collection..
13279 return this.items[this.length-1];
13282 _sort : function(property, dir, fn){
13283 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13284 fn = fn || function(a, b){
13287 var c = [], k = this.keys, items = this.items;
13288 for(var i = 0, len = items.length; i < len; i++){
13289 c[c.length] = {key: k[i], value: items[i], index: i};
13291 c.sort(function(a, b){
13292 var v = fn(a[property], b[property]) * dsc;
13294 v = (a.index < b.index ? -1 : 1);
13298 for(var i = 0, len = c.length; i < len; i++){
13299 items[i] = c[i].value;
13302 this.fireEvent("sort", this);
13306 * Sorts this collection with the passed comparison function
13307 * @param {String} direction (optional) "ASC" or "DESC"
13308 * @param {Function} fn (optional) comparison function
13310 sort : function(dir, fn){
13311 this._sort("value", dir, fn);
13315 * Sorts this collection by keys
13316 * @param {String} direction (optional) "ASC" or "DESC"
13317 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13319 keySort : function(dir, fn){
13320 this._sort("key", dir, fn || function(a, b){
13321 return String(a).toUpperCase()-String(b).toUpperCase();
13326 * Returns a range of items in this collection
13327 * @param {Number} startIndex (optional) defaults to 0
13328 * @param {Number} endIndex (optional) default to the last item
13329 * @return {Array} An array of items
13331 getRange : function(start, end){
13332 var items = this.items;
13333 if(items.length < 1){
13336 start = start || 0;
13337 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13340 for(var i = start; i <= end; i++) {
13341 r[r.length] = items[i];
13344 for(var i = start; i >= end; i--) {
13345 r[r.length] = items[i];
13352 * Filter the <i>objects</i> in this collection by a specific property.
13353 * Returns a new collection that has been filtered.
13354 * @param {String} property A property on your objects
13355 * @param {String/RegExp} value Either string that the property values
13356 * should start with or a RegExp to test against the property
13357 * @return {MixedCollection} The new filtered collection
13359 filter : function(property, value){
13360 if(!value.exec){ // not a regex
13361 value = String(value);
13362 if(value.length == 0){
13363 return this.clone();
13365 value = new RegExp("^" + Roo.escapeRe(value), "i");
13367 return this.filterBy(function(o){
13368 return o && value.test(o[property]);
13373 * Filter by a function. * Returns a new collection that has been filtered.
13374 * The passed function will be called with each
13375 * object in the collection. If the function returns true, the value is included
13376 * otherwise it is filtered.
13377 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13378 * @param {Object} scope (optional) The scope of the function (defaults to this)
13379 * @return {MixedCollection} The new filtered collection
13381 filterBy : function(fn, scope){
13382 var r = new Roo.util.MixedCollection();
13383 r.getKey = this.getKey;
13384 var k = this.keys, it = this.items;
13385 for(var i = 0, len = it.length; i < len; i++){
13386 if(fn.call(scope||this, it[i], k[i])){
13387 r.add(k[i], it[i]);
13394 * Creates a duplicate of this collection
13395 * @return {MixedCollection}
13397 clone : function(){
13398 var r = new Roo.util.MixedCollection();
13399 var k = this.keys, it = this.items;
13400 for(var i = 0, len = it.length; i < len; i++){
13401 r.add(k[i], it[i]);
13403 r.getKey = this.getKey;
13408 * Returns the item associated with the passed key or index.
13410 * @param {String/Number} key The key or index of the item.
13411 * @return {Object} The item associated with the passed key.
13413 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13415 * Ext JS Library 1.1.1
13416 * Copyright(c) 2006-2007, Ext JS, LLC.
13418 * Originally Released Under LGPL - original licence link has changed is not relivant.
13421 * <script type="text/javascript">
13424 * @class Roo.util.JSON
13425 * Modified version of Douglas Crockford"s json.js that doesn"t
13426 * mess with the Object prototype
13427 * http://www.json.org/js.html
13430 Roo.util.JSON = new (function(){
13431 var useHasOwn = {}.hasOwnProperty ? true : false;
13433 // crashes Safari in some instances
13434 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13436 var pad = function(n) {
13437 return n < 10 ? "0" + n : n;
13450 var encodeString = function(s){
13451 if (/["\\\x00-\x1f]/.test(s)) {
13452 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13457 c = b.charCodeAt();
13459 Math.floor(c / 16).toString(16) +
13460 (c % 16).toString(16);
13463 return '"' + s + '"';
13466 var encodeArray = function(o){
13467 var a = ["["], b, i, l = o.length, v;
13468 for (i = 0; i < l; i += 1) {
13470 switch (typeof v) {
13479 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13487 var encodeDate = function(o){
13488 return '"' + o.getFullYear() + "-" +
13489 pad(o.getMonth() + 1) + "-" +
13490 pad(o.getDate()) + "T" +
13491 pad(o.getHours()) + ":" +
13492 pad(o.getMinutes()) + ":" +
13493 pad(o.getSeconds()) + '"';
13497 * Encodes an Object, Array or other value
13498 * @param {Mixed} o The variable to encode
13499 * @return {String} The JSON string
13501 this.encode = function(o)
13503 // should this be extended to fully wrap stringify..
13505 if(typeof o == "undefined" || o === null){
13507 }else if(o instanceof Array){
13508 return encodeArray(o);
13509 }else if(o instanceof Date){
13510 return encodeDate(o);
13511 }else if(typeof o == "string"){
13512 return encodeString(o);
13513 }else if(typeof o == "number"){
13514 return isFinite(o) ? String(o) : "null";
13515 }else if(typeof o == "boolean"){
13518 var a = ["{"], b, i, v;
13520 if(!useHasOwn || o.hasOwnProperty(i)) {
13522 switch (typeof v) {
13531 a.push(this.encode(i), ":",
13532 v === null ? "null" : this.encode(v));
13543 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13544 * @param {String} json The JSON string
13545 * @return {Object} The resulting object
13547 this.decode = function(json){
13549 return /** eval:var:json */ eval("(" + json + ')');
13553 * Shorthand for {@link Roo.util.JSON#encode}
13554 * @member Roo encode
13556 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13558 * Shorthand for {@link Roo.util.JSON#decode}
13559 * @member Roo decode
13561 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13564 * Ext JS Library 1.1.1
13565 * Copyright(c) 2006-2007, Ext JS, LLC.
13567 * Originally Released Under LGPL - original licence link has changed is not relivant.
13570 * <script type="text/javascript">
13574 * @class Roo.util.Format
13575 * Reusable data formatting functions
13578 Roo.util.Format = function(){
13579 var trimRe = /^\s+|\s+$/g;
13582 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13583 * @param {String} value The string to truncate
13584 * @param {Number} length The maximum length to allow before truncating
13585 * @return {String} The converted text
13587 ellipsis : function(value, len){
13588 if(value && value.length > len){
13589 return value.substr(0, len-3)+"...";
13595 * Checks a reference and converts it to empty string if it is undefined
13596 * @param {Mixed} value Reference to check
13597 * @return {Mixed} Empty string if converted, otherwise the original value
13599 undef : function(value){
13600 return typeof value != "undefined" ? value : "";
13604 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13605 * @param {String} value The string to encode
13606 * @return {String} The encoded text
13608 htmlEncode : function(value){
13609 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13613 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13614 * @param {String} value The string to decode
13615 * @return {String} The decoded text
13617 htmlDecode : function(value){
13618 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13622 * Trims any whitespace from either side of a string
13623 * @param {String} value The text to trim
13624 * @return {String} The trimmed text
13626 trim : function(value){
13627 return String(value).replace(trimRe, "");
13631 * Returns a substring from within an original string
13632 * @param {String} value The original text
13633 * @param {Number} start The start index of the substring
13634 * @param {Number} length The length of the substring
13635 * @return {String} The substring
13637 substr : function(value, start, length){
13638 return String(value).substr(start, length);
13642 * Converts a string to all lower case letters
13643 * @param {String} value The text to convert
13644 * @return {String} The converted text
13646 lowercase : function(value){
13647 return String(value).toLowerCase();
13651 * Converts a string to all upper case letters
13652 * @param {String} value The text to convert
13653 * @return {String} The converted text
13655 uppercase : function(value){
13656 return String(value).toUpperCase();
13660 * Converts the first character only of a string to upper case
13661 * @param {String} value The text to convert
13662 * @return {String} The converted text
13664 capitalize : function(value){
13665 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13669 call : function(value, fn){
13670 if(arguments.length > 2){
13671 var args = Array.prototype.slice.call(arguments, 2);
13672 args.unshift(value);
13674 return /** eval:var:value */ eval(fn).apply(window, args);
13676 /** eval:var:value */
13677 return /** eval:var:value */ eval(fn).call(window, value);
13683 * safer version of Math.toFixed..??/
13684 * @param {Number/String} value The numeric value to format
13685 * @param {Number/String} value Decimal places
13686 * @return {String} The formatted currency string
13688 toFixed : function(v, n)
13690 // why not use to fixed - precision is buggered???
13692 return Math.round(v-0);
13694 var fact = Math.pow(10,n+1);
13695 v = (Math.round((v-0)*fact))/fact;
13696 var z = (''+fact).substring(2);
13697 if (v == Math.floor(v)) {
13698 return Math.floor(v) + '.' + z;
13701 // now just padd decimals..
13702 var ps = String(v).split('.');
13703 var fd = (ps[1] + z);
13704 var r = fd.substring(0,n);
13705 var rm = fd.substring(n);
13707 return ps[0] + '.' + r;
13709 r*=1; // turn it into a number;
13711 if (String(r).length != n) {
13714 r = String(r).substring(1); // chop the end off.
13717 return ps[0] + '.' + r;
13722 * Format a number as US currency
13723 * @param {Number/String} value The numeric value to format
13724 * @return {String} The formatted currency string
13726 usMoney : function(v){
13727 return '$' + Roo.util.Format.number(v);
13732 * eventually this should probably emulate php's number_format
13733 * @param {Number/String} value The numeric value to format
13734 * @param {Number} decimals number of decimal places
13735 * @return {String} The formatted currency string
13737 number : function(v,decimals)
13739 // multiply and round.
13740 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13741 var mul = Math.pow(10, decimals);
13742 var zero = String(mul).substring(1);
13743 v = (Math.round((v-0)*mul))/mul;
13745 // if it's '0' number.. then
13747 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13749 var ps = v.split('.');
13753 var r = /(\d+)(\d{3})/;
13755 while (r.test(whole)) {
13756 whole = whole.replace(r, '$1' + ',' + '$2');
13762 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13763 // does not have decimals
13764 (decimals ? ('.' + zero) : '');
13767 return whole + sub ;
13771 * Parse a value into a formatted date using the specified format pattern.
13772 * @param {Mixed} value The value to format
13773 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13774 * @return {String} The formatted date string
13776 date : function(v, format){
13780 if(!(v instanceof Date)){
13781 v = new Date(Date.parse(v));
13783 return v.dateFormat(format || Roo.util.Format.defaults.date);
13787 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13788 * @param {String} format Any valid date format string
13789 * @return {Function} The date formatting function
13791 dateRenderer : function(format){
13792 return function(v){
13793 return Roo.util.Format.date(v, format);
13798 stripTagsRE : /<\/?[^>]+>/gi,
13801 * Strips all HTML tags
13802 * @param {Mixed} value The text from which to strip tags
13803 * @return {String} The stripped text
13805 stripTags : function(v){
13806 return !v ? v : String(v).replace(this.stripTagsRE, "");
13810 Roo.util.Format.defaults = {
13814 * Ext JS Library 1.1.1
13815 * Copyright(c) 2006-2007, Ext JS, LLC.
13817 * Originally Released Under LGPL - original licence link has changed is not relivant.
13820 * <script type="text/javascript">
13827 * @class Roo.MasterTemplate
13828 * @extends Roo.Template
13829 * Provides a template that can have child templates. The syntax is:
13831 var t = new Roo.MasterTemplate(
13832 '<select name="{name}">',
13833 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13836 t.add('options', {value: 'foo', text: 'bar'});
13837 // or you can add multiple child elements in one shot
13838 t.addAll('options', [
13839 {value: 'foo', text: 'bar'},
13840 {value: 'foo2', text: 'bar2'},
13841 {value: 'foo3', text: 'bar3'}
13843 // then append, applying the master template values
13844 t.append('my-form', {name: 'my-select'});
13846 * A name attribute for the child template is not required if you have only one child
13847 * template or you want to refer to them by index.
13849 Roo.MasterTemplate = function(){
13850 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13851 this.originalHtml = this.html;
13853 var m, re = this.subTemplateRe;
13856 while(m = re.exec(this.html)){
13857 var name = m[1], content = m[2];
13862 tpl : new Roo.Template(content)
13865 st[name] = st[subIndex];
13867 st[subIndex].tpl.compile();
13868 st[subIndex].tpl.call = this.call.createDelegate(this);
13871 this.subCount = subIndex;
13874 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13876 * The regular expression used to match sub templates
13880 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13883 * Applies the passed values to a child template.
13884 * @param {String/Number} name (optional) The name or index of the child template
13885 * @param {Array/Object} values The values to be applied to the template
13886 * @return {MasterTemplate} this
13888 add : function(name, values){
13889 if(arguments.length == 1){
13890 values = arguments[0];
13893 var s = this.subs[name];
13894 s.buffer[s.buffer.length] = s.tpl.apply(values);
13899 * Applies all the passed values to a child template.
13900 * @param {String/Number} name (optional) The name or index of the child template
13901 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13902 * @param {Boolean} reset (optional) True to reset the template first
13903 * @return {MasterTemplate} this
13905 fill : function(name, values, reset){
13907 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13915 for(var i = 0, len = values.length; i < len; i++){
13916 this.add(name, values[i]);
13922 * Resets the template for reuse
13923 * @return {MasterTemplate} this
13925 reset : function(){
13927 for(var i = 0; i < this.subCount; i++){
13933 applyTemplate : function(values){
13935 var replaceIndex = -1;
13936 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13937 return s[++replaceIndex].buffer.join("");
13939 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13942 apply : function(){
13943 return this.applyTemplate.apply(this, arguments);
13946 compile : function(){return this;}
13950 * Alias for fill().
13953 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13955 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13956 * var tpl = Roo.MasterTemplate.from('element-id');
13957 * @param {String/HTMLElement} el
13958 * @param {Object} config
13961 Roo.MasterTemplate.from = function(el, config){
13962 el = Roo.getDom(el);
13963 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13966 * Ext JS Library 1.1.1
13967 * Copyright(c) 2006-2007, Ext JS, LLC.
13969 * Originally Released Under LGPL - original licence link has changed is not relivant.
13972 * <script type="text/javascript">
13977 * @class Roo.util.CSS
13978 * Utility class for manipulating CSS rules
13981 Roo.util.CSS = function(){
13983 var doc = document;
13985 var camelRe = /(-[a-z])/gi;
13986 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13990 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13991 * tag and appended to the HEAD of the document.
13992 * @param {String|Object} cssText The text containing the css rules
13993 * @param {String} id An id to add to the stylesheet for later removal
13994 * @return {StyleSheet}
13996 createStyleSheet : function(cssText, id){
13998 var head = doc.getElementsByTagName("head")[0];
13999 var nrules = doc.createElement("style");
14000 nrules.setAttribute("type", "text/css");
14002 nrules.setAttribute("id", id);
14004 if (typeof(cssText) != 'string') {
14005 // support object maps..
14006 // not sure if this a good idea..
14007 // perhaps it should be merged with the general css handling
14008 // and handle js style props.
14009 var cssTextNew = [];
14010 for(var n in cssText) {
14012 for(var k in cssText[n]) {
14013 citems.push( k + ' : ' +cssText[n][k] + ';' );
14015 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14018 cssText = cssTextNew.join("\n");
14024 head.appendChild(nrules);
14025 ss = nrules.styleSheet;
14026 ss.cssText = cssText;
14029 nrules.appendChild(doc.createTextNode(cssText));
14031 nrules.cssText = cssText;
14033 head.appendChild(nrules);
14034 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14036 this.cacheStyleSheet(ss);
14041 * Removes a style or link tag by id
14042 * @param {String} id The id of the tag
14044 removeStyleSheet : function(id){
14045 var existing = doc.getElementById(id);
14047 existing.parentNode.removeChild(existing);
14052 * Dynamically swaps an existing stylesheet reference for a new one
14053 * @param {String} id The id of an existing link tag to remove
14054 * @param {String} url The href of the new stylesheet to include
14056 swapStyleSheet : function(id, url){
14057 this.removeStyleSheet(id);
14058 var ss = doc.createElement("link");
14059 ss.setAttribute("rel", "stylesheet");
14060 ss.setAttribute("type", "text/css");
14061 ss.setAttribute("id", id);
14062 ss.setAttribute("href", url);
14063 doc.getElementsByTagName("head")[0].appendChild(ss);
14067 * Refresh the rule cache if you have dynamically added stylesheets
14068 * @return {Object} An object (hash) of rules indexed by selector
14070 refreshCache : function(){
14071 return this.getRules(true);
14075 cacheStyleSheet : function(stylesheet){
14079 try{// try catch for cross domain access issue
14080 var ssRules = stylesheet.cssRules || stylesheet.rules;
14081 for(var j = ssRules.length-1; j >= 0; --j){
14082 rules[ssRules[j].selectorText] = ssRules[j];
14088 * Gets all css rules for the document
14089 * @param {Boolean} refreshCache true to refresh the internal cache
14090 * @return {Object} An object (hash) of rules indexed by selector
14092 getRules : function(refreshCache){
14093 if(rules == null || refreshCache){
14095 var ds = doc.styleSheets;
14096 for(var i =0, len = ds.length; i < len; i++){
14098 this.cacheStyleSheet(ds[i]);
14106 * Gets an an individual CSS rule by selector(s)
14107 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14108 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14109 * @return {CSSRule} The CSS rule or null if one is not found
14111 getRule : function(selector, refreshCache){
14112 var rs = this.getRules(refreshCache);
14113 if(!(selector instanceof Array)){
14114 return rs[selector];
14116 for(var i = 0; i < selector.length; i++){
14117 if(rs[selector[i]]){
14118 return rs[selector[i]];
14126 * Updates a rule property
14127 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14128 * @param {String} property The css property
14129 * @param {String} value The new value for the property
14130 * @return {Boolean} true If a rule was found and updated
14132 updateRule : function(selector, property, value){
14133 if(!(selector instanceof Array)){
14134 var rule = this.getRule(selector);
14136 rule.style[property.replace(camelRe, camelFn)] = value;
14140 for(var i = 0; i < selector.length; i++){
14141 if(this.updateRule(selector[i], property, value)){
14151 * Ext JS Library 1.1.1
14152 * Copyright(c) 2006-2007, Ext JS, LLC.
14154 * Originally Released Under LGPL - original licence link has changed is not relivant.
14157 * <script type="text/javascript">
14163 * @class Roo.util.ClickRepeater
14164 * @extends Roo.util.Observable
14166 * A wrapper class which can be applied to any element. Fires a "click" event while the
14167 * mouse is pressed. The interval between firings may be specified in the config but
14168 * defaults to 10 milliseconds.
14170 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14172 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14173 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14174 * Similar to an autorepeat key delay.
14175 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14176 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14177 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14178 * "interval" and "delay" are ignored. "immediate" is honored.
14179 * @cfg {Boolean} preventDefault True to prevent the default click event
14180 * @cfg {Boolean} stopDefault True to stop the default click event
14183 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14184 * 2007-02-02 jvs Renamed to ClickRepeater
14185 * 2007-02-03 jvs Modifications for FF Mac and Safari
14188 * @param {String/HTMLElement/Element} el The element to listen on
14189 * @param {Object} config
14191 Roo.util.ClickRepeater = function(el, config)
14193 this.el = Roo.get(el);
14194 this.el.unselectable();
14196 Roo.apply(this, config);
14201 * Fires when the mouse button is depressed.
14202 * @param {Roo.util.ClickRepeater} this
14204 "mousedown" : true,
14207 * Fires on a specified interval during the time the element is pressed.
14208 * @param {Roo.util.ClickRepeater} this
14213 * Fires when the mouse key is released.
14214 * @param {Roo.util.ClickRepeater} this
14219 this.el.on("mousedown", this.handleMouseDown, this);
14220 if(this.preventDefault || this.stopDefault){
14221 this.el.on("click", function(e){
14222 if(this.preventDefault){
14223 e.preventDefault();
14225 if(this.stopDefault){
14231 // allow inline handler
14233 this.on("click", this.handler, this.scope || this);
14236 Roo.util.ClickRepeater.superclass.constructor.call(this);
14239 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14242 preventDefault : true,
14243 stopDefault : false,
14247 handleMouseDown : function(){
14248 clearTimeout(this.timer);
14250 if(this.pressClass){
14251 this.el.addClass(this.pressClass);
14253 this.mousedownTime = new Date();
14255 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14256 this.el.on("mouseout", this.handleMouseOut, this);
14258 this.fireEvent("mousedown", this);
14259 this.fireEvent("click", this);
14261 this.timer = this.click.defer(this.delay || this.interval, this);
14265 click : function(){
14266 this.fireEvent("click", this);
14267 this.timer = this.click.defer(this.getInterval(), this);
14271 getInterval: function(){
14272 if(!this.accelerate){
14273 return this.interval;
14275 var pressTime = this.mousedownTime.getElapsed();
14276 if(pressTime < 500){
14278 }else if(pressTime < 1700){
14280 }else if(pressTime < 2600){
14282 }else if(pressTime < 3500){
14284 }else if(pressTime < 4400){
14286 }else if(pressTime < 5300){
14288 }else if(pressTime < 6200){
14296 handleMouseOut : function(){
14297 clearTimeout(this.timer);
14298 if(this.pressClass){
14299 this.el.removeClass(this.pressClass);
14301 this.el.on("mouseover", this.handleMouseReturn, this);
14305 handleMouseReturn : function(){
14306 this.el.un("mouseover", this.handleMouseReturn);
14307 if(this.pressClass){
14308 this.el.addClass(this.pressClass);
14314 handleMouseUp : function(){
14315 clearTimeout(this.timer);
14316 this.el.un("mouseover", this.handleMouseReturn);
14317 this.el.un("mouseout", this.handleMouseOut);
14318 Roo.get(document).un("mouseup", this.handleMouseUp);
14319 this.el.removeClass(this.pressClass);
14320 this.fireEvent("mouseup", this);
14324 * Ext JS Library 1.1.1
14325 * Copyright(c) 2006-2007, Ext JS, LLC.
14327 * Originally Released Under LGPL - original licence link has changed is not relivant.
14330 * <script type="text/javascript">
14335 * @class Roo.KeyNav
14336 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14337 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14338 * way to implement custom navigation schemes for any UI component.</p>
14339 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14340 * pageUp, pageDown, del, home, end. Usage:</p>
14342 var nav = new Roo.KeyNav("my-element", {
14343 "left" : function(e){
14344 this.moveLeft(e.ctrlKey);
14346 "right" : function(e){
14347 this.moveRight(e.ctrlKey);
14349 "enter" : function(e){
14356 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14357 * @param {Object} config The config
14359 Roo.KeyNav = function(el, config){
14360 this.el = Roo.get(el);
14361 Roo.apply(this, config);
14362 if(!this.disabled){
14363 this.disabled = true;
14368 Roo.KeyNav.prototype = {
14370 * @cfg {Boolean} disabled
14371 * True to disable this KeyNav instance (defaults to false)
14375 * @cfg {String} defaultEventAction
14376 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14377 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14378 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14380 defaultEventAction: "stopEvent",
14382 * @cfg {Boolean} forceKeyDown
14383 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14384 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14385 * handle keydown instead of keypress.
14387 forceKeyDown : false,
14390 prepareEvent : function(e){
14391 var k = e.getKey();
14392 var h = this.keyToHandler[k];
14393 //if(h && this[h]){
14394 // e.stopPropagation();
14396 if(Roo.isSafari && h && k >= 37 && k <= 40){
14402 relay : function(e){
14403 var k = e.getKey();
14404 var h = this.keyToHandler[k];
14406 if(this.doRelay(e, this[h], h) !== true){
14407 e[this.defaultEventAction]();
14413 doRelay : function(e, h, hname){
14414 return h.call(this.scope || this, e);
14417 // possible handlers
14431 // quick lookup hash
14448 * Enable this KeyNav
14450 enable: function(){
14452 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14453 // the EventObject will normalize Safari automatically
14454 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14455 this.el.on("keydown", this.relay, this);
14457 this.el.on("keydown", this.prepareEvent, this);
14458 this.el.on("keypress", this.relay, this);
14460 this.disabled = false;
14465 * Disable this KeyNav
14467 disable: function(){
14468 if(!this.disabled){
14469 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14470 this.el.un("keydown", this.relay);
14472 this.el.un("keydown", this.prepareEvent);
14473 this.el.un("keypress", this.relay);
14475 this.disabled = true;
14480 * Ext JS Library 1.1.1
14481 * Copyright(c) 2006-2007, Ext JS, LLC.
14483 * Originally Released Under LGPL - original licence link has changed is not relivant.
14486 * <script type="text/javascript">
14491 * @class Roo.KeyMap
14492 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14493 * The constructor accepts the same config object as defined by {@link #addBinding}.
14494 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14495 * combination it will call the function with this signature (if the match is a multi-key
14496 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14497 * A KeyMap can also handle a string representation of keys.<br />
14500 // map one key by key code
14501 var map = new Roo.KeyMap("my-element", {
14502 key: 13, // or Roo.EventObject.ENTER
14507 // map multiple keys to one action by string
14508 var map = new Roo.KeyMap("my-element", {
14514 // map multiple keys to multiple actions by strings and array of codes
14515 var map = new Roo.KeyMap("my-element", [
14518 fn: function(){ alert("Return was pressed"); }
14521 fn: function(){ alert('a, b or c was pressed'); }
14526 fn: function(){ alert('Control + shift + tab was pressed.'); }
14530 * <b>Note: A KeyMap starts enabled</b>
14532 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14533 * @param {Object} config The config (see {@link #addBinding})
14534 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14536 Roo.KeyMap = function(el, config, eventName){
14537 this.el = Roo.get(el);
14538 this.eventName = eventName || "keydown";
14539 this.bindings = [];
14541 this.addBinding(config);
14546 Roo.KeyMap.prototype = {
14548 * True to stop the event from bubbling and prevent the default browser action if the
14549 * key was handled by the KeyMap (defaults to false)
14555 * Add a new binding to this KeyMap. The following config object properties are supported:
14557 Property Type Description
14558 ---------- --------------- ----------------------------------------------------------------------
14559 key String/Array A single keycode or an array of keycodes to handle
14560 shift Boolean True to handle key only when shift is pressed (defaults to false)
14561 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14562 alt Boolean True to handle key only when alt is pressed (defaults to false)
14563 fn Function The function to call when KeyMap finds the expected key combination
14564 scope Object The scope of the callback function
14570 var map = new Roo.KeyMap(document, {
14571 key: Roo.EventObject.ENTER,
14576 //Add a new binding to the existing KeyMap later
14584 * @param {Object/Array} config A single KeyMap config or an array of configs
14586 addBinding : function(config){
14587 if(config instanceof Array){
14588 for(var i = 0, len = config.length; i < len; i++){
14589 this.addBinding(config[i]);
14593 var keyCode = config.key,
14594 shift = config.shift,
14595 ctrl = config.ctrl,
14598 scope = config.scope;
14599 if(typeof keyCode == "string"){
14601 var keyString = keyCode.toUpperCase();
14602 for(var j = 0, len = keyString.length; j < len; j++){
14603 ks.push(keyString.charCodeAt(j));
14607 var keyArray = keyCode instanceof Array;
14608 var handler = function(e){
14609 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14610 var k = e.getKey();
14612 for(var i = 0, len = keyCode.length; i < len; i++){
14613 if(keyCode[i] == k){
14614 if(this.stopEvent){
14617 fn.call(scope || window, k, e);
14623 if(this.stopEvent){
14626 fn.call(scope || window, k, e);
14631 this.bindings.push(handler);
14635 * Shorthand for adding a single key listener
14636 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14637 * following options:
14638 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14639 * @param {Function} fn The function to call
14640 * @param {Object} scope (optional) The scope of the function
14642 on : function(key, fn, scope){
14643 var keyCode, shift, ctrl, alt;
14644 if(typeof key == "object" && !(key instanceof Array)){
14663 handleKeyDown : function(e){
14664 if(this.enabled){ //just in case
14665 var b = this.bindings;
14666 for(var i = 0, len = b.length; i < len; i++){
14667 b[i].call(this, e);
14673 * Returns true if this KeyMap is enabled
14674 * @return {Boolean}
14676 isEnabled : function(){
14677 return this.enabled;
14681 * Enables this KeyMap
14683 enable: function(){
14685 this.el.on(this.eventName, this.handleKeyDown, this);
14686 this.enabled = true;
14691 * Disable this KeyMap
14693 disable: function(){
14695 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14696 this.enabled = false;
14701 * Ext JS Library 1.1.1
14702 * Copyright(c) 2006-2007, Ext JS, LLC.
14704 * Originally Released Under LGPL - original licence link has changed is not relivant.
14707 * <script type="text/javascript">
14712 * @class Roo.util.TextMetrics
14713 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14714 * wide, in pixels, a given block of text will be.
14717 Roo.util.TextMetrics = function(){
14721 * Measures the size of the specified text
14722 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14723 * that can affect the size of the rendered text
14724 * @param {String} text The text to measure
14725 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14726 * in order to accurately measure the text height
14727 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14729 measure : function(el, text, fixedWidth){
14731 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14734 shared.setFixedWidth(fixedWidth || 'auto');
14735 return shared.getSize(text);
14739 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14740 * the overhead of multiple calls to initialize the style properties on each measurement.
14741 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14742 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14743 * in order to accurately measure the text height
14744 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14746 createInstance : function(el, fixedWidth){
14747 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14754 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14755 var ml = new Roo.Element(document.createElement('div'));
14756 document.body.appendChild(ml.dom);
14757 ml.position('absolute');
14758 ml.setLeftTop(-1000, -1000);
14762 ml.setWidth(fixedWidth);
14767 * Returns the size of the specified text based on the internal element's style and width properties
14768 * @memberOf Roo.util.TextMetrics.Instance#
14769 * @param {String} text The text to measure
14770 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14772 getSize : function(text){
14774 var s = ml.getSize();
14780 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14781 * that can affect the size of the rendered text
14782 * @memberOf Roo.util.TextMetrics.Instance#
14783 * @param {String/HTMLElement} el The element, dom node or id
14785 bind : function(el){
14787 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14792 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14793 * to set a fixed width in order to accurately measure the text height.
14794 * @memberOf Roo.util.TextMetrics.Instance#
14795 * @param {Number} width The width to set on the element
14797 setFixedWidth : function(width){
14798 ml.setWidth(width);
14802 * Returns the measured width of the specified text
14803 * @memberOf Roo.util.TextMetrics.Instance#
14804 * @param {String} text The text to measure
14805 * @return {Number} width The width in pixels
14807 getWidth : function(text){
14808 ml.dom.style.width = 'auto';
14809 return this.getSize(text).width;
14813 * Returns the measured height of the specified text. For multiline text, be sure to call
14814 * {@link #setFixedWidth} if necessary.
14815 * @memberOf Roo.util.TextMetrics.Instance#
14816 * @param {String} text The text to measure
14817 * @return {Number} height The height in pixels
14819 getHeight : function(text){
14820 return this.getSize(text).height;
14824 instance.bind(bindTo);
14829 // backwards compat
14830 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14832 * Ext JS Library 1.1.1
14833 * Copyright(c) 2006-2007, Ext JS, LLC.
14835 * Originally Released Under LGPL - original licence link has changed is not relivant.
14838 * <script type="text/javascript">
14842 * @class Roo.state.Provider
14843 * Abstract base class for state provider implementations. This class provides methods
14844 * for encoding and decoding <b>typed</b> variables including dates and defines the
14845 * Provider interface.
14847 Roo.state.Provider = function(){
14849 * @event statechange
14850 * Fires when a state change occurs.
14851 * @param {Provider} this This state provider
14852 * @param {String} key The state key which was changed
14853 * @param {String} value The encoded value for the state
14856 "statechange": true
14859 Roo.state.Provider.superclass.constructor.call(this);
14861 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14863 * Returns the current value for a key
14864 * @param {String} name The key name
14865 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14866 * @return {Mixed} The state data
14868 get : function(name, defaultValue){
14869 return typeof this.state[name] == "undefined" ?
14870 defaultValue : this.state[name];
14874 * Clears a value from the state
14875 * @param {String} name The key name
14877 clear : function(name){
14878 delete this.state[name];
14879 this.fireEvent("statechange", this, name, null);
14883 * Sets the value for a key
14884 * @param {String} name The key name
14885 * @param {Mixed} value The value to set
14887 set : function(name, value){
14888 this.state[name] = value;
14889 this.fireEvent("statechange", this, name, value);
14893 * Decodes a string previously encoded with {@link #encodeValue}.
14894 * @param {String} value The value to decode
14895 * @return {Mixed} The decoded value
14897 decodeValue : function(cookie){
14898 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14899 var matches = re.exec(unescape(cookie));
14900 if(!matches || !matches[1]) {
14901 return; // non state cookie
14903 var type = matches[1];
14904 var v = matches[2];
14907 return parseFloat(v);
14909 return new Date(Date.parse(v));
14914 var values = v.split("^");
14915 for(var i = 0, len = values.length; i < len; i++){
14916 all.push(this.decodeValue(values[i]));
14921 var values = v.split("^");
14922 for(var i = 0, len = values.length; i < len; i++){
14923 var kv = values[i].split("=");
14924 all[kv[0]] = this.decodeValue(kv[1]);
14933 * Encodes a value including type information. Decode with {@link #decodeValue}.
14934 * @param {Mixed} value The value to encode
14935 * @return {String} The encoded value
14937 encodeValue : function(v){
14939 if(typeof v == "number"){
14941 }else if(typeof v == "boolean"){
14942 enc = "b:" + (v ? "1" : "0");
14943 }else if(v instanceof Date){
14944 enc = "d:" + v.toGMTString();
14945 }else if(v instanceof Array){
14947 for(var i = 0, len = v.length; i < len; i++){
14948 flat += this.encodeValue(v[i]);
14954 }else if(typeof v == "object"){
14957 if(typeof v[key] != "function"){
14958 flat += key + "=" + this.encodeValue(v[key]) + "^";
14961 enc = "o:" + flat.substring(0, flat.length-1);
14965 return escape(enc);
14971 * Ext JS Library 1.1.1
14972 * Copyright(c) 2006-2007, Ext JS, LLC.
14974 * Originally Released Under LGPL - original licence link has changed is not relivant.
14977 * <script type="text/javascript">
14980 * @class Roo.state.Manager
14981 * This is the global state manager. By default all components that are "state aware" check this class
14982 * for state information if you don't pass them a custom state provider. In order for this class
14983 * to be useful, it must be initialized with a provider when your application initializes.
14985 // in your initialization function
14987 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14989 // supposed you have a {@link Roo.BorderLayout}
14990 var layout = new Roo.BorderLayout(...);
14991 layout.restoreState();
14992 // or a {Roo.BasicDialog}
14993 var dialog = new Roo.BasicDialog(...);
14994 dialog.restoreState();
14998 Roo.state.Manager = function(){
14999 var provider = new Roo.state.Provider();
15003 * Configures the default state provider for your application
15004 * @param {Provider} stateProvider The state provider to set
15006 setProvider : function(stateProvider){
15007 provider = stateProvider;
15011 * Returns the current value for a key
15012 * @param {String} name The key name
15013 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15014 * @return {Mixed} The state data
15016 get : function(key, defaultValue){
15017 return provider.get(key, defaultValue);
15021 * Sets the value for a key
15022 * @param {String} name The key name
15023 * @param {Mixed} value The state data
15025 set : function(key, value){
15026 provider.set(key, value);
15030 * Clears a value from the state
15031 * @param {String} name The key name
15033 clear : function(key){
15034 provider.clear(key);
15038 * Gets the currently configured state provider
15039 * @return {Provider} The state provider
15041 getProvider : function(){
15048 * Ext JS Library 1.1.1
15049 * Copyright(c) 2006-2007, Ext JS, LLC.
15051 * Originally Released Under LGPL - original licence link has changed is not relivant.
15054 * <script type="text/javascript">
15057 * @class Roo.state.CookieProvider
15058 * @extends Roo.state.Provider
15059 * The default Provider implementation which saves state via cookies.
15062 var cp = new Roo.state.CookieProvider({
15064 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15065 domain: "roojs.com"
15067 Roo.state.Manager.setProvider(cp);
15069 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15070 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15071 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15072 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15073 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15074 * domain the page is running on including the 'www' like 'www.roojs.com')
15075 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15077 * Create a new CookieProvider
15078 * @param {Object} config The configuration object
15080 Roo.state.CookieProvider = function(config){
15081 Roo.state.CookieProvider.superclass.constructor.call(this);
15083 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15084 this.domain = null;
15085 this.secure = false;
15086 Roo.apply(this, config);
15087 this.state = this.readCookies();
15090 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15092 set : function(name, value){
15093 if(typeof value == "undefined" || value === null){
15097 this.setCookie(name, value);
15098 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15102 clear : function(name){
15103 this.clearCookie(name);
15104 Roo.state.CookieProvider.superclass.clear.call(this, name);
15108 readCookies : function(){
15110 var c = document.cookie + ";";
15111 var re = /\s?(.*?)=(.*?);/g;
15113 while((matches = re.exec(c)) != null){
15114 var name = matches[1];
15115 var value = matches[2];
15116 if(name && name.substring(0,3) == "ys-"){
15117 cookies[name.substr(3)] = this.decodeValue(value);
15124 setCookie : function(name, value){
15125 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15126 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15127 ((this.path == null) ? "" : ("; path=" + this.path)) +
15128 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15129 ((this.secure == true) ? "; secure" : "");
15133 clearCookie : function(name){
15134 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15135 ((this.path == null) ? "" : ("; path=" + this.path)) +
15136 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15137 ((this.secure == true) ? "; secure" : "");
15141 * Ext JS Library 1.1.1
15142 * Copyright(c) 2006-2007, Ext JS, LLC.
15144 * Originally Released Under LGPL - original licence link has changed is not relivant.
15147 * <script type="text/javascript">
15152 * @class Roo.ComponentMgr
15153 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15156 Roo.ComponentMgr = function(){
15157 var all = new Roo.util.MixedCollection();
15161 * Registers a component.
15162 * @param {Roo.Component} c The component
15164 register : function(c){
15169 * Unregisters a component.
15170 * @param {Roo.Component} c The component
15172 unregister : function(c){
15177 * Returns a component by id
15178 * @param {String} id The component id
15180 get : function(id){
15181 return all.get(id);
15185 * Registers a function that will be called when a specified component is added to ComponentMgr
15186 * @param {String} id The component id
15187 * @param {Funtction} fn The callback function
15188 * @param {Object} scope The scope of the callback
15190 onAvailable : function(id, fn, scope){
15191 all.on("add", function(index, o){
15193 fn.call(scope || o, o);
15194 all.un("add", fn, scope);
15201 * Ext JS Library 1.1.1
15202 * Copyright(c) 2006-2007, Ext JS, LLC.
15204 * Originally Released Under LGPL - original licence link has changed is not relivant.
15207 * <script type="text/javascript">
15211 * @class Roo.Component
15212 * @extends Roo.util.Observable
15213 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15214 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15215 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15216 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15217 * All visual components (widgets) that require rendering into a layout should subclass Component.
15219 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15220 * 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
15221 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15223 Roo.Component = function(config){
15224 config = config || {};
15225 if(config.tagName || config.dom || typeof config == "string"){ // element object
15226 config = {el: config, id: config.id || config};
15228 this.initialConfig = config;
15230 Roo.apply(this, config);
15234 * Fires after the component is disabled.
15235 * @param {Roo.Component} this
15240 * Fires after the component is enabled.
15241 * @param {Roo.Component} this
15245 * @event beforeshow
15246 * Fires before the component is shown. Return false to stop the show.
15247 * @param {Roo.Component} this
15252 * Fires after the component is shown.
15253 * @param {Roo.Component} this
15257 * @event beforehide
15258 * Fires before the component is hidden. Return false to stop the hide.
15259 * @param {Roo.Component} this
15264 * Fires after the component is hidden.
15265 * @param {Roo.Component} this
15269 * @event beforerender
15270 * Fires before the component is rendered. Return false to stop the render.
15271 * @param {Roo.Component} this
15273 beforerender : true,
15276 * Fires after the component is rendered.
15277 * @param {Roo.Component} this
15281 * @event beforedestroy
15282 * Fires before the component is destroyed. Return false to stop the destroy.
15283 * @param {Roo.Component} this
15285 beforedestroy : true,
15288 * Fires after the component is destroyed.
15289 * @param {Roo.Component} this
15294 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15296 Roo.ComponentMgr.register(this);
15297 Roo.Component.superclass.constructor.call(this);
15298 this.initComponent();
15299 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15300 this.render(this.renderTo);
15301 delete this.renderTo;
15306 Roo.Component.AUTO_ID = 1000;
15308 Roo.extend(Roo.Component, Roo.util.Observable, {
15310 * @scope Roo.Component.prototype
15312 * true if this component is hidden. Read-only.
15317 * true if this component is disabled. Read-only.
15322 * true if this component has been rendered. Read-only.
15326 /** @cfg {String} disableClass
15327 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15329 disabledClass : "x-item-disabled",
15330 /** @cfg {Boolean} allowDomMove
15331 * Whether the component can move the Dom node when rendering (defaults to true).
15333 allowDomMove : true,
15334 /** @cfg {String} hideMode (display|visibility)
15335 * How this component should hidden. Supported values are
15336 * "visibility" (css visibility), "offsets" (negative offset position) and
15337 * "display" (css display) - defaults to "display".
15339 hideMode: 'display',
15342 ctype : "Roo.Component",
15345 * @cfg {String} actionMode
15346 * which property holds the element that used for hide() / show() / disable() / enable()
15352 getActionEl : function(){
15353 return this[this.actionMode];
15356 initComponent : Roo.emptyFn,
15358 * If this is a lazy rendering component, render it to its container element.
15359 * @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.
15361 render : function(container, position){
15362 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15363 if(!container && this.el){
15364 this.el = Roo.get(this.el);
15365 container = this.el.dom.parentNode;
15366 this.allowDomMove = false;
15368 this.container = Roo.get(container);
15369 this.rendered = true;
15370 if(position !== undefined){
15371 if(typeof position == 'number'){
15372 position = this.container.dom.childNodes[position];
15374 position = Roo.getDom(position);
15377 this.onRender(this.container, position || null);
15379 this.el.addClass(this.cls);
15383 this.el.applyStyles(this.style);
15386 this.fireEvent("render", this);
15387 this.afterRender(this.container);
15399 // default function is not really useful
15400 onRender : function(ct, position){
15402 this.el = Roo.get(this.el);
15403 if(this.allowDomMove !== false){
15404 ct.dom.insertBefore(this.el.dom, position);
15410 getAutoCreate : function(){
15411 var cfg = typeof this.autoCreate == "object" ?
15412 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15413 if(this.id && !cfg.id){
15420 afterRender : Roo.emptyFn,
15423 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15424 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15426 destroy : function(){
15427 if(this.fireEvent("beforedestroy", this) !== false){
15428 this.purgeListeners();
15429 this.beforeDestroy();
15431 this.el.removeAllListeners();
15433 if(this.actionMode == "container"){
15434 this.container.remove();
15438 Roo.ComponentMgr.unregister(this);
15439 this.fireEvent("destroy", this);
15444 beforeDestroy : function(){
15449 onDestroy : function(){
15454 * Returns the underlying {@link Roo.Element}.
15455 * @return {Roo.Element} The element
15457 getEl : function(){
15462 * Returns the id of this component.
15465 getId : function(){
15470 * Try to focus this component.
15471 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15472 * @return {Roo.Component} this
15474 focus : function(selectText){
15477 if(selectText === true){
15478 this.el.dom.select();
15493 * Disable this component.
15494 * @return {Roo.Component} this
15496 disable : function(){
15500 this.disabled = true;
15501 this.fireEvent("disable", this);
15506 onDisable : function(){
15507 this.getActionEl().addClass(this.disabledClass);
15508 this.el.dom.disabled = true;
15512 * Enable this component.
15513 * @return {Roo.Component} this
15515 enable : function(){
15519 this.disabled = false;
15520 this.fireEvent("enable", this);
15525 onEnable : function(){
15526 this.getActionEl().removeClass(this.disabledClass);
15527 this.el.dom.disabled = false;
15531 * Convenience function for setting disabled/enabled by boolean.
15532 * @param {Boolean} disabled
15534 setDisabled : function(disabled){
15535 this[disabled ? "disable" : "enable"]();
15539 * Show this component.
15540 * @return {Roo.Component} this
15543 if(this.fireEvent("beforeshow", this) !== false){
15544 this.hidden = false;
15548 this.fireEvent("show", this);
15554 onShow : function(){
15555 var ae = this.getActionEl();
15556 if(this.hideMode == 'visibility'){
15557 ae.dom.style.visibility = "visible";
15558 }else if(this.hideMode == 'offsets'){
15559 ae.removeClass('x-hidden');
15561 ae.dom.style.display = "";
15566 * Hide this component.
15567 * @return {Roo.Component} this
15570 if(this.fireEvent("beforehide", this) !== false){
15571 this.hidden = true;
15575 this.fireEvent("hide", this);
15581 onHide : function(){
15582 var ae = this.getActionEl();
15583 if(this.hideMode == 'visibility'){
15584 ae.dom.style.visibility = "hidden";
15585 }else if(this.hideMode == 'offsets'){
15586 ae.addClass('x-hidden');
15588 ae.dom.style.display = "none";
15593 * Convenience function to hide or show this component by boolean.
15594 * @param {Boolean} visible True to show, false to hide
15595 * @return {Roo.Component} this
15597 setVisible: function(visible){
15607 * Returns true if this component is visible.
15609 isVisible : function(){
15610 return this.getActionEl().isVisible();
15613 cloneConfig : function(overrides){
15614 overrides = overrides || {};
15615 var id = overrides.id || Roo.id();
15616 var cfg = Roo.applyIf(overrides, this.initialConfig);
15617 cfg.id = id; // prevent dup id
15618 return new this.constructor(cfg);
15622 * Ext JS Library 1.1.1
15623 * Copyright(c) 2006-2007, Ext JS, LLC.
15625 * Originally Released Under LGPL - original licence link has changed is not relivant.
15628 * <script type="text/javascript">
15632 * @class Roo.BoxComponent
15633 * @extends Roo.Component
15634 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15635 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15636 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15637 * layout containers.
15639 * @param {Roo.Element/String/Object} config The configuration options.
15641 Roo.BoxComponent = function(config){
15642 Roo.Component.call(this, config);
15646 * Fires after the component is resized.
15647 * @param {Roo.Component} this
15648 * @param {Number} adjWidth The box-adjusted width that was set
15649 * @param {Number} adjHeight The box-adjusted height that was set
15650 * @param {Number} rawWidth The width that was originally specified
15651 * @param {Number} rawHeight The height that was originally specified
15656 * Fires after the component is moved.
15657 * @param {Roo.Component} this
15658 * @param {Number} x The new x position
15659 * @param {Number} y The new y position
15665 Roo.extend(Roo.BoxComponent, Roo.Component, {
15666 // private, set in afterRender to signify that the component has been rendered
15668 // private, used to defer height settings to subclasses
15669 deferHeight: false,
15670 /** @cfg {Number} width
15671 * width (optional) size of component
15673 /** @cfg {Number} height
15674 * height (optional) size of component
15678 * Sets the width and height of the component. This method fires the resize event. This method can accept
15679 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15680 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15681 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15682 * @return {Roo.BoxComponent} this
15684 setSize : function(w, h){
15685 // support for standard size objects
15686 if(typeof w == 'object'){
15691 if(!this.boxReady){
15697 // prevent recalcs when not needed
15698 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15701 this.lastSize = {width: w, height: h};
15703 var adj = this.adjustSize(w, h);
15704 var aw = adj.width, ah = adj.height;
15705 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15706 var rz = this.getResizeEl();
15707 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15708 rz.setSize(aw, ah);
15709 }else if(!this.deferHeight && ah !== undefined){
15711 }else if(aw !== undefined){
15714 this.onResize(aw, ah, w, h);
15715 this.fireEvent('resize', this, aw, ah, w, h);
15721 * Gets the current size of the component's underlying element.
15722 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15724 getSize : function(){
15725 return this.el.getSize();
15729 * Gets the current XY position of the component's underlying element.
15730 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15731 * @return {Array} The XY position of the element (e.g., [100, 200])
15733 getPosition : function(local){
15734 if(local === true){
15735 return [this.el.getLeft(true), this.el.getTop(true)];
15737 return this.xy || this.el.getXY();
15741 * Gets the current box measurements of the component's underlying element.
15742 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15743 * @returns {Object} box An object in the format {x, y, width, height}
15745 getBox : function(local){
15746 var s = this.el.getSize();
15748 s.x = this.el.getLeft(true);
15749 s.y = this.el.getTop(true);
15751 var xy = this.xy || this.el.getXY();
15759 * Sets the current box measurements of the component's underlying element.
15760 * @param {Object} box An object in the format {x, y, width, height}
15761 * @returns {Roo.BoxComponent} this
15763 updateBox : function(box){
15764 this.setSize(box.width, box.height);
15765 this.setPagePosition(box.x, box.y);
15770 getResizeEl : function(){
15771 return this.resizeEl || this.el;
15775 getPositionEl : function(){
15776 return this.positionEl || this.el;
15780 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15781 * This method fires the move event.
15782 * @param {Number} left The new left
15783 * @param {Number} top The new top
15784 * @returns {Roo.BoxComponent} this
15786 setPosition : function(x, y){
15789 if(!this.boxReady){
15792 var adj = this.adjustPosition(x, y);
15793 var ax = adj.x, ay = adj.y;
15795 var el = this.getPositionEl();
15796 if(ax !== undefined || ay !== undefined){
15797 if(ax !== undefined && ay !== undefined){
15798 el.setLeftTop(ax, ay);
15799 }else if(ax !== undefined){
15801 }else if(ay !== undefined){
15804 this.onPosition(ax, ay);
15805 this.fireEvent('move', this, ax, ay);
15811 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15812 * This method fires the move event.
15813 * @param {Number} x The new x position
15814 * @param {Number} y The new y position
15815 * @returns {Roo.BoxComponent} this
15817 setPagePosition : function(x, y){
15820 if(!this.boxReady){
15823 if(x === undefined || y === undefined){ // cannot translate undefined points
15826 var p = this.el.translatePoints(x, y);
15827 this.setPosition(p.left, p.top);
15832 onRender : function(ct, position){
15833 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15835 this.resizeEl = Roo.get(this.resizeEl);
15837 if(this.positionEl){
15838 this.positionEl = Roo.get(this.positionEl);
15843 afterRender : function(){
15844 Roo.BoxComponent.superclass.afterRender.call(this);
15845 this.boxReady = true;
15846 this.setSize(this.width, this.height);
15847 if(this.x || this.y){
15848 this.setPosition(this.x, this.y);
15850 if(this.pageX || this.pageY){
15851 this.setPagePosition(this.pageX, this.pageY);
15856 * Force the component's size to recalculate based on the underlying element's current height and width.
15857 * @returns {Roo.BoxComponent} this
15859 syncSize : function(){
15860 delete this.lastSize;
15861 this.setSize(this.el.getWidth(), this.el.getHeight());
15866 * Called after the component is resized, this method is empty by default but can be implemented by any
15867 * subclass that needs to perform custom logic after a resize occurs.
15868 * @param {Number} adjWidth The box-adjusted width that was set
15869 * @param {Number} adjHeight The box-adjusted height that was set
15870 * @param {Number} rawWidth The width that was originally specified
15871 * @param {Number} rawHeight The height that was originally specified
15873 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15878 * Called after the component is moved, this method is empty by default but can be implemented by any
15879 * subclass that needs to perform custom logic after a move occurs.
15880 * @param {Number} x The new x position
15881 * @param {Number} y The new y position
15883 onPosition : function(x, y){
15888 adjustSize : function(w, h){
15889 if(this.autoWidth){
15892 if(this.autoHeight){
15895 return {width : w, height: h};
15899 adjustPosition : function(x, y){
15900 return {x : x, y: y};
15903 * Original code for Roojs - LGPL
15904 * <script type="text/javascript">
15908 * @class Roo.XComponent
15909 * A delayed Element creator...
15910 * Or a way to group chunks of interface together.
15911 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15912 * used in conjunction with XComponent.build() it will create an instance of each element,
15913 * then call addxtype() to build the User interface.
15915 * Mypart.xyx = new Roo.XComponent({
15917 parent : 'Mypart.xyz', // empty == document.element.!!
15921 disabled : function() {}
15923 tree : function() { // return an tree of xtype declared components
15927 xtype : 'NestedLayoutPanel',
15934 * It can be used to build a big heiracy, with parent etc.
15935 * or you can just use this to render a single compoent to a dom element
15936 * MYPART.render(Roo.Element | String(id) | dom_element )
15943 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15944 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15946 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15948 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15949 * - if mulitple topModules exist, the last one is defined as the top module.
15953 * When the top level or multiple modules are to embedded into a existing HTML page,
15954 * the parent element can container '#id' of the element where the module will be drawn.
15958 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15959 * it relies more on a include mechanism, where sub modules are included into an outer page.
15960 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15962 * Bootstrap Roo Included elements
15964 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15965 * hence confusing the component builder as it thinks there are multiple top level elements.
15969 * @extends Roo.util.Observable
15971 * @param cfg {Object} configuration of component
15974 Roo.XComponent = function(cfg) {
15975 Roo.apply(this, cfg);
15979 * Fires when this the componnt is built
15980 * @param {Roo.XComponent} c the component
15985 this.region = this.region || 'center'; // default..
15986 Roo.XComponent.register(this);
15987 this.modules = false;
15988 this.el = false; // where the layout goes..
15992 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15995 * The created element (with Roo.factory())
15996 * @type {Roo.Layout}
16002 * for BC - use el in new code
16003 * @type {Roo.Layout}
16009 * for BC - use el in new code
16010 * @type {Roo.Layout}
16015 * @cfg {Function|boolean} disabled
16016 * If this module is disabled by some rule, return true from the funtion
16021 * @cfg {String} parent
16022 * Name of parent element which it get xtype added to..
16027 * @cfg {String} order
16028 * Used to set the order in which elements are created (usefull for multiple tabs)
16033 * @cfg {String} name
16034 * String to display while loading.
16038 * @cfg {String} region
16039 * Region to render component to (defaults to center)
16044 * @cfg {Array} items
16045 * A single item array - the first element is the root of the tree..
16046 * It's done this way to stay compatible with the Xtype system...
16052 * The method that retuns the tree of parts that make up this compoennt
16059 * render element to dom or tree
16060 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16063 render : function(el)
16067 var hp = this.parent ? 1 : 0;
16068 Roo.debug && Roo.log(this);
16070 var tree = this._tree ? this._tree() : this.tree();
16073 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16074 // if parent is a '#.....' string, then let's use that..
16075 var ename = this.parent.substr(1);
16076 this.parent = false;
16077 Roo.debug && Roo.log(ename);
16079 case 'bootstrap-body':
16080 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16081 // this is the BorderLayout standard?
16082 this.parent = { el : true };
16085 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16086 // need to insert stuff...
16088 el : new Roo.bootstrap.layout.Border({
16089 el : document.body,
16095 tabPosition: 'top',
16096 //resizeTabs: true,
16097 alwaysShowTabs: true,
16107 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16108 this.parent = { el : new Roo.bootstrap.Body() };
16109 Roo.debug && Roo.log("setting el to doc body");
16112 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16116 this.parent = { el : true};
16119 el = Roo.get(ename);
16120 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16121 this.parent = { el : true};
16128 if (!el && !this.parent) {
16129 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16134 Roo.debug && Roo.log("EL:");
16135 Roo.debug && Roo.log(el);
16136 Roo.debug && Roo.log("this.parent.el:");
16137 Roo.debug && Roo.log(this.parent.el);
16140 // altertive root elements ??? - we need a better way to indicate these.
16141 var is_alt = Roo.XComponent.is_alt ||
16142 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16143 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16144 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16148 if (!this.parent && is_alt) {
16149 //el = Roo.get(document.body);
16150 this.parent = { el : true };
16155 if (!this.parent) {
16157 Roo.debug && Roo.log("no parent - creating one");
16159 el = el ? Roo.get(el) : false;
16161 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16164 el : new Roo.bootstrap.layout.Border({
16165 el: el || document.body,
16171 tabPosition: 'top',
16172 //resizeTabs: true,
16173 alwaysShowTabs: false,
16176 overflow: 'visible'
16182 // it's a top level one..
16184 el : new Roo.BorderLayout(el || document.body, {
16189 tabPosition: 'top',
16190 //resizeTabs: true,
16191 alwaysShowTabs: el && hp? false : true,
16192 hideTabs: el || !hp ? true : false,
16200 if (!this.parent.el) {
16201 // probably an old style ctor, which has been disabled.
16205 // The 'tree' method is '_tree now'
16207 tree.region = tree.region || this.region;
16208 var is_body = false;
16209 if (this.parent.el === true) {
16210 // bootstrap... - body..
16214 this.parent.el = Roo.factory(tree);
16218 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16219 this.fireEvent('built', this);
16221 this.panel = this.el;
16222 this.layout = this.panel.layout;
16223 this.parentLayout = this.parent.layout || false;
16229 Roo.apply(Roo.XComponent, {
16231 * @property hideProgress
16232 * true to disable the building progress bar.. usefull on single page renders.
16235 hideProgress : false,
16237 * @property buildCompleted
16238 * True when the builder has completed building the interface.
16241 buildCompleted : false,
16244 * @property topModule
16245 * the upper most module - uses document.element as it's constructor.
16252 * @property modules
16253 * array of modules to be created by registration system.
16254 * @type {Array} of Roo.XComponent
16259 * @property elmodules
16260 * array of modules to be created by which use #ID
16261 * @type {Array} of Roo.XComponent
16268 * Is an alternative Root - normally used by bootstrap or other systems,
16269 * where the top element in the tree can wrap 'body'
16270 * @type {boolean} (default false)
16275 * @property build_from_html
16276 * Build elements from html - used by bootstrap HTML stuff
16277 * - this is cleared after build is completed
16278 * @type {boolean} (default false)
16281 build_from_html : false,
16283 * Register components to be built later.
16285 * This solves the following issues
16286 * - Building is not done on page load, but after an authentication process has occured.
16287 * - Interface elements are registered on page load
16288 * - Parent Interface elements may not be loaded before child, so this handles that..
16295 module : 'Pman.Tab.projectMgr',
16297 parent : 'Pman.layout',
16298 disabled : false, // or use a function..
16301 * * @param {Object} details about module
16303 register : function(obj) {
16305 Roo.XComponent.event.fireEvent('register', obj);
16306 switch(typeof(obj.disabled) ) {
16312 if ( obj.disabled() ) {
16318 if (obj.disabled) {
16324 this.modules.push(obj);
16328 * convert a string to an object..
16329 * eg. 'AAA.BBB' -> finds AAA.BBB
16333 toObject : function(str)
16335 if (!str || typeof(str) == 'object') {
16338 if (str.substring(0,1) == '#') {
16342 var ar = str.split('.');
16347 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16349 throw "Module not found : " + str;
16353 throw "Module not found : " + str;
16355 Roo.each(ar, function(e) {
16356 if (typeof(o[e]) == 'undefined') {
16357 throw "Module not found : " + str;
16368 * move modules into their correct place in the tree..
16371 preBuild : function ()
16374 Roo.each(this.modules , function (obj)
16376 Roo.XComponent.event.fireEvent('beforebuild', obj);
16378 var opar = obj.parent;
16380 obj.parent = this.toObject(opar);
16382 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16387 Roo.debug && Roo.log("GOT top level module");
16388 Roo.debug && Roo.log(obj);
16389 obj.modules = new Roo.util.MixedCollection(false,
16390 function(o) { return o.order + '' }
16392 this.topModule = obj;
16395 // parent is a string (usually a dom element name..)
16396 if (typeof(obj.parent) == 'string') {
16397 this.elmodules.push(obj);
16400 if (obj.parent.constructor != Roo.XComponent) {
16401 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16403 if (!obj.parent.modules) {
16404 obj.parent.modules = new Roo.util.MixedCollection(false,
16405 function(o) { return o.order + '' }
16408 if (obj.parent.disabled) {
16409 obj.disabled = true;
16411 obj.parent.modules.add(obj);
16416 * make a list of modules to build.
16417 * @return {Array} list of modules.
16420 buildOrder : function()
16423 var cmp = function(a,b) {
16424 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16426 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16427 throw "No top level modules to build";
16430 // make a flat list in order of modules to build.
16431 var mods = this.topModule ? [ this.topModule ] : [];
16434 // elmodules (is a list of DOM based modules )
16435 Roo.each(this.elmodules, function(e) {
16437 if (!this.topModule &&
16438 typeof(e.parent) == 'string' &&
16439 e.parent.substring(0,1) == '#' &&
16440 Roo.get(e.parent.substr(1))
16443 _this.topModule = e;
16449 // add modules to their parents..
16450 var addMod = function(m) {
16451 Roo.debug && Roo.log("build Order: add: " + m.name);
16454 if (m.modules && !m.disabled) {
16455 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16456 m.modules.keySort('ASC', cmp );
16457 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16459 m.modules.each(addMod);
16461 Roo.debug && Roo.log("build Order: no child modules");
16463 // not sure if this is used any more..
16465 m.finalize.name = m.name + " (clean up) ";
16466 mods.push(m.finalize);
16470 if (this.topModule && this.topModule.modules) {
16471 this.topModule.modules.keySort('ASC', cmp );
16472 this.topModule.modules.each(addMod);
16478 * Build the registered modules.
16479 * @param {Object} parent element.
16480 * @param {Function} optional method to call after module has been added.
16484 build : function(opts)
16487 if (typeof(opts) != 'undefined') {
16488 Roo.apply(this,opts);
16492 var mods = this.buildOrder();
16494 //this.allmods = mods;
16495 //Roo.debug && Roo.log(mods);
16497 if (!mods.length) { // should not happen
16498 throw "NO modules!!!";
16502 var msg = "Building Interface...";
16503 // flash it up as modal - so we store the mask!?
16504 if (!this.hideProgress && Roo.MessageBox) {
16505 Roo.MessageBox.show({ title: 'loading' });
16506 Roo.MessageBox.show({
16507 title: "Please wait...",
16516 var total = mods.length;
16519 var progressRun = function() {
16520 if (!mods.length) {
16521 Roo.debug && Roo.log('hide?');
16522 if (!this.hideProgress && Roo.MessageBox) {
16523 Roo.MessageBox.hide();
16525 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16527 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16533 var m = mods.shift();
16536 Roo.debug && Roo.log(m);
16537 // not sure if this is supported any more.. - modules that are are just function
16538 if (typeof(m) == 'function') {
16540 return progressRun.defer(10, _this);
16544 msg = "Building Interface " + (total - mods.length) +
16546 (m.name ? (' - ' + m.name) : '');
16547 Roo.debug && Roo.log(msg);
16548 if (!_this.hideProgress && Roo.MessageBox) {
16549 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16553 // is the module disabled?
16554 var disabled = (typeof(m.disabled) == 'function') ?
16555 m.disabled.call(m.module.disabled) : m.disabled;
16559 return progressRun(); // we do not update the display!
16567 // it's 10 on top level, and 1 on others??? why...
16568 return progressRun.defer(10, _this);
16571 progressRun.defer(1, _this);
16585 * wrapper for event.on - aliased later..
16586 * Typically use to register a event handler for register:
16588 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16597 Roo.XComponent.event = new Roo.util.Observable({
16601 * Fires when an Component is registered,
16602 * set the disable property on the Component to stop registration.
16603 * @param {Roo.XComponent} c the component being registerd.
16608 * @event beforebuild
16609 * Fires before each Component is built
16610 * can be used to apply permissions.
16611 * @param {Roo.XComponent} c the component being registerd.
16614 'beforebuild' : true,
16616 * @event buildcomplete
16617 * Fires on the top level element when all elements have been built
16618 * @param {Roo.XComponent} the top level component.
16620 'buildcomplete' : true
16625 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16628 * marked - a markdown parser
16629 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16630 * https://github.com/chjj/marked
16636 * Roo.Markdown - is a very crude wrapper around marked..
16640 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16642 * Note: move the sample code to the bottom of this
16643 * file before uncommenting it.
16648 Roo.Markdown.toHtml = function(text) {
16650 var c = new Roo.Markdown.marked.setOptions({
16651 renderer: new Roo.Markdown.marked.Renderer(),
16662 text = text.replace(/\\\n/g,' ');
16663 return Roo.Markdown.marked(text);
16668 // Wraps all "globals" so that the only thing
16669 // exposed is makeHtml().
16674 * Block-Level Grammar
16679 code: /^( {4}[^\n]+\n*)+/,
16681 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16682 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16684 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16685 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16686 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16687 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16688 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16690 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16694 block.bullet = /(?:[*+-]|\d+\.)/;
16695 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16696 block.item = replace(block.item, 'gm')
16697 (/bull/g, block.bullet)
16700 block.list = replace(block.list)
16701 (/bull/g, block.bullet)
16702 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16703 ('def', '\\n+(?=' + block.def.source + ')')
16706 block.blockquote = replace(block.blockquote)
16710 block._tag = '(?!(?:'
16711 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16712 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16713 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16715 block.html = replace(block.html)
16716 ('comment', /<!--[\s\S]*?-->/)
16717 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16718 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16719 (/tag/g, block._tag)
16722 block.paragraph = replace(block.paragraph)
16724 ('heading', block.heading)
16725 ('lheading', block.lheading)
16726 ('blockquote', block.blockquote)
16727 ('tag', '<' + block._tag)
16732 * Normal Block Grammar
16735 block.normal = merge({}, block);
16738 * GFM Block Grammar
16741 block.gfm = merge({}, block.normal, {
16742 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16744 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16747 block.gfm.paragraph = replace(block.paragraph)
16749 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16750 + block.list.source.replace('\\1', '\\3') + '|')
16754 * GFM + Tables Block Grammar
16757 block.tables = merge({}, block.gfm, {
16758 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16759 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16766 function Lexer(options) {
16768 this.tokens.links = {};
16769 this.options = options || marked.defaults;
16770 this.rules = block.normal;
16772 if (this.options.gfm) {
16773 if (this.options.tables) {
16774 this.rules = block.tables;
16776 this.rules = block.gfm;
16782 * Expose Block Rules
16785 Lexer.rules = block;
16788 * Static Lex Method
16791 Lexer.lex = function(src, options) {
16792 var lexer = new Lexer(options);
16793 return lexer.lex(src);
16800 Lexer.prototype.lex = function(src) {
16802 .replace(/\r\n|\r/g, '\n')
16803 .replace(/\t/g, ' ')
16804 .replace(/\u00a0/g, ' ')
16805 .replace(/\u2424/g, '\n');
16807 return this.token(src, true);
16814 Lexer.prototype.token = function(src, top, bq) {
16815 var src = src.replace(/^ +$/gm, '')
16828 if (cap = this.rules.newline.exec(src)) {
16829 src = src.substring(cap[0].length);
16830 if (cap[0].length > 1) {
16838 if (cap = this.rules.code.exec(src)) {
16839 src = src.substring(cap[0].length);
16840 cap = cap[0].replace(/^ {4}/gm, '');
16843 text: !this.options.pedantic
16844 ? cap.replace(/\n+$/, '')
16851 if (cap = this.rules.fences.exec(src)) {
16852 src = src.substring(cap[0].length);
16862 if (cap = this.rules.heading.exec(src)) {
16863 src = src.substring(cap[0].length);
16866 depth: cap[1].length,
16872 // table no leading pipe (gfm)
16873 if (top && (cap = this.rules.nptable.exec(src))) {
16874 src = src.substring(cap[0].length);
16878 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16879 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16880 cells: cap[3].replace(/\n$/, '').split('\n')
16883 for (i = 0; i < item.align.length; i++) {
16884 if (/^ *-+: *$/.test(item.align[i])) {
16885 item.align[i] = 'right';
16886 } else if (/^ *:-+: *$/.test(item.align[i])) {
16887 item.align[i] = 'center';
16888 } else if (/^ *:-+ *$/.test(item.align[i])) {
16889 item.align[i] = 'left';
16891 item.align[i] = null;
16895 for (i = 0; i < item.cells.length; i++) {
16896 item.cells[i] = item.cells[i].split(/ *\| */);
16899 this.tokens.push(item);
16905 if (cap = this.rules.lheading.exec(src)) {
16906 src = src.substring(cap[0].length);
16909 depth: cap[2] === '=' ? 1 : 2,
16916 if (cap = this.rules.hr.exec(src)) {
16917 src = src.substring(cap[0].length);
16925 if (cap = this.rules.blockquote.exec(src)) {
16926 src = src.substring(cap[0].length);
16929 type: 'blockquote_start'
16932 cap = cap[0].replace(/^ *> ?/gm, '');
16934 // Pass `top` to keep the current
16935 // "toplevel" state. This is exactly
16936 // how markdown.pl works.
16937 this.token(cap, top, true);
16940 type: 'blockquote_end'
16947 if (cap = this.rules.list.exec(src)) {
16948 src = src.substring(cap[0].length);
16952 type: 'list_start',
16953 ordered: bull.length > 1
16956 // Get each top-level item.
16957 cap = cap[0].match(this.rules.item);
16963 for (; i < l; i++) {
16966 // Remove the list item's bullet
16967 // so it is seen as the next token.
16968 space = item.length;
16969 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16971 // Outdent whatever the
16972 // list item contains. Hacky.
16973 if (~item.indexOf('\n ')) {
16974 space -= item.length;
16975 item = !this.options.pedantic
16976 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16977 : item.replace(/^ {1,4}/gm, '');
16980 // Determine whether the next list item belongs here.
16981 // Backpedal if it does not belong in this list.
16982 if (this.options.smartLists && i !== l - 1) {
16983 b = block.bullet.exec(cap[i + 1])[0];
16984 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16985 src = cap.slice(i + 1).join('\n') + src;
16990 // Determine whether item is loose or not.
16991 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16992 // for discount behavior.
16993 loose = next || /\n\n(?!\s*$)/.test(item);
16995 next = item.charAt(item.length - 1) === '\n';
16996 if (!loose) { loose = next; }
17001 ? 'loose_item_start'
17002 : 'list_item_start'
17006 this.token(item, false, bq);
17009 type: 'list_item_end'
17021 if (cap = this.rules.html.exec(src)) {
17022 src = src.substring(cap[0].length);
17024 type: this.options.sanitize
17027 pre: !this.options.sanitizer
17028 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17035 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17036 src = src.substring(cap[0].length);
17037 this.tokens.links[cap[1].toLowerCase()] = {
17045 if (top && (cap = this.rules.table.exec(src))) {
17046 src = src.substring(cap[0].length);
17050 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17051 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17052 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17055 for (i = 0; i < item.align.length; i++) {
17056 if (/^ *-+: *$/.test(item.align[i])) {
17057 item.align[i] = 'right';
17058 } else if (/^ *:-+: *$/.test(item.align[i])) {
17059 item.align[i] = 'center';
17060 } else if (/^ *:-+ *$/.test(item.align[i])) {
17061 item.align[i] = 'left';
17063 item.align[i] = null;
17067 for (i = 0; i < item.cells.length; i++) {
17068 item.cells[i] = item.cells[i]
17069 .replace(/^ *\| *| *\| *$/g, '')
17073 this.tokens.push(item);
17078 // top-level paragraph
17079 if (top && (cap = this.rules.paragraph.exec(src))) {
17080 src = src.substring(cap[0].length);
17083 text: cap[1].charAt(cap[1].length - 1) === '\n'
17084 ? cap[1].slice(0, -1)
17091 if (cap = this.rules.text.exec(src)) {
17092 // Top-level should never reach here.
17093 src = src.substring(cap[0].length);
17103 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17107 return this.tokens;
17111 * Inline-Level Grammar
17115 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17116 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17118 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17119 link: /^!?\[(inside)\]\(href\)/,
17120 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17121 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17122 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17123 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17124 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17125 br: /^ {2,}\n(?!\s*$)/,
17127 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17130 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17131 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17133 inline.link = replace(inline.link)
17134 ('inside', inline._inside)
17135 ('href', inline._href)
17138 inline.reflink = replace(inline.reflink)
17139 ('inside', inline._inside)
17143 * Normal Inline Grammar
17146 inline.normal = merge({}, inline);
17149 * Pedantic Inline Grammar
17152 inline.pedantic = merge({}, inline.normal, {
17153 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17154 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17158 * GFM Inline Grammar
17161 inline.gfm = merge({}, inline.normal, {
17162 escape: replace(inline.escape)('])', '~|])')(),
17163 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17164 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17165 text: replace(inline.text)
17167 ('|', '|https?://|')
17172 * GFM + Line Breaks Inline Grammar
17175 inline.breaks = merge({}, inline.gfm, {
17176 br: replace(inline.br)('{2,}', '*')(),
17177 text: replace(inline.gfm.text)('{2,}', '*')()
17181 * Inline Lexer & Compiler
17184 function InlineLexer(links, options) {
17185 this.options = options || marked.defaults;
17186 this.links = links;
17187 this.rules = inline.normal;
17188 this.renderer = this.options.renderer || new Renderer;
17189 this.renderer.options = this.options;
17193 Error('Tokens array requires a `links` property.');
17196 if (this.options.gfm) {
17197 if (this.options.breaks) {
17198 this.rules = inline.breaks;
17200 this.rules = inline.gfm;
17202 } else if (this.options.pedantic) {
17203 this.rules = inline.pedantic;
17208 * Expose Inline Rules
17211 InlineLexer.rules = inline;
17214 * Static Lexing/Compiling Method
17217 InlineLexer.output = function(src, links, options) {
17218 var inline = new InlineLexer(links, options);
17219 return inline.output(src);
17226 InlineLexer.prototype.output = function(src) {
17235 if (cap = this.rules.escape.exec(src)) {
17236 src = src.substring(cap[0].length);
17242 if (cap = this.rules.autolink.exec(src)) {
17243 src = src.substring(cap[0].length);
17244 if (cap[2] === '@') {
17245 text = cap[1].charAt(6) === ':'
17246 ? this.mangle(cap[1].substring(7))
17247 : this.mangle(cap[1]);
17248 href = this.mangle('mailto:') + text;
17250 text = escape(cap[1]);
17253 out += this.renderer.link(href, null, text);
17258 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17259 src = src.substring(cap[0].length);
17260 text = escape(cap[1]);
17262 out += this.renderer.link(href, null, text);
17267 if (cap = this.rules.tag.exec(src)) {
17268 if (!this.inLink && /^<a /i.test(cap[0])) {
17269 this.inLink = true;
17270 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17271 this.inLink = false;
17273 src = src.substring(cap[0].length);
17274 out += this.options.sanitize
17275 ? this.options.sanitizer
17276 ? this.options.sanitizer(cap[0])
17283 if (cap = this.rules.link.exec(src)) {
17284 src = src.substring(cap[0].length);
17285 this.inLink = true;
17286 out += this.outputLink(cap, {
17290 this.inLink = false;
17295 if ((cap = this.rules.reflink.exec(src))
17296 || (cap = this.rules.nolink.exec(src))) {
17297 src = src.substring(cap[0].length);
17298 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17299 link = this.links[link.toLowerCase()];
17300 if (!link || !link.href) {
17301 out += cap[0].charAt(0);
17302 src = cap[0].substring(1) + src;
17305 this.inLink = true;
17306 out += this.outputLink(cap, link);
17307 this.inLink = false;
17312 if (cap = this.rules.strong.exec(src)) {
17313 src = src.substring(cap[0].length);
17314 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17319 if (cap = this.rules.em.exec(src)) {
17320 src = src.substring(cap[0].length);
17321 out += this.renderer.em(this.output(cap[2] || cap[1]));
17326 if (cap = this.rules.code.exec(src)) {
17327 src = src.substring(cap[0].length);
17328 out += this.renderer.codespan(escape(cap[2], true));
17333 if (cap = this.rules.br.exec(src)) {
17334 src = src.substring(cap[0].length);
17335 out += this.renderer.br();
17340 if (cap = this.rules.del.exec(src)) {
17341 src = src.substring(cap[0].length);
17342 out += this.renderer.del(this.output(cap[1]));
17347 if (cap = this.rules.text.exec(src)) {
17348 src = src.substring(cap[0].length);
17349 out += this.renderer.text(escape(this.smartypants(cap[0])));
17355 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17366 InlineLexer.prototype.outputLink = function(cap, link) {
17367 var href = escape(link.href)
17368 , title = link.title ? escape(link.title) : null;
17370 return cap[0].charAt(0) !== '!'
17371 ? this.renderer.link(href, title, this.output(cap[1]))
17372 : this.renderer.image(href, title, escape(cap[1]));
17376 * Smartypants Transformations
17379 InlineLexer.prototype.smartypants = function(text) {
17380 if (!this.options.smartypants) { return text; }
17383 .replace(/---/g, '\u2014')
17385 .replace(/--/g, '\u2013')
17387 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17388 // closing singles & apostrophes
17389 .replace(/'/g, '\u2019')
17391 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17393 .replace(/"/g, '\u201d')
17395 .replace(/\.{3}/g, '\u2026');
17402 InlineLexer.prototype.mangle = function(text) {
17403 if (!this.options.mangle) { return text; }
17409 for (; i < l; i++) {
17410 ch = text.charCodeAt(i);
17411 if (Math.random() > 0.5) {
17412 ch = 'x' + ch.toString(16);
17414 out += '&#' + ch + ';';
17424 function Renderer(options) {
17425 this.options = options || {};
17428 Renderer.prototype.code = function(code, lang, escaped) {
17429 if (this.options.highlight) {
17430 var out = this.options.highlight(code, lang);
17431 if (out != null && out !== code) {
17436 // hack!!! - it's already escapeD?
17441 return '<pre><code>'
17442 + (escaped ? code : escape(code, true))
17443 + '\n</code></pre>';
17446 return '<pre><code class="'
17447 + this.options.langPrefix
17448 + escape(lang, true)
17450 + (escaped ? code : escape(code, true))
17451 + '\n</code></pre>\n';
17454 Renderer.prototype.blockquote = function(quote) {
17455 return '<blockquote>\n' + quote + '</blockquote>\n';
17458 Renderer.prototype.html = function(html) {
17462 Renderer.prototype.heading = function(text, level, raw) {
17466 + this.options.headerPrefix
17467 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17475 Renderer.prototype.hr = function() {
17476 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17479 Renderer.prototype.list = function(body, ordered) {
17480 var type = ordered ? 'ol' : 'ul';
17481 return '<' + type + '>\n' + body + '</' + type + '>\n';
17484 Renderer.prototype.listitem = function(text) {
17485 return '<li>' + text + '</li>\n';
17488 Renderer.prototype.paragraph = function(text) {
17489 return '<p>' + text + '</p>\n';
17492 Renderer.prototype.table = function(header, body) {
17493 return '<table class="table table-striped">\n'
17503 Renderer.prototype.tablerow = function(content) {
17504 return '<tr>\n' + content + '</tr>\n';
17507 Renderer.prototype.tablecell = function(content, flags) {
17508 var type = flags.header ? 'th' : 'td';
17509 var tag = flags.align
17510 ? '<' + type + ' style="text-align:' + flags.align + '">'
17511 : '<' + type + '>';
17512 return tag + content + '</' + type + '>\n';
17515 // span level renderer
17516 Renderer.prototype.strong = function(text) {
17517 return '<strong>' + text + '</strong>';
17520 Renderer.prototype.em = function(text) {
17521 return '<em>' + text + '</em>';
17524 Renderer.prototype.codespan = function(text) {
17525 return '<code>' + text + '</code>';
17528 Renderer.prototype.br = function() {
17529 return this.options.xhtml ? '<br/>' : '<br>';
17532 Renderer.prototype.del = function(text) {
17533 return '<del>' + text + '</del>';
17536 Renderer.prototype.link = function(href, title, text) {
17537 if (this.options.sanitize) {
17539 var prot = decodeURIComponent(unescape(href))
17540 .replace(/[^\w:]/g, '')
17545 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17549 var out = '<a href="' + href + '"';
17551 out += ' title="' + title + '"';
17553 out += '>' + text + '</a>';
17557 Renderer.prototype.image = function(href, title, text) {
17558 var out = '<img src="' + href + '" alt="' + text + '"';
17560 out += ' title="' + title + '"';
17562 out += this.options.xhtml ? '/>' : '>';
17566 Renderer.prototype.text = function(text) {
17571 * Parsing & Compiling
17574 function Parser(options) {
17577 this.options = options || marked.defaults;
17578 this.options.renderer = this.options.renderer || new Renderer;
17579 this.renderer = this.options.renderer;
17580 this.renderer.options = this.options;
17584 * Static Parse Method
17587 Parser.parse = function(src, options, renderer) {
17588 var parser = new Parser(options, renderer);
17589 return parser.parse(src);
17596 Parser.prototype.parse = function(src) {
17597 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17598 this.tokens = src.reverse();
17601 while (this.next()) {
17612 Parser.prototype.next = function() {
17613 return this.token = this.tokens.pop();
17617 * Preview Next Token
17620 Parser.prototype.peek = function() {
17621 return this.tokens[this.tokens.length - 1] || 0;
17625 * Parse Text Tokens
17628 Parser.prototype.parseText = function() {
17629 var body = this.token.text;
17631 while (this.peek().type === 'text') {
17632 body += '\n' + this.next().text;
17635 return this.inline.output(body);
17639 * Parse Current Token
17642 Parser.prototype.tok = function() {
17643 switch (this.token.type) {
17648 return this.renderer.hr();
17651 return this.renderer.heading(
17652 this.inline.output(this.token.text),
17657 return this.renderer.code(this.token.text,
17659 this.token.escaped);
17672 for (i = 0; i < this.token.header.length; i++) {
17673 flags = { header: true, align: this.token.align[i] };
17674 cell += this.renderer.tablecell(
17675 this.inline.output(this.token.header[i]),
17676 { header: true, align: this.token.align[i] }
17679 header += this.renderer.tablerow(cell);
17681 for (i = 0; i < this.token.cells.length; i++) {
17682 row = this.token.cells[i];
17685 for (j = 0; j < row.length; j++) {
17686 cell += this.renderer.tablecell(
17687 this.inline.output(row[j]),
17688 { header: false, align: this.token.align[j] }
17692 body += this.renderer.tablerow(cell);
17694 return this.renderer.table(header, body);
17696 case 'blockquote_start': {
17699 while (this.next().type !== 'blockquote_end') {
17700 body += this.tok();
17703 return this.renderer.blockquote(body);
17705 case 'list_start': {
17707 , ordered = this.token.ordered;
17709 while (this.next().type !== 'list_end') {
17710 body += this.tok();
17713 return this.renderer.list(body, ordered);
17715 case 'list_item_start': {
17718 while (this.next().type !== 'list_item_end') {
17719 body += this.token.type === 'text'
17724 return this.renderer.listitem(body);
17726 case 'loose_item_start': {
17729 while (this.next().type !== 'list_item_end') {
17730 body += this.tok();
17733 return this.renderer.listitem(body);
17736 var html = !this.token.pre && !this.options.pedantic
17737 ? this.inline.output(this.token.text)
17739 return this.renderer.html(html);
17741 case 'paragraph': {
17742 return this.renderer.paragraph(this.inline.output(this.token.text));
17745 return this.renderer.paragraph(this.parseText());
17754 function escape(html, encode) {
17756 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17757 .replace(/</g, '<')
17758 .replace(/>/g, '>')
17759 .replace(/"/g, '"')
17760 .replace(/'/g, ''');
17763 function unescape(html) {
17764 // explicitly match decimal, hex, and named HTML entities
17765 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17766 n = n.toLowerCase();
17767 if (n === 'colon') { return ':'; }
17768 if (n.charAt(0) === '#') {
17769 return n.charAt(1) === 'x'
17770 ? String.fromCharCode(parseInt(n.substring(2), 16))
17771 : String.fromCharCode(+n.substring(1));
17777 function replace(regex, opt) {
17778 regex = regex.source;
17780 return function self(name, val) {
17781 if (!name) { return new RegExp(regex, opt); }
17782 val = val.source || val;
17783 val = val.replace(/(^|[^\[])\^/g, '$1');
17784 regex = regex.replace(name, val);
17792 function merge(obj) {
17797 for (; i < arguments.length; i++) {
17798 target = arguments[i];
17799 for (key in target) {
17800 if (Object.prototype.hasOwnProperty.call(target, key)) {
17801 obj[key] = target[key];
17814 function marked(src, opt, callback) {
17815 if (callback || typeof opt === 'function') {
17821 opt = merge({}, marked.defaults, opt || {});
17823 var highlight = opt.highlight
17829 tokens = Lexer.lex(src, opt)
17831 return callback(e);
17834 pending = tokens.length;
17836 var done = function(err) {
17838 opt.highlight = highlight;
17839 return callback(err);
17845 out = Parser.parse(tokens, opt);
17850 opt.highlight = highlight;
17854 : callback(null, out);
17857 if (!highlight || highlight.length < 3) {
17861 delete opt.highlight;
17863 if (!pending) { return done(); }
17865 for (; i < tokens.length; i++) {
17867 if (token.type !== 'code') {
17868 return --pending || done();
17870 return highlight(token.text, token.lang, function(err, code) {
17871 if (err) { return done(err); }
17872 if (code == null || code === token.text) {
17873 return --pending || done();
17876 token.escaped = true;
17877 --pending || done();
17885 if (opt) { opt = merge({}, marked.defaults, opt); }
17886 return Parser.parse(Lexer.lex(src, opt), opt);
17888 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17889 if ((opt || marked.defaults).silent) {
17890 return '<p>An error occured:</p><pre>'
17891 + escape(e.message + '', true)
17903 marked.setOptions = function(opt) {
17904 merge(marked.defaults, opt);
17908 marked.defaults = {
17919 langPrefix: 'lang-',
17920 smartypants: false,
17922 renderer: new Renderer,
17930 marked.Parser = Parser;
17931 marked.parser = Parser.parse;
17933 marked.Renderer = Renderer;
17935 marked.Lexer = Lexer;
17936 marked.lexer = Lexer.lex;
17938 marked.InlineLexer = InlineLexer;
17939 marked.inlineLexer = InlineLexer.output;
17941 marked.parse = marked;
17943 Roo.Markdown.marked = marked;
17947 * Ext JS Library 1.1.1
17948 * Copyright(c) 2006-2007, Ext JS, LLC.
17950 * Originally Released Under LGPL - original licence link has changed is not relivant.
17953 * <script type="text/javascript">
17959 * These classes are derivatives of the similarly named classes in the YUI Library.
17960 * The original license:
17961 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17962 * Code licensed under the BSD License:
17963 * http://developer.yahoo.net/yui/license.txt
17968 var Event=Roo.EventManager;
17969 var Dom=Roo.lib.Dom;
17972 * @class Roo.dd.DragDrop
17973 * @extends Roo.util.Observable
17974 * Defines the interface and base operation of items that that can be
17975 * dragged or can be drop targets. It was designed to be extended, overriding
17976 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17977 * Up to three html elements can be associated with a DragDrop instance:
17979 * <li>linked element: the element that is passed into the constructor.
17980 * This is the element which defines the boundaries for interaction with
17981 * other DragDrop objects.</li>
17982 * <li>handle element(s): The drag operation only occurs if the element that
17983 * was clicked matches a handle element. By default this is the linked
17984 * element, but there are times that you will want only a portion of the
17985 * linked element to initiate the drag operation, and the setHandleElId()
17986 * method provides a way to define this.</li>
17987 * <li>drag element: this represents the element that would be moved along
17988 * with the cursor during a drag operation. By default, this is the linked
17989 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
17990 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17993 * This class should not be instantiated until the onload event to ensure that
17994 * the associated elements are available.
17995 * The following would define a DragDrop obj that would interact with any
17996 * other DragDrop obj in the "group1" group:
17998 * dd = new Roo.dd.DragDrop("div1", "group1");
18000 * Since none of the event handlers have been implemented, nothing would
18001 * actually happen if you were to run the code above. Normally you would
18002 * override this class or one of the default implementations, but you can
18003 * also override the methods you want on an instance of the class...
18005 * dd.onDragDrop = function(e, id) {
18006 * alert("dd was dropped on " + id);
18010 * @param {String} id of the element that is linked to this instance
18011 * @param {String} sGroup the group of related DragDrop objects
18012 * @param {object} config an object containing configurable attributes
18013 * Valid properties for DragDrop:
18014 * padding, isTarget, maintainOffset, primaryButtonOnly
18016 Roo.dd.DragDrop = function(id, sGroup, config) {
18018 this.init(id, sGroup, config);
18023 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18026 * The id of the element associated with this object. This is what we
18027 * refer to as the "linked element" because the size and position of
18028 * this element is used to determine when the drag and drop objects have
18036 * Configuration attributes passed into the constructor
18043 * The id of the element that will be dragged. By default this is same
18044 * as the linked element , but could be changed to another element. Ex:
18046 * @property dragElId
18053 * the id of the element that initiates the drag operation. By default
18054 * this is the linked element, but could be changed to be a child of this
18055 * element. This lets us do things like only starting the drag when the
18056 * header element within the linked html element is clicked.
18057 * @property handleElId
18064 * An associative array of HTML tags that will be ignored if clicked.
18065 * @property invalidHandleTypes
18066 * @type {string: string}
18068 invalidHandleTypes: null,
18071 * An associative array of ids for elements that will be ignored if clicked
18072 * @property invalidHandleIds
18073 * @type {string: string}
18075 invalidHandleIds: null,
18078 * An indexted array of css class names for elements that will be ignored
18080 * @property invalidHandleClasses
18083 invalidHandleClasses: null,
18086 * The linked element's absolute X position at the time the drag was
18088 * @property startPageX
18095 * The linked element's absolute X position at the time the drag was
18097 * @property startPageY
18104 * The group defines a logical collection of DragDrop objects that are
18105 * related. Instances only get events when interacting with other
18106 * DragDrop object in the same group. This lets us define multiple
18107 * groups using a single DragDrop subclass if we want.
18109 * @type {string: string}
18114 * Individual drag/drop instances can be locked. This will prevent
18115 * onmousedown start drag.
18123 * Lock this instance
18126 lock: function() { this.locked = true; },
18129 * Unlock this instace
18132 unlock: function() { this.locked = false; },
18135 * By default, all insances can be a drop target. This can be disabled by
18136 * setting isTarget to false.
18143 * The padding configured for this drag and drop object for calculating
18144 * the drop zone intersection with this object.
18151 * Cached reference to the linked element
18152 * @property _domRef
18158 * Internal typeof flag
18159 * @property __ygDragDrop
18162 __ygDragDrop: true,
18165 * Set to true when horizontal contraints are applied
18166 * @property constrainX
18173 * Set to true when vertical contraints are applied
18174 * @property constrainY
18181 * The left constraint
18189 * The right constraint
18197 * The up constraint
18206 * The down constraint
18214 * Maintain offsets when we resetconstraints. Set to true when you want
18215 * the position of the element relative to its parent to stay the same
18216 * when the page changes
18218 * @property maintainOffset
18221 maintainOffset: false,
18224 * Array of pixel locations the element will snap to if we specified a
18225 * horizontal graduation/interval. This array is generated automatically
18226 * when you define a tick interval.
18233 * Array of pixel locations the element will snap to if we specified a
18234 * vertical graduation/interval. This array is generated automatically
18235 * when you define a tick interval.
18242 * By default the drag and drop instance will only respond to the primary
18243 * button click (left button for a right-handed mouse). Set to true to
18244 * allow drag and drop to start with any mouse click that is propogated
18246 * @property primaryButtonOnly
18249 primaryButtonOnly: true,
18252 * The availabe property is false until the linked dom element is accessible.
18253 * @property available
18259 * By default, drags can only be initiated if the mousedown occurs in the
18260 * region the linked element is. This is done in part to work around a
18261 * bug in some browsers that mis-report the mousedown if the previous
18262 * mouseup happened outside of the window. This property is set to true
18263 * if outer handles are defined.
18265 * @property hasOuterHandles
18269 hasOuterHandles: false,
18272 * Code that executes immediately before the startDrag event
18273 * @method b4StartDrag
18276 b4StartDrag: function(x, y) { },
18279 * Abstract method called after a drag/drop object is clicked
18280 * and the drag or mousedown time thresholds have beeen met.
18281 * @method startDrag
18282 * @param {int} X click location
18283 * @param {int} Y click location
18285 startDrag: function(x, y) { /* override this */ },
18288 * Code that executes immediately before the onDrag event
18292 b4Drag: function(e) { },
18295 * Abstract method called during the onMouseMove event while dragging an
18298 * @param {Event} e the mousemove event
18300 onDrag: function(e) { /* override this */ },
18303 * Abstract method called when this element fist begins hovering over
18304 * another DragDrop obj
18305 * @method onDragEnter
18306 * @param {Event} e the mousemove event
18307 * @param {String|DragDrop[]} id In POINT mode, the element
18308 * id this is hovering over. In INTERSECT mode, an array of one or more
18309 * dragdrop items being hovered over.
18311 onDragEnter: function(e, id) { /* override this */ },
18314 * Code that executes immediately before the onDragOver event
18315 * @method b4DragOver
18318 b4DragOver: function(e) { },
18321 * Abstract method called when this element is hovering over another
18323 * @method onDragOver
18324 * @param {Event} e the mousemove event
18325 * @param {String|DragDrop[]} id In POINT mode, the element
18326 * id this is hovering over. In INTERSECT mode, an array of dd items
18327 * being hovered over.
18329 onDragOver: function(e, id) { /* override this */ },
18332 * Code that executes immediately before the onDragOut event
18333 * @method b4DragOut
18336 b4DragOut: function(e) { },
18339 * Abstract method called when we are no longer hovering over an element
18340 * @method onDragOut
18341 * @param {Event} e the mousemove event
18342 * @param {String|DragDrop[]} id In POINT mode, the element
18343 * id this was hovering over. In INTERSECT mode, an array of dd items
18344 * that the mouse is no longer over.
18346 onDragOut: function(e, id) { /* override this */ },
18349 * Code that executes immediately before the onDragDrop event
18350 * @method b4DragDrop
18353 b4DragDrop: function(e) { },
18356 * Abstract method called when this item is dropped on another DragDrop
18358 * @method onDragDrop
18359 * @param {Event} e the mouseup event
18360 * @param {String|DragDrop[]} id In POINT mode, the element
18361 * id this was dropped on. In INTERSECT mode, an array of dd items this
18364 onDragDrop: function(e, id) { /* override this */ },
18367 * Abstract method called when this item is dropped on an area with no
18369 * @method onInvalidDrop
18370 * @param {Event} e the mouseup event
18372 onInvalidDrop: function(e) { /* override this */ },
18375 * Code that executes immediately before the endDrag event
18376 * @method b4EndDrag
18379 b4EndDrag: function(e) { },
18382 * Fired when we are done dragging the object
18384 * @param {Event} e the mouseup event
18386 endDrag: function(e) { /* override this */ },
18389 * Code executed immediately before the onMouseDown event
18390 * @method b4MouseDown
18391 * @param {Event} e the mousedown event
18394 b4MouseDown: function(e) { },
18397 * Event handler that fires when a drag/drop obj gets a mousedown
18398 * @method onMouseDown
18399 * @param {Event} e the mousedown event
18401 onMouseDown: function(e) { /* override this */ },
18404 * Event handler that fires when a drag/drop obj gets a mouseup
18405 * @method onMouseUp
18406 * @param {Event} e the mouseup event
18408 onMouseUp: function(e) { /* override this */ },
18411 * Override the onAvailable method to do what is needed after the initial
18412 * position was determined.
18413 * @method onAvailable
18415 onAvailable: function () {
18419 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18422 defaultPadding : {left:0, right:0, top:0, bottom:0},
18425 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18429 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18430 { dragElId: "existingProxyDiv" });
18431 dd.startDrag = function(){
18432 this.constrainTo("parent-id");
18435 * Or you can initalize it using the {@link Roo.Element} object:
18437 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18438 startDrag : function(){
18439 this.constrainTo("parent-id");
18443 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18444 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18445 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18446 * an object containing the sides to pad. For example: {right:10, bottom:10}
18447 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18449 constrainTo : function(constrainTo, pad, inContent){
18450 if(typeof pad == "number"){
18451 pad = {left: pad, right:pad, top:pad, bottom:pad};
18453 pad = pad || this.defaultPadding;
18454 var b = Roo.get(this.getEl()).getBox();
18455 var ce = Roo.get(constrainTo);
18456 var s = ce.getScroll();
18457 var c, cd = ce.dom;
18458 if(cd == document.body){
18459 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18462 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18466 var topSpace = b.y - c.y;
18467 var leftSpace = b.x - c.x;
18469 this.resetConstraints();
18470 this.setXConstraint(leftSpace - (pad.left||0), // left
18471 c.width - leftSpace - b.width - (pad.right||0) //right
18473 this.setYConstraint(topSpace - (pad.top||0), //top
18474 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18479 * Returns a reference to the linked element
18481 * @return {HTMLElement} the html element
18483 getEl: function() {
18484 if (!this._domRef) {
18485 this._domRef = Roo.getDom(this.id);
18488 return this._domRef;
18492 * Returns a reference to the actual element to drag. By default this is
18493 * the same as the html element, but it can be assigned to another
18494 * element. An example of this can be found in Roo.dd.DDProxy
18495 * @method getDragEl
18496 * @return {HTMLElement} the html element
18498 getDragEl: function() {
18499 return Roo.getDom(this.dragElId);
18503 * Sets up the DragDrop object. Must be called in the constructor of any
18504 * Roo.dd.DragDrop subclass
18506 * @param id the id of the linked element
18507 * @param {String} sGroup the group of related items
18508 * @param {object} config configuration attributes
18510 init: function(id, sGroup, config) {
18511 this.initTarget(id, sGroup, config);
18512 if (!Roo.isTouch) {
18513 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18515 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18516 // Event.on(this.id, "selectstart", Event.preventDefault);
18520 * Initializes Targeting functionality only... the object does not
18521 * get a mousedown handler.
18522 * @method initTarget
18523 * @param id the id of the linked element
18524 * @param {String} sGroup the group of related items
18525 * @param {object} config configuration attributes
18527 initTarget: function(id, sGroup, config) {
18529 // configuration attributes
18530 this.config = config || {};
18532 // create a local reference to the drag and drop manager
18533 this.DDM = Roo.dd.DDM;
18534 // initialize the groups array
18537 // assume that we have an element reference instead of an id if the
18538 // parameter is not a string
18539 if (typeof id !== "string") {
18546 // add to an interaction group
18547 this.addToGroup((sGroup) ? sGroup : "default");
18549 // We don't want to register this as the handle with the manager
18550 // so we just set the id rather than calling the setter.
18551 this.handleElId = id;
18553 // the linked element is the element that gets dragged by default
18554 this.setDragElId(id);
18556 // by default, clicked anchors will not start drag operations.
18557 this.invalidHandleTypes = { A: "A" };
18558 this.invalidHandleIds = {};
18559 this.invalidHandleClasses = [];
18561 this.applyConfig();
18563 this.handleOnAvailable();
18567 * Applies the configuration parameters that were passed into the constructor.
18568 * This is supposed to happen at each level through the inheritance chain. So
18569 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18570 * DragDrop in order to get all of the parameters that are available in
18572 * @method applyConfig
18574 applyConfig: function() {
18576 // configurable properties:
18577 // padding, isTarget, maintainOffset, primaryButtonOnly
18578 this.padding = this.config.padding || [0, 0, 0, 0];
18579 this.isTarget = (this.config.isTarget !== false);
18580 this.maintainOffset = (this.config.maintainOffset);
18581 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18586 * Executed when the linked element is available
18587 * @method handleOnAvailable
18590 handleOnAvailable: function() {
18591 this.available = true;
18592 this.resetConstraints();
18593 this.onAvailable();
18597 * Configures the padding for the target zone in px. Effectively expands
18598 * (or reduces) the virtual object size for targeting calculations.
18599 * Supports css-style shorthand; if only one parameter is passed, all sides
18600 * will have that padding, and if only two are passed, the top and bottom
18601 * will have the first param, the left and right the second.
18602 * @method setPadding
18603 * @param {int} iTop Top pad
18604 * @param {int} iRight Right pad
18605 * @param {int} iBot Bot pad
18606 * @param {int} iLeft Left pad
18608 setPadding: function(iTop, iRight, iBot, iLeft) {
18609 // this.padding = [iLeft, iRight, iTop, iBot];
18610 if (!iRight && 0 !== iRight) {
18611 this.padding = [iTop, iTop, iTop, iTop];
18612 } else if (!iBot && 0 !== iBot) {
18613 this.padding = [iTop, iRight, iTop, iRight];
18615 this.padding = [iTop, iRight, iBot, iLeft];
18620 * Stores the initial placement of the linked element.
18621 * @method setInitialPosition
18622 * @param {int} diffX the X offset, default 0
18623 * @param {int} diffY the Y offset, default 0
18625 setInitPosition: function(diffX, diffY) {
18626 var el = this.getEl();
18628 if (!this.DDM.verifyEl(el)) {
18632 var dx = diffX || 0;
18633 var dy = diffY || 0;
18635 var p = Dom.getXY( el );
18637 this.initPageX = p[0] - dx;
18638 this.initPageY = p[1] - dy;
18640 this.lastPageX = p[0];
18641 this.lastPageY = p[1];
18644 this.setStartPosition(p);
18648 * Sets the start position of the element. This is set when the obj
18649 * is initialized, the reset when a drag is started.
18650 * @method setStartPosition
18651 * @param pos current position (from previous lookup)
18654 setStartPosition: function(pos) {
18655 var p = pos || Dom.getXY( this.getEl() );
18656 this.deltaSetXY = null;
18658 this.startPageX = p[0];
18659 this.startPageY = p[1];
18663 * Add this instance to a group of related drag/drop objects. All
18664 * instances belong to at least one group, and can belong to as many
18665 * groups as needed.
18666 * @method addToGroup
18667 * @param sGroup {string} the name of the group
18669 addToGroup: function(sGroup) {
18670 this.groups[sGroup] = true;
18671 this.DDM.regDragDrop(this, sGroup);
18675 * Remove's this instance from the supplied interaction group
18676 * @method removeFromGroup
18677 * @param {string} sGroup The group to drop
18679 removeFromGroup: function(sGroup) {
18680 if (this.groups[sGroup]) {
18681 delete this.groups[sGroup];
18684 this.DDM.removeDDFromGroup(this, sGroup);
18688 * Allows you to specify that an element other than the linked element
18689 * will be moved with the cursor during a drag
18690 * @method setDragElId
18691 * @param id {string} the id of the element that will be used to initiate the drag
18693 setDragElId: function(id) {
18694 this.dragElId = id;
18698 * Allows you to specify a child of the linked element that should be
18699 * used to initiate the drag operation. An example of this would be if
18700 * you have a content div with text and links. Clicking anywhere in the
18701 * content area would normally start the drag operation. Use this method
18702 * to specify that an element inside of the content div is the element
18703 * that starts the drag operation.
18704 * @method setHandleElId
18705 * @param id {string} the id of the element that will be used to
18706 * initiate the drag.
18708 setHandleElId: function(id) {
18709 if (typeof id !== "string") {
18712 this.handleElId = id;
18713 this.DDM.regHandle(this.id, id);
18717 * Allows you to set an element outside of the linked element as a drag
18719 * @method setOuterHandleElId
18720 * @param id the id of the element that will be used to initiate the drag
18722 setOuterHandleElId: function(id) {
18723 if (typeof id !== "string") {
18726 Event.on(id, "mousedown",
18727 this.handleMouseDown, this);
18728 this.setHandleElId(id);
18730 this.hasOuterHandles = true;
18734 * Remove all drag and drop hooks for this element
18737 unreg: function() {
18738 Event.un(this.id, "mousedown",
18739 this.handleMouseDown);
18740 Event.un(this.id, "touchstart",
18741 this.handleMouseDown);
18742 this._domRef = null;
18743 this.DDM._remove(this);
18746 destroy : function(){
18751 * Returns true if this instance is locked, or the drag drop mgr is locked
18752 * (meaning that all drag/drop is disabled on the page.)
18754 * @return {boolean} true if this obj or all drag/drop is locked, else
18757 isLocked: function() {
18758 return (this.DDM.isLocked() || this.locked);
18762 * Fired when this object is clicked
18763 * @method handleMouseDown
18765 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18768 handleMouseDown: function(e, oDD){
18770 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18771 //Roo.log('not touch/ button !=0');
18774 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18775 return; // double touch..
18779 if (this.isLocked()) {
18780 //Roo.log('locked');
18784 this.DDM.refreshCache(this.groups);
18785 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18786 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18787 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18788 //Roo.log('no outer handes or not over target');
18791 // Roo.log('check validator');
18792 if (this.clickValidator(e)) {
18793 // Roo.log('validate success');
18794 // set the initial element position
18795 this.setStartPosition();
18798 this.b4MouseDown(e);
18799 this.onMouseDown(e);
18801 this.DDM.handleMouseDown(e, this);
18803 this.DDM.stopEvent(e);
18811 clickValidator: function(e) {
18812 var target = e.getTarget();
18813 return ( this.isValidHandleChild(target) &&
18814 (this.id == this.handleElId ||
18815 this.DDM.handleWasClicked(target, this.id)) );
18819 * Allows you to specify a tag name that should not start a drag operation
18820 * when clicked. This is designed to facilitate embedding links within a
18821 * drag handle that do something other than start the drag.
18822 * @method addInvalidHandleType
18823 * @param {string} tagName the type of element to exclude
18825 addInvalidHandleType: function(tagName) {
18826 var type = tagName.toUpperCase();
18827 this.invalidHandleTypes[type] = type;
18831 * Lets you to specify an element id for a child of a drag handle
18832 * that should not initiate a drag
18833 * @method addInvalidHandleId
18834 * @param {string} id the element id of the element you wish to ignore
18836 addInvalidHandleId: function(id) {
18837 if (typeof id !== "string") {
18840 this.invalidHandleIds[id] = id;
18844 * Lets you specify a css class of elements that will not initiate a drag
18845 * @method addInvalidHandleClass
18846 * @param {string} cssClass the class of the elements you wish to ignore
18848 addInvalidHandleClass: function(cssClass) {
18849 this.invalidHandleClasses.push(cssClass);
18853 * Unsets an excluded tag name set by addInvalidHandleType
18854 * @method removeInvalidHandleType
18855 * @param {string} tagName the type of element to unexclude
18857 removeInvalidHandleType: function(tagName) {
18858 var type = tagName.toUpperCase();
18859 // this.invalidHandleTypes[type] = null;
18860 delete this.invalidHandleTypes[type];
18864 * Unsets an invalid handle id
18865 * @method removeInvalidHandleId
18866 * @param {string} id the id of the element to re-enable
18868 removeInvalidHandleId: function(id) {
18869 if (typeof id !== "string") {
18872 delete this.invalidHandleIds[id];
18876 * Unsets an invalid css class
18877 * @method removeInvalidHandleClass
18878 * @param {string} cssClass the class of the element(s) you wish to
18881 removeInvalidHandleClass: function(cssClass) {
18882 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18883 if (this.invalidHandleClasses[i] == cssClass) {
18884 delete this.invalidHandleClasses[i];
18890 * Checks the tag exclusion list to see if this click should be ignored
18891 * @method isValidHandleChild
18892 * @param {HTMLElement} node the HTMLElement to evaluate
18893 * @return {boolean} true if this is a valid tag type, false if not
18895 isValidHandleChild: function(node) {
18898 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18901 nodeName = node.nodeName.toUpperCase();
18903 nodeName = node.nodeName;
18905 valid = valid && !this.invalidHandleTypes[nodeName];
18906 valid = valid && !this.invalidHandleIds[node.id];
18908 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18909 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18918 * Create the array of horizontal tick marks if an interval was specified
18919 * in setXConstraint().
18920 * @method setXTicks
18923 setXTicks: function(iStartX, iTickSize) {
18925 this.xTickSize = iTickSize;
18929 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18931 this.xTicks[this.xTicks.length] = i;
18936 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18938 this.xTicks[this.xTicks.length] = i;
18943 this.xTicks.sort(this.DDM.numericSort) ;
18947 * Create the array of vertical tick marks if an interval was specified in
18948 * setYConstraint().
18949 * @method setYTicks
18952 setYTicks: function(iStartY, iTickSize) {
18954 this.yTickSize = iTickSize;
18958 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18960 this.yTicks[this.yTicks.length] = i;
18965 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18967 this.yTicks[this.yTicks.length] = i;
18972 this.yTicks.sort(this.DDM.numericSort) ;
18976 * By default, the element can be dragged any place on the screen. Use
18977 * this method to limit the horizontal travel of the element. Pass in
18978 * 0,0 for the parameters if you want to lock the drag to the y axis.
18979 * @method setXConstraint
18980 * @param {int} iLeft the number of pixels the element can move to the left
18981 * @param {int} iRight the number of pixels the element can move to the
18983 * @param {int} iTickSize optional parameter for specifying that the
18985 * should move iTickSize pixels at a time.
18987 setXConstraint: function(iLeft, iRight, iTickSize) {
18988 this.leftConstraint = iLeft;
18989 this.rightConstraint = iRight;
18991 this.minX = this.initPageX - iLeft;
18992 this.maxX = this.initPageX + iRight;
18993 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18995 this.constrainX = true;
18999 * Clears any constraints applied to this instance. Also clears ticks
19000 * since they can't exist independent of a constraint at this time.
19001 * @method clearConstraints
19003 clearConstraints: function() {
19004 this.constrainX = false;
19005 this.constrainY = false;
19010 * Clears any tick interval defined for this instance
19011 * @method clearTicks
19013 clearTicks: function() {
19014 this.xTicks = null;
19015 this.yTicks = null;
19016 this.xTickSize = 0;
19017 this.yTickSize = 0;
19021 * By default, the element can be dragged any place on the screen. Set
19022 * this to limit the vertical travel of the element. Pass in 0,0 for the
19023 * parameters if you want to lock the drag to the x axis.
19024 * @method setYConstraint
19025 * @param {int} iUp the number of pixels the element can move up
19026 * @param {int} iDown the number of pixels the element can move down
19027 * @param {int} iTickSize optional parameter for specifying that the
19028 * element should move iTickSize pixels at a time.
19030 setYConstraint: function(iUp, iDown, iTickSize) {
19031 this.topConstraint = iUp;
19032 this.bottomConstraint = iDown;
19034 this.minY = this.initPageY - iUp;
19035 this.maxY = this.initPageY + iDown;
19036 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19038 this.constrainY = true;
19043 * resetConstraints must be called if you manually reposition a dd element.
19044 * @method resetConstraints
19045 * @param {boolean} maintainOffset
19047 resetConstraints: function() {
19050 // Maintain offsets if necessary
19051 if (this.initPageX || this.initPageX === 0) {
19052 // figure out how much this thing has moved
19053 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19054 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19056 this.setInitPosition(dx, dy);
19058 // This is the first time we have detected the element's position
19060 this.setInitPosition();
19063 if (this.constrainX) {
19064 this.setXConstraint( this.leftConstraint,
19065 this.rightConstraint,
19069 if (this.constrainY) {
19070 this.setYConstraint( this.topConstraint,
19071 this.bottomConstraint,
19077 * Normally the drag element is moved pixel by pixel, but we can specify
19078 * that it move a number of pixels at a time. This method resolves the
19079 * location when we have it set up like this.
19081 * @param {int} val where we want to place the object
19082 * @param {int[]} tickArray sorted array of valid points
19083 * @return {int} the closest tick
19086 getTick: function(val, tickArray) {
19089 // If tick interval is not defined, it is effectively 1 pixel,
19090 // so we return the value passed to us.
19092 } else if (tickArray[0] >= val) {
19093 // The value is lower than the first tick, so we return the first
19095 return tickArray[0];
19097 for (var i=0, len=tickArray.length; i<len; ++i) {
19099 if (tickArray[next] && tickArray[next] >= val) {
19100 var diff1 = val - tickArray[i];
19101 var diff2 = tickArray[next] - val;
19102 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19106 // The value is larger than the last tick, so we return the last
19108 return tickArray[tickArray.length - 1];
19115 * @return {string} string representation of the dd obj
19117 toString: function() {
19118 return ("DragDrop " + this.id);
19126 * Ext JS Library 1.1.1
19127 * Copyright(c) 2006-2007, Ext JS, LLC.
19129 * Originally Released Under LGPL - original licence link has changed is not relivant.
19132 * <script type="text/javascript">
19137 * The drag and drop utility provides a framework for building drag and drop
19138 * applications. In addition to enabling drag and drop for specific elements,
19139 * the drag and drop elements are tracked by the manager class, and the
19140 * interactions between the various elements are tracked during the drag and
19141 * the implementing code is notified about these important moments.
19144 // Only load the library once. Rewriting the manager class would orphan
19145 // existing drag and drop instances.
19146 if (!Roo.dd.DragDropMgr) {
19149 * @class Roo.dd.DragDropMgr
19150 * DragDropMgr is a singleton that tracks the element interaction for
19151 * all DragDrop items in the window. Generally, you will not call
19152 * this class directly, but it does have helper methods that could
19153 * be useful in your DragDrop implementations.
19156 Roo.dd.DragDropMgr = function() {
19158 var Event = Roo.EventManager;
19163 * Two dimensional Array of registered DragDrop objects. The first
19164 * dimension is the DragDrop item group, the second the DragDrop
19167 * @type {string: string}
19174 * Array of element ids defined as drag handles. Used to determine
19175 * if the element that generated the mousedown event is actually the
19176 * handle and not the html element itself.
19177 * @property handleIds
19178 * @type {string: string}
19185 * the DragDrop object that is currently being dragged
19186 * @property dragCurrent
19194 * the DragDrop object(s) that are being hovered over
19195 * @property dragOvers
19203 * the X distance between the cursor and the object being dragged
19212 * the Y distance between the cursor and the object being dragged
19221 * Flag to determine if we should prevent the default behavior of the
19222 * events we define. By default this is true, but this can be set to
19223 * false if you need the default behavior (not recommended)
19224 * @property preventDefault
19228 preventDefault: true,
19231 * Flag to determine if we should stop the propagation of the events
19232 * we generate. This is true by default but you may want to set it to
19233 * false if the html element contains other features that require the
19235 * @property stopPropagation
19239 stopPropagation: true,
19242 * Internal flag that is set to true when drag and drop has been
19244 * @property initialized
19251 * All drag and drop can be disabled.
19259 * Called the first time an element is registered.
19265 this.initialized = true;
19269 * In point mode, drag and drop interaction is defined by the
19270 * location of the cursor during the drag/drop
19278 * In intersect mode, drag and drop interactio nis defined by the
19279 * overlap of two or more drag and drop objects.
19280 * @property INTERSECT
19287 * The current drag and drop mode. Default: POINT
19295 * Runs method on all drag and drop objects
19296 * @method _execOnAll
19300 _execOnAll: function(sMethod, args) {
19301 for (var i in this.ids) {
19302 for (var j in this.ids[i]) {
19303 var oDD = this.ids[i][j];
19304 if (! this.isTypeOfDD(oDD)) {
19307 oDD[sMethod].apply(oDD, args);
19313 * Drag and drop initialization. Sets up the global event handlers
19318 _onLoad: function() {
19322 if (!Roo.isTouch) {
19323 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19324 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19326 Event.on(document, "touchend", this.handleMouseUp, this, true);
19327 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19329 Event.on(window, "unload", this._onUnload, this, true);
19330 Event.on(window, "resize", this._onResize, this, true);
19331 // Event.on(window, "mouseout", this._test);
19336 * Reset constraints on all drag and drop objs
19337 * @method _onResize
19341 _onResize: function(e) {
19342 this._execOnAll("resetConstraints", []);
19346 * Lock all drag and drop functionality
19350 lock: function() { this.locked = true; },
19353 * Unlock all drag and drop functionality
19357 unlock: function() { this.locked = false; },
19360 * Is drag and drop locked?
19362 * @return {boolean} True if drag and drop is locked, false otherwise.
19365 isLocked: function() { return this.locked; },
19368 * Location cache that is set for all drag drop objects when a drag is
19369 * initiated, cleared when the drag is finished.
19370 * @property locationCache
19377 * Set useCache to false if you want to force object the lookup of each
19378 * drag and drop linked element constantly during a drag.
19379 * @property useCache
19386 * The number of pixels that the mouse needs to move after the
19387 * mousedown before the drag is initiated. Default=3;
19388 * @property clickPixelThresh
19392 clickPixelThresh: 3,
19395 * The number of milliseconds after the mousedown event to initiate the
19396 * drag if we don't get a mouseup event. Default=1000
19397 * @property clickTimeThresh
19401 clickTimeThresh: 350,
19404 * Flag that indicates that either the drag pixel threshold or the
19405 * mousdown time threshold has been met
19406 * @property dragThreshMet
19411 dragThreshMet: false,
19414 * Timeout used for the click time threshold
19415 * @property clickTimeout
19420 clickTimeout: null,
19423 * The X position of the mousedown event stored for later use when a
19424 * drag threshold is met.
19433 * The Y position of the mousedown event stored for later use when a
19434 * drag threshold is met.
19443 * Each DragDrop instance must be registered with the DragDropMgr.
19444 * This is executed in DragDrop.init()
19445 * @method regDragDrop
19446 * @param {DragDrop} oDD the DragDrop object to register
19447 * @param {String} sGroup the name of the group this element belongs to
19450 regDragDrop: function(oDD, sGroup) {
19451 if (!this.initialized) { this.init(); }
19453 if (!this.ids[sGroup]) {
19454 this.ids[sGroup] = {};
19456 this.ids[sGroup][oDD.id] = oDD;
19460 * Removes the supplied dd instance from the supplied group. Executed
19461 * by DragDrop.removeFromGroup, so don't call this function directly.
19462 * @method removeDDFromGroup
19466 removeDDFromGroup: function(oDD, sGroup) {
19467 if (!this.ids[sGroup]) {
19468 this.ids[sGroup] = {};
19471 var obj = this.ids[sGroup];
19472 if (obj && obj[oDD.id]) {
19473 delete obj[oDD.id];
19478 * Unregisters a drag and drop item. This is executed in
19479 * DragDrop.unreg, use that method instead of calling this directly.
19484 _remove: function(oDD) {
19485 for (var g in oDD.groups) {
19486 if (g && this.ids[g][oDD.id]) {
19487 delete this.ids[g][oDD.id];
19490 delete this.handleIds[oDD.id];
19494 * Each DragDrop handle element must be registered. This is done
19495 * automatically when executing DragDrop.setHandleElId()
19496 * @method regHandle
19497 * @param {String} sDDId the DragDrop id this element is a handle for
19498 * @param {String} sHandleId the id of the element that is the drag
19502 regHandle: function(sDDId, sHandleId) {
19503 if (!this.handleIds[sDDId]) {
19504 this.handleIds[sDDId] = {};
19506 this.handleIds[sDDId][sHandleId] = sHandleId;
19510 * Utility function to determine if a given element has been
19511 * registered as a drag drop item.
19512 * @method isDragDrop
19513 * @param {String} id the element id to check
19514 * @return {boolean} true if this element is a DragDrop item,
19518 isDragDrop: function(id) {
19519 return ( this.getDDById(id) ) ? true : false;
19523 * Returns the drag and drop instances that are in all groups the
19524 * passed in instance belongs to.
19525 * @method getRelated
19526 * @param {DragDrop} p_oDD the obj to get related data for
19527 * @param {boolean} bTargetsOnly if true, only return targetable objs
19528 * @return {DragDrop[]} the related instances
19531 getRelated: function(p_oDD, bTargetsOnly) {
19533 for (var i in p_oDD.groups) {
19534 for (j in this.ids[i]) {
19535 var dd = this.ids[i][j];
19536 if (! this.isTypeOfDD(dd)) {
19539 if (!bTargetsOnly || dd.isTarget) {
19540 oDDs[oDDs.length] = dd;
19549 * Returns true if the specified dd target is a legal target for
19550 * the specifice drag obj
19551 * @method isLegalTarget
19552 * @param {DragDrop} the drag obj
19553 * @param {DragDrop} the target
19554 * @return {boolean} true if the target is a legal target for the
19558 isLegalTarget: function (oDD, oTargetDD) {
19559 var targets = this.getRelated(oDD, true);
19560 for (var i=0, len=targets.length;i<len;++i) {
19561 if (targets[i].id == oTargetDD.id) {
19570 * My goal is to be able to transparently determine if an object is
19571 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19572 * returns "object", oDD.constructor.toString() always returns
19573 * "DragDrop" and not the name of the subclass. So for now it just
19574 * evaluates a well-known variable in DragDrop.
19575 * @method isTypeOfDD
19576 * @param {Object} the object to evaluate
19577 * @return {boolean} true if typeof oDD = DragDrop
19580 isTypeOfDD: function (oDD) {
19581 return (oDD && oDD.__ygDragDrop);
19585 * Utility function to determine if a given element has been
19586 * registered as a drag drop handle for the given Drag Drop object.
19588 * @param {String} id the element id to check
19589 * @return {boolean} true if this element is a DragDrop handle, false
19593 isHandle: function(sDDId, sHandleId) {
19594 return ( this.handleIds[sDDId] &&
19595 this.handleIds[sDDId][sHandleId] );
19599 * Returns the DragDrop instance for a given id
19600 * @method getDDById
19601 * @param {String} id the id of the DragDrop object
19602 * @return {DragDrop} the drag drop object, null if it is not found
19605 getDDById: function(id) {
19606 for (var i in this.ids) {
19607 if (this.ids[i][id]) {
19608 return this.ids[i][id];
19615 * Fired after a registered DragDrop object gets the mousedown event.
19616 * Sets up the events required to track the object being dragged
19617 * @method handleMouseDown
19618 * @param {Event} e the event
19619 * @param oDD the DragDrop object being dragged
19623 handleMouseDown: function(e, oDD) {
19625 Roo.QuickTips.disable();
19627 this.currentTarget = e.getTarget();
19629 this.dragCurrent = oDD;
19631 var el = oDD.getEl();
19633 // track start position
19634 this.startX = e.getPageX();
19635 this.startY = e.getPageY();
19637 this.deltaX = this.startX - el.offsetLeft;
19638 this.deltaY = this.startY - el.offsetTop;
19640 this.dragThreshMet = false;
19642 this.clickTimeout = setTimeout(
19644 var DDM = Roo.dd.DDM;
19645 DDM.startDrag(DDM.startX, DDM.startY);
19647 this.clickTimeThresh );
19651 * Fired when either the drag pixel threshol or the mousedown hold
19652 * time threshold has been met.
19653 * @method startDrag
19654 * @param x {int} the X position of the original mousedown
19655 * @param y {int} the Y position of the original mousedown
19658 startDrag: function(x, y) {
19659 clearTimeout(this.clickTimeout);
19660 if (this.dragCurrent) {
19661 this.dragCurrent.b4StartDrag(x, y);
19662 this.dragCurrent.startDrag(x, y);
19664 this.dragThreshMet = true;
19668 * Internal function to handle the mouseup event. Will be invoked
19669 * from the context of the document.
19670 * @method handleMouseUp
19671 * @param {Event} e the event
19675 handleMouseUp: function(e) {
19678 Roo.QuickTips.enable();
19680 if (! this.dragCurrent) {
19684 clearTimeout(this.clickTimeout);
19686 if (this.dragThreshMet) {
19687 this.fireEvents(e, true);
19697 * Utility to stop event propagation and event default, if these
19698 * features are turned on.
19699 * @method stopEvent
19700 * @param {Event} e the event as returned by this.getEvent()
19703 stopEvent: function(e){
19704 if(this.stopPropagation) {
19705 e.stopPropagation();
19708 if (this.preventDefault) {
19709 e.preventDefault();
19714 * Internal function to clean up event handlers after the drag
19715 * operation is complete
19717 * @param {Event} e the event
19721 stopDrag: function(e) {
19722 // Fire the drag end event for the item that was dragged
19723 if (this.dragCurrent) {
19724 if (this.dragThreshMet) {
19725 this.dragCurrent.b4EndDrag(e);
19726 this.dragCurrent.endDrag(e);
19729 this.dragCurrent.onMouseUp(e);
19732 this.dragCurrent = null;
19733 this.dragOvers = {};
19737 * Internal function to handle the mousemove event. Will be invoked
19738 * from the context of the html element.
19740 * @TODO figure out what we can do about mouse events lost when the
19741 * user drags objects beyond the window boundary. Currently we can
19742 * detect this in internet explorer by verifying that the mouse is
19743 * down during the mousemove event. Firefox doesn't give us the
19744 * button state on the mousemove event.
19745 * @method handleMouseMove
19746 * @param {Event} e the event
19750 handleMouseMove: function(e) {
19751 if (! this.dragCurrent) {
19755 // var button = e.which || e.button;
19757 // check for IE mouseup outside of page boundary
19758 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19760 return this.handleMouseUp(e);
19763 if (!this.dragThreshMet) {
19764 var diffX = Math.abs(this.startX - e.getPageX());
19765 var diffY = Math.abs(this.startY - e.getPageY());
19766 if (diffX > this.clickPixelThresh ||
19767 diffY > this.clickPixelThresh) {
19768 this.startDrag(this.startX, this.startY);
19772 if (this.dragThreshMet) {
19773 this.dragCurrent.b4Drag(e);
19774 this.dragCurrent.onDrag(e);
19775 if(!this.dragCurrent.moveOnly){
19776 this.fireEvents(e, false);
19786 * Iterates over all of the DragDrop elements to find ones we are
19787 * hovering over or dropping on
19788 * @method fireEvents
19789 * @param {Event} e the event
19790 * @param {boolean} isDrop is this a drop op or a mouseover op?
19794 fireEvents: function(e, isDrop) {
19795 var dc = this.dragCurrent;
19797 // If the user did the mouse up outside of the window, we could
19798 // get here even though we have ended the drag.
19799 if (!dc || dc.isLocked()) {
19803 var pt = e.getPoint();
19805 // cache the previous dragOver array
19811 var enterEvts = [];
19813 // Check to see if the object(s) we were hovering over is no longer
19814 // being hovered over so we can fire the onDragOut event
19815 for (var i in this.dragOvers) {
19817 var ddo = this.dragOvers[i];
19819 if (! this.isTypeOfDD(ddo)) {
19823 if (! this.isOverTarget(pt, ddo, this.mode)) {
19824 outEvts.push( ddo );
19827 oldOvers[i] = true;
19828 delete this.dragOvers[i];
19831 for (var sGroup in dc.groups) {
19833 if ("string" != typeof sGroup) {
19837 for (i in this.ids[sGroup]) {
19838 var oDD = this.ids[sGroup][i];
19839 if (! this.isTypeOfDD(oDD)) {
19843 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19844 if (this.isOverTarget(pt, oDD, this.mode)) {
19845 // look for drop interactions
19847 dropEvts.push( oDD );
19848 // look for drag enter and drag over interactions
19851 // initial drag over: dragEnter fires
19852 if (!oldOvers[oDD.id]) {
19853 enterEvts.push( oDD );
19854 // subsequent drag overs: dragOver fires
19856 overEvts.push( oDD );
19859 this.dragOvers[oDD.id] = oDD;
19867 if (outEvts.length) {
19868 dc.b4DragOut(e, outEvts);
19869 dc.onDragOut(e, outEvts);
19872 if (enterEvts.length) {
19873 dc.onDragEnter(e, enterEvts);
19876 if (overEvts.length) {
19877 dc.b4DragOver(e, overEvts);
19878 dc.onDragOver(e, overEvts);
19881 if (dropEvts.length) {
19882 dc.b4DragDrop(e, dropEvts);
19883 dc.onDragDrop(e, dropEvts);
19887 // fire dragout events
19889 for (i=0, len=outEvts.length; i<len; ++i) {
19890 dc.b4DragOut(e, outEvts[i].id);
19891 dc.onDragOut(e, outEvts[i].id);
19894 // fire enter events
19895 for (i=0,len=enterEvts.length; i<len; ++i) {
19896 // dc.b4DragEnter(e, oDD.id);
19897 dc.onDragEnter(e, enterEvts[i].id);
19900 // fire over events
19901 for (i=0,len=overEvts.length; i<len; ++i) {
19902 dc.b4DragOver(e, overEvts[i].id);
19903 dc.onDragOver(e, overEvts[i].id);
19906 // fire drop events
19907 for (i=0, len=dropEvts.length; i<len; ++i) {
19908 dc.b4DragDrop(e, dropEvts[i].id);
19909 dc.onDragDrop(e, dropEvts[i].id);
19914 // notify about a drop that did not find a target
19915 if (isDrop && !dropEvts.length) {
19916 dc.onInvalidDrop(e);
19922 * Helper function for getting the best match from the list of drag
19923 * and drop objects returned by the drag and drop events when we are
19924 * in INTERSECT mode. It returns either the first object that the
19925 * cursor is over, or the object that has the greatest overlap with
19926 * the dragged element.
19927 * @method getBestMatch
19928 * @param {DragDrop[]} dds The array of drag and drop objects
19930 * @return {DragDrop} The best single match
19933 getBestMatch: function(dds) {
19935 // Return null if the input is not what we expect
19936 //if (!dds || !dds.length || dds.length == 0) {
19938 // If there is only one item, it wins
19939 //} else if (dds.length == 1) {
19941 var len = dds.length;
19946 // Loop through the targeted items
19947 for (var i=0; i<len; ++i) {
19949 // If the cursor is over the object, it wins. If the
19950 // cursor is over multiple matches, the first one we come
19952 if (dd.cursorIsOver) {
19955 // Otherwise the object with the most overlap wins
19958 winner.overlap.getArea() < dd.overlap.getArea()) {
19969 * Refreshes the cache of the top-left and bottom-right points of the
19970 * drag and drop objects in the specified group(s). This is in the
19971 * format that is stored in the drag and drop instance, so typical
19974 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19978 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19980 * @TODO this really should be an indexed array. Alternatively this
19981 * method could accept both.
19982 * @method refreshCache
19983 * @param {Object} groups an associative array of groups to refresh
19986 refreshCache: function(groups) {
19987 for (var sGroup in groups) {
19988 if ("string" != typeof sGroup) {
19991 for (var i in this.ids[sGroup]) {
19992 var oDD = this.ids[sGroup][i];
19994 if (this.isTypeOfDD(oDD)) {
19995 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19996 var loc = this.getLocation(oDD);
19998 this.locationCache[oDD.id] = loc;
20000 delete this.locationCache[oDD.id];
20001 // this will unregister the drag and drop object if
20002 // the element is not in a usable state
20011 * This checks to make sure an element exists and is in the DOM. The
20012 * main purpose is to handle cases where innerHTML is used to remove
20013 * drag and drop objects from the DOM. IE provides an 'unspecified
20014 * error' when trying to access the offsetParent of such an element
20016 * @param {HTMLElement} el the element to check
20017 * @return {boolean} true if the element looks usable
20020 verifyEl: function(el) {
20025 parent = el.offsetParent;
20028 parent = el.offsetParent;
20039 * Returns a Region object containing the drag and drop element's position
20040 * and size, including the padding configured for it
20041 * @method getLocation
20042 * @param {DragDrop} oDD the drag and drop object to get the
20044 * @return {Roo.lib.Region} a Region object representing the total area
20045 * the element occupies, including any padding
20046 * the instance is configured for.
20049 getLocation: function(oDD) {
20050 if (! this.isTypeOfDD(oDD)) {
20054 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20057 pos= Roo.lib.Dom.getXY(el);
20065 x2 = x1 + el.offsetWidth;
20067 y2 = y1 + el.offsetHeight;
20069 t = y1 - oDD.padding[0];
20070 r = x2 + oDD.padding[1];
20071 b = y2 + oDD.padding[2];
20072 l = x1 - oDD.padding[3];
20074 return new Roo.lib.Region( t, r, b, l );
20078 * Checks the cursor location to see if it over the target
20079 * @method isOverTarget
20080 * @param {Roo.lib.Point} pt The point to evaluate
20081 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20082 * @return {boolean} true if the mouse is over the target
20086 isOverTarget: function(pt, oTarget, intersect) {
20087 // use cache if available
20088 var loc = this.locationCache[oTarget.id];
20089 if (!loc || !this.useCache) {
20090 loc = this.getLocation(oTarget);
20091 this.locationCache[oTarget.id] = loc;
20099 oTarget.cursorIsOver = loc.contains( pt );
20101 // DragDrop is using this as a sanity check for the initial mousedown
20102 // in this case we are done. In POINT mode, if the drag obj has no
20103 // contraints, we are also done. Otherwise we need to evaluate the
20104 // location of the target as related to the actual location of the
20105 // dragged element.
20106 var dc = this.dragCurrent;
20107 if (!dc || !dc.getTargetCoord ||
20108 (!intersect && !dc.constrainX && !dc.constrainY)) {
20109 return oTarget.cursorIsOver;
20112 oTarget.overlap = null;
20114 // Get the current location of the drag element, this is the
20115 // location of the mouse event less the delta that represents
20116 // where the original mousedown happened on the element. We
20117 // need to consider constraints and ticks as well.
20118 var pos = dc.getTargetCoord(pt.x, pt.y);
20120 var el = dc.getDragEl();
20121 var curRegion = new Roo.lib.Region( pos.y,
20122 pos.x + el.offsetWidth,
20123 pos.y + el.offsetHeight,
20126 var overlap = curRegion.intersect(loc);
20129 oTarget.overlap = overlap;
20130 return (intersect) ? true : oTarget.cursorIsOver;
20137 * unload event handler
20138 * @method _onUnload
20142 _onUnload: function(e, me) {
20143 Roo.dd.DragDropMgr.unregAll();
20147 * Cleans up the drag and drop events and objects.
20152 unregAll: function() {
20154 if (this.dragCurrent) {
20156 this.dragCurrent = null;
20159 this._execOnAll("unreg", []);
20161 for (i in this.elementCache) {
20162 delete this.elementCache[i];
20165 this.elementCache = {};
20170 * A cache of DOM elements
20171 * @property elementCache
20178 * Get the wrapper for the DOM element specified
20179 * @method getElWrapper
20180 * @param {String} id the id of the element to get
20181 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20183 * @deprecated This wrapper isn't that useful
20186 getElWrapper: function(id) {
20187 var oWrapper = this.elementCache[id];
20188 if (!oWrapper || !oWrapper.el) {
20189 oWrapper = this.elementCache[id] =
20190 new this.ElementWrapper(Roo.getDom(id));
20196 * Returns the actual DOM element
20197 * @method getElement
20198 * @param {String} id the id of the elment to get
20199 * @return {Object} The element
20200 * @deprecated use Roo.getDom instead
20203 getElement: function(id) {
20204 return Roo.getDom(id);
20208 * Returns the style property for the DOM element (i.e.,
20209 * document.getElById(id).style)
20211 * @param {String} id the id of the elment to get
20212 * @return {Object} The style property of the element
20213 * @deprecated use Roo.getDom instead
20216 getCss: function(id) {
20217 var el = Roo.getDom(id);
20218 return (el) ? el.style : null;
20222 * Inner class for cached elements
20223 * @class DragDropMgr.ElementWrapper
20228 ElementWrapper: function(el) {
20233 this.el = el || null;
20238 this.id = this.el && el.id;
20240 * A reference to the style property
20243 this.css = this.el && el.style;
20247 * Returns the X position of an html element
20249 * @param el the element for which to get the position
20250 * @return {int} the X coordinate
20252 * @deprecated use Roo.lib.Dom.getX instead
20255 getPosX: function(el) {
20256 return Roo.lib.Dom.getX(el);
20260 * Returns the Y position of an html element
20262 * @param el the element for which to get the position
20263 * @return {int} the Y coordinate
20264 * @deprecated use Roo.lib.Dom.getY instead
20267 getPosY: function(el) {
20268 return Roo.lib.Dom.getY(el);
20272 * Swap two nodes. In IE, we use the native method, for others we
20273 * emulate the IE behavior
20275 * @param n1 the first node to swap
20276 * @param n2 the other node to swap
20279 swapNode: function(n1, n2) {
20283 var p = n2.parentNode;
20284 var s = n2.nextSibling;
20287 p.insertBefore(n1, n2);
20288 } else if (n2 == n1.nextSibling) {
20289 p.insertBefore(n2, n1);
20291 n1.parentNode.replaceChild(n2, n1);
20292 p.insertBefore(n1, s);
20298 * Returns the current scroll position
20299 * @method getScroll
20303 getScroll: function () {
20304 var t, l, dde=document.documentElement, db=document.body;
20305 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20307 l = dde.scrollLeft;
20314 return { top: t, left: l };
20318 * Returns the specified element style property
20320 * @param {HTMLElement} el the element
20321 * @param {string} styleProp the style property
20322 * @return {string} The value of the style property
20323 * @deprecated use Roo.lib.Dom.getStyle
20326 getStyle: function(el, styleProp) {
20327 return Roo.fly(el).getStyle(styleProp);
20331 * Gets the scrollTop
20332 * @method getScrollTop
20333 * @return {int} the document's scrollTop
20336 getScrollTop: function () { return this.getScroll().top; },
20339 * Gets the scrollLeft
20340 * @method getScrollLeft
20341 * @return {int} the document's scrollTop
20344 getScrollLeft: function () { return this.getScroll().left; },
20347 * Sets the x/y position of an element to the location of the
20350 * @param {HTMLElement} moveEl The element to move
20351 * @param {HTMLElement} targetEl The position reference element
20354 moveToEl: function (moveEl, targetEl) {
20355 var aCoord = Roo.lib.Dom.getXY(targetEl);
20356 Roo.lib.Dom.setXY(moveEl, aCoord);
20360 * Numeric array sort function
20361 * @method numericSort
20364 numericSort: function(a, b) { return (a - b); },
20368 * @property _timeoutCount
20375 * Trying to make the load order less important. Without this we get
20376 * an error if this file is loaded before the Event Utility.
20377 * @method _addListeners
20381 _addListeners: function() {
20382 var DDM = Roo.dd.DDM;
20383 if ( Roo.lib.Event && document ) {
20386 if (DDM._timeoutCount > 2000) {
20388 setTimeout(DDM._addListeners, 10);
20389 if (document && document.body) {
20390 DDM._timeoutCount += 1;
20397 * Recursively searches the immediate parent and all child nodes for
20398 * the handle element in order to determine wheter or not it was
20400 * @method handleWasClicked
20401 * @param node the html element to inspect
20404 handleWasClicked: function(node, id) {
20405 if (this.isHandle(id, node.id)) {
20408 // check to see if this is a text node child of the one we want
20409 var p = node.parentNode;
20412 if (this.isHandle(id, p.id)) {
20427 // shorter alias, save a few bytes
20428 Roo.dd.DDM = Roo.dd.DragDropMgr;
20429 Roo.dd.DDM._addListeners();
20433 * Ext JS Library 1.1.1
20434 * Copyright(c) 2006-2007, Ext JS, LLC.
20436 * Originally Released Under LGPL - original licence link has changed is not relivant.
20439 * <script type="text/javascript">
20444 * A DragDrop implementation where the linked element follows the
20445 * mouse cursor during a drag.
20446 * @extends Roo.dd.DragDrop
20448 * @param {String} id the id of the linked element
20449 * @param {String} sGroup the group of related DragDrop items
20450 * @param {object} config an object containing configurable attributes
20451 * Valid properties for DD:
20454 Roo.dd.DD = function(id, sGroup, config) {
20456 this.init(id, sGroup, config);
20460 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20463 * When set to true, the utility automatically tries to scroll the browser
20464 * window wehn a drag and drop element is dragged near the viewport boundary.
20465 * Defaults to true.
20472 * Sets the pointer offset to the distance between the linked element's top
20473 * left corner and the location the element was clicked
20474 * @method autoOffset
20475 * @param {int} iPageX the X coordinate of the click
20476 * @param {int} iPageY the Y coordinate of the click
20478 autoOffset: function(iPageX, iPageY) {
20479 var x = iPageX - this.startPageX;
20480 var y = iPageY - this.startPageY;
20481 this.setDelta(x, y);
20485 * Sets the pointer offset. You can call this directly to force the
20486 * offset to be in a particular location (e.g., pass in 0,0 to set it
20487 * to the center of the object)
20489 * @param {int} iDeltaX the distance from the left
20490 * @param {int} iDeltaY the distance from the top
20492 setDelta: function(iDeltaX, iDeltaY) {
20493 this.deltaX = iDeltaX;
20494 this.deltaY = iDeltaY;
20498 * Sets the drag element to the location of the mousedown or click event,
20499 * maintaining the cursor location relative to the location on the element
20500 * that was clicked. Override this if you want to place the element in a
20501 * location other than where the cursor is.
20502 * @method setDragElPos
20503 * @param {int} iPageX the X coordinate of the mousedown or drag event
20504 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20506 setDragElPos: function(iPageX, iPageY) {
20507 // the first time we do this, we are going to check to make sure
20508 // the element has css positioning
20510 var el = this.getDragEl();
20511 this.alignElWithMouse(el, iPageX, iPageY);
20515 * Sets the element to the location of the mousedown or click event,
20516 * maintaining the cursor location relative to the location on the element
20517 * that was clicked. Override this if you want to place the element in a
20518 * location other than where the cursor is.
20519 * @method alignElWithMouse
20520 * @param {HTMLElement} el the element to move
20521 * @param {int} iPageX the X coordinate of the mousedown or drag event
20522 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20524 alignElWithMouse: function(el, iPageX, iPageY) {
20525 var oCoord = this.getTargetCoord(iPageX, iPageY);
20526 var fly = el.dom ? el : Roo.fly(el);
20527 if (!this.deltaSetXY) {
20528 var aCoord = [oCoord.x, oCoord.y];
20530 var newLeft = fly.getLeft(true);
20531 var newTop = fly.getTop(true);
20532 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20534 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20537 this.cachePosition(oCoord.x, oCoord.y);
20538 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20543 * Saves the most recent position so that we can reset the constraints and
20544 * tick marks on-demand. We need to know this so that we can calculate the
20545 * number of pixels the element is offset from its original position.
20546 * @method cachePosition
20547 * @param iPageX the current x position (optional, this just makes it so we
20548 * don't have to look it up again)
20549 * @param iPageY the current y position (optional, this just makes it so we
20550 * don't have to look it up again)
20552 cachePosition: function(iPageX, iPageY) {
20554 this.lastPageX = iPageX;
20555 this.lastPageY = iPageY;
20557 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20558 this.lastPageX = aCoord[0];
20559 this.lastPageY = aCoord[1];
20564 * Auto-scroll the window if the dragged object has been moved beyond the
20565 * visible window boundary.
20566 * @method autoScroll
20567 * @param {int} x the drag element's x position
20568 * @param {int} y the drag element's y position
20569 * @param {int} h the height of the drag element
20570 * @param {int} w the width of the drag element
20573 autoScroll: function(x, y, h, w) {
20576 // The client height
20577 var clientH = Roo.lib.Dom.getViewWidth();
20579 // The client width
20580 var clientW = Roo.lib.Dom.getViewHeight();
20582 // The amt scrolled down
20583 var st = this.DDM.getScrollTop();
20585 // The amt scrolled right
20586 var sl = this.DDM.getScrollLeft();
20588 // Location of the bottom of the element
20591 // Location of the right of the element
20594 // The distance from the cursor to the bottom of the visible area,
20595 // adjusted so that we don't scroll if the cursor is beyond the
20596 // element drag constraints
20597 var toBot = (clientH + st - y - this.deltaY);
20599 // The distance from the cursor to the right of the visible area
20600 var toRight = (clientW + sl - x - this.deltaX);
20603 // How close to the edge the cursor must be before we scroll
20604 // var thresh = (document.all) ? 100 : 40;
20607 // How many pixels to scroll per autoscroll op. This helps to reduce
20608 // clunky scrolling. IE is more sensitive about this ... it needs this
20609 // value to be higher.
20610 var scrAmt = (document.all) ? 80 : 30;
20612 // Scroll down if we are near the bottom of the visible page and the
20613 // obj extends below the crease
20614 if ( bot > clientH && toBot < thresh ) {
20615 window.scrollTo(sl, st + scrAmt);
20618 // Scroll up if the window is scrolled down and the top of the object
20619 // goes above the top border
20620 if ( y < st && st > 0 && y - st < thresh ) {
20621 window.scrollTo(sl, st - scrAmt);
20624 // Scroll right if the obj is beyond the right border and the cursor is
20625 // near the border.
20626 if ( right > clientW && toRight < thresh ) {
20627 window.scrollTo(sl + scrAmt, st);
20630 // Scroll left if the window has been scrolled to the right and the obj
20631 // extends past the left border
20632 if ( x < sl && sl > 0 && x - sl < thresh ) {
20633 window.scrollTo(sl - scrAmt, st);
20639 * Finds the location the element should be placed if we want to move
20640 * it to where the mouse location less the click offset would place us.
20641 * @method getTargetCoord
20642 * @param {int} iPageX the X coordinate of the click
20643 * @param {int} iPageY the Y coordinate of the click
20644 * @return an object that contains the coordinates (Object.x and Object.y)
20647 getTargetCoord: function(iPageX, iPageY) {
20650 var x = iPageX - this.deltaX;
20651 var y = iPageY - this.deltaY;
20653 if (this.constrainX) {
20654 if (x < this.minX) { x = this.minX; }
20655 if (x > this.maxX) { x = this.maxX; }
20658 if (this.constrainY) {
20659 if (y < this.minY) { y = this.minY; }
20660 if (y > this.maxY) { y = this.maxY; }
20663 x = this.getTick(x, this.xTicks);
20664 y = this.getTick(y, this.yTicks);
20671 * Sets up config options specific to this class. Overrides
20672 * Roo.dd.DragDrop, but all versions of this method through the
20673 * inheritance chain are called
20675 applyConfig: function() {
20676 Roo.dd.DD.superclass.applyConfig.call(this);
20677 this.scroll = (this.config.scroll !== false);
20681 * Event that fires prior to the onMouseDown event. Overrides
20684 b4MouseDown: function(e) {
20685 // this.resetConstraints();
20686 this.autoOffset(e.getPageX(),
20691 * Event that fires prior to the onDrag event. Overrides
20694 b4Drag: function(e) {
20695 this.setDragElPos(e.getPageX(),
20699 toString: function() {
20700 return ("DD " + this.id);
20703 //////////////////////////////////////////////////////////////////////////
20704 // Debugging ygDragDrop events that can be overridden
20705 //////////////////////////////////////////////////////////////////////////
20707 startDrag: function(x, y) {
20710 onDrag: function(e) {
20713 onDragEnter: function(e, id) {
20716 onDragOver: function(e, id) {
20719 onDragOut: function(e, id) {
20722 onDragDrop: function(e, id) {
20725 endDrag: function(e) {
20732 * Ext JS Library 1.1.1
20733 * Copyright(c) 2006-2007, Ext JS, LLC.
20735 * Originally Released Under LGPL - original licence link has changed is not relivant.
20738 * <script type="text/javascript">
20742 * @class Roo.dd.DDProxy
20743 * A DragDrop implementation that inserts an empty, bordered div into
20744 * the document that follows the cursor during drag operations. At the time of
20745 * the click, the frame div is resized to the dimensions of the linked html
20746 * element, and moved to the exact location of the linked element.
20748 * References to the "frame" element refer to the single proxy element that
20749 * was created to be dragged in place of all DDProxy elements on the
20752 * @extends Roo.dd.DD
20754 * @param {String} id the id of the linked html element
20755 * @param {String} sGroup the group of related DragDrop objects
20756 * @param {object} config an object containing configurable attributes
20757 * Valid properties for DDProxy in addition to those in DragDrop:
20758 * resizeFrame, centerFrame, dragElId
20760 Roo.dd.DDProxy = function(id, sGroup, config) {
20762 this.init(id, sGroup, config);
20768 * The default drag frame div id
20769 * @property Roo.dd.DDProxy.dragElId
20773 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20775 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20778 * By default we resize the drag frame to be the same size as the element
20779 * we want to drag (this is to get the frame effect). We can turn it off
20780 * if we want a different behavior.
20781 * @property resizeFrame
20787 * By default the frame is positioned exactly where the drag element is, so
20788 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20789 * you do not have constraints on the obj is to have the drag frame centered
20790 * around the cursor. Set centerFrame to true for this effect.
20791 * @property centerFrame
20794 centerFrame: false,
20797 * Creates the proxy element if it does not yet exist
20798 * @method createFrame
20800 createFrame: function() {
20802 var body = document.body;
20804 if (!body || !body.firstChild) {
20805 setTimeout( function() { self.createFrame(); }, 50 );
20809 var div = this.getDragEl();
20812 div = document.createElement("div");
20813 div.id = this.dragElId;
20816 s.position = "absolute";
20817 s.visibility = "hidden";
20819 s.border = "2px solid #aaa";
20822 // appendChild can blow up IE if invoked prior to the window load event
20823 // while rendering a table. It is possible there are other scenarios
20824 // that would cause this to happen as well.
20825 body.insertBefore(div, body.firstChild);
20830 * Initialization for the drag frame element. Must be called in the
20831 * constructor of all subclasses
20832 * @method initFrame
20834 initFrame: function() {
20835 this.createFrame();
20838 applyConfig: function() {
20839 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20841 this.resizeFrame = (this.config.resizeFrame !== false);
20842 this.centerFrame = (this.config.centerFrame);
20843 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20847 * Resizes the drag frame to the dimensions of the clicked object, positions
20848 * it over the object, and finally displays it
20849 * @method showFrame
20850 * @param {int} iPageX X click position
20851 * @param {int} iPageY Y click position
20854 showFrame: function(iPageX, iPageY) {
20855 var el = this.getEl();
20856 var dragEl = this.getDragEl();
20857 var s = dragEl.style;
20859 this._resizeProxy();
20861 if (this.centerFrame) {
20862 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20863 Math.round(parseInt(s.height, 10)/2) );
20866 this.setDragElPos(iPageX, iPageY);
20868 Roo.fly(dragEl).show();
20872 * The proxy is automatically resized to the dimensions of the linked
20873 * element when a drag is initiated, unless resizeFrame is set to false
20874 * @method _resizeProxy
20877 _resizeProxy: function() {
20878 if (this.resizeFrame) {
20879 var el = this.getEl();
20880 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20884 // overrides Roo.dd.DragDrop
20885 b4MouseDown: function(e) {
20886 var x = e.getPageX();
20887 var y = e.getPageY();
20888 this.autoOffset(x, y);
20889 this.setDragElPos(x, y);
20892 // overrides Roo.dd.DragDrop
20893 b4StartDrag: function(x, y) {
20894 // show the drag frame
20895 this.showFrame(x, y);
20898 // overrides Roo.dd.DragDrop
20899 b4EndDrag: function(e) {
20900 Roo.fly(this.getDragEl()).hide();
20903 // overrides Roo.dd.DragDrop
20904 // By default we try to move the element to the last location of the frame.
20905 // This is so that the default behavior mirrors that of Roo.dd.DD.
20906 endDrag: function(e) {
20908 var lel = this.getEl();
20909 var del = this.getDragEl();
20911 // Show the drag frame briefly so we can get its position
20912 del.style.visibility = "";
20915 // Hide the linked element before the move to get around a Safari
20917 lel.style.visibility = "hidden";
20918 Roo.dd.DDM.moveToEl(lel, del);
20919 del.style.visibility = "hidden";
20920 lel.style.visibility = "";
20925 beforeMove : function(){
20929 afterDrag : function(){
20933 toString: function() {
20934 return ("DDProxy " + this.id);
20940 * Ext JS Library 1.1.1
20941 * Copyright(c) 2006-2007, Ext JS, LLC.
20943 * Originally Released Under LGPL - original licence link has changed is not relivant.
20946 * <script type="text/javascript">
20950 * @class Roo.dd.DDTarget
20951 * A DragDrop implementation that does not move, but can be a drop
20952 * target. You would get the same result by simply omitting implementation
20953 * for the event callbacks, but this way we reduce the processing cost of the
20954 * event listener and the callbacks.
20955 * @extends Roo.dd.DragDrop
20957 * @param {String} id the id of the element that is a drop target
20958 * @param {String} sGroup the group of related DragDrop objects
20959 * @param {object} config an object containing configurable attributes
20960 * Valid properties for DDTarget in addition to those in
20964 Roo.dd.DDTarget = function(id, sGroup, config) {
20966 this.initTarget(id, sGroup, config);
20968 if (config.listeners || config.events) {
20969 Roo.dd.DragDrop.superclass.constructor.call(this, {
20970 listeners : config.listeners || {},
20971 events : config.events || {}
20976 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20977 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20978 toString: function() {
20979 return ("DDTarget " + this.id);
20984 * Ext JS Library 1.1.1
20985 * Copyright(c) 2006-2007, Ext JS, LLC.
20987 * Originally Released Under LGPL - original licence link has changed is not relivant.
20990 * <script type="text/javascript">
20995 * @class Roo.dd.ScrollManager
20996 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20997 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21000 Roo.dd.ScrollManager = function(){
21001 var ddm = Roo.dd.DragDropMgr;
21008 var onStop = function(e){
21013 var triggerRefresh = function(){
21014 if(ddm.dragCurrent){
21015 ddm.refreshCache(ddm.dragCurrent.groups);
21019 var doScroll = function(){
21020 if(ddm.dragCurrent){
21021 var dds = Roo.dd.ScrollManager;
21023 if(proc.el.scroll(proc.dir, dds.increment)){
21027 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21032 var clearProc = function(){
21034 clearInterval(proc.id);
21041 var startProc = function(el, dir){
21042 Roo.log('scroll startproc');
21046 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21049 var onFire = function(e, isDrop){
21051 if(isDrop || !ddm.dragCurrent){ return; }
21052 var dds = Roo.dd.ScrollManager;
21053 if(!dragEl || dragEl != ddm.dragCurrent){
21054 dragEl = ddm.dragCurrent;
21055 // refresh regions on drag start
21056 dds.refreshCache();
21059 var xy = Roo.lib.Event.getXY(e);
21060 var pt = new Roo.lib.Point(xy[0], xy[1]);
21061 for(var id in els){
21062 var el = els[id], r = el._region;
21063 if(r && r.contains(pt) && el.isScrollable()){
21064 if(r.bottom - pt.y <= dds.thresh){
21066 startProc(el, "down");
21069 }else if(r.right - pt.x <= dds.thresh){
21071 startProc(el, "left");
21074 }else if(pt.y - r.top <= dds.thresh){
21076 startProc(el, "up");
21079 }else if(pt.x - r.left <= dds.thresh){
21081 startProc(el, "right");
21090 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21091 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21095 * Registers new overflow element(s) to auto scroll
21096 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21098 register : function(el){
21099 if(el instanceof Array){
21100 for(var i = 0, len = el.length; i < len; i++) {
21101 this.register(el[i]);
21107 Roo.dd.ScrollManager.els = els;
21111 * Unregisters overflow element(s) so they are no longer scrolled
21112 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21114 unregister : function(el){
21115 if(el instanceof Array){
21116 for(var i = 0, len = el.length; i < len; i++) {
21117 this.unregister(el[i]);
21126 * The number of pixels from the edge of a container the pointer needs to be to
21127 * trigger scrolling (defaults to 25)
21133 * The number of pixels to scroll in each scroll increment (defaults to 50)
21139 * The frequency of scrolls in milliseconds (defaults to 500)
21145 * True to animate the scroll (defaults to true)
21151 * The animation duration in seconds -
21152 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21158 * Manually trigger a cache refresh.
21160 refreshCache : function(){
21161 for(var id in els){
21162 if(typeof els[id] == 'object'){ // for people extending the object prototype
21163 els[id]._region = els[id].getRegion();
21170 * Ext JS Library 1.1.1
21171 * Copyright(c) 2006-2007, Ext JS, LLC.
21173 * Originally Released Under LGPL - original licence link has changed is not relivant.
21176 * <script type="text/javascript">
21181 * @class Roo.dd.Registry
21182 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21183 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21186 Roo.dd.Registry = function(){
21189 var autoIdSeed = 0;
21191 var getId = function(el, autogen){
21192 if(typeof el == "string"){
21196 if(!id && autogen !== false){
21197 id = "roodd-" + (++autoIdSeed);
21205 * Register a drag drop element
21206 * @param {String|HTMLElement} element The id or DOM node to register
21207 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21208 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21209 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21210 * populated in the data object (if applicable):
21212 Value Description<br />
21213 --------- ------------------------------------------<br />
21214 handles Array of DOM nodes that trigger dragging<br />
21215 for the element being registered<br />
21216 isHandle True if the element passed in triggers<br />
21217 dragging itself, else false
21220 register : function(el, data){
21222 if(typeof el == "string"){
21223 el = document.getElementById(el);
21226 elements[getId(el)] = data;
21227 if(data.isHandle !== false){
21228 handles[data.ddel.id] = data;
21231 var hs = data.handles;
21232 for(var i = 0, len = hs.length; i < len; i++){
21233 handles[getId(hs[i])] = data;
21239 * Unregister a drag drop element
21240 * @param {String|HTMLElement} element The id or DOM node to unregister
21242 unregister : function(el){
21243 var id = getId(el, false);
21244 var data = elements[id];
21246 delete elements[id];
21248 var hs = data.handles;
21249 for(var i = 0, len = hs.length; i < len; i++){
21250 delete handles[getId(hs[i], false)];
21257 * Returns the handle registered for a DOM Node by id
21258 * @param {String|HTMLElement} id The DOM node or id to look up
21259 * @return {Object} handle The custom handle data
21261 getHandle : function(id){
21262 if(typeof id != "string"){ // must be element?
21265 return handles[id];
21269 * Returns the handle that is registered for the DOM node that is the target of the event
21270 * @param {Event} e The event
21271 * @return {Object} handle The custom handle data
21273 getHandleFromEvent : function(e){
21274 var t = Roo.lib.Event.getTarget(e);
21275 return t ? handles[t.id] : null;
21279 * Returns a custom data object that is registered for a DOM node by id
21280 * @param {String|HTMLElement} id The DOM node or id to look up
21281 * @return {Object} data The custom data
21283 getTarget : function(id){
21284 if(typeof id != "string"){ // must be element?
21287 return elements[id];
21291 * Returns a custom data object that is registered for the DOM node that is the target of the event
21292 * @param {Event} e The event
21293 * @return {Object} data The custom data
21295 getTargetFromEvent : function(e){
21296 var t = Roo.lib.Event.getTarget(e);
21297 return t ? elements[t.id] || handles[t.id] : null;
21302 * Ext JS Library 1.1.1
21303 * Copyright(c) 2006-2007, Ext JS, LLC.
21305 * Originally Released Under LGPL - original licence link has changed is not relivant.
21308 * <script type="text/javascript">
21313 * @class Roo.dd.StatusProxy
21314 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21315 * default drag proxy used by all Roo.dd components.
21317 * @param {Object} config
21319 Roo.dd.StatusProxy = function(config){
21320 Roo.apply(this, config);
21321 this.id = this.id || Roo.id();
21322 this.el = new Roo.Layer({
21324 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21325 {tag: "div", cls: "x-dd-drop-icon"},
21326 {tag: "div", cls: "x-dd-drag-ghost"}
21329 shadow: !config || config.shadow !== false
21331 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21332 this.dropStatus = this.dropNotAllowed;
21335 Roo.dd.StatusProxy.prototype = {
21337 * @cfg {String} dropAllowed
21338 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21340 dropAllowed : "x-dd-drop-ok",
21342 * @cfg {String} dropNotAllowed
21343 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21345 dropNotAllowed : "x-dd-drop-nodrop",
21348 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21349 * over the current target element.
21350 * @param {String} cssClass The css class for the new drop status indicator image
21352 setStatus : function(cssClass){
21353 cssClass = cssClass || this.dropNotAllowed;
21354 if(this.dropStatus != cssClass){
21355 this.el.replaceClass(this.dropStatus, cssClass);
21356 this.dropStatus = cssClass;
21361 * Resets the status indicator to the default dropNotAllowed value
21362 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21364 reset : function(clearGhost){
21365 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21366 this.dropStatus = this.dropNotAllowed;
21368 this.ghost.update("");
21373 * Updates the contents of the ghost element
21374 * @param {String} html The html that will replace the current innerHTML of the ghost element
21376 update : function(html){
21377 if(typeof html == "string"){
21378 this.ghost.update(html);
21380 this.ghost.update("");
21381 html.style.margin = "0";
21382 this.ghost.dom.appendChild(html);
21384 // ensure float = none set?? cant remember why though.
21385 var el = this.ghost.dom.firstChild;
21387 Roo.fly(el).setStyle('float', 'none');
21392 * Returns the underlying proxy {@link Roo.Layer}
21393 * @return {Roo.Layer} el
21395 getEl : function(){
21400 * Returns the ghost element
21401 * @return {Roo.Element} el
21403 getGhost : function(){
21409 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21411 hide : function(clear){
21419 * Stops the repair animation if it's currently running
21422 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21428 * Displays this proxy
21435 * Force the Layer to sync its shadow and shim positions to the element
21442 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21443 * invalid drop operation by the item being dragged.
21444 * @param {Array} xy The XY position of the element ([x, y])
21445 * @param {Function} callback The function to call after the repair is complete
21446 * @param {Object} scope The scope in which to execute the callback
21448 repair : function(xy, callback, scope){
21449 this.callback = callback;
21450 this.scope = scope;
21451 if(xy && this.animRepair !== false){
21452 this.el.addClass("x-dd-drag-repair");
21453 this.el.hideUnders(true);
21454 this.anim = this.el.shift({
21455 duration: this.repairDuration || .5,
21459 callback: this.afterRepair,
21463 this.afterRepair();
21468 afterRepair : function(){
21470 if(typeof this.callback == "function"){
21471 this.callback.call(this.scope || this);
21473 this.callback = null;
21478 * Ext JS Library 1.1.1
21479 * Copyright(c) 2006-2007, Ext JS, LLC.
21481 * Originally Released Under LGPL - original licence link has changed is not relivant.
21484 * <script type="text/javascript">
21488 * @class Roo.dd.DragSource
21489 * @extends Roo.dd.DDProxy
21490 * A simple class that provides the basic implementation needed to make any element draggable.
21492 * @param {String/HTMLElement/Element} el The container element
21493 * @param {Object} config
21495 Roo.dd.DragSource = function(el, config){
21496 this.el = Roo.get(el);
21497 this.dragData = {};
21499 Roo.apply(this, config);
21502 this.proxy = new Roo.dd.StatusProxy();
21505 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21506 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21508 this.dragging = false;
21511 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21513 * @cfg {String} dropAllowed
21514 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21516 dropAllowed : "x-dd-drop-ok",
21518 * @cfg {String} dropNotAllowed
21519 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21521 dropNotAllowed : "x-dd-drop-nodrop",
21524 * Returns the data object associated with this drag source
21525 * @return {Object} data An object containing arbitrary data
21527 getDragData : function(e){
21528 return this.dragData;
21532 onDragEnter : function(e, id){
21533 var target = Roo.dd.DragDropMgr.getDDById(id);
21534 this.cachedTarget = target;
21535 if(this.beforeDragEnter(target, e, id) !== false){
21536 if(target.isNotifyTarget){
21537 var status = target.notifyEnter(this, e, this.dragData);
21538 this.proxy.setStatus(status);
21540 this.proxy.setStatus(this.dropAllowed);
21543 if(this.afterDragEnter){
21545 * An empty function by default, but provided so that you can perform a custom action
21546 * when the dragged item enters the drop target by providing an implementation.
21547 * @param {Roo.dd.DragDrop} target The drop target
21548 * @param {Event} e The event object
21549 * @param {String} id The id of the dragged element
21550 * @method afterDragEnter
21552 this.afterDragEnter(target, e, id);
21558 * An empty function by default, but provided so that you can perform a custom action
21559 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21560 * @param {Roo.dd.DragDrop} target The drop target
21561 * @param {Event} e The event object
21562 * @param {String} id The id of the dragged element
21563 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21565 beforeDragEnter : function(target, e, id){
21570 alignElWithMouse: function() {
21571 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21576 onDragOver : function(e, id){
21577 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21578 if(this.beforeDragOver(target, e, id) !== false){
21579 if(target.isNotifyTarget){
21580 var status = target.notifyOver(this, e, this.dragData);
21581 this.proxy.setStatus(status);
21584 if(this.afterDragOver){
21586 * An empty function by default, but provided so that you can perform a custom action
21587 * while the dragged item is over the drop target by providing an implementation.
21588 * @param {Roo.dd.DragDrop} target The drop target
21589 * @param {Event} e The event object
21590 * @param {String} id The id of the dragged element
21591 * @method afterDragOver
21593 this.afterDragOver(target, e, id);
21599 * An empty function by default, but provided so that you can perform a custom action
21600 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21601 * @param {Roo.dd.DragDrop} target The drop target
21602 * @param {Event} e The event object
21603 * @param {String} id The id of the dragged element
21604 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21606 beforeDragOver : function(target, e, id){
21611 onDragOut : function(e, id){
21612 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21613 if(this.beforeDragOut(target, e, id) !== false){
21614 if(target.isNotifyTarget){
21615 target.notifyOut(this, e, this.dragData);
21617 this.proxy.reset();
21618 if(this.afterDragOut){
21620 * An empty function by default, but provided so that you can perform a custom action
21621 * after the dragged item is dragged out of the target without dropping.
21622 * @param {Roo.dd.DragDrop} target The drop target
21623 * @param {Event} e The event object
21624 * @param {String} id The id of the dragged element
21625 * @method afterDragOut
21627 this.afterDragOut(target, e, id);
21630 this.cachedTarget = null;
21634 * An empty function by default, but provided so that you can perform a custom action before the dragged
21635 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21636 * @param {Roo.dd.DragDrop} target The drop target
21637 * @param {Event} e The event object
21638 * @param {String} id The id of the dragged element
21639 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21641 beforeDragOut : function(target, e, id){
21646 onDragDrop : function(e, id){
21647 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21648 if(this.beforeDragDrop(target, e, id) !== false){
21649 if(target.isNotifyTarget){
21650 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21651 this.onValidDrop(target, e, id);
21653 this.onInvalidDrop(target, e, id);
21656 this.onValidDrop(target, e, id);
21659 if(this.afterDragDrop){
21661 * An empty function by default, but provided so that you can perform a custom action
21662 * after a valid drag drop has occurred by providing an implementation.
21663 * @param {Roo.dd.DragDrop} target The drop target
21664 * @param {Event} e The event object
21665 * @param {String} id The id of the dropped element
21666 * @method afterDragDrop
21668 this.afterDragDrop(target, e, id);
21671 delete this.cachedTarget;
21675 * An empty function by default, but provided so that you can perform a custom action before the dragged
21676 * item is dropped onto the target and optionally cancel the onDragDrop.
21677 * @param {Roo.dd.DragDrop} target The drop target
21678 * @param {Event} e The event object
21679 * @param {String} id The id of the dragged element
21680 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21682 beforeDragDrop : function(target, e, id){
21687 onValidDrop : function(target, e, id){
21689 if(this.afterValidDrop){
21691 * An empty function by default, but provided so that you can perform a custom action
21692 * after a valid drop has occurred by providing an implementation.
21693 * @param {Object} target The target DD
21694 * @param {Event} e The event object
21695 * @param {String} id The id of the dropped element
21696 * @method afterInvalidDrop
21698 this.afterValidDrop(target, e, id);
21703 getRepairXY : function(e, data){
21704 return this.el.getXY();
21708 onInvalidDrop : function(target, e, id){
21709 this.beforeInvalidDrop(target, e, id);
21710 if(this.cachedTarget){
21711 if(this.cachedTarget.isNotifyTarget){
21712 this.cachedTarget.notifyOut(this, e, this.dragData);
21714 this.cacheTarget = null;
21716 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21718 if(this.afterInvalidDrop){
21720 * An empty function by default, but provided so that you can perform a custom action
21721 * after an invalid drop has occurred by providing an implementation.
21722 * @param {Event} e The event object
21723 * @param {String} id The id of the dropped element
21724 * @method afterInvalidDrop
21726 this.afterInvalidDrop(e, id);
21731 afterRepair : function(){
21733 this.el.highlight(this.hlColor || "c3daf9");
21735 this.dragging = false;
21739 * An empty function by default, but provided so that you can perform a custom action after an invalid
21740 * drop has occurred.
21741 * @param {Roo.dd.DragDrop} target The drop target
21742 * @param {Event} e The event object
21743 * @param {String} id The id of the dragged element
21744 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21746 beforeInvalidDrop : function(target, e, id){
21751 handleMouseDown : function(e){
21752 if(this.dragging) {
21755 var data = this.getDragData(e);
21756 if(data && this.onBeforeDrag(data, e) !== false){
21757 this.dragData = data;
21759 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21764 * An empty function by default, but provided so that you can perform a custom action before the initial
21765 * drag event begins and optionally cancel it.
21766 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21767 * @param {Event} e The event object
21768 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21770 onBeforeDrag : function(data, e){
21775 * An empty function by default, but provided so that you can perform a custom action once the initial
21776 * drag event has begun. The drag cannot be canceled from this function.
21777 * @param {Number} x The x position of the click on the dragged object
21778 * @param {Number} y The y position of the click on the dragged object
21780 onStartDrag : Roo.emptyFn,
21782 // private - YUI override
21783 startDrag : function(x, y){
21784 this.proxy.reset();
21785 this.dragging = true;
21786 this.proxy.update("");
21787 this.onInitDrag(x, y);
21792 onInitDrag : function(x, y){
21793 var clone = this.el.dom.cloneNode(true);
21794 clone.id = Roo.id(); // prevent duplicate ids
21795 this.proxy.update(clone);
21796 this.onStartDrag(x, y);
21801 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21802 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21804 getProxy : function(){
21809 * Hides the drag source's {@link Roo.dd.StatusProxy}
21811 hideProxy : function(){
21813 this.proxy.reset(true);
21814 this.dragging = false;
21818 triggerCacheRefresh : function(){
21819 Roo.dd.DDM.refreshCache(this.groups);
21822 // private - override to prevent hiding
21823 b4EndDrag: function(e) {
21826 // private - override to prevent moving
21827 endDrag : function(e){
21828 this.onEndDrag(this.dragData, e);
21832 onEndDrag : function(data, e){
21835 // private - pin to cursor
21836 autoOffset : function(x, y) {
21837 this.setDelta(-12, -20);
21841 * Ext JS Library 1.1.1
21842 * Copyright(c) 2006-2007, Ext JS, LLC.
21844 * Originally Released Under LGPL - original licence link has changed is not relivant.
21847 * <script type="text/javascript">
21852 * @class Roo.dd.DropTarget
21853 * @extends Roo.dd.DDTarget
21854 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21855 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21857 * @param {String/HTMLElement/Element} el The container element
21858 * @param {Object} config
21860 Roo.dd.DropTarget = function(el, config){
21861 this.el = Roo.get(el);
21863 var listeners = false; ;
21864 if (config && config.listeners) {
21865 listeners= config.listeners;
21866 delete config.listeners;
21868 Roo.apply(this, config);
21870 if(this.containerScroll){
21871 Roo.dd.ScrollManager.register(this.el);
21875 * @scope Roo.dd.DropTarget
21880 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21881 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21882 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21884 * IMPORTANT : it should set this.overClass and this.dropAllowed
21886 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21887 * @param {Event} e The event
21888 * @param {Object} data An object containing arbitrary data supplied by the drag source
21894 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21895 * This method will be called on every mouse movement while the drag source is over the drop target.
21896 * This default implementation simply returns the dropAllowed config value.
21898 * IMPORTANT : it should set this.dropAllowed
21900 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21901 * @param {Event} e The event
21902 * @param {Object} data An object containing arbitrary data supplied by the drag source
21908 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21909 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21910 * overClass (if any) from the drop element.
21912 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21913 * @param {Event} e The event
21914 * @param {Object} data An object containing arbitrary data supplied by the drag source
21920 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21921 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21922 * implementation that does something to process the drop event and returns true so that the drag source's
21923 * repair action does not run.
21925 * IMPORTANT : it should set this.success
21927 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21928 * @param {Event} e The event
21929 * @param {Object} data An object containing arbitrary data supplied by the drag source
21935 Roo.dd.DropTarget.superclass.constructor.call( this,
21937 this.ddGroup || this.group,
21940 listeners : listeners || {}
21948 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21950 * @cfg {String} overClass
21951 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21954 * @cfg {String} ddGroup
21955 * The drag drop group to handle drop events for
21959 * @cfg {String} dropAllowed
21960 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21962 dropAllowed : "x-dd-drop-ok",
21964 * @cfg {String} dropNotAllowed
21965 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21967 dropNotAllowed : "x-dd-drop-nodrop",
21969 * @cfg {boolean} success
21970 * set this after drop listener..
21974 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21975 * if the drop point is valid for over/enter..
21982 isNotifyTarget : true,
21987 notifyEnter : function(dd, e, data)
21990 this.fireEvent('enter', dd, e, data);
21991 if(this.overClass){
21992 this.el.addClass(this.overClass);
21994 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21995 this.valid ? this.dropAllowed : this.dropNotAllowed
22002 notifyOver : function(dd, e, data)
22005 this.fireEvent('over', dd, e, data);
22006 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22007 this.valid ? this.dropAllowed : this.dropNotAllowed
22014 notifyOut : function(dd, e, data)
22016 this.fireEvent('out', dd, e, data);
22017 if(this.overClass){
22018 this.el.removeClass(this.overClass);
22025 notifyDrop : function(dd, e, data)
22027 this.success = false;
22028 this.fireEvent('drop', dd, e, data);
22029 return this.success;
22033 * Ext JS Library 1.1.1
22034 * Copyright(c) 2006-2007, Ext JS, LLC.
22036 * Originally Released Under LGPL - original licence link has changed is not relivant.
22039 * <script type="text/javascript">
22044 * @class Roo.dd.DragZone
22045 * @extends Roo.dd.DragSource
22046 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22047 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22049 * @param {String/HTMLElement/Element} el The container element
22050 * @param {Object} config
22052 Roo.dd.DragZone = function(el, config){
22053 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22054 if(this.containerScroll){
22055 Roo.dd.ScrollManager.register(this.el);
22059 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22061 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22062 * for auto scrolling during drag operations.
22065 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22066 * method after a failed drop (defaults to "c3daf9" - light blue)
22070 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22071 * for a valid target to drag based on the mouse down. Override this method
22072 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22073 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22074 * @param {EventObject} e The mouse down event
22075 * @return {Object} The dragData
22077 getDragData : function(e){
22078 return Roo.dd.Registry.getHandleFromEvent(e);
22082 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22083 * this.dragData.ddel
22084 * @param {Number} x The x position of the click on the dragged object
22085 * @param {Number} y The y position of the click on the dragged object
22086 * @return {Boolean} true to continue the drag, false to cancel
22088 onInitDrag : function(x, y){
22089 this.proxy.update(this.dragData.ddel.cloneNode(true));
22090 this.onStartDrag(x, y);
22095 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22097 afterRepair : function(){
22099 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22101 this.dragging = false;
22105 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22106 * the XY of this.dragData.ddel
22107 * @param {EventObject} e The mouse up event
22108 * @return {Array} The xy location (e.g. [100, 200])
22110 getRepairXY : function(e){
22111 return Roo.Element.fly(this.dragData.ddel).getXY();
22115 * Ext JS Library 1.1.1
22116 * Copyright(c) 2006-2007, Ext JS, LLC.
22118 * Originally Released Under LGPL - original licence link has changed is not relivant.
22121 * <script type="text/javascript">
22124 * @class Roo.dd.DropZone
22125 * @extends Roo.dd.DropTarget
22126 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22127 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22129 * @param {String/HTMLElement/Element} el The container element
22130 * @param {Object} config
22132 Roo.dd.DropZone = function(el, config){
22133 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22136 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22138 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22139 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22140 * provide your own custom lookup.
22141 * @param {Event} e The event
22142 * @return {Object} data The custom data
22144 getTargetFromEvent : function(e){
22145 return Roo.dd.Registry.getTargetFromEvent(e);
22149 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22150 * that it has registered. This method has no default implementation and should be overridden to provide
22151 * node-specific processing if necessary.
22152 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22153 * {@link #getTargetFromEvent} for this node)
22154 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22155 * @param {Event} e The event
22156 * @param {Object} data An object containing arbitrary data supplied by the drag source
22158 onNodeEnter : function(n, dd, e, data){
22163 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22164 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22165 * overridden to provide the proper feedback.
22166 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22167 * {@link #getTargetFromEvent} for this node)
22168 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22169 * @param {Event} e The event
22170 * @param {Object} data An object containing arbitrary data supplied by the drag source
22171 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22172 * underlying {@link Roo.dd.StatusProxy} can be updated
22174 onNodeOver : function(n, dd, e, data){
22175 return this.dropAllowed;
22179 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22180 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22181 * node-specific processing if necessary.
22182 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22183 * {@link #getTargetFromEvent} for this node)
22184 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22185 * @param {Event} e The event
22186 * @param {Object} data An object containing arbitrary data supplied by the drag source
22188 onNodeOut : function(n, dd, e, data){
22193 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22194 * the drop node. The default implementation returns false, so it should be overridden to provide the
22195 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22196 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22197 * {@link #getTargetFromEvent} for this node)
22198 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22199 * @param {Event} e The event
22200 * @param {Object} data An object containing arbitrary data supplied by the drag source
22201 * @return {Boolean} True if the drop was valid, else false
22203 onNodeDrop : function(n, dd, e, data){
22208 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22209 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22210 * it should be overridden to provide the proper feedback if necessary.
22211 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22212 * @param {Event} e The event
22213 * @param {Object} data An object containing arbitrary data supplied by the drag source
22214 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22215 * underlying {@link Roo.dd.StatusProxy} can be updated
22217 onContainerOver : function(dd, e, data){
22218 return this.dropNotAllowed;
22222 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22223 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22224 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22225 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22226 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22227 * @param {Event} e The event
22228 * @param {Object} data An object containing arbitrary data supplied by the drag source
22229 * @return {Boolean} True if the drop was valid, else false
22231 onContainerDrop : function(dd, e, data){
22236 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22237 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22238 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22239 * you should override this method and provide a custom implementation.
22240 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22241 * @param {Event} e The event
22242 * @param {Object} data An object containing arbitrary data supplied by the drag source
22243 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22244 * underlying {@link Roo.dd.StatusProxy} can be updated
22246 notifyEnter : function(dd, e, data){
22247 return this.dropNotAllowed;
22251 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22252 * This method will be called on every mouse movement while the drag source is over the drop zone.
22253 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22254 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22255 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22256 * registered node, it will call {@link #onContainerOver}.
22257 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22258 * @param {Event} e The event
22259 * @param {Object} data An object containing arbitrary data supplied by the drag source
22260 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22261 * underlying {@link Roo.dd.StatusProxy} can be updated
22263 notifyOver : function(dd, e, data){
22264 var n = this.getTargetFromEvent(e);
22265 if(!n){ // not over valid drop target
22266 if(this.lastOverNode){
22267 this.onNodeOut(this.lastOverNode, dd, e, data);
22268 this.lastOverNode = null;
22270 return this.onContainerOver(dd, e, data);
22272 if(this.lastOverNode != n){
22273 if(this.lastOverNode){
22274 this.onNodeOut(this.lastOverNode, dd, e, data);
22276 this.onNodeEnter(n, dd, e, data);
22277 this.lastOverNode = n;
22279 return this.onNodeOver(n, dd, e, data);
22283 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22284 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22285 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22286 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22287 * @param {Event} e The event
22288 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22290 notifyOut : function(dd, e, data){
22291 if(this.lastOverNode){
22292 this.onNodeOut(this.lastOverNode, dd, e, data);
22293 this.lastOverNode = null;
22298 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22299 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22300 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22301 * otherwise it will call {@link #onContainerDrop}.
22302 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22303 * @param {Event} e The event
22304 * @param {Object} data An object containing arbitrary data supplied by the drag source
22305 * @return {Boolean} True if the drop was valid, else false
22307 notifyDrop : function(dd, e, data){
22308 if(this.lastOverNode){
22309 this.onNodeOut(this.lastOverNode, dd, e, data);
22310 this.lastOverNode = null;
22312 var n = this.getTargetFromEvent(e);
22314 this.onNodeDrop(n, dd, e, data) :
22315 this.onContainerDrop(dd, e, data);
22319 triggerCacheRefresh : function(){
22320 Roo.dd.DDM.refreshCache(this.groups);
22324 * Ext JS Library 1.1.1
22325 * Copyright(c) 2006-2007, Ext JS, LLC.
22327 * Originally Released Under LGPL - original licence link has changed is not relivant.
22330 * <script type="text/javascript">
22335 * @class Roo.data.SortTypes
22337 * Defines the default sorting (casting?) comparison functions used when sorting data.
22339 Roo.data.SortTypes = {
22341 * Default sort that does nothing
22342 * @param {Mixed} s The value being converted
22343 * @return {Mixed} The comparison value
22345 none : function(s){
22350 * The regular expression used to strip tags
22354 stripTagsRE : /<\/?[^>]+>/gi,
22357 * Strips all HTML tags to sort on text only
22358 * @param {Mixed} s The value being converted
22359 * @return {String} The comparison value
22361 asText : function(s){
22362 return String(s).replace(this.stripTagsRE, "");
22366 * Strips all HTML tags to sort on text only - Case insensitive
22367 * @param {Mixed} s The value being converted
22368 * @return {String} The comparison value
22370 asUCText : function(s){
22371 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22375 * Case insensitive string
22376 * @param {Mixed} s The value being converted
22377 * @return {String} The comparison value
22379 asUCString : function(s) {
22380 return String(s).toUpperCase();
22385 * @param {Mixed} s The value being converted
22386 * @return {Number} The comparison value
22388 asDate : function(s) {
22392 if(s instanceof Date){
22393 return s.getTime();
22395 return Date.parse(String(s));
22400 * @param {Mixed} s The value being converted
22401 * @return {Float} The comparison value
22403 asFloat : function(s) {
22404 var val = parseFloat(String(s).replace(/,/g, ""));
22413 * @param {Mixed} s The value being converted
22414 * @return {Number} The comparison value
22416 asInt : function(s) {
22417 var val = parseInt(String(s).replace(/,/g, ""));
22425 * Ext JS Library 1.1.1
22426 * Copyright(c) 2006-2007, Ext JS, LLC.
22428 * Originally Released Under LGPL - original licence link has changed is not relivant.
22431 * <script type="text/javascript">
22435 * @class Roo.data.Record
22436 * Instances of this class encapsulate both record <em>definition</em> information, and record
22437 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22438 * to access Records cached in an {@link Roo.data.Store} object.<br>
22440 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22441 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22444 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22446 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22447 * {@link #create}. The parameters are the same.
22448 * @param {Array} data An associative Array of data values keyed by the field name.
22449 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22450 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22451 * not specified an integer id is generated.
22453 Roo.data.Record = function(data, id){
22454 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22459 * Generate a constructor for a specific record layout.
22460 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22461 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22462 * Each field definition object may contain the following properties: <ul>
22463 * <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,
22464 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22465 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22466 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22467 * is being used, then this is a string containing the javascript expression to reference the data relative to
22468 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22469 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22470 * this may be omitted.</p></li>
22471 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22472 * <ul><li>auto (Default, implies no conversion)</li>
22477 * <li>date</li></ul></p></li>
22478 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22479 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22480 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22481 * by the Reader into an object that will be stored in the Record. It is passed the
22482 * following parameters:<ul>
22483 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22485 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22487 * <br>usage:<br><pre><code>
22488 var TopicRecord = Roo.data.Record.create(
22489 {name: 'title', mapping: 'topic_title'},
22490 {name: 'author', mapping: 'username'},
22491 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22492 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22493 {name: 'lastPoster', mapping: 'user2'},
22494 {name: 'excerpt', mapping: 'post_text'}
22497 var myNewRecord = new TopicRecord({
22498 title: 'Do my job please',
22501 lastPost: new Date(),
22502 lastPoster: 'Animal',
22503 excerpt: 'No way dude!'
22505 myStore.add(myNewRecord);
22510 Roo.data.Record.create = function(o){
22511 var f = function(){
22512 f.superclass.constructor.apply(this, arguments);
22514 Roo.extend(f, Roo.data.Record);
22515 var p = f.prototype;
22516 p.fields = new Roo.util.MixedCollection(false, function(field){
22519 for(var i = 0, len = o.length; i < len; i++){
22520 p.fields.add(new Roo.data.Field(o[i]));
22522 f.getField = function(name){
22523 return p.fields.get(name);
22528 Roo.data.Record.AUTO_ID = 1000;
22529 Roo.data.Record.EDIT = 'edit';
22530 Roo.data.Record.REJECT = 'reject';
22531 Roo.data.Record.COMMIT = 'commit';
22533 Roo.data.Record.prototype = {
22535 * Readonly flag - true if this record has been modified.
22544 join : function(store){
22545 this.store = store;
22549 * Set the named field to the specified value.
22550 * @param {String} name The name of the field to set.
22551 * @param {Object} value The value to set the field to.
22553 set : function(name, value){
22554 if(this.data[name] == value){
22558 if(!this.modified){
22559 this.modified = {};
22561 if(typeof this.modified[name] == 'undefined'){
22562 this.modified[name] = this.data[name];
22564 this.data[name] = value;
22565 if(!this.editing && this.store){
22566 this.store.afterEdit(this);
22571 * Get the value of the named field.
22572 * @param {String} name The name of the field to get the value of.
22573 * @return {Object} The value of the field.
22575 get : function(name){
22576 return this.data[name];
22580 beginEdit : function(){
22581 this.editing = true;
22582 this.modified = {};
22586 cancelEdit : function(){
22587 this.editing = false;
22588 delete this.modified;
22592 endEdit : function(){
22593 this.editing = false;
22594 if(this.dirty && this.store){
22595 this.store.afterEdit(this);
22600 * Usually called by the {@link Roo.data.Store} which owns the Record.
22601 * Rejects all changes made to the Record since either creation, or the last commit operation.
22602 * Modified fields are reverted to their original values.
22604 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22605 * of reject operations.
22607 reject : function(){
22608 var m = this.modified;
22610 if(typeof m[n] != "function"){
22611 this.data[n] = m[n];
22614 this.dirty = false;
22615 delete this.modified;
22616 this.editing = false;
22618 this.store.afterReject(this);
22623 * Usually called by the {@link Roo.data.Store} which owns the Record.
22624 * Commits all changes made to the Record since either creation, or the last commit operation.
22626 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22627 * of commit operations.
22629 commit : function(){
22630 this.dirty = false;
22631 delete this.modified;
22632 this.editing = false;
22634 this.store.afterCommit(this);
22639 hasError : function(){
22640 return this.error != null;
22644 clearError : function(){
22649 * Creates a copy of this record.
22650 * @param {String} id (optional) A new record id if you don't want to use this record's id
22653 copy : function(newId) {
22654 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22658 * Ext JS Library 1.1.1
22659 * Copyright(c) 2006-2007, Ext JS, LLC.
22661 * Originally Released Under LGPL - original licence link has changed is not relivant.
22664 * <script type="text/javascript">
22670 * @class Roo.data.Store
22671 * @extends Roo.util.Observable
22672 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22673 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22675 * 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
22676 * has no knowledge of the format of the data returned by the Proxy.<br>
22678 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22679 * instances from the data object. These records are cached and made available through accessor functions.
22681 * Creates a new Store.
22682 * @param {Object} config A config object containing the objects needed for the Store to access data,
22683 * and read the data into Records.
22685 Roo.data.Store = function(config){
22686 this.data = new Roo.util.MixedCollection(false);
22687 this.data.getKey = function(o){
22690 this.baseParams = {};
22692 this.paramNames = {
22697 "multisort" : "_multisort"
22700 if(config && config.data){
22701 this.inlineData = config.data;
22702 delete config.data;
22705 Roo.apply(this, config);
22707 if(this.reader){ // reader passed
22708 this.reader = Roo.factory(this.reader, Roo.data);
22709 this.reader.xmodule = this.xmodule || false;
22710 if(!this.recordType){
22711 this.recordType = this.reader.recordType;
22713 if(this.reader.onMetaChange){
22714 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22718 if(this.recordType){
22719 this.fields = this.recordType.prototype.fields;
22721 this.modified = [];
22725 * @event datachanged
22726 * Fires when the data cache has changed, and a widget which is using this Store
22727 * as a Record cache should refresh its view.
22728 * @param {Store} this
22730 datachanged : true,
22732 * @event metachange
22733 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22734 * @param {Store} this
22735 * @param {Object} meta The JSON metadata
22740 * Fires when Records have been added to the Store
22741 * @param {Store} this
22742 * @param {Roo.data.Record[]} records The array of Records added
22743 * @param {Number} index The index at which the record(s) were added
22748 * Fires when a Record has been removed from the Store
22749 * @param {Store} this
22750 * @param {Roo.data.Record} record The Record that was removed
22751 * @param {Number} index The index at which the record was removed
22756 * Fires when a Record has been updated
22757 * @param {Store} this
22758 * @param {Roo.data.Record} record The Record that was updated
22759 * @param {String} operation The update operation being performed. Value may be one of:
22761 Roo.data.Record.EDIT
22762 Roo.data.Record.REJECT
22763 Roo.data.Record.COMMIT
22769 * Fires when the data cache has been cleared.
22770 * @param {Store} this
22774 * @event beforeload
22775 * Fires before a request is made for a new data object. If the beforeload handler returns false
22776 * the load action will be canceled.
22777 * @param {Store} this
22778 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22782 * @event beforeloadadd
22783 * Fires after a new set of Records has been loaded.
22784 * @param {Store} this
22785 * @param {Roo.data.Record[]} records The Records that were loaded
22786 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22788 beforeloadadd : true,
22791 * Fires after a new set of Records has been loaded, before they are added to the store.
22792 * @param {Store} this
22793 * @param {Roo.data.Record[]} records The Records that were loaded
22794 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22795 * @params {Object} return from reader
22799 * @event loadexception
22800 * Fires if an exception occurs in the Proxy during loading.
22801 * Called with the signature of the Proxy's "loadexception" event.
22802 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22805 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22806 * @param {Object} load options
22807 * @param {Object} jsonData from your request (normally this contains the Exception)
22809 loadexception : true
22813 this.proxy = Roo.factory(this.proxy, Roo.data);
22814 this.proxy.xmodule = this.xmodule || false;
22815 this.relayEvents(this.proxy, ["loadexception"]);
22817 this.sortToggle = {};
22818 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22820 Roo.data.Store.superclass.constructor.call(this);
22822 if(this.inlineData){
22823 this.loadData(this.inlineData);
22824 delete this.inlineData;
22828 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22830 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22831 * without a remote query - used by combo/forms at present.
22835 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22838 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22841 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22842 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22845 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22846 * on any HTTP request
22849 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22852 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22856 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22857 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22859 remoteSort : false,
22862 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22863 * loaded or when a record is removed. (defaults to false).
22865 pruneModifiedRecords : false,
22868 lastOptions : null,
22871 * Add Records to the Store and fires the add event.
22872 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22874 add : function(records){
22875 records = [].concat(records);
22876 for(var i = 0, len = records.length; i < len; i++){
22877 records[i].join(this);
22879 var index = this.data.length;
22880 this.data.addAll(records);
22881 this.fireEvent("add", this, records, index);
22885 * Remove a Record from the Store and fires the remove event.
22886 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
22888 remove : function(record){
22889 var index = this.data.indexOf(record);
22890 this.data.removeAt(index);
22891 if(this.pruneModifiedRecords){
22892 this.modified.remove(record);
22894 this.fireEvent("remove", this, record, index);
22898 * Remove all Records from the Store and fires the clear event.
22900 removeAll : function(){
22902 if(this.pruneModifiedRecords){
22903 this.modified = [];
22905 this.fireEvent("clear", this);
22909 * Inserts Records to the Store at the given index and fires the add event.
22910 * @param {Number} index The start index at which to insert the passed Records.
22911 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22913 insert : function(index, records){
22914 records = [].concat(records);
22915 for(var i = 0, len = records.length; i < len; i++){
22916 this.data.insert(index, records[i]);
22917 records[i].join(this);
22919 this.fireEvent("add", this, records, index);
22923 * Get the index within the cache of the passed Record.
22924 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
22925 * @return {Number} The index of the passed Record. Returns -1 if not found.
22927 indexOf : function(record){
22928 return this.data.indexOf(record);
22932 * Get the index within the cache of the Record with the passed id.
22933 * @param {String} id The id of the Record to find.
22934 * @return {Number} The index of the Record. Returns -1 if not found.
22936 indexOfId : function(id){
22937 return this.data.indexOfKey(id);
22941 * Get the Record with the specified id.
22942 * @param {String} id The id of the Record to find.
22943 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
22945 getById : function(id){
22946 return this.data.key(id);
22950 * Get the Record at the specified index.
22951 * @param {Number} index The index of the Record to find.
22952 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
22954 getAt : function(index){
22955 return this.data.itemAt(index);
22959 * Returns a range of Records between specified indices.
22960 * @param {Number} startIndex (optional) The starting index (defaults to 0)
22961 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
22962 * @return {Roo.data.Record[]} An array of Records
22964 getRange : function(start, end){
22965 return this.data.getRange(start, end);
22969 storeOptions : function(o){
22970 o = Roo.apply({}, o);
22973 this.lastOptions = o;
22977 * Loads the Record cache from the configured Proxy using the configured Reader.
22979 * If using remote paging, then the first load call must specify the <em>start</em>
22980 * and <em>limit</em> properties in the options.params property to establish the initial
22981 * position within the dataset, and the number of Records to cache on each read from the Proxy.
22983 * <strong>It is important to note that for remote data sources, loading is asynchronous,
22984 * and this call will return before the new data has been loaded. Perform any post-processing
22985 * in a callback function, or in a "load" event handler.</strong>
22987 * @param {Object} options An object containing properties which control loading options:<ul>
22988 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
22989 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
22990 * passed the following arguments:<ul>
22991 * <li>r : Roo.data.Record[]</li>
22992 * <li>options: Options object from the load call</li>
22993 * <li>success: Boolean success indicator</li></ul></li>
22994 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
22995 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
22998 load : function(options){
22999 options = options || {};
23000 if(this.fireEvent("beforeload", this, options) !== false){
23001 this.storeOptions(options);
23002 var p = Roo.apply(options.params || {}, this.baseParams);
23003 // if meta was not loaded from remote source.. try requesting it.
23004 if (!this.reader.metaFromRemote) {
23005 p._requestMeta = 1;
23007 if(this.sortInfo && this.remoteSort){
23008 var pn = this.paramNames;
23009 p[pn["sort"]] = this.sortInfo.field;
23010 p[pn["dir"]] = this.sortInfo.direction;
23012 if (this.multiSort) {
23013 var pn = this.paramNames;
23014 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23017 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23022 * Reloads the Record cache from the configured Proxy using the configured Reader and
23023 * the options from the last load operation performed.
23024 * @param {Object} options (optional) An object containing properties which may override the options
23025 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23026 * the most recently used options are reused).
23028 reload : function(options){
23029 this.load(Roo.applyIf(options||{}, this.lastOptions));
23033 // Called as a callback by the Reader during a load operation.
23034 loadRecords : function(o, options, success){
23035 if(!o || success === false){
23036 if(success !== false){
23037 this.fireEvent("load", this, [], options, o);
23039 if(options.callback){
23040 options.callback.call(options.scope || this, [], options, false);
23044 // if data returned failure - throw an exception.
23045 if (o.success === false) {
23046 // show a message if no listener is registered.
23047 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23048 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23050 // loadmask wil be hooked into this..
23051 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23054 var r = o.records, t = o.totalRecords || r.length;
23056 this.fireEvent("beforeloadadd", this, r, options, o);
23058 if(!options || options.add !== true){
23059 if(this.pruneModifiedRecords){
23060 this.modified = [];
23062 for(var i = 0, len = r.length; i < len; i++){
23066 this.data = this.snapshot;
23067 delete this.snapshot;
23070 this.data.addAll(r);
23071 this.totalLength = t;
23073 this.fireEvent("datachanged", this);
23075 this.totalLength = Math.max(t, this.data.length+r.length);
23078 this.fireEvent("load", this, r, options, o);
23079 if(options.callback){
23080 options.callback.call(options.scope || this, r, options, true);
23086 * Loads data from a passed data block. A Reader which understands the format of the data
23087 * must have been configured in the constructor.
23088 * @param {Object} data The data block from which to read the Records. The format of the data expected
23089 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23090 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23092 loadData : function(o, append){
23093 var r = this.reader.readRecords(o);
23094 this.loadRecords(r, {add: append}, true);
23098 * Gets the number of cached records.
23100 * <em>If using paging, this may not be the total size of the dataset. If the data object
23101 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23102 * the data set size</em>
23104 getCount : function(){
23105 return this.data.length || 0;
23109 * Gets the total number of records in the dataset as returned by the server.
23111 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23112 * the dataset size</em>
23114 getTotalCount : function(){
23115 return this.totalLength || 0;
23119 * Returns the sort state of the Store as an object with two properties:
23121 field {String} The name of the field by which the Records are sorted
23122 direction {String} The sort order, "ASC" or "DESC"
23125 getSortState : function(){
23126 return this.sortInfo;
23130 applySort : function(){
23131 if(this.sortInfo && !this.remoteSort){
23132 var s = this.sortInfo, f = s.field;
23133 var st = this.fields.get(f).sortType;
23134 var fn = function(r1, r2){
23135 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23136 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23138 this.data.sort(s.direction, fn);
23139 if(this.snapshot && this.snapshot != this.data){
23140 this.snapshot.sort(s.direction, fn);
23146 * Sets the default sort column and order to be used by the next load operation.
23147 * @param {String} fieldName The name of the field to sort by.
23148 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23150 setDefaultSort : function(field, dir){
23151 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23155 * Sort the Records.
23156 * If remote sorting is used, the sort is performed on the server, and the cache is
23157 * reloaded. If local sorting is used, the cache is sorted internally.
23158 * @param {String} fieldName The name of the field to sort by.
23159 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23161 sort : function(fieldName, dir){
23162 var f = this.fields.get(fieldName);
23164 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23166 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23167 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23172 this.sortToggle[f.name] = dir;
23173 this.sortInfo = {field: f.name, direction: dir};
23174 if(!this.remoteSort){
23176 this.fireEvent("datachanged", this);
23178 this.load(this.lastOptions);
23183 * Calls the specified function for each of the Records in the cache.
23184 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23185 * Returning <em>false</em> aborts and exits the iteration.
23186 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23188 each : function(fn, scope){
23189 this.data.each(fn, scope);
23193 * Gets all records modified since the last commit. Modified records are persisted across load operations
23194 * (e.g., during paging).
23195 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23197 getModifiedRecords : function(){
23198 return this.modified;
23202 createFilterFn : function(property, value, anyMatch){
23203 if(!value.exec){ // not a regex
23204 value = String(value);
23205 if(value.length == 0){
23208 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23210 return function(r){
23211 return value.test(r.data[property]);
23216 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23217 * @param {String} property A field on your records
23218 * @param {Number} start The record index to start at (defaults to 0)
23219 * @param {Number} end The last record index to include (defaults to length - 1)
23220 * @return {Number} The sum
23222 sum : function(property, start, end){
23223 var rs = this.data.items, v = 0;
23224 start = start || 0;
23225 end = (end || end === 0) ? end : rs.length-1;
23227 for(var i = start; i <= end; i++){
23228 v += (rs[i].data[property] || 0);
23234 * Filter the records by a specified property.
23235 * @param {String} field A field on your records
23236 * @param {String/RegExp} value Either a string that the field
23237 * should start with or a RegExp to test against the field
23238 * @param {Boolean} anyMatch True to match any part not just the beginning
23240 filter : function(property, value, anyMatch){
23241 var fn = this.createFilterFn(property, value, anyMatch);
23242 return fn ? this.filterBy(fn) : this.clearFilter();
23246 * Filter by a function. The specified function will be called with each
23247 * record in this data source. If the function returns true the record is included,
23248 * otherwise it is filtered.
23249 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23250 * @param {Object} scope (optional) The scope of the function (defaults to this)
23252 filterBy : function(fn, scope){
23253 this.snapshot = this.snapshot || this.data;
23254 this.data = this.queryBy(fn, scope||this);
23255 this.fireEvent("datachanged", this);
23259 * Query the records by a specified property.
23260 * @param {String} field A field on your records
23261 * @param {String/RegExp} value Either a string that the field
23262 * should start with or a RegExp to test against the field
23263 * @param {Boolean} anyMatch True to match any part not just the beginning
23264 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23266 query : function(property, value, anyMatch){
23267 var fn = this.createFilterFn(property, value, anyMatch);
23268 return fn ? this.queryBy(fn) : this.data.clone();
23272 * Query by a function. The specified function will be called with each
23273 * record in this data source. If the function returns true the record is included
23275 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23276 * @param {Object} scope (optional) The scope of the function (defaults to this)
23277 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23279 queryBy : function(fn, scope){
23280 var data = this.snapshot || this.data;
23281 return data.filterBy(fn, scope||this);
23285 * Collects unique values for a particular dataIndex from this store.
23286 * @param {String} dataIndex The property to collect
23287 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23288 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23289 * @return {Array} An array of the unique values
23291 collect : function(dataIndex, allowNull, bypassFilter){
23292 var d = (bypassFilter === true && this.snapshot) ?
23293 this.snapshot.items : this.data.items;
23294 var v, sv, r = [], l = {};
23295 for(var i = 0, len = d.length; i < len; i++){
23296 v = d[i].data[dataIndex];
23298 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23307 * Revert to a view of the Record cache with no filtering applied.
23308 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23310 clearFilter : function(suppressEvent){
23311 if(this.snapshot && this.snapshot != this.data){
23312 this.data = this.snapshot;
23313 delete this.snapshot;
23314 if(suppressEvent !== true){
23315 this.fireEvent("datachanged", this);
23321 afterEdit : function(record){
23322 if(this.modified.indexOf(record) == -1){
23323 this.modified.push(record);
23325 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23329 afterReject : function(record){
23330 this.modified.remove(record);
23331 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23335 afterCommit : function(record){
23336 this.modified.remove(record);
23337 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23341 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23342 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23344 commitChanges : function(){
23345 var m = this.modified.slice(0);
23346 this.modified = [];
23347 for(var i = 0, len = m.length; i < len; i++){
23353 * Cancel outstanding changes on all changed records.
23355 rejectChanges : function(){
23356 var m = this.modified.slice(0);
23357 this.modified = [];
23358 for(var i = 0, len = m.length; i < len; i++){
23363 onMetaChange : function(meta, rtype, o){
23364 this.recordType = rtype;
23365 this.fields = rtype.prototype.fields;
23366 delete this.snapshot;
23367 this.sortInfo = meta.sortInfo || this.sortInfo;
23368 this.modified = [];
23369 this.fireEvent('metachange', this, this.reader.meta);
23372 moveIndex : function(data, type)
23374 var index = this.indexOf(data);
23376 var newIndex = index + type;
23380 this.insert(newIndex, data);
23385 * Ext JS Library 1.1.1
23386 * Copyright(c) 2006-2007, Ext JS, LLC.
23388 * Originally Released Under LGPL - original licence link has changed is not relivant.
23391 * <script type="text/javascript">
23395 * @class Roo.data.SimpleStore
23396 * @extends Roo.data.Store
23397 * Small helper class to make creating Stores from Array data easier.
23398 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23399 * @cfg {Array} fields An array of field definition objects, or field name strings.
23400 * @cfg {Array} data The multi-dimensional array of data
23402 * @param {Object} config
23404 Roo.data.SimpleStore = function(config){
23405 Roo.data.SimpleStore.superclass.constructor.call(this, {
23407 reader: new Roo.data.ArrayReader({
23410 Roo.data.Record.create(config.fields)
23412 proxy : new Roo.data.MemoryProxy(config.data)
23416 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23418 * Ext JS Library 1.1.1
23419 * Copyright(c) 2006-2007, Ext JS, LLC.
23421 * Originally Released Under LGPL - original licence link has changed is not relivant.
23424 * <script type="text/javascript">
23429 * @extends Roo.data.Store
23430 * @class Roo.data.JsonStore
23431 * Small helper class to make creating Stores for JSON data easier. <br/>
23433 var store = new Roo.data.JsonStore({
23434 url: 'get-images.php',
23436 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23439 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23440 * JsonReader and HttpProxy (unless inline data is provided).</b>
23441 * @cfg {Array} fields An array of field definition objects, or field name strings.
23443 * @param {Object} config
23445 Roo.data.JsonStore = function(c){
23446 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23447 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23448 reader: new Roo.data.JsonReader(c, c.fields)
23451 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23453 * Ext JS Library 1.1.1
23454 * Copyright(c) 2006-2007, Ext JS, LLC.
23456 * Originally Released Under LGPL - original licence link has changed is not relivant.
23459 * <script type="text/javascript">
23463 Roo.data.Field = function(config){
23464 if(typeof config == "string"){
23465 config = {name: config};
23467 Roo.apply(this, config);
23470 this.type = "auto";
23473 var st = Roo.data.SortTypes;
23474 // named sortTypes are supported, here we look them up
23475 if(typeof this.sortType == "string"){
23476 this.sortType = st[this.sortType];
23479 // set default sortType for strings and dates
23480 if(!this.sortType){
23483 this.sortType = st.asUCString;
23486 this.sortType = st.asDate;
23489 this.sortType = st.none;
23494 var stripRe = /[\$,%]/g;
23496 // prebuilt conversion function for this field, instead of
23497 // switching every time we're reading a value
23499 var cv, dateFormat = this.dateFormat;
23504 cv = function(v){ return v; };
23507 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23511 return v !== undefined && v !== null && v !== '' ?
23512 parseInt(String(v).replace(stripRe, ""), 10) : '';
23517 return v !== undefined && v !== null && v !== '' ?
23518 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23523 cv = function(v){ return v === true || v === "true" || v == 1; };
23530 if(v instanceof Date){
23534 if(dateFormat == "timestamp"){
23535 return new Date(v*1000);
23537 return Date.parseDate(v, dateFormat);
23539 var parsed = Date.parse(v);
23540 return parsed ? new Date(parsed) : null;
23549 Roo.data.Field.prototype = {
23557 * Ext JS Library 1.1.1
23558 * Copyright(c) 2006-2007, Ext JS, LLC.
23560 * Originally Released Under LGPL - original licence link has changed is not relivant.
23563 * <script type="text/javascript">
23566 // Base class for reading structured data from a data source. This class is intended to be
23567 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23570 * @class Roo.data.DataReader
23571 * Base class for reading structured data from a data source. This class is intended to be
23572 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23575 Roo.data.DataReader = function(meta, recordType){
23579 this.recordType = recordType instanceof Array ?
23580 Roo.data.Record.create(recordType) : recordType;
23583 Roo.data.DataReader.prototype = {
23585 * Create an empty record
23586 * @param {Object} data (optional) - overlay some values
23587 * @return {Roo.data.Record} record created.
23589 newRow : function(d) {
23591 this.recordType.prototype.fields.each(function(c) {
23593 case 'int' : da[c.name] = 0; break;
23594 case 'date' : da[c.name] = new Date(); break;
23595 case 'float' : da[c.name] = 0.0; break;
23596 case 'boolean' : da[c.name] = false; break;
23597 default : da[c.name] = ""; break;
23601 return new this.recordType(Roo.apply(da, d));
23606 * Ext JS Library 1.1.1
23607 * Copyright(c) 2006-2007, Ext JS, LLC.
23609 * Originally Released Under LGPL - original licence link has changed is not relivant.
23612 * <script type="text/javascript">
23616 * @class Roo.data.DataProxy
23617 * @extends Roo.data.Observable
23618 * This class is an abstract base class for implementations which provide retrieval of
23619 * unformatted data objects.<br>
23621 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23622 * (of the appropriate type which knows how to parse the data object) to provide a block of
23623 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23625 * Custom implementations must implement the load method as described in
23626 * {@link Roo.data.HttpProxy#load}.
23628 Roo.data.DataProxy = function(){
23631 * @event beforeload
23632 * Fires before a network request is made to retrieve a data object.
23633 * @param {Object} This DataProxy object.
23634 * @param {Object} params The params parameter to the load function.
23639 * Fires before the load method's callback is called.
23640 * @param {Object} This DataProxy object.
23641 * @param {Object} o The data object.
23642 * @param {Object} arg The callback argument object passed to the load function.
23646 * @event loadexception
23647 * Fires if an Exception occurs during data retrieval.
23648 * @param {Object} This DataProxy object.
23649 * @param {Object} o The data object.
23650 * @param {Object} arg The callback argument object passed to the load function.
23651 * @param {Object} e The Exception.
23653 loadexception : true
23655 Roo.data.DataProxy.superclass.constructor.call(this);
23658 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23661 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23665 * Ext JS Library 1.1.1
23666 * Copyright(c) 2006-2007, Ext JS, LLC.
23668 * Originally Released Under LGPL - original licence link has changed is not relivant.
23671 * <script type="text/javascript">
23674 * @class Roo.data.MemoryProxy
23675 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23676 * to the Reader when its load method is called.
23678 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23680 Roo.data.MemoryProxy = function(data){
23684 Roo.data.MemoryProxy.superclass.constructor.call(this);
23688 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23691 * Load data from the requested source (in this case an in-memory
23692 * data object passed to the constructor), read the data object into
23693 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23694 * process that block using the passed callback.
23695 * @param {Object} params This parameter is not used by the MemoryProxy class.
23696 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23697 * object into a block of Roo.data.Records.
23698 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23699 * The function must be passed <ul>
23700 * <li>The Record block object</li>
23701 * <li>The "arg" argument from the load function</li>
23702 * <li>A boolean success indicator</li>
23704 * @param {Object} scope The scope in which to call the callback
23705 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23707 load : function(params, reader, callback, scope, arg){
23708 params = params || {};
23711 result = reader.readRecords(this.data);
23713 this.fireEvent("loadexception", this, arg, null, e);
23714 callback.call(scope, null, arg, false);
23717 callback.call(scope, result, arg, true);
23721 update : function(params, records){
23726 * Ext JS Library 1.1.1
23727 * Copyright(c) 2006-2007, Ext JS, LLC.
23729 * Originally Released Under LGPL - original licence link has changed is not relivant.
23732 * <script type="text/javascript">
23735 * @class Roo.data.HttpProxy
23736 * @extends Roo.data.DataProxy
23737 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23738 * configured to reference a certain URL.<br><br>
23740 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23741 * from which the running page was served.<br><br>
23743 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23745 * Be aware that to enable the browser to parse an XML document, the server must set
23746 * the Content-Type header in the HTTP response to "text/xml".
23748 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23749 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23750 * will be used to make the request.
23752 Roo.data.HttpProxy = function(conn){
23753 Roo.data.HttpProxy.superclass.constructor.call(this);
23754 // is conn a conn config or a real conn?
23756 this.useAjax = !conn || !conn.events;
23760 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23761 // thse are take from connection...
23764 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23767 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23768 * extra parameters to each request made by this object. (defaults to undefined)
23771 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23772 * to each request made by this object. (defaults to undefined)
23775 * @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)
23778 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23781 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23787 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23791 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23792 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23793 * a finer-grained basis than the DataProxy events.
23795 getConnection : function(){
23796 return this.useAjax ? Roo.Ajax : this.conn;
23800 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23801 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23802 * process that block using the passed callback.
23803 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23804 * for the request to the remote server.
23805 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23806 * object into a block of Roo.data.Records.
23807 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23808 * The function must be passed <ul>
23809 * <li>The Record block object</li>
23810 * <li>The "arg" argument from the load function</li>
23811 * <li>A boolean success indicator</li>
23813 * @param {Object} scope The scope in which to call the callback
23814 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23816 load : function(params, reader, callback, scope, arg){
23817 if(this.fireEvent("beforeload", this, params) !== false){
23819 params : params || {},
23821 callback : callback,
23826 callback : this.loadResponse,
23830 Roo.applyIf(o, this.conn);
23831 if(this.activeRequest){
23832 Roo.Ajax.abort(this.activeRequest);
23834 this.activeRequest = Roo.Ajax.request(o);
23836 this.conn.request(o);
23839 callback.call(scope||this, null, arg, false);
23844 loadResponse : function(o, success, response){
23845 delete this.activeRequest;
23847 this.fireEvent("loadexception", this, o, response);
23848 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23853 result = o.reader.read(response);
23855 this.fireEvent("loadexception", this, o, response, e);
23856 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23860 this.fireEvent("load", this, o, o.request.arg);
23861 o.request.callback.call(o.request.scope, result, o.request.arg, true);
23865 update : function(dataSet){
23870 updateResponse : function(dataSet){
23875 * Ext JS Library 1.1.1
23876 * Copyright(c) 2006-2007, Ext JS, LLC.
23878 * Originally Released Under LGPL - original licence link has changed is not relivant.
23881 * <script type="text/javascript">
23885 * @class Roo.data.ScriptTagProxy
23886 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
23887 * other than the originating domain of the running page.<br><br>
23889 * <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
23890 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
23892 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
23893 * source code that is used as the source inside a <script> tag.<br><br>
23895 * In order for the browser to process the returned data, the server must wrap the data object
23896 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
23897 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
23898 * depending on whether the callback name was passed:
23901 boolean scriptTag = false;
23902 String cb = request.getParameter("callback");
23905 response.setContentType("text/javascript");
23907 response.setContentType("application/x-json");
23909 Writer out = response.getWriter();
23911 out.write(cb + "(");
23913 out.print(dataBlock.toJsonString());
23920 * @param {Object} config A configuration object.
23922 Roo.data.ScriptTagProxy = function(config){
23923 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
23924 Roo.apply(this, config);
23925 this.head = document.getElementsByTagName("head")[0];
23928 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
23930 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
23932 * @cfg {String} url The URL from which to request the data object.
23935 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
23939 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
23940 * the server the name of the callback function set up by the load call to process the returned data object.
23941 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
23942 * javascript output which calls this named function passing the data object as its only parameter.
23944 callbackParam : "callback",
23946 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
23947 * name to the request.
23952 * Load data from the configured URL, read the data object into
23953 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23954 * process that block using the passed callback.
23955 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23956 * for the request to the remote server.
23957 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23958 * object into a block of Roo.data.Records.
23959 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23960 * The function must be passed <ul>
23961 * <li>The Record block object</li>
23962 * <li>The "arg" argument from the load function</li>
23963 * <li>A boolean success indicator</li>
23965 * @param {Object} scope The scope in which to call the callback
23966 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23968 load : function(params, reader, callback, scope, arg){
23969 if(this.fireEvent("beforeload", this, params) !== false){
23971 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
23973 var url = this.url;
23974 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
23976 url += "&_dc=" + (new Date().getTime());
23978 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
23981 cb : "stcCallback"+transId,
23982 scriptId : "stcScript"+transId,
23986 callback : callback,
23992 window[trans.cb] = function(o){
23993 conn.handleResponse(o, trans);
23996 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
23998 if(this.autoAbort !== false){
24002 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24004 var script = document.createElement("script");
24005 script.setAttribute("src", url);
24006 script.setAttribute("type", "text/javascript");
24007 script.setAttribute("id", trans.scriptId);
24008 this.head.appendChild(script);
24010 this.trans = trans;
24012 callback.call(scope||this, null, arg, false);
24017 isLoading : function(){
24018 return this.trans ? true : false;
24022 * Abort the current server request.
24024 abort : function(){
24025 if(this.isLoading()){
24026 this.destroyTrans(this.trans);
24031 destroyTrans : function(trans, isLoaded){
24032 this.head.removeChild(document.getElementById(trans.scriptId));
24033 clearTimeout(trans.timeoutId);
24035 window[trans.cb] = undefined;
24037 delete window[trans.cb];
24040 // if hasn't been loaded, wait for load to remove it to prevent script error
24041 window[trans.cb] = function(){
24042 window[trans.cb] = undefined;
24044 delete window[trans.cb];
24051 handleResponse : function(o, trans){
24052 this.trans = false;
24053 this.destroyTrans(trans, true);
24056 result = trans.reader.readRecords(o);
24058 this.fireEvent("loadexception", this, o, trans.arg, e);
24059 trans.callback.call(trans.scope||window, null, trans.arg, false);
24062 this.fireEvent("load", this, o, trans.arg);
24063 trans.callback.call(trans.scope||window, result, trans.arg, true);
24067 handleFailure : function(trans){
24068 this.trans = false;
24069 this.destroyTrans(trans, false);
24070 this.fireEvent("loadexception", this, null, trans.arg);
24071 trans.callback.call(trans.scope||window, null, trans.arg, false);
24075 * Ext JS Library 1.1.1
24076 * Copyright(c) 2006-2007, Ext JS, LLC.
24078 * Originally Released Under LGPL - original licence link has changed is not relivant.
24081 * <script type="text/javascript">
24085 * @class Roo.data.JsonReader
24086 * @extends Roo.data.DataReader
24087 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24088 * based on mappings in a provided Roo.data.Record constructor.
24090 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24091 * in the reply previously.
24096 var RecordDef = Roo.data.Record.create([
24097 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24098 {name: 'occupation'} // This field will use "occupation" as the mapping.
24100 var myReader = new Roo.data.JsonReader({
24101 totalProperty: "results", // The property which contains the total dataset size (optional)
24102 root: "rows", // The property which contains an Array of row objects
24103 id: "id" // The property within each row object that provides an ID for the record (optional)
24107 * This would consume a JSON file like this:
24109 { 'results': 2, 'rows': [
24110 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24111 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24114 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24115 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24116 * paged from the remote server.
24117 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24118 * @cfg {String} root name of the property which contains the Array of row objects.
24119 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24120 * @cfg {Array} fields Array of field definition objects
24122 * Create a new JsonReader
24123 * @param {Object} meta Metadata configuration options
24124 * @param {Object} recordType Either an Array of field definition objects,
24125 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24127 Roo.data.JsonReader = function(meta, recordType){
24130 // set some defaults:
24131 Roo.applyIf(meta, {
24132 totalProperty: 'total',
24133 successProperty : 'success',
24138 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24140 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24143 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24144 * Used by Store query builder to append _requestMeta to params.
24147 metaFromRemote : false,
24149 * This method is only used by a DataProxy which has retrieved data from a remote server.
24150 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24151 * @return {Object} data A data block which is used by an Roo.data.Store object as
24152 * a cache of Roo.data.Records.
24154 read : function(response){
24155 var json = response.responseText;
24157 var o = /* eval:var:o */ eval("("+json+")");
24159 throw {message: "JsonReader.read: Json object not found"};
24165 this.metaFromRemote = true;
24166 this.meta = o.metaData;
24167 this.recordType = Roo.data.Record.create(o.metaData.fields);
24168 this.onMetaChange(this.meta, this.recordType, o);
24170 return this.readRecords(o);
24173 // private function a store will implement
24174 onMetaChange : function(meta, recordType, o){
24181 simpleAccess: function(obj, subsc) {
24188 getJsonAccessor: function(){
24190 return function(expr) {
24192 return(re.test(expr))
24193 ? new Function("obj", "return obj." + expr)
24198 return Roo.emptyFn;
24203 * Create a data block containing Roo.data.Records from an XML document.
24204 * @param {Object} o An object which contains an Array of row objects in the property specified
24205 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24206 * which contains the total size of the dataset.
24207 * @return {Object} data A data block which is used by an Roo.data.Store object as
24208 * a cache of Roo.data.Records.
24210 readRecords : function(o){
24212 * After any data loads, the raw JSON data is available for further custom processing.
24216 var s = this.meta, Record = this.recordType,
24217 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24219 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24221 if(s.totalProperty) {
24222 this.getTotal = this.getJsonAccessor(s.totalProperty);
24224 if(s.successProperty) {
24225 this.getSuccess = this.getJsonAccessor(s.successProperty);
24227 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24229 var g = this.getJsonAccessor(s.id);
24230 this.getId = function(rec) {
24232 return (r === undefined || r === "") ? null : r;
24235 this.getId = function(){return null;};
24238 for(var jj = 0; jj < fl; jj++){
24240 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24241 this.ef[jj] = this.getJsonAccessor(map);
24245 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24246 if(s.totalProperty){
24247 var vt = parseInt(this.getTotal(o), 10);
24252 if(s.successProperty){
24253 var vs = this.getSuccess(o);
24254 if(vs === false || vs === 'false'){
24259 for(var i = 0; i < c; i++){
24262 var id = this.getId(n);
24263 for(var j = 0; j < fl; j++){
24265 var v = this.ef[j](n);
24267 Roo.log('missing convert for ' + f.name);
24271 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24273 var record = new Record(values, id);
24275 records[i] = record;
24281 totalRecords : totalRecords
24286 * Ext JS Library 1.1.1
24287 * Copyright(c) 2006-2007, Ext JS, LLC.
24289 * Originally Released Under LGPL - original licence link has changed is not relivant.
24292 * <script type="text/javascript">
24296 * @class Roo.data.XmlReader
24297 * @extends Roo.data.DataReader
24298 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24299 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24301 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24302 * header in the HTTP response must be set to "text/xml".</em>
24306 var RecordDef = Roo.data.Record.create([
24307 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24308 {name: 'occupation'} // This field will use "occupation" as the mapping.
24310 var myReader = new Roo.data.XmlReader({
24311 totalRecords: "results", // The element which contains the total dataset size (optional)
24312 record: "row", // The repeated element which contains row information
24313 id: "id" // The element within the row that provides an ID for the record (optional)
24317 * This would consume an XML file like this:
24321 <results>2</results>
24324 <name>Bill</name>
24325 <occupation>Gardener</occupation>
24329 <name>Ben</name>
24330 <occupation>Horticulturalist</occupation>
24334 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24335 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24336 * paged from the remote server.
24337 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24338 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24339 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24340 * a record identifier value.
24342 * Create a new XmlReader
24343 * @param {Object} meta Metadata configuration options
24344 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24345 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24346 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24348 Roo.data.XmlReader = function(meta, recordType){
24350 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24352 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24354 * This method is only used by a DataProxy which has retrieved data from a remote server.
24355 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24356 * to contain a method called 'responseXML' that returns an XML document object.
24357 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24358 * a cache of Roo.data.Records.
24360 read : function(response){
24361 var doc = response.responseXML;
24363 throw {message: "XmlReader.read: XML Document not available"};
24365 return this.readRecords(doc);
24369 * Create a data block containing Roo.data.Records from an XML document.
24370 * @param {Object} doc A parsed XML document.
24371 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24372 * a cache of Roo.data.Records.
24374 readRecords : function(doc){
24376 * After any data loads/reads, the raw XML Document is available for further custom processing.
24377 * @type XMLDocument
24379 this.xmlData = doc;
24380 var root = doc.documentElement || doc;
24381 var q = Roo.DomQuery;
24382 var recordType = this.recordType, fields = recordType.prototype.fields;
24383 var sid = this.meta.id;
24384 var totalRecords = 0, success = true;
24385 if(this.meta.totalRecords){
24386 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24389 if(this.meta.success){
24390 var sv = q.selectValue(this.meta.success, root, true);
24391 success = sv !== false && sv !== 'false';
24394 var ns = q.select(this.meta.record, root);
24395 for(var i = 0, len = ns.length; i < len; i++) {
24398 var id = sid ? q.selectValue(sid, n) : undefined;
24399 for(var j = 0, jlen = fields.length; j < jlen; j++){
24400 var f = fields.items[j];
24401 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24403 values[f.name] = v;
24405 var record = new recordType(values, id);
24407 records[records.length] = record;
24413 totalRecords : totalRecords || records.length
24418 * Ext JS Library 1.1.1
24419 * Copyright(c) 2006-2007, Ext JS, LLC.
24421 * Originally Released Under LGPL - original licence link has changed is not relivant.
24424 * <script type="text/javascript">
24428 * @class Roo.data.ArrayReader
24429 * @extends Roo.data.DataReader
24430 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24431 * Each element of that Array represents a row of data fields. The
24432 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24433 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24437 var RecordDef = Roo.data.Record.create([
24438 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24439 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24441 var myReader = new Roo.data.ArrayReader({
24442 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24446 * This would consume an Array like this:
24448 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24450 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24452 * Create a new JsonReader
24453 * @param {Object} meta Metadata configuration options.
24454 * @param {Object} recordType Either an Array of field definition objects
24455 * as specified to {@link Roo.data.Record#create},
24456 * or an {@link Roo.data.Record} object
24457 * created using {@link Roo.data.Record#create}.
24459 Roo.data.ArrayReader = function(meta, recordType){
24460 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24463 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24465 * Create a data block containing Roo.data.Records from an XML document.
24466 * @param {Object} o An Array of row objects which represents the dataset.
24467 * @return {Object} data A data block which is used by an Roo.data.Store object as
24468 * a cache of Roo.data.Records.
24470 readRecords : function(o){
24471 var sid = this.meta ? this.meta.id : null;
24472 var recordType = this.recordType, fields = recordType.prototype.fields;
24475 for(var i = 0; i < root.length; i++){
24478 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24479 for(var j = 0, jlen = fields.length; j < jlen; j++){
24480 var f = fields.items[j];
24481 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24482 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24484 values[f.name] = v;
24486 var record = new recordType(values, id);
24488 records[records.length] = record;
24492 totalRecords : records.length
24497 * Ext JS Library 1.1.1
24498 * Copyright(c) 2006-2007, Ext JS, LLC.
24500 * Originally Released Under LGPL - original licence link has changed is not relivant.
24503 * <script type="text/javascript">
24508 * @class Roo.data.Tree
24509 * @extends Roo.util.Observable
24510 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24511 * in the tree have most standard DOM functionality.
24513 * @param {Node} root (optional) The root node
24515 Roo.data.Tree = function(root){
24516 this.nodeHash = {};
24518 * The root node for this tree
24523 this.setRootNode(root);
24528 * Fires when a new child node is appended to a node in this tree.
24529 * @param {Tree} tree The owner tree
24530 * @param {Node} parent The parent node
24531 * @param {Node} node The newly appended node
24532 * @param {Number} index The index of the newly appended node
24537 * Fires when a child node is removed from a node in this tree.
24538 * @param {Tree} tree The owner tree
24539 * @param {Node} parent The parent node
24540 * @param {Node} node The child node removed
24545 * Fires when a node is moved to a new location in the tree
24546 * @param {Tree} tree The owner tree
24547 * @param {Node} node The node moved
24548 * @param {Node} oldParent The old parent of this node
24549 * @param {Node} newParent The new parent of this node
24550 * @param {Number} index The index it was moved to
24555 * Fires when a new child node is inserted in a node in this tree.
24556 * @param {Tree} tree The owner tree
24557 * @param {Node} parent The parent node
24558 * @param {Node} node The child node inserted
24559 * @param {Node} refNode The child node the node was inserted before
24563 * @event beforeappend
24564 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24565 * @param {Tree} tree The owner tree
24566 * @param {Node} parent The parent node
24567 * @param {Node} node The child node to be appended
24569 "beforeappend" : true,
24571 * @event beforeremove
24572 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24573 * @param {Tree} tree The owner tree
24574 * @param {Node} parent The parent node
24575 * @param {Node} node The child node to be removed
24577 "beforeremove" : true,
24579 * @event beforemove
24580 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24581 * @param {Tree} tree The owner tree
24582 * @param {Node} node The node being moved
24583 * @param {Node} oldParent The parent of the node
24584 * @param {Node} newParent The new parent the node is moving to
24585 * @param {Number} index The index it is being moved to
24587 "beforemove" : true,
24589 * @event beforeinsert
24590 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24591 * @param {Tree} tree The owner tree
24592 * @param {Node} parent The parent node
24593 * @param {Node} node The child node to be inserted
24594 * @param {Node} refNode The child node the node is being inserted before
24596 "beforeinsert" : true
24599 Roo.data.Tree.superclass.constructor.call(this);
24602 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24603 pathSeparator: "/",
24605 proxyNodeEvent : function(){
24606 return this.fireEvent.apply(this, arguments);
24610 * Returns the root node for this tree.
24613 getRootNode : function(){
24618 * Sets the root node for this tree.
24619 * @param {Node} node
24622 setRootNode : function(node){
24624 node.ownerTree = this;
24625 node.isRoot = true;
24626 this.registerNode(node);
24631 * Gets a node in this tree by its id.
24632 * @param {String} id
24635 getNodeById : function(id){
24636 return this.nodeHash[id];
24639 registerNode : function(node){
24640 this.nodeHash[node.id] = node;
24643 unregisterNode : function(node){
24644 delete this.nodeHash[node.id];
24647 toString : function(){
24648 return "[Tree"+(this.id?" "+this.id:"")+"]";
24653 * @class Roo.data.Node
24654 * @extends Roo.util.Observable
24655 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24656 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24658 * @param {Object} attributes The attributes/config for the node
24660 Roo.data.Node = function(attributes){
24662 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24665 this.attributes = attributes || {};
24666 this.leaf = this.attributes.leaf;
24668 * The node id. @type String
24670 this.id = this.attributes.id;
24672 this.id = Roo.id(null, "ynode-");
24673 this.attributes.id = this.id;
24678 * All child nodes of this node. @type Array
24680 this.childNodes = [];
24681 if(!this.childNodes.indexOf){ // indexOf is a must
24682 this.childNodes.indexOf = function(o){
24683 for(var i = 0, len = this.length; i < len; i++){
24692 * The parent node for this node. @type Node
24694 this.parentNode = null;
24696 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24698 this.firstChild = null;
24700 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24702 this.lastChild = null;
24704 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24706 this.previousSibling = null;
24708 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24710 this.nextSibling = null;
24715 * Fires when a new child node is appended
24716 * @param {Tree} tree The owner tree
24717 * @param {Node} this This node
24718 * @param {Node} node The newly appended node
24719 * @param {Number} index The index of the newly appended node
24724 * Fires when a child node is removed
24725 * @param {Tree} tree The owner tree
24726 * @param {Node} this This node
24727 * @param {Node} node The removed node
24732 * Fires when this node is moved to a new location in the tree
24733 * @param {Tree} tree The owner tree
24734 * @param {Node} this This node
24735 * @param {Node} oldParent The old parent of this node
24736 * @param {Node} newParent The new parent of this node
24737 * @param {Number} index The index it was moved to
24742 * Fires when a new child node is inserted.
24743 * @param {Tree} tree The owner tree
24744 * @param {Node} this This node
24745 * @param {Node} node The child node inserted
24746 * @param {Node} refNode The child node the node was inserted before
24750 * @event beforeappend
24751 * Fires before a new child is appended, return false to cancel the append.
24752 * @param {Tree} tree The owner tree
24753 * @param {Node} this This node
24754 * @param {Node} node The child node to be appended
24756 "beforeappend" : true,
24758 * @event beforeremove
24759 * Fires before a child is removed, return false to cancel the remove.
24760 * @param {Tree} tree The owner tree
24761 * @param {Node} this This node
24762 * @param {Node} node The child node to be removed
24764 "beforeremove" : true,
24766 * @event beforemove
24767 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24768 * @param {Tree} tree The owner tree
24769 * @param {Node} this This node
24770 * @param {Node} oldParent The parent of this node
24771 * @param {Node} newParent The new parent this node is moving to
24772 * @param {Number} index The index it is being moved to
24774 "beforemove" : true,
24776 * @event beforeinsert
24777 * Fires before a new child is inserted, return false to cancel the insert.
24778 * @param {Tree} tree The owner tree
24779 * @param {Node} this This node
24780 * @param {Node} node The child node to be inserted
24781 * @param {Node} refNode The child node the node is being inserted before
24783 "beforeinsert" : true
24785 this.listeners = this.attributes.listeners;
24786 Roo.data.Node.superclass.constructor.call(this);
24789 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24790 fireEvent : function(evtName){
24791 // first do standard event for this node
24792 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24795 // then bubble it up to the tree if the event wasn't cancelled
24796 var ot = this.getOwnerTree();
24798 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24806 * Returns true if this node is a leaf
24807 * @return {Boolean}
24809 isLeaf : function(){
24810 return this.leaf === true;
24814 setFirstChild : function(node){
24815 this.firstChild = node;
24819 setLastChild : function(node){
24820 this.lastChild = node;
24825 * Returns true if this node is the last child of its parent
24826 * @return {Boolean}
24828 isLast : function(){
24829 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24833 * Returns true if this node is the first child of its parent
24834 * @return {Boolean}
24836 isFirst : function(){
24837 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24840 hasChildNodes : function(){
24841 return !this.isLeaf() && this.childNodes.length > 0;
24845 * Insert node(s) as the last child node of this node.
24846 * @param {Node/Array} node The node or Array of nodes to append
24847 * @return {Node} The appended node if single append, or null if an array was passed
24849 appendChild : function(node){
24851 if(node instanceof Array){
24853 }else if(arguments.length > 1){
24856 // if passed an array or multiple args do them one by one
24858 for(var i = 0, len = multi.length; i < len; i++) {
24859 this.appendChild(multi[i]);
24862 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
24865 var index = this.childNodes.length;
24866 var oldParent = node.parentNode;
24867 // it's a move, make sure we move it cleanly
24869 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
24872 oldParent.removeChild(node);
24874 index = this.childNodes.length;
24876 this.setFirstChild(node);
24878 this.childNodes.push(node);
24879 node.parentNode = this;
24880 var ps = this.childNodes[index-1];
24882 node.previousSibling = ps;
24883 ps.nextSibling = node;
24885 node.previousSibling = null;
24887 node.nextSibling = null;
24888 this.setLastChild(node);
24889 node.setOwnerTree(this.getOwnerTree());
24890 this.fireEvent("append", this.ownerTree, this, node, index);
24892 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
24899 * Removes a child node from this node.
24900 * @param {Node} node The node to remove
24901 * @return {Node} The removed node
24903 removeChild : function(node){
24904 var index = this.childNodes.indexOf(node);
24908 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
24912 // remove it from childNodes collection
24913 this.childNodes.splice(index, 1);
24916 if(node.previousSibling){
24917 node.previousSibling.nextSibling = node.nextSibling;
24919 if(node.nextSibling){
24920 node.nextSibling.previousSibling = node.previousSibling;
24923 // update child refs
24924 if(this.firstChild == node){
24925 this.setFirstChild(node.nextSibling);
24927 if(this.lastChild == node){
24928 this.setLastChild(node.previousSibling);
24931 node.setOwnerTree(null);
24932 // clear any references from the node
24933 node.parentNode = null;
24934 node.previousSibling = null;
24935 node.nextSibling = null;
24936 this.fireEvent("remove", this.ownerTree, this, node);
24941 * Inserts the first node before the second node in this nodes childNodes collection.
24942 * @param {Node} node The node to insert
24943 * @param {Node} refNode The node to insert before (if null the node is appended)
24944 * @return {Node} The inserted node
24946 insertBefore : function(node, refNode){
24947 if(!refNode){ // like standard Dom, refNode can be null for append
24948 return this.appendChild(node);
24951 if(node == refNode){
24955 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
24958 var index = this.childNodes.indexOf(refNode);
24959 var oldParent = node.parentNode;
24960 var refIndex = index;
24962 // when moving internally, indexes will change after remove
24963 if(oldParent == this && this.childNodes.indexOf(node) < index){
24967 // it's a move, make sure we move it cleanly
24969 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
24972 oldParent.removeChild(node);
24975 this.setFirstChild(node);
24977 this.childNodes.splice(refIndex, 0, node);
24978 node.parentNode = this;
24979 var ps = this.childNodes[refIndex-1];
24981 node.previousSibling = ps;
24982 ps.nextSibling = node;
24984 node.previousSibling = null;
24986 node.nextSibling = refNode;
24987 refNode.previousSibling = node;
24988 node.setOwnerTree(this.getOwnerTree());
24989 this.fireEvent("insert", this.ownerTree, this, node, refNode);
24991 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
24997 * Returns the child node at the specified index.
24998 * @param {Number} index
25001 item : function(index){
25002 return this.childNodes[index];
25006 * Replaces one child node in this node with another.
25007 * @param {Node} newChild The replacement node
25008 * @param {Node} oldChild The node to replace
25009 * @return {Node} The replaced node
25011 replaceChild : function(newChild, oldChild){
25012 this.insertBefore(newChild, oldChild);
25013 this.removeChild(oldChild);
25018 * Returns the index of a child node
25019 * @param {Node} node
25020 * @return {Number} The index of the node or -1 if it was not found
25022 indexOf : function(child){
25023 return this.childNodes.indexOf(child);
25027 * Returns the tree this node is in.
25030 getOwnerTree : function(){
25031 // if it doesn't have one, look for one
25032 if(!this.ownerTree){
25036 this.ownerTree = p.ownerTree;
25042 return this.ownerTree;
25046 * Returns depth of this node (the root node has a depth of 0)
25049 getDepth : function(){
25052 while(p.parentNode){
25060 setOwnerTree : function(tree){
25061 // if it's move, we need to update everyone
25062 if(tree != this.ownerTree){
25063 if(this.ownerTree){
25064 this.ownerTree.unregisterNode(this);
25066 this.ownerTree = tree;
25067 var cs = this.childNodes;
25068 for(var i = 0, len = cs.length; i < len; i++) {
25069 cs[i].setOwnerTree(tree);
25072 tree.registerNode(this);
25078 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25079 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25080 * @return {String} The path
25082 getPath : function(attr){
25083 attr = attr || "id";
25084 var p = this.parentNode;
25085 var b = [this.attributes[attr]];
25087 b.unshift(p.attributes[attr]);
25090 var sep = this.getOwnerTree().pathSeparator;
25091 return sep + b.join(sep);
25095 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25096 * function call will be the scope provided or the current node. The arguments to the function
25097 * will be the args provided or the current node. If the function returns false at any point,
25098 * the bubble is stopped.
25099 * @param {Function} fn The function to call
25100 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25101 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25103 bubble : function(fn, scope, args){
25106 if(fn.call(scope || p, args || p) === false){
25114 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25115 * function call will be the scope provided or the current node. The arguments to the function
25116 * will be the args provided or the current node. If the function returns false at any point,
25117 * the cascade is stopped on that branch.
25118 * @param {Function} fn The function to call
25119 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25120 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25122 cascade : function(fn, scope, args){
25123 if(fn.call(scope || this, args || this) !== false){
25124 var cs = this.childNodes;
25125 for(var i = 0, len = cs.length; i < len; i++) {
25126 cs[i].cascade(fn, scope, args);
25132 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25133 * function call will be the scope provided or the current node. The arguments to the function
25134 * will be the args provided or the current node. If the function returns false at any point,
25135 * the iteration stops.
25136 * @param {Function} fn The function to call
25137 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25138 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25140 eachChild : function(fn, scope, args){
25141 var cs = this.childNodes;
25142 for(var i = 0, len = cs.length; i < len; i++) {
25143 if(fn.call(scope || this, args || cs[i]) === false){
25150 * Finds the first child that has the attribute with the specified value.
25151 * @param {String} attribute The attribute name
25152 * @param {Mixed} value The value to search for
25153 * @return {Node} The found child or null if none was found
25155 findChild : function(attribute, value){
25156 var cs = this.childNodes;
25157 for(var i = 0, len = cs.length; i < len; i++) {
25158 if(cs[i].attributes[attribute] == value){
25166 * Finds the first child by a custom function. The child matches if the function passed
25168 * @param {Function} fn
25169 * @param {Object} scope (optional)
25170 * @return {Node} The found child or null if none was found
25172 findChildBy : function(fn, scope){
25173 var cs = this.childNodes;
25174 for(var i = 0, len = cs.length; i < len; i++) {
25175 if(fn.call(scope||cs[i], cs[i]) === true){
25183 * Sorts this nodes children using the supplied sort function
25184 * @param {Function} fn
25185 * @param {Object} scope (optional)
25187 sort : function(fn, scope){
25188 var cs = this.childNodes;
25189 var len = cs.length;
25191 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25193 for(var i = 0; i < len; i++){
25195 n.previousSibling = cs[i-1];
25196 n.nextSibling = cs[i+1];
25198 this.setFirstChild(n);
25201 this.setLastChild(n);
25208 * Returns true if this node is an ancestor (at any point) of the passed node.
25209 * @param {Node} node
25210 * @return {Boolean}
25212 contains : function(node){
25213 return node.isAncestor(this);
25217 * Returns true if the passed node is an ancestor (at any point) of this node.
25218 * @param {Node} node
25219 * @return {Boolean}
25221 isAncestor : function(node){
25222 var p = this.parentNode;
25232 toString : function(){
25233 return "[Node"+(this.id?" "+this.id:"")+"]";
25237 * Ext JS Library 1.1.1
25238 * Copyright(c) 2006-2007, Ext JS, LLC.
25240 * Originally Released Under LGPL - original licence link has changed is not relivant.
25243 * <script type="text/javascript">
25248 * @extends Roo.Element
25249 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25250 * automatic maintaining of shadow/shim positions.
25251 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25252 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25253 * you can pass a string with a CSS class name. False turns off the shadow.
25254 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25255 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25256 * @cfg {String} cls CSS class to add to the element
25257 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25258 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25260 * @param {Object} config An object with config options.
25261 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25264 Roo.Layer = function(config, existingEl){
25265 config = config || {};
25266 var dh = Roo.DomHelper;
25267 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25269 this.dom = Roo.getDom(existingEl);
25272 var o = config.dh || {tag: "div", cls: "x-layer"};
25273 this.dom = dh.append(pel, o);
25276 this.addClass(config.cls);
25278 this.constrain = config.constrain !== false;
25279 this.visibilityMode = Roo.Element.VISIBILITY;
25281 this.id = this.dom.id = config.id;
25283 this.id = Roo.id(this.dom);
25285 this.zindex = config.zindex || this.getZIndex();
25286 this.position("absolute", this.zindex);
25288 this.shadowOffset = config.shadowOffset || 4;
25289 this.shadow = new Roo.Shadow({
25290 offset : this.shadowOffset,
25291 mode : config.shadow
25294 this.shadowOffset = 0;
25296 this.useShim = config.shim !== false && Roo.useShims;
25297 this.useDisplay = config.useDisplay;
25301 var supr = Roo.Element.prototype;
25303 // shims are shared among layer to keep from having 100 iframes
25306 Roo.extend(Roo.Layer, Roo.Element, {
25308 getZIndex : function(){
25309 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25312 getShim : function(){
25319 var shim = shims.shift();
25321 shim = this.createShim();
25322 shim.enableDisplayMode('block');
25323 shim.dom.style.display = 'none';
25324 shim.dom.style.visibility = 'visible';
25326 var pn = this.dom.parentNode;
25327 if(shim.dom.parentNode != pn){
25328 pn.insertBefore(shim.dom, this.dom);
25330 shim.setStyle('z-index', this.getZIndex()-2);
25335 hideShim : function(){
25337 this.shim.setDisplayed(false);
25338 shims.push(this.shim);
25343 disableShadow : function(){
25345 this.shadowDisabled = true;
25346 this.shadow.hide();
25347 this.lastShadowOffset = this.shadowOffset;
25348 this.shadowOffset = 0;
25352 enableShadow : function(show){
25354 this.shadowDisabled = false;
25355 this.shadowOffset = this.lastShadowOffset;
25356 delete this.lastShadowOffset;
25364 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25365 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25366 sync : function(doShow){
25367 var sw = this.shadow;
25368 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25369 var sh = this.getShim();
25371 var w = this.getWidth(),
25372 h = this.getHeight();
25374 var l = this.getLeft(true),
25375 t = this.getTop(true);
25377 if(sw && !this.shadowDisabled){
25378 if(doShow && !sw.isVisible()){
25381 sw.realign(l, t, w, h);
25387 // fit the shim behind the shadow, so it is shimmed too
25388 var a = sw.adjusts, s = sh.dom.style;
25389 s.left = (Math.min(l, l+a.l))+"px";
25390 s.top = (Math.min(t, t+a.t))+"px";
25391 s.width = (w+a.w)+"px";
25392 s.height = (h+a.h)+"px";
25399 sh.setLeftTop(l, t);
25406 destroy : function(){
25409 this.shadow.hide();
25411 this.removeAllListeners();
25412 var pn = this.dom.parentNode;
25414 pn.removeChild(this.dom);
25416 Roo.Element.uncache(this.id);
25419 remove : function(){
25424 beginUpdate : function(){
25425 this.updating = true;
25429 endUpdate : function(){
25430 this.updating = false;
25435 hideUnders : function(negOffset){
25437 this.shadow.hide();
25443 constrainXY : function(){
25444 if(this.constrain){
25445 var vw = Roo.lib.Dom.getViewWidth(),
25446 vh = Roo.lib.Dom.getViewHeight();
25447 var s = Roo.get(document).getScroll();
25449 var xy = this.getXY();
25450 var x = xy[0], y = xy[1];
25451 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25452 // only move it if it needs it
25454 // first validate right/bottom
25455 if((x + w) > vw+s.left){
25456 x = vw - w - this.shadowOffset;
25459 if((y + h) > vh+s.top){
25460 y = vh - h - this.shadowOffset;
25463 // then make sure top/left isn't negative
25474 var ay = this.avoidY;
25475 if(y <= ay && (y+h) >= ay){
25481 supr.setXY.call(this, xy);
25487 isVisible : function(){
25488 return this.visible;
25492 showAction : function(){
25493 this.visible = true; // track visibility to prevent getStyle calls
25494 if(this.useDisplay === true){
25495 this.setDisplayed("");
25496 }else if(this.lastXY){
25497 supr.setXY.call(this, this.lastXY);
25498 }else if(this.lastLT){
25499 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25504 hideAction : function(){
25505 this.visible = false;
25506 if(this.useDisplay === true){
25507 this.setDisplayed(false);
25509 this.setLeftTop(-10000,-10000);
25513 // overridden Element method
25514 setVisible : function(v, a, d, c, e){
25519 var cb = function(){
25524 }.createDelegate(this);
25525 supr.setVisible.call(this, true, true, d, cb, e);
25528 this.hideUnders(true);
25537 }.createDelegate(this);
25539 supr.setVisible.call(this, v, a, d, cb, e);
25548 storeXY : function(xy){
25549 delete this.lastLT;
25553 storeLeftTop : function(left, top){
25554 delete this.lastXY;
25555 this.lastLT = [left, top];
25559 beforeFx : function(){
25560 this.beforeAction();
25561 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25565 afterFx : function(){
25566 Roo.Layer.superclass.afterFx.apply(this, arguments);
25567 this.sync(this.isVisible());
25571 beforeAction : function(){
25572 if(!this.updating && this.shadow){
25573 this.shadow.hide();
25577 // overridden Element method
25578 setLeft : function(left){
25579 this.storeLeftTop(left, this.getTop(true));
25580 supr.setLeft.apply(this, arguments);
25584 setTop : function(top){
25585 this.storeLeftTop(this.getLeft(true), top);
25586 supr.setTop.apply(this, arguments);
25590 setLeftTop : function(left, top){
25591 this.storeLeftTop(left, top);
25592 supr.setLeftTop.apply(this, arguments);
25596 setXY : function(xy, a, d, c, e){
25598 this.beforeAction();
25600 var cb = this.createCB(c);
25601 supr.setXY.call(this, xy, a, d, cb, e);
25608 createCB : function(c){
25619 // overridden Element method
25620 setX : function(x, a, d, c, e){
25621 this.setXY([x, this.getY()], a, d, c, e);
25624 // overridden Element method
25625 setY : function(y, a, d, c, e){
25626 this.setXY([this.getX(), y], a, d, c, e);
25629 // overridden Element method
25630 setSize : function(w, h, a, d, c, e){
25631 this.beforeAction();
25632 var cb = this.createCB(c);
25633 supr.setSize.call(this, w, h, a, d, cb, e);
25639 // overridden Element method
25640 setWidth : function(w, a, d, c, e){
25641 this.beforeAction();
25642 var cb = this.createCB(c);
25643 supr.setWidth.call(this, w, a, d, cb, e);
25649 // overridden Element method
25650 setHeight : function(h, a, d, c, e){
25651 this.beforeAction();
25652 var cb = this.createCB(c);
25653 supr.setHeight.call(this, h, a, d, cb, e);
25659 // overridden Element method
25660 setBounds : function(x, y, w, h, a, d, c, e){
25661 this.beforeAction();
25662 var cb = this.createCB(c);
25664 this.storeXY([x, y]);
25665 supr.setXY.call(this, [x, y]);
25666 supr.setSize.call(this, w, h, a, d, cb, e);
25669 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25675 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25676 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25677 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25678 * @param {Number} zindex The new z-index to set
25679 * @return {this} The Layer
25681 setZIndex : function(zindex){
25682 this.zindex = zindex;
25683 this.setStyle("z-index", zindex + 2);
25685 this.shadow.setZIndex(zindex + 1);
25688 this.shim.setStyle("z-index", zindex);
25694 * Ext JS Library 1.1.1
25695 * Copyright(c) 2006-2007, Ext JS, LLC.
25697 * Originally Released Under LGPL - original licence link has changed is not relivant.
25700 * <script type="text/javascript">
25705 * @class Roo.Shadow
25706 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25707 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25708 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25710 * Create a new Shadow
25711 * @param {Object} config The config object
25713 Roo.Shadow = function(config){
25714 Roo.apply(this, config);
25715 if(typeof this.mode != "string"){
25716 this.mode = this.defaultMode;
25718 var o = this.offset, a = {h: 0};
25719 var rad = Math.floor(this.offset/2);
25720 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25726 a.l -= this.offset + rad;
25727 a.t -= this.offset + rad;
25738 a.l -= (this.offset - rad);
25739 a.t -= this.offset + rad;
25741 a.w -= (this.offset - rad)*2;
25752 a.l -= (this.offset - rad);
25753 a.t -= (this.offset - rad);
25755 a.w -= (this.offset + rad + 1);
25756 a.h -= (this.offset + rad);
25765 Roo.Shadow.prototype = {
25767 * @cfg {String} mode
25768 * The shadow display mode. Supports the following options:<br />
25769 * sides: Shadow displays on both sides and bottom only<br />
25770 * frame: Shadow displays equally on all four sides<br />
25771 * drop: Traditional bottom-right drop shadow (default)
25774 * @cfg {String} offset
25775 * The number of pixels to offset the shadow from the element (defaults to 4)
25780 defaultMode: "drop",
25783 * Displays the shadow under the target element
25784 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25786 show : function(target){
25787 target = Roo.get(target);
25789 this.el = Roo.Shadow.Pool.pull();
25790 if(this.el.dom.nextSibling != target.dom){
25791 this.el.insertBefore(target);
25794 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25796 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25799 target.getLeft(true),
25800 target.getTop(true),
25804 this.el.dom.style.display = "block";
25808 * Returns true if the shadow is visible, else false
25810 isVisible : function(){
25811 return this.el ? true : false;
25815 * Direct alignment when values are already available. Show must be called at least once before
25816 * calling this method to ensure it is initialized.
25817 * @param {Number} left The target element left position
25818 * @param {Number} top The target element top position
25819 * @param {Number} width The target element width
25820 * @param {Number} height The target element height
25822 realign : function(l, t, w, h){
25826 var a = this.adjusts, d = this.el.dom, s = d.style;
25828 s.left = (l+a.l)+"px";
25829 s.top = (t+a.t)+"px";
25830 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25832 if(s.width != sws || s.height != shs){
25836 var cn = d.childNodes;
25837 var sww = Math.max(0, (sw-12))+"px";
25838 cn[0].childNodes[1].style.width = sww;
25839 cn[1].childNodes[1].style.width = sww;
25840 cn[2].childNodes[1].style.width = sww;
25841 cn[1].style.height = Math.max(0, (sh-12))+"px";
25847 * Hides this shadow
25851 this.el.dom.style.display = "none";
25852 Roo.Shadow.Pool.push(this.el);
25858 * Adjust the z-index of this shadow
25859 * @param {Number} zindex The new z-index
25861 setZIndex : function(z){
25864 this.el.setStyle("z-index", z);
25869 // Private utility class that manages the internal Shadow cache
25870 Roo.Shadow.Pool = function(){
25872 var markup = Roo.isIE ?
25873 '<div class="x-ie-shadow"></div>' :
25874 '<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>';
25877 var sh = p.shift();
25879 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
25880 sh.autoBoxAdjust = false;
25885 push : function(sh){
25891 * Ext JS Library 1.1.1
25892 * Copyright(c) 2006-2007, Ext JS, LLC.
25894 * Originally Released Under LGPL - original licence link has changed is not relivant.
25897 * <script type="text/javascript">
25902 * @class Roo.SplitBar
25903 * @extends Roo.util.Observable
25904 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
25908 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
25909 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
25910 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
25911 split.minSize = 100;
25912 split.maxSize = 600;
25913 split.animate = true;
25914 split.on('moved', splitterMoved);
25917 * Create a new SplitBar
25918 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
25919 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
25920 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25921 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
25922 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
25923 position of the SplitBar).
25925 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
25928 this.el = Roo.get(dragElement, true);
25929 this.el.dom.unselectable = "on";
25931 this.resizingEl = Roo.get(resizingElement, true);
25935 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25936 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
25939 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
25942 * The minimum size of the resizing element. (Defaults to 0)
25948 * The maximum size of the resizing element. (Defaults to 2000)
25951 this.maxSize = 2000;
25954 * Whether to animate the transition to the new size
25957 this.animate = false;
25960 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
25963 this.useShim = false;
25968 if(!existingProxy){
25970 this.proxy = Roo.SplitBar.createProxy(this.orientation);
25972 this.proxy = Roo.get(existingProxy).dom;
25975 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
25978 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
25981 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
25984 this.dragSpecs = {};
25987 * @private The adapter to use to positon and resize elements
25989 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
25990 this.adapter.init(this);
25992 if(this.orientation == Roo.SplitBar.HORIZONTAL){
25994 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
25995 this.el.addClass("x-splitbar-h");
25998 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
25999 this.el.addClass("x-splitbar-v");
26005 * Fires when the splitter is moved (alias for {@link #event-moved})
26006 * @param {Roo.SplitBar} this
26007 * @param {Number} newSize the new width or height
26012 * Fires when the splitter is moved
26013 * @param {Roo.SplitBar} this
26014 * @param {Number} newSize the new width or height
26018 * @event beforeresize
26019 * Fires before the splitter is dragged
26020 * @param {Roo.SplitBar} this
26022 "beforeresize" : true,
26024 "beforeapply" : true
26027 Roo.util.Observable.call(this);
26030 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26031 onStartProxyDrag : function(x, y){
26032 this.fireEvent("beforeresize", this);
26034 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26036 o.enableDisplayMode("block");
26037 // all splitbars share the same overlay
26038 Roo.SplitBar.prototype.overlay = o;
26040 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26041 this.overlay.show();
26042 Roo.get(this.proxy).setDisplayed("block");
26043 var size = this.adapter.getElementSize(this);
26044 this.activeMinSize = this.getMinimumSize();;
26045 this.activeMaxSize = this.getMaximumSize();;
26046 var c1 = size - this.activeMinSize;
26047 var c2 = Math.max(this.activeMaxSize - size, 0);
26048 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26049 this.dd.resetConstraints();
26050 this.dd.setXConstraint(
26051 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26052 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26054 this.dd.setYConstraint(0, 0);
26056 this.dd.resetConstraints();
26057 this.dd.setXConstraint(0, 0);
26058 this.dd.setYConstraint(
26059 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26060 this.placement == Roo.SplitBar.TOP ? c2 : c1
26063 this.dragSpecs.startSize = size;
26064 this.dragSpecs.startPoint = [x, y];
26065 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26069 * @private Called after the drag operation by the DDProxy
26071 onEndProxyDrag : function(e){
26072 Roo.get(this.proxy).setDisplayed(false);
26073 var endPoint = Roo.lib.Event.getXY(e);
26075 this.overlay.hide();
26078 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26079 newSize = this.dragSpecs.startSize +
26080 (this.placement == Roo.SplitBar.LEFT ?
26081 endPoint[0] - this.dragSpecs.startPoint[0] :
26082 this.dragSpecs.startPoint[0] - endPoint[0]
26085 newSize = this.dragSpecs.startSize +
26086 (this.placement == Roo.SplitBar.TOP ?
26087 endPoint[1] - this.dragSpecs.startPoint[1] :
26088 this.dragSpecs.startPoint[1] - endPoint[1]
26091 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26092 if(newSize != this.dragSpecs.startSize){
26093 if(this.fireEvent('beforeapply', this, newSize) !== false){
26094 this.adapter.setElementSize(this, newSize);
26095 this.fireEvent("moved", this, newSize);
26096 this.fireEvent("resize", this, newSize);
26102 * Get the adapter this SplitBar uses
26103 * @return The adapter object
26105 getAdapter : function(){
26106 return this.adapter;
26110 * Set the adapter this SplitBar uses
26111 * @param {Object} adapter A SplitBar adapter object
26113 setAdapter : function(adapter){
26114 this.adapter = adapter;
26115 this.adapter.init(this);
26119 * Gets the minimum size for the resizing element
26120 * @return {Number} The minimum size
26122 getMinimumSize : function(){
26123 return this.minSize;
26127 * Sets the minimum size for the resizing element
26128 * @param {Number} minSize The minimum size
26130 setMinimumSize : function(minSize){
26131 this.minSize = minSize;
26135 * Gets the maximum size for the resizing element
26136 * @return {Number} The maximum size
26138 getMaximumSize : function(){
26139 return this.maxSize;
26143 * Sets the maximum size for the resizing element
26144 * @param {Number} maxSize The maximum size
26146 setMaximumSize : function(maxSize){
26147 this.maxSize = maxSize;
26151 * Sets the initialize size for the resizing element
26152 * @param {Number} size The initial size
26154 setCurrentSize : function(size){
26155 var oldAnimate = this.animate;
26156 this.animate = false;
26157 this.adapter.setElementSize(this, size);
26158 this.animate = oldAnimate;
26162 * Destroy this splitbar.
26163 * @param {Boolean} removeEl True to remove the element
26165 destroy : function(removeEl){
26167 this.shim.remove();
26170 this.proxy.parentNode.removeChild(this.proxy);
26178 * @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.
26180 Roo.SplitBar.createProxy = function(dir){
26181 var proxy = new Roo.Element(document.createElement("div"));
26182 proxy.unselectable();
26183 var cls = 'x-splitbar-proxy';
26184 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26185 document.body.appendChild(proxy.dom);
26190 * @class Roo.SplitBar.BasicLayoutAdapter
26191 * Default Adapter. It assumes the splitter and resizing element are not positioned
26192 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26194 Roo.SplitBar.BasicLayoutAdapter = function(){
26197 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26198 // do nothing for now
26199 init : function(s){
26203 * Called before drag operations to get the current size of the resizing element.
26204 * @param {Roo.SplitBar} s The SplitBar using this adapter
26206 getElementSize : function(s){
26207 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26208 return s.resizingEl.getWidth();
26210 return s.resizingEl.getHeight();
26215 * Called after drag operations to set the size of the resizing element.
26216 * @param {Roo.SplitBar} s The SplitBar using this adapter
26217 * @param {Number} newSize The new size to set
26218 * @param {Function} onComplete A function to be invoked when resizing is complete
26220 setElementSize : function(s, newSize, onComplete){
26221 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26223 s.resizingEl.setWidth(newSize);
26225 onComplete(s, newSize);
26228 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26233 s.resizingEl.setHeight(newSize);
26235 onComplete(s, newSize);
26238 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26245 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26246 * @extends Roo.SplitBar.BasicLayoutAdapter
26247 * Adapter that moves the splitter element to align with the resized sizing element.
26248 * Used with an absolute positioned SplitBar.
26249 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26250 * document.body, make sure you assign an id to the body element.
26252 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26253 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26254 this.container = Roo.get(container);
26257 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26258 init : function(s){
26259 this.basic.init(s);
26262 getElementSize : function(s){
26263 return this.basic.getElementSize(s);
26266 setElementSize : function(s, newSize, onComplete){
26267 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26270 moveSplitter : function(s){
26271 var yes = Roo.SplitBar;
26272 switch(s.placement){
26274 s.el.setX(s.resizingEl.getRight());
26277 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26280 s.el.setY(s.resizingEl.getBottom());
26283 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26290 * Orientation constant - Create a vertical SplitBar
26294 Roo.SplitBar.VERTICAL = 1;
26297 * Orientation constant - Create a horizontal SplitBar
26301 Roo.SplitBar.HORIZONTAL = 2;
26304 * Placement constant - The resizing element is to the left of the splitter element
26308 Roo.SplitBar.LEFT = 1;
26311 * Placement constant - The resizing element is to the right of the splitter element
26315 Roo.SplitBar.RIGHT = 2;
26318 * Placement constant - The resizing element is positioned above the splitter element
26322 Roo.SplitBar.TOP = 3;
26325 * Placement constant - The resizing element is positioned under splitter element
26329 Roo.SplitBar.BOTTOM = 4;
26332 * Ext JS Library 1.1.1
26333 * Copyright(c) 2006-2007, Ext JS, LLC.
26335 * Originally Released Under LGPL - original licence link has changed is not relivant.
26338 * <script type="text/javascript">
26343 * @extends Roo.util.Observable
26344 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26345 * This class also supports single and multi selection modes. <br>
26346 * Create a data model bound view:
26348 var store = new Roo.data.Store(...);
26350 var view = new Roo.View({
26352 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26354 singleSelect: true,
26355 selectedClass: "ydataview-selected",
26359 // listen for node click?
26360 view.on("click", function(vw, index, node, e){
26361 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26365 dataModel.load("foobar.xml");
26367 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26369 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26370 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26372 * Note: old style constructor is still suported (container, template, config)
26375 * Create a new View
26376 * @param {Object} config The config object
26379 Roo.View = function(config, depreciated_tpl, depreciated_config){
26381 this.parent = false;
26383 if (typeof(depreciated_tpl) == 'undefined') {
26384 // new way.. - universal constructor.
26385 Roo.apply(this, config);
26386 this.el = Roo.get(this.el);
26389 this.el = Roo.get(config);
26390 this.tpl = depreciated_tpl;
26391 Roo.apply(this, depreciated_config);
26393 this.wrapEl = this.el.wrap().wrap();
26394 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26397 if(typeof(this.tpl) == "string"){
26398 this.tpl = new Roo.Template(this.tpl);
26400 // support xtype ctors..
26401 this.tpl = new Roo.factory(this.tpl, Roo);
26405 this.tpl.compile();
26410 * @event beforeclick
26411 * Fires before a click is processed. Returns false to cancel the default action.
26412 * @param {Roo.View} this
26413 * @param {Number} index The index of the target node
26414 * @param {HTMLElement} node The target node
26415 * @param {Roo.EventObject} e The raw event object
26417 "beforeclick" : true,
26420 * Fires when a template node is clicked.
26421 * @param {Roo.View} this
26422 * @param {Number} index The index of the target node
26423 * @param {HTMLElement} node The target node
26424 * @param {Roo.EventObject} e The raw event object
26429 * Fires when a template node is double clicked.
26430 * @param {Roo.View} this
26431 * @param {Number} index The index of the target node
26432 * @param {HTMLElement} node The target node
26433 * @param {Roo.EventObject} e The raw event object
26437 * @event contextmenu
26438 * Fires when a template node is right clicked.
26439 * @param {Roo.View} this
26440 * @param {Number} index The index of the target node
26441 * @param {HTMLElement} node The target node
26442 * @param {Roo.EventObject} e The raw event object
26444 "contextmenu" : true,
26446 * @event selectionchange
26447 * Fires when the selected nodes change.
26448 * @param {Roo.View} this
26449 * @param {Array} selections Array of the selected nodes
26451 "selectionchange" : true,
26454 * @event beforeselect
26455 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26456 * @param {Roo.View} this
26457 * @param {HTMLElement} node The node to be selected
26458 * @param {Array} selections Array of currently selected nodes
26460 "beforeselect" : true,
26462 * @event preparedata
26463 * Fires on every row to render, to allow you to change the data.
26464 * @param {Roo.View} this
26465 * @param {Object} data to be rendered (change this)
26467 "preparedata" : true
26475 "click": this.onClick,
26476 "dblclick": this.onDblClick,
26477 "contextmenu": this.onContextMenu,
26481 this.selections = [];
26483 this.cmp = new Roo.CompositeElementLite([]);
26485 this.store = Roo.factory(this.store, Roo.data);
26486 this.setStore(this.store, true);
26489 if ( this.footer && this.footer.xtype) {
26491 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26493 this.footer.dataSource = this.store;
26494 this.footer.container = fctr;
26495 this.footer = Roo.factory(this.footer, Roo);
26496 fctr.insertFirst(this.el);
26498 // this is a bit insane - as the paging toolbar seems to detach the el..
26499 // dom.parentNode.parentNode.parentNode
26500 // they get detached?
26504 Roo.View.superclass.constructor.call(this);
26509 Roo.extend(Roo.View, Roo.util.Observable, {
26512 * @cfg {Roo.data.Store} store Data store to load data from.
26517 * @cfg {String|Roo.Element} el The container element.
26522 * @cfg {String|Roo.Template} tpl The template used by this View
26526 * @cfg {String} dataName the named area of the template to use as the data area
26527 * Works with domtemplates roo-name="name"
26531 * @cfg {String} selectedClass The css class to add to selected nodes
26533 selectedClass : "x-view-selected",
26535 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26540 * @cfg {String} text to display on mask (default Loading)
26544 * @cfg {Boolean} multiSelect Allow multiple selection
26546 multiSelect : false,
26548 * @cfg {Boolean} singleSelect Allow single selection
26550 singleSelect: false,
26553 * @cfg {Boolean} toggleSelect - selecting
26555 toggleSelect : false,
26558 * @cfg {Boolean} tickable - selecting
26563 * Returns the element this view is bound to.
26564 * @return {Roo.Element}
26566 getEl : function(){
26567 return this.wrapEl;
26573 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26575 refresh : function(){
26576 //Roo.log('refresh');
26579 // if we are using something like 'domtemplate', then
26580 // the what gets used is:
26581 // t.applySubtemplate(NAME, data, wrapping data..)
26582 // the outer template then get' applied with
26583 // the store 'extra data'
26584 // and the body get's added to the
26585 // roo-name="data" node?
26586 // <span class='roo-tpl-{name}'></span> ?????
26590 this.clearSelections();
26591 this.el.update("");
26593 var records = this.store.getRange();
26594 if(records.length < 1) {
26596 // is this valid?? = should it render a template??
26598 this.el.update(this.emptyText);
26602 if (this.dataName) {
26603 this.el.update(t.apply(this.store.meta)); //????
26604 el = this.el.child('.roo-tpl-' + this.dataName);
26607 for(var i = 0, len = records.length; i < len; i++){
26608 var data = this.prepareData(records[i].data, i, records[i]);
26609 this.fireEvent("preparedata", this, data, i, records[i]);
26611 var d = Roo.apply({}, data);
26614 Roo.apply(d, {'roo-id' : Roo.id()});
26618 Roo.each(this.parent.item, function(item){
26619 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26622 Roo.apply(d, {'roo-data-checked' : 'checked'});
26626 html[html.length] = Roo.util.Format.trim(
26628 t.applySubtemplate(this.dataName, d, this.store.meta) :
26635 el.update(html.join(""));
26636 this.nodes = el.dom.childNodes;
26637 this.updateIndexes(0);
26642 * Function to override to reformat the data that is sent to
26643 * the template for each node.
26644 * DEPRICATED - use the preparedata event handler.
26645 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26646 * a JSON object for an UpdateManager bound view).
26648 prepareData : function(data, index, record)
26650 this.fireEvent("preparedata", this, data, index, record);
26654 onUpdate : function(ds, record){
26655 // Roo.log('on update');
26656 this.clearSelections();
26657 var index = this.store.indexOf(record);
26658 var n = this.nodes[index];
26659 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26660 n.parentNode.removeChild(n);
26661 this.updateIndexes(index, index);
26667 onAdd : function(ds, records, index)
26669 //Roo.log(['on Add', ds, records, index] );
26670 this.clearSelections();
26671 if(this.nodes.length == 0){
26675 var n = this.nodes[index];
26676 for(var i = 0, len = records.length; i < len; i++){
26677 var d = this.prepareData(records[i].data, i, records[i]);
26679 this.tpl.insertBefore(n, d);
26682 this.tpl.append(this.el, d);
26685 this.updateIndexes(index);
26688 onRemove : function(ds, record, index){
26689 // Roo.log('onRemove');
26690 this.clearSelections();
26691 var el = this.dataName ?
26692 this.el.child('.roo-tpl-' + this.dataName) :
26695 el.dom.removeChild(this.nodes[index]);
26696 this.updateIndexes(index);
26700 * Refresh an individual node.
26701 * @param {Number} index
26703 refreshNode : function(index){
26704 this.onUpdate(this.store, this.store.getAt(index));
26707 updateIndexes : function(startIndex, endIndex){
26708 var ns = this.nodes;
26709 startIndex = startIndex || 0;
26710 endIndex = endIndex || ns.length - 1;
26711 for(var i = startIndex; i <= endIndex; i++){
26712 ns[i].nodeIndex = i;
26717 * Changes the data store this view uses and refresh the view.
26718 * @param {Store} store
26720 setStore : function(store, initial){
26721 if(!initial && this.store){
26722 this.store.un("datachanged", this.refresh);
26723 this.store.un("add", this.onAdd);
26724 this.store.un("remove", this.onRemove);
26725 this.store.un("update", this.onUpdate);
26726 this.store.un("clear", this.refresh);
26727 this.store.un("beforeload", this.onBeforeLoad);
26728 this.store.un("load", this.onLoad);
26729 this.store.un("loadexception", this.onLoad);
26733 store.on("datachanged", this.refresh, this);
26734 store.on("add", this.onAdd, this);
26735 store.on("remove", this.onRemove, this);
26736 store.on("update", this.onUpdate, this);
26737 store.on("clear", this.refresh, this);
26738 store.on("beforeload", this.onBeforeLoad, this);
26739 store.on("load", this.onLoad, this);
26740 store.on("loadexception", this.onLoad, this);
26748 * onbeforeLoad - masks the loading area.
26751 onBeforeLoad : function(store,opts)
26753 //Roo.log('onBeforeLoad');
26755 this.el.update("");
26757 this.el.mask(this.mask ? this.mask : "Loading" );
26759 onLoad : function ()
26766 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26767 * @param {HTMLElement} node
26768 * @return {HTMLElement} The template node
26770 findItemFromChild : function(node){
26771 var el = this.dataName ?
26772 this.el.child('.roo-tpl-' + this.dataName,true) :
26775 if(!node || node.parentNode == el){
26778 var p = node.parentNode;
26779 while(p && p != el){
26780 if(p.parentNode == el){
26789 onClick : function(e){
26790 var item = this.findItemFromChild(e.getTarget());
26792 var index = this.indexOf(item);
26793 if(this.onItemClick(item, index, e) !== false){
26794 this.fireEvent("click", this, index, item, e);
26797 this.clearSelections();
26802 onContextMenu : function(e){
26803 var item = this.findItemFromChild(e.getTarget());
26805 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26810 onDblClick : function(e){
26811 var item = this.findItemFromChild(e.getTarget());
26813 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26817 onItemClick : function(item, index, e)
26819 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26822 if (this.toggleSelect) {
26823 var m = this.isSelected(item) ? 'unselect' : 'select';
26826 _t[m](item, true, false);
26829 if(this.multiSelect || this.singleSelect){
26830 if(this.multiSelect && e.shiftKey && this.lastSelection){
26831 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26833 this.select(item, this.multiSelect && e.ctrlKey);
26834 this.lastSelection = item;
26837 if(!this.tickable){
26838 e.preventDefault();
26846 * Get the number of selected nodes.
26849 getSelectionCount : function(){
26850 return this.selections.length;
26854 * Get the currently selected nodes.
26855 * @return {Array} An array of HTMLElements
26857 getSelectedNodes : function(){
26858 return this.selections;
26862 * Get the indexes of the selected nodes.
26865 getSelectedIndexes : function(){
26866 var indexes = [], s = this.selections;
26867 for(var i = 0, len = s.length; i < len; i++){
26868 indexes.push(s[i].nodeIndex);
26874 * Clear all selections
26875 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
26877 clearSelections : function(suppressEvent){
26878 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
26879 this.cmp.elements = this.selections;
26880 this.cmp.removeClass(this.selectedClass);
26881 this.selections = [];
26882 if(!suppressEvent){
26883 this.fireEvent("selectionchange", this, this.selections);
26889 * Returns true if the passed node is selected
26890 * @param {HTMLElement/Number} node The node or node index
26891 * @return {Boolean}
26893 isSelected : function(node){
26894 var s = this.selections;
26898 node = this.getNode(node);
26899 return s.indexOf(node) !== -1;
26904 * @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
26905 * @param {Boolean} keepExisting (optional) true to keep existing selections
26906 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26908 select : function(nodeInfo, keepExisting, suppressEvent){
26909 if(nodeInfo instanceof Array){
26911 this.clearSelections(true);
26913 for(var i = 0, len = nodeInfo.length; i < len; i++){
26914 this.select(nodeInfo[i], true, true);
26918 var node = this.getNode(nodeInfo);
26919 if(!node || this.isSelected(node)){
26920 return; // already selected.
26923 this.clearSelections(true);
26926 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
26927 Roo.fly(node).addClass(this.selectedClass);
26928 this.selections.push(node);
26929 if(!suppressEvent){
26930 this.fireEvent("selectionchange", this, this.selections);
26938 * @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
26939 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
26940 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26942 unselect : function(nodeInfo, keepExisting, suppressEvent)
26944 if(nodeInfo instanceof Array){
26945 Roo.each(this.selections, function(s) {
26946 this.unselect(s, nodeInfo);
26950 var node = this.getNode(nodeInfo);
26951 if(!node || !this.isSelected(node)){
26952 //Roo.log("not selected");
26953 return; // not selected.
26957 Roo.each(this.selections, function(s) {
26959 Roo.fly(node).removeClass(this.selectedClass);
26966 this.selections= ns;
26967 this.fireEvent("selectionchange", this, this.selections);
26971 * Gets a template node.
26972 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26973 * @return {HTMLElement} The node or null if it wasn't found
26975 getNode : function(nodeInfo){
26976 if(typeof nodeInfo == "string"){
26977 return document.getElementById(nodeInfo);
26978 }else if(typeof nodeInfo == "number"){
26979 return this.nodes[nodeInfo];
26985 * Gets a range template nodes.
26986 * @param {Number} startIndex
26987 * @param {Number} endIndex
26988 * @return {Array} An array of nodes
26990 getNodes : function(start, end){
26991 var ns = this.nodes;
26992 start = start || 0;
26993 end = typeof end == "undefined" ? ns.length - 1 : end;
26996 for(var i = start; i <= end; i++){
27000 for(var i = start; i >= end; i--){
27008 * Finds the index of the passed node
27009 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27010 * @return {Number} The index of the node or -1
27012 indexOf : function(node){
27013 node = this.getNode(node);
27014 if(typeof node.nodeIndex == "number"){
27015 return node.nodeIndex;
27017 var ns = this.nodes;
27018 for(var i = 0, len = ns.length; i < len; i++){
27028 * Ext JS Library 1.1.1
27029 * Copyright(c) 2006-2007, Ext JS, LLC.
27031 * Originally Released Under LGPL - original licence link has changed is not relivant.
27034 * <script type="text/javascript">
27038 * @class Roo.JsonView
27039 * @extends Roo.View
27040 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27042 var view = new Roo.JsonView({
27043 container: "my-element",
27044 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27049 // listen for node click?
27050 view.on("click", function(vw, index, node, e){
27051 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27054 // direct load of JSON data
27055 view.load("foobar.php");
27057 // Example from my blog list
27058 var tpl = new Roo.Template(
27059 '<div class="entry">' +
27060 '<a class="entry-title" href="{link}">{title}</a>' +
27061 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27062 "</div><hr />"
27065 var moreView = new Roo.JsonView({
27066 container : "entry-list",
27070 moreView.on("beforerender", this.sortEntries, this);
27072 url: "/blog/get-posts.php",
27073 params: "allposts=true",
27074 text: "Loading Blog Entries..."
27078 * Note: old code is supported with arguments : (container, template, config)
27082 * Create a new JsonView
27084 * @param {Object} config The config object
27087 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27090 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27092 var um = this.el.getUpdateManager();
27093 um.setRenderer(this);
27094 um.on("update", this.onLoad, this);
27095 um.on("failure", this.onLoadException, this);
27098 * @event beforerender
27099 * Fires before rendering of the downloaded JSON data.
27100 * @param {Roo.JsonView} this
27101 * @param {Object} data The JSON data loaded
27105 * Fires when data is loaded.
27106 * @param {Roo.JsonView} this
27107 * @param {Object} data The JSON data loaded
27108 * @param {Object} response The raw Connect response object
27111 * @event loadexception
27112 * Fires when loading fails.
27113 * @param {Roo.JsonView} this
27114 * @param {Object} response The raw Connect response object
27117 'beforerender' : true,
27119 'loadexception' : true
27122 Roo.extend(Roo.JsonView, Roo.View, {
27124 * @type {String} The root property in the loaded JSON object that contains the data
27129 * Refreshes the view.
27131 refresh : function(){
27132 this.clearSelections();
27133 this.el.update("");
27135 var o = this.jsonData;
27136 if(o && o.length > 0){
27137 for(var i = 0, len = o.length; i < len; i++){
27138 var data = this.prepareData(o[i], i, o);
27139 html[html.length] = this.tpl.apply(data);
27142 html.push(this.emptyText);
27144 this.el.update(html.join(""));
27145 this.nodes = this.el.dom.childNodes;
27146 this.updateIndexes(0);
27150 * 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.
27151 * @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:
27154 url: "your-url.php",
27155 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27156 callback: yourFunction,
27157 scope: yourObject, //(optional scope)
27160 text: "Loading...",
27165 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27166 * 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.
27167 * @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}
27168 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27169 * @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.
27172 var um = this.el.getUpdateManager();
27173 um.update.apply(um, arguments);
27176 // note - render is a standard framework call...
27177 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27178 render : function(el, response){
27180 this.clearSelections();
27181 this.el.update("");
27184 if (response != '') {
27185 o = Roo.util.JSON.decode(response.responseText);
27188 o = o[this.jsonRoot];
27194 * The current JSON data or null
27197 this.beforeRender();
27202 * Get the number of records in the current JSON dataset
27205 getCount : function(){
27206 return this.jsonData ? this.jsonData.length : 0;
27210 * Returns the JSON object for the specified node(s)
27211 * @param {HTMLElement/Array} node The node or an array of nodes
27212 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27213 * you get the JSON object for the node
27215 getNodeData : function(node){
27216 if(node instanceof Array){
27218 for(var i = 0, len = node.length; i < len; i++){
27219 data.push(this.getNodeData(node[i]));
27223 return this.jsonData[this.indexOf(node)] || null;
27226 beforeRender : function(){
27227 this.snapshot = this.jsonData;
27229 this.sort.apply(this, this.sortInfo);
27231 this.fireEvent("beforerender", this, this.jsonData);
27234 onLoad : function(el, o){
27235 this.fireEvent("load", this, this.jsonData, o);
27238 onLoadException : function(el, o){
27239 this.fireEvent("loadexception", this, o);
27243 * Filter the data by a specific property.
27244 * @param {String} property A property on your JSON objects
27245 * @param {String/RegExp} value Either string that the property values
27246 * should start with, or a RegExp to test against the property
27248 filter : function(property, value){
27251 var ss = this.snapshot;
27252 if(typeof value == "string"){
27253 var vlen = value.length;
27255 this.clearFilter();
27258 value = value.toLowerCase();
27259 for(var i = 0, len = ss.length; i < len; i++){
27261 if(o[property].substr(0, vlen).toLowerCase() == value){
27265 } else if(value.exec){ // regex?
27266 for(var i = 0, len = ss.length; i < len; i++){
27268 if(value.test(o[property])){
27275 this.jsonData = data;
27281 * Filter by a function. The passed function will be called with each
27282 * object in the current dataset. If the function returns true the value is kept,
27283 * otherwise it is filtered.
27284 * @param {Function} fn
27285 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27287 filterBy : function(fn, scope){
27290 var ss = this.snapshot;
27291 for(var i = 0, len = ss.length; i < len; i++){
27293 if(fn.call(scope || this, o)){
27297 this.jsonData = data;
27303 * Clears the current filter.
27305 clearFilter : function(){
27306 if(this.snapshot && this.jsonData != this.snapshot){
27307 this.jsonData = this.snapshot;
27314 * Sorts the data for this view and refreshes it.
27315 * @param {String} property A property on your JSON objects to sort on
27316 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27317 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27319 sort : function(property, dir, sortType){
27320 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27323 var dsc = dir && dir.toLowerCase() == "desc";
27324 var f = function(o1, o2){
27325 var v1 = sortType ? sortType(o1[p]) : o1[p];
27326 var v2 = sortType ? sortType(o2[p]) : o2[p];
27329 return dsc ? +1 : -1;
27330 } else if(v1 > v2){
27331 return dsc ? -1 : +1;
27336 this.jsonData.sort(f);
27338 if(this.jsonData != this.snapshot){
27339 this.snapshot.sort(f);
27345 * Ext JS Library 1.1.1
27346 * Copyright(c) 2006-2007, Ext JS, LLC.
27348 * Originally Released Under LGPL - original licence link has changed is not relivant.
27351 * <script type="text/javascript">
27356 * @class Roo.ColorPalette
27357 * @extends Roo.Component
27358 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27359 * Here's an example of typical usage:
27361 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27362 cp.render('my-div');
27364 cp.on('select', function(palette, selColor){
27365 // do something with selColor
27369 * Create a new ColorPalette
27370 * @param {Object} config The config object
27372 Roo.ColorPalette = function(config){
27373 Roo.ColorPalette.superclass.constructor.call(this, config);
27377 * Fires when a color is selected
27378 * @param {ColorPalette} this
27379 * @param {String} color The 6-digit color hex code (without the # symbol)
27385 this.on("select", this.handler, this.scope, true);
27388 Roo.extend(Roo.ColorPalette, Roo.Component, {
27390 * @cfg {String} itemCls
27391 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27393 itemCls : "x-color-palette",
27395 * @cfg {String} value
27396 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27397 * the hex codes are case-sensitive.
27400 clickEvent:'click',
27402 ctype: "Roo.ColorPalette",
27405 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27407 allowReselect : false,
27410 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27411 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27412 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27413 * of colors with the width setting until the box is symmetrical.</p>
27414 * <p>You can override individual colors if needed:</p>
27416 var cp = new Roo.ColorPalette();
27417 cp.colors[0] = "FF0000"; // change the first box to red
27420 Or you can provide a custom array of your own for complete control:
27422 var cp = new Roo.ColorPalette();
27423 cp.colors = ["000000", "993300", "333300"];
27428 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27429 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27430 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27431 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27432 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27436 onRender : function(container, position){
27437 var t = new Roo.MasterTemplate(
27438 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27440 var c = this.colors;
27441 for(var i = 0, len = c.length; i < len; i++){
27444 var el = document.createElement("div");
27445 el.className = this.itemCls;
27447 container.dom.insertBefore(el, position);
27448 this.el = Roo.get(el);
27449 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27450 if(this.clickEvent != 'click'){
27451 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27456 afterRender : function(){
27457 Roo.ColorPalette.superclass.afterRender.call(this);
27459 var s = this.value;
27466 handleClick : function(e, t){
27467 e.preventDefault();
27468 if(!this.disabled){
27469 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27470 this.select(c.toUpperCase());
27475 * Selects the specified color in the palette (fires the select event)
27476 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27478 select : function(color){
27479 color = color.replace("#", "");
27480 if(color != this.value || this.allowReselect){
27483 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27485 el.child("a.color-"+color).addClass("x-color-palette-sel");
27486 this.value = color;
27487 this.fireEvent("select", this, color);
27492 * Ext JS Library 1.1.1
27493 * Copyright(c) 2006-2007, Ext JS, LLC.
27495 * Originally Released Under LGPL - original licence link has changed is not relivant.
27498 * <script type="text/javascript">
27502 * @class Roo.DatePicker
27503 * @extends Roo.Component
27504 * Simple date picker class.
27506 * Create a new DatePicker
27507 * @param {Object} config The config object
27509 Roo.DatePicker = function(config){
27510 Roo.DatePicker.superclass.constructor.call(this, config);
27512 this.value = config && config.value ?
27513 config.value.clearTime() : new Date().clearTime();
27518 * Fires when a date is selected
27519 * @param {DatePicker} this
27520 * @param {Date} date The selected date
27524 * @event monthchange
27525 * Fires when the displayed month changes
27526 * @param {DatePicker} this
27527 * @param {Date} date The selected month
27529 'monthchange': true
27533 this.on("select", this.handler, this.scope || this);
27535 // build the disabledDatesRE
27536 if(!this.disabledDatesRE && this.disabledDates){
27537 var dd = this.disabledDates;
27539 for(var i = 0; i < dd.length; i++){
27541 if(i != dd.length-1) {
27545 this.disabledDatesRE = new RegExp(re + ")");
27549 Roo.extend(Roo.DatePicker, Roo.Component, {
27551 * @cfg {String} todayText
27552 * The text to display on the button that selects the current date (defaults to "Today")
27554 todayText : "Today",
27556 * @cfg {String} okText
27557 * The text to display on the ok button
27559 okText : " OK ", //   to give the user extra clicking room
27561 * @cfg {String} cancelText
27562 * The text to display on the cancel button
27564 cancelText : "Cancel",
27566 * @cfg {String} todayTip
27567 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27569 todayTip : "{0} (Spacebar)",
27571 * @cfg {Date} minDate
27572 * Minimum allowable date (JavaScript date object, defaults to null)
27576 * @cfg {Date} maxDate
27577 * Maximum allowable date (JavaScript date object, defaults to null)
27581 * @cfg {String} minText
27582 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27584 minText : "This date is before the minimum date",
27586 * @cfg {String} maxText
27587 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27589 maxText : "This date is after the maximum date",
27591 * @cfg {String} format
27592 * The default date format string which can be overriden for localization support. The format must be
27593 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27597 * @cfg {Array} disabledDays
27598 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27600 disabledDays : null,
27602 * @cfg {String} disabledDaysText
27603 * The tooltip to display when the date falls on a disabled day (defaults to "")
27605 disabledDaysText : "",
27607 * @cfg {RegExp} disabledDatesRE
27608 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27610 disabledDatesRE : null,
27612 * @cfg {String} disabledDatesText
27613 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27615 disabledDatesText : "",
27617 * @cfg {Boolean} constrainToViewport
27618 * True to constrain the date picker to the viewport (defaults to true)
27620 constrainToViewport : true,
27622 * @cfg {Array} monthNames
27623 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27625 monthNames : Date.monthNames,
27627 * @cfg {Array} dayNames
27628 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27630 dayNames : Date.dayNames,
27632 * @cfg {String} nextText
27633 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27635 nextText: 'Next Month (Control+Right)',
27637 * @cfg {String} prevText
27638 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27640 prevText: 'Previous Month (Control+Left)',
27642 * @cfg {String} monthYearText
27643 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27645 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27647 * @cfg {Number} startDay
27648 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27652 * @cfg {Bool} showClear
27653 * Show a clear button (usefull for date form elements that can be blank.)
27659 * Sets the value of the date field
27660 * @param {Date} value The date to set
27662 setValue : function(value){
27663 var old = this.value;
27665 if (typeof(value) == 'string') {
27667 value = Date.parseDate(value, this.format);
27670 value = new Date();
27673 this.value = value.clearTime(true);
27675 this.update(this.value);
27680 * Gets the current selected value of the date field
27681 * @return {Date} The selected date
27683 getValue : function(){
27688 focus : function(){
27690 this.update(this.activeDate);
27695 onRender : function(container, position){
27698 '<table cellspacing="0">',
27699 '<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>',
27700 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27701 var dn = this.dayNames;
27702 for(var i = 0; i < 7; i++){
27703 var d = this.startDay+i;
27707 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27709 m[m.length] = "</tr></thead><tbody><tr>";
27710 for(var i = 0; i < 42; i++) {
27711 if(i % 7 == 0 && i != 0){
27712 m[m.length] = "</tr><tr>";
27714 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27716 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27717 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27719 var el = document.createElement("div");
27720 el.className = "x-date-picker";
27721 el.innerHTML = m.join("");
27723 container.dom.insertBefore(el, position);
27725 this.el = Roo.get(el);
27726 this.eventEl = Roo.get(el.firstChild);
27728 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27729 handler: this.showPrevMonth,
27731 preventDefault:true,
27735 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27736 handler: this.showNextMonth,
27738 preventDefault:true,
27742 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27744 this.monthPicker = this.el.down('div.x-date-mp');
27745 this.monthPicker.enableDisplayMode('block');
27747 var kn = new Roo.KeyNav(this.eventEl, {
27748 "left" : function(e){
27750 this.showPrevMonth() :
27751 this.update(this.activeDate.add("d", -1));
27754 "right" : function(e){
27756 this.showNextMonth() :
27757 this.update(this.activeDate.add("d", 1));
27760 "up" : function(e){
27762 this.showNextYear() :
27763 this.update(this.activeDate.add("d", -7));
27766 "down" : function(e){
27768 this.showPrevYear() :
27769 this.update(this.activeDate.add("d", 7));
27772 "pageUp" : function(e){
27773 this.showNextMonth();
27776 "pageDown" : function(e){
27777 this.showPrevMonth();
27780 "enter" : function(e){
27781 e.stopPropagation();
27788 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27790 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27792 this.el.unselectable();
27794 this.cells = this.el.select("table.x-date-inner tbody td");
27795 this.textNodes = this.el.query("table.x-date-inner tbody span");
27797 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27799 tooltip: this.monthYearText
27802 this.mbtn.on('click', this.showMonthPicker, this);
27803 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27806 var today = (new Date()).dateFormat(this.format);
27808 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27809 if (this.showClear) {
27810 baseTb.add( new Roo.Toolbar.Fill());
27813 text: String.format(this.todayText, today),
27814 tooltip: String.format(this.todayTip, today),
27815 handler: this.selectToday,
27819 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27822 if (this.showClear) {
27824 baseTb.add( new Roo.Toolbar.Fill());
27827 cls: 'x-btn-icon x-btn-clear',
27828 handler: function() {
27830 this.fireEvent("select", this, '');
27840 this.update(this.value);
27843 createMonthPicker : function(){
27844 if(!this.monthPicker.dom.firstChild){
27845 var buf = ['<table border="0" cellspacing="0">'];
27846 for(var i = 0; i < 6; i++){
27848 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27849 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27851 '<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>' :
27852 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27856 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27858 '</button><button type="button" class="x-date-mp-cancel">',
27860 '</button></td></tr>',
27863 this.monthPicker.update(buf.join(''));
27864 this.monthPicker.on('click', this.onMonthClick, this);
27865 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
27867 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
27868 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
27870 this.mpMonths.each(function(m, a, i){
27873 m.dom.xmonth = 5 + Math.round(i * .5);
27875 m.dom.xmonth = Math.round((i-1) * .5);
27881 showMonthPicker : function(){
27882 this.createMonthPicker();
27883 var size = this.el.getSize();
27884 this.monthPicker.setSize(size);
27885 this.monthPicker.child('table').setSize(size);
27887 this.mpSelMonth = (this.activeDate || this.value).getMonth();
27888 this.updateMPMonth(this.mpSelMonth);
27889 this.mpSelYear = (this.activeDate || this.value).getFullYear();
27890 this.updateMPYear(this.mpSelYear);
27892 this.monthPicker.slideIn('t', {duration:.2});
27895 updateMPYear : function(y){
27897 var ys = this.mpYears.elements;
27898 for(var i = 1; i <= 10; i++){
27899 var td = ys[i-1], y2;
27901 y2 = y + Math.round(i * .5);
27902 td.firstChild.innerHTML = y2;
27905 y2 = y - (5-Math.round(i * .5));
27906 td.firstChild.innerHTML = y2;
27909 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
27913 updateMPMonth : function(sm){
27914 this.mpMonths.each(function(m, a, i){
27915 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
27919 selectMPMonth: function(m){
27923 onMonthClick : function(e, t){
27925 var el = new Roo.Element(t), pn;
27926 if(el.is('button.x-date-mp-cancel')){
27927 this.hideMonthPicker();
27929 else if(el.is('button.x-date-mp-ok')){
27930 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27931 this.hideMonthPicker();
27933 else if(pn = el.up('td.x-date-mp-month', 2)){
27934 this.mpMonths.removeClass('x-date-mp-sel');
27935 pn.addClass('x-date-mp-sel');
27936 this.mpSelMonth = pn.dom.xmonth;
27938 else if(pn = el.up('td.x-date-mp-year', 2)){
27939 this.mpYears.removeClass('x-date-mp-sel');
27940 pn.addClass('x-date-mp-sel');
27941 this.mpSelYear = pn.dom.xyear;
27943 else if(el.is('a.x-date-mp-prev')){
27944 this.updateMPYear(this.mpyear-10);
27946 else if(el.is('a.x-date-mp-next')){
27947 this.updateMPYear(this.mpyear+10);
27951 onMonthDblClick : function(e, t){
27953 var el = new Roo.Element(t), pn;
27954 if(pn = el.up('td.x-date-mp-month', 2)){
27955 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
27956 this.hideMonthPicker();
27958 else if(pn = el.up('td.x-date-mp-year', 2)){
27959 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27960 this.hideMonthPicker();
27964 hideMonthPicker : function(disableAnim){
27965 if(this.monthPicker){
27966 if(disableAnim === true){
27967 this.monthPicker.hide();
27969 this.monthPicker.slideOut('t', {duration:.2});
27975 showPrevMonth : function(e){
27976 this.update(this.activeDate.add("mo", -1));
27980 showNextMonth : function(e){
27981 this.update(this.activeDate.add("mo", 1));
27985 showPrevYear : function(){
27986 this.update(this.activeDate.add("y", -1));
27990 showNextYear : function(){
27991 this.update(this.activeDate.add("y", 1));
27995 handleMouseWheel : function(e){
27996 var delta = e.getWheelDelta();
27998 this.showPrevMonth();
28000 } else if(delta < 0){
28001 this.showNextMonth();
28007 handleDateClick : function(e, t){
28009 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28010 this.setValue(new Date(t.dateValue));
28011 this.fireEvent("select", this, this.value);
28016 selectToday : function(){
28017 this.setValue(new Date().clearTime());
28018 this.fireEvent("select", this, this.value);
28022 update : function(date)
28024 var vd = this.activeDate;
28025 this.activeDate = date;
28027 var t = date.getTime();
28028 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28029 this.cells.removeClass("x-date-selected");
28030 this.cells.each(function(c){
28031 if(c.dom.firstChild.dateValue == t){
28032 c.addClass("x-date-selected");
28033 setTimeout(function(){
28034 try{c.dom.firstChild.focus();}catch(e){}
28043 var days = date.getDaysInMonth();
28044 var firstOfMonth = date.getFirstDateOfMonth();
28045 var startingPos = firstOfMonth.getDay()-this.startDay;
28047 if(startingPos <= this.startDay){
28051 var pm = date.add("mo", -1);
28052 var prevStart = pm.getDaysInMonth()-startingPos;
28054 var cells = this.cells.elements;
28055 var textEls = this.textNodes;
28056 days += startingPos;
28058 // convert everything to numbers so it's fast
28059 var day = 86400000;
28060 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28061 var today = new Date().clearTime().getTime();
28062 var sel = date.clearTime().getTime();
28063 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28064 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28065 var ddMatch = this.disabledDatesRE;
28066 var ddText = this.disabledDatesText;
28067 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28068 var ddaysText = this.disabledDaysText;
28069 var format = this.format;
28071 var setCellClass = function(cal, cell){
28073 var t = d.getTime();
28074 cell.firstChild.dateValue = t;
28076 cell.className += " x-date-today";
28077 cell.title = cal.todayText;
28080 cell.className += " x-date-selected";
28081 setTimeout(function(){
28082 try{cell.firstChild.focus();}catch(e){}
28087 cell.className = " x-date-disabled";
28088 cell.title = cal.minText;
28092 cell.className = " x-date-disabled";
28093 cell.title = cal.maxText;
28097 if(ddays.indexOf(d.getDay()) != -1){
28098 cell.title = ddaysText;
28099 cell.className = " x-date-disabled";
28102 if(ddMatch && format){
28103 var fvalue = d.dateFormat(format);
28104 if(ddMatch.test(fvalue)){
28105 cell.title = ddText.replace("%0", fvalue);
28106 cell.className = " x-date-disabled";
28112 for(; i < startingPos; i++) {
28113 textEls[i].innerHTML = (++prevStart);
28114 d.setDate(d.getDate()+1);
28115 cells[i].className = "x-date-prevday";
28116 setCellClass(this, cells[i]);
28118 for(; i < days; i++){
28119 intDay = i - startingPos + 1;
28120 textEls[i].innerHTML = (intDay);
28121 d.setDate(d.getDate()+1);
28122 cells[i].className = "x-date-active";
28123 setCellClass(this, cells[i]);
28126 for(; i < 42; i++) {
28127 textEls[i].innerHTML = (++extraDays);
28128 d.setDate(d.getDate()+1);
28129 cells[i].className = "x-date-nextday";
28130 setCellClass(this, cells[i]);
28133 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28134 this.fireEvent('monthchange', this, date);
28136 if(!this.internalRender){
28137 var main = this.el.dom.firstChild;
28138 var w = main.offsetWidth;
28139 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28140 Roo.fly(main).setWidth(w);
28141 this.internalRender = true;
28142 // opera does not respect the auto grow header center column
28143 // then, after it gets a width opera refuses to recalculate
28144 // without a second pass
28145 if(Roo.isOpera && !this.secondPass){
28146 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28147 this.secondPass = true;
28148 this.update.defer(10, this, [date]);
28156 * Ext JS Library 1.1.1
28157 * Copyright(c) 2006-2007, Ext JS, LLC.
28159 * Originally Released Under LGPL - original licence link has changed is not relivant.
28162 * <script type="text/javascript">
28165 * @class Roo.TabPanel
28166 * @extends Roo.util.Observable
28167 * A lightweight tab container.
28171 // basic tabs 1, built from existing content
28172 var tabs = new Roo.TabPanel("tabs1");
28173 tabs.addTab("script", "View Script");
28174 tabs.addTab("markup", "View Markup");
28175 tabs.activate("script");
28177 // more advanced tabs, built from javascript
28178 var jtabs = new Roo.TabPanel("jtabs");
28179 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28181 // set up the UpdateManager
28182 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28183 var updater = tab2.getUpdateManager();
28184 updater.setDefaultUrl("ajax1.htm");
28185 tab2.on('activate', updater.refresh, updater, true);
28187 // Use setUrl for Ajax loading
28188 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28189 tab3.setUrl("ajax2.htm", null, true);
28192 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28195 jtabs.activate("jtabs-1");
28198 * Create a new TabPanel.
28199 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28200 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28202 Roo.TabPanel = function(container, config){
28204 * The container element for this TabPanel.
28205 * @type Roo.Element
28207 this.el = Roo.get(container, true);
28209 if(typeof config == "boolean"){
28210 this.tabPosition = config ? "bottom" : "top";
28212 Roo.apply(this, config);
28215 if(this.tabPosition == "bottom"){
28216 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28217 this.el.addClass("x-tabs-bottom");
28219 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28220 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28221 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28223 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28225 if(this.tabPosition != "bottom"){
28226 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28227 * @type Roo.Element
28229 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28230 this.el.addClass("x-tabs-top");
28234 this.bodyEl.setStyle("position", "relative");
28236 this.active = null;
28237 this.activateDelegate = this.activate.createDelegate(this);
28242 * Fires when the active tab changes
28243 * @param {Roo.TabPanel} this
28244 * @param {Roo.TabPanelItem} activePanel The new active tab
28248 * @event beforetabchange
28249 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28250 * @param {Roo.TabPanel} this
28251 * @param {Object} e Set cancel to true on this object to cancel the tab change
28252 * @param {Roo.TabPanelItem} tab The tab being changed to
28254 "beforetabchange" : true
28257 Roo.EventManager.onWindowResize(this.onResize, this);
28258 this.cpad = this.el.getPadding("lr");
28259 this.hiddenCount = 0;
28262 // toolbar on the tabbar support...
28263 if (this.toolbar) {
28264 var tcfg = this.toolbar;
28265 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28266 this.toolbar = new Roo.Toolbar(tcfg);
28267 if (Roo.isSafari) {
28268 var tbl = tcfg.container.child('table', true);
28269 tbl.setAttribute('width', '100%');
28276 Roo.TabPanel.superclass.constructor.call(this);
28279 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28281 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28283 tabPosition : "top",
28285 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28287 currentTabWidth : 0,
28289 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28293 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28297 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28299 preferredTabWidth : 175,
28301 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28303 resizeTabs : false,
28305 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28307 monitorResize : true,
28309 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28314 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28315 * @param {String} id The id of the div to use <b>or create</b>
28316 * @param {String} text The text for the tab
28317 * @param {String} content (optional) Content to put in the TabPanelItem body
28318 * @param {Boolean} closable (optional) True to create a close icon on the tab
28319 * @return {Roo.TabPanelItem} The created TabPanelItem
28321 addTab : function(id, text, content, closable){
28322 var item = new Roo.TabPanelItem(this, id, text, closable);
28323 this.addTabItem(item);
28325 item.setContent(content);
28331 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28332 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28333 * @return {Roo.TabPanelItem}
28335 getTab : function(id){
28336 return this.items[id];
28340 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28341 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28343 hideTab : function(id){
28344 var t = this.items[id];
28347 this.hiddenCount++;
28348 this.autoSizeTabs();
28353 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28354 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28356 unhideTab : function(id){
28357 var t = this.items[id];
28359 t.setHidden(false);
28360 this.hiddenCount--;
28361 this.autoSizeTabs();
28366 * Adds an existing {@link Roo.TabPanelItem}.
28367 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28369 addTabItem : function(item){
28370 this.items[item.id] = item;
28371 this.items.push(item);
28372 if(this.resizeTabs){
28373 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28374 this.autoSizeTabs();
28381 * Removes a {@link Roo.TabPanelItem}.
28382 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28384 removeTab : function(id){
28385 var items = this.items;
28386 var tab = items[id];
28387 if(!tab) { return; }
28388 var index = items.indexOf(tab);
28389 if(this.active == tab && items.length > 1){
28390 var newTab = this.getNextAvailable(index);
28395 this.stripEl.dom.removeChild(tab.pnode.dom);
28396 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28397 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28399 items.splice(index, 1);
28400 delete this.items[tab.id];
28401 tab.fireEvent("close", tab);
28402 tab.purgeListeners();
28403 this.autoSizeTabs();
28406 getNextAvailable : function(start){
28407 var items = this.items;
28409 // look for a next tab that will slide over to
28410 // replace the one being removed
28411 while(index < items.length){
28412 var item = items[++index];
28413 if(item && !item.isHidden()){
28417 // if one isn't found select the previous tab (on the left)
28420 var item = items[--index];
28421 if(item && !item.isHidden()){
28429 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28430 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28432 disableTab : function(id){
28433 var tab = this.items[id];
28434 if(tab && this.active != tab){
28440 * Enables a {@link Roo.TabPanelItem} that is disabled.
28441 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28443 enableTab : function(id){
28444 var tab = this.items[id];
28449 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28450 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28451 * @return {Roo.TabPanelItem} The TabPanelItem.
28453 activate : function(id){
28454 var tab = this.items[id];
28458 if(tab == this.active || tab.disabled){
28462 this.fireEvent("beforetabchange", this, e, tab);
28463 if(e.cancel !== true && !tab.disabled){
28465 this.active.hide();
28467 this.active = this.items[id];
28468 this.active.show();
28469 this.fireEvent("tabchange", this, this.active);
28475 * Gets the active {@link Roo.TabPanelItem}.
28476 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28478 getActiveTab : function(){
28479 return this.active;
28483 * Updates the tab body element to fit the height of the container element
28484 * for overflow scrolling
28485 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28487 syncHeight : function(targetHeight){
28488 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28489 var bm = this.bodyEl.getMargins();
28490 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28491 this.bodyEl.setHeight(newHeight);
28495 onResize : function(){
28496 if(this.monitorResize){
28497 this.autoSizeTabs();
28502 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28504 beginUpdate : function(){
28505 this.updating = true;
28509 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28511 endUpdate : function(){
28512 this.updating = false;
28513 this.autoSizeTabs();
28517 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28519 autoSizeTabs : function(){
28520 var count = this.items.length;
28521 var vcount = count - this.hiddenCount;
28522 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28525 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28526 var availWidth = Math.floor(w / vcount);
28527 var b = this.stripBody;
28528 if(b.getWidth() > w){
28529 var tabs = this.items;
28530 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28531 if(availWidth < this.minTabWidth){
28532 /*if(!this.sleft){ // incomplete scrolling code
28533 this.createScrollButtons();
28536 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28539 if(this.currentTabWidth < this.preferredTabWidth){
28540 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28546 * Returns the number of tabs in this TabPanel.
28549 getCount : function(){
28550 return this.items.length;
28554 * Resizes all the tabs to the passed width
28555 * @param {Number} The new width
28557 setTabWidth : function(width){
28558 this.currentTabWidth = width;
28559 for(var i = 0, len = this.items.length; i < len; i++) {
28560 if(!this.items[i].isHidden()) {
28561 this.items[i].setWidth(width);
28567 * Destroys this TabPanel
28568 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28570 destroy : function(removeEl){
28571 Roo.EventManager.removeResizeListener(this.onResize, this);
28572 for(var i = 0, len = this.items.length; i < len; i++){
28573 this.items[i].purgeListeners();
28575 if(removeEl === true){
28576 this.el.update("");
28583 * @class Roo.TabPanelItem
28584 * @extends Roo.util.Observable
28585 * Represents an individual item (tab plus body) in a TabPanel.
28586 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28587 * @param {String} id The id of this TabPanelItem
28588 * @param {String} text The text for the tab of this TabPanelItem
28589 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28591 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28593 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28594 * @type Roo.TabPanel
28596 this.tabPanel = tabPanel;
28598 * The id for this TabPanelItem
28603 this.disabled = false;
28607 this.loaded = false;
28608 this.closable = closable;
28611 * The body element for this TabPanelItem.
28612 * @type Roo.Element
28614 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28615 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28616 this.bodyEl.setStyle("display", "block");
28617 this.bodyEl.setStyle("zoom", "1");
28620 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28622 this.el = Roo.get(els.el, true);
28623 this.inner = Roo.get(els.inner, true);
28624 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28625 this.pnode = Roo.get(els.el.parentNode, true);
28626 this.el.on("mousedown", this.onTabMouseDown, this);
28627 this.el.on("click", this.onTabClick, this);
28630 var c = Roo.get(els.close, true);
28631 c.dom.title = this.closeText;
28632 c.addClassOnOver("close-over");
28633 c.on("click", this.closeClick, this);
28639 * Fires when this tab becomes the active tab.
28640 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28641 * @param {Roo.TabPanelItem} this
28645 * @event beforeclose
28646 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28647 * @param {Roo.TabPanelItem} this
28648 * @param {Object} e Set cancel to true on this object to cancel the close.
28650 "beforeclose": true,
28653 * Fires when this tab is closed.
28654 * @param {Roo.TabPanelItem} this
28658 * @event deactivate
28659 * Fires when this tab is no longer the active tab.
28660 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28661 * @param {Roo.TabPanelItem} this
28663 "deactivate" : true
28665 this.hidden = false;
28667 Roo.TabPanelItem.superclass.constructor.call(this);
28670 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28671 purgeListeners : function(){
28672 Roo.util.Observable.prototype.purgeListeners.call(this);
28673 this.el.removeAllListeners();
28676 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28679 this.pnode.addClass("on");
28682 this.tabPanel.stripWrap.repaint();
28684 this.fireEvent("activate", this.tabPanel, this);
28688 * Returns true if this tab is the active tab.
28689 * @return {Boolean}
28691 isActive : function(){
28692 return this.tabPanel.getActiveTab() == this;
28696 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28699 this.pnode.removeClass("on");
28701 this.fireEvent("deactivate", this.tabPanel, this);
28704 hideAction : function(){
28705 this.bodyEl.hide();
28706 this.bodyEl.setStyle("position", "absolute");
28707 this.bodyEl.setLeft("-20000px");
28708 this.bodyEl.setTop("-20000px");
28711 showAction : function(){
28712 this.bodyEl.setStyle("position", "relative");
28713 this.bodyEl.setTop("");
28714 this.bodyEl.setLeft("");
28715 this.bodyEl.show();
28719 * Set the tooltip for the tab.
28720 * @param {String} tooltip The tab's tooltip
28722 setTooltip : function(text){
28723 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28724 this.textEl.dom.qtip = text;
28725 this.textEl.dom.removeAttribute('title');
28727 this.textEl.dom.title = text;
28731 onTabClick : function(e){
28732 e.preventDefault();
28733 this.tabPanel.activate(this.id);
28736 onTabMouseDown : function(e){
28737 e.preventDefault();
28738 this.tabPanel.activate(this.id);
28741 getWidth : function(){
28742 return this.inner.getWidth();
28745 setWidth : function(width){
28746 var iwidth = width - this.pnode.getPadding("lr");
28747 this.inner.setWidth(iwidth);
28748 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28749 this.pnode.setWidth(width);
28753 * Show or hide the tab
28754 * @param {Boolean} hidden True to hide or false to show.
28756 setHidden : function(hidden){
28757 this.hidden = hidden;
28758 this.pnode.setStyle("display", hidden ? "none" : "");
28762 * Returns true if this tab is "hidden"
28763 * @return {Boolean}
28765 isHidden : function(){
28766 return this.hidden;
28770 * Returns the text for this tab
28773 getText : function(){
28777 autoSize : function(){
28778 //this.el.beginMeasure();
28779 this.textEl.setWidth(1);
28781 * #2804 [new] Tabs in Roojs
28782 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28784 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28785 //this.el.endMeasure();
28789 * Sets the text for the tab (Note: this also sets the tooltip text)
28790 * @param {String} text The tab's text and tooltip
28792 setText : function(text){
28794 this.textEl.update(text);
28795 this.setTooltip(text);
28796 if(!this.tabPanel.resizeTabs){
28801 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28803 activate : function(){
28804 this.tabPanel.activate(this.id);
28808 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28810 disable : function(){
28811 if(this.tabPanel.active != this){
28812 this.disabled = true;
28813 this.pnode.addClass("disabled");
28818 * Enables this TabPanelItem if it was previously disabled.
28820 enable : function(){
28821 this.disabled = false;
28822 this.pnode.removeClass("disabled");
28826 * Sets the content for this TabPanelItem.
28827 * @param {String} content The content
28828 * @param {Boolean} loadScripts true to look for and load scripts
28830 setContent : function(content, loadScripts){
28831 this.bodyEl.update(content, loadScripts);
28835 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28836 * @return {Roo.UpdateManager} The UpdateManager
28838 getUpdateManager : function(){
28839 return this.bodyEl.getUpdateManager();
28843 * Set a URL to be used to load the content for this TabPanelItem.
28844 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28845 * @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)
28846 * @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)
28847 * @return {Roo.UpdateManager} The UpdateManager
28849 setUrl : function(url, params, loadOnce){
28850 if(this.refreshDelegate){
28851 this.un('activate', this.refreshDelegate);
28853 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28854 this.on("activate", this.refreshDelegate);
28855 return this.bodyEl.getUpdateManager();
28859 _handleRefresh : function(url, params, loadOnce){
28860 if(!loadOnce || !this.loaded){
28861 var updater = this.bodyEl.getUpdateManager();
28862 updater.update(url, params, this._setLoaded.createDelegate(this));
28867 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
28868 * Will fail silently if the setUrl method has not been called.
28869 * This does not activate the panel, just updates its content.
28871 refresh : function(){
28872 if(this.refreshDelegate){
28873 this.loaded = false;
28874 this.refreshDelegate();
28879 _setLoaded : function(){
28880 this.loaded = true;
28884 closeClick : function(e){
28887 this.fireEvent("beforeclose", this, o);
28888 if(o.cancel !== true){
28889 this.tabPanel.removeTab(this.id);
28893 * The text displayed in the tooltip for the close icon.
28896 closeText : "Close this tab"
28900 Roo.TabPanel.prototype.createStrip = function(container){
28901 var strip = document.createElement("div");
28902 strip.className = "x-tabs-wrap";
28903 container.appendChild(strip);
28907 Roo.TabPanel.prototype.createStripList = function(strip){
28908 // div wrapper for retard IE
28909 // returns the "tr" element.
28910 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
28911 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
28912 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
28913 return strip.firstChild.firstChild.firstChild.firstChild;
28916 Roo.TabPanel.prototype.createBody = function(container){
28917 var body = document.createElement("div");
28918 Roo.id(body, "tab-body");
28919 Roo.fly(body).addClass("x-tabs-body");
28920 container.appendChild(body);
28924 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
28925 var body = Roo.getDom(id);
28927 body = document.createElement("div");
28930 Roo.fly(body).addClass("x-tabs-item-body");
28931 bodyEl.insertBefore(body, bodyEl.firstChild);
28935 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
28936 var td = document.createElement("td");
28937 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
28938 //stripEl.appendChild(td);
28940 td.className = "x-tabs-closable";
28941 if(!this.closeTpl){
28942 this.closeTpl = new Roo.Template(
28943 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28944 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
28945 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
28948 var el = this.closeTpl.overwrite(td, {"text": text});
28949 var close = el.getElementsByTagName("div")[0];
28950 var inner = el.getElementsByTagName("em")[0];
28951 return {"el": el, "close": close, "inner": inner};
28954 this.tabTpl = new Roo.Template(
28955 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28956 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
28959 var el = this.tabTpl.overwrite(td, {"text": text});
28960 var inner = el.getElementsByTagName("em")[0];
28961 return {"el": el, "inner": inner};
28965 * Ext JS Library 1.1.1
28966 * Copyright(c) 2006-2007, Ext JS, LLC.
28968 * Originally Released Under LGPL - original licence link has changed is not relivant.
28971 * <script type="text/javascript">
28975 * @class Roo.Button
28976 * @extends Roo.util.Observable
28977 * Simple Button class
28978 * @cfg {String} text The button text
28979 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
28980 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
28981 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
28982 * @cfg {Object} scope The scope of the handler
28983 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
28984 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
28985 * @cfg {Boolean} hidden True to start hidden (defaults to false)
28986 * @cfg {Boolean} disabled True to start disabled (defaults to false)
28987 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
28988 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
28989 applies if enableToggle = true)
28990 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
28991 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
28992 an {@link Roo.util.ClickRepeater} config object (defaults to false).
28994 * Create a new button
28995 * @param {Object} config The config object
28997 Roo.Button = function(renderTo, config)
29001 renderTo = config.renderTo || false;
29004 Roo.apply(this, config);
29008 * Fires when this button is clicked
29009 * @param {Button} this
29010 * @param {EventObject} e The click event
29015 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29016 * @param {Button} this
29017 * @param {Boolean} pressed
29022 * Fires when the mouse hovers over the button
29023 * @param {Button} this
29024 * @param {Event} e The event object
29026 'mouseover' : true,
29029 * Fires when the mouse exits the button
29030 * @param {Button} this
29031 * @param {Event} e The event object
29036 * Fires when the button is rendered
29037 * @param {Button} this
29042 this.menu = Roo.menu.MenuMgr.get(this.menu);
29044 // register listeners first!! - so render can be captured..
29045 Roo.util.Observable.call(this);
29047 this.render(renderTo);
29053 Roo.extend(Roo.Button, Roo.util.Observable, {
29059 * Read-only. True if this button is hidden
29064 * Read-only. True if this button is disabled
29069 * Read-only. True if this button is pressed (only if enableToggle = true)
29075 * @cfg {Number} tabIndex
29076 * The DOM tabIndex for this button (defaults to undefined)
29078 tabIndex : undefined,
29081 * @cfg {Boolean} enableToggle
29082 * True to enable pressed/not pressed toggling (defaults to false)
29084 enableToggle: false,
29086 * @cfg {Mixed} menu
29087 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29091 * @cfg {String} menuAlign
29092 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29094 menuAlign : "tl-bl?",
29097 * @cfg {String} iconCls
29098 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29100 iconCls : undefined,
29102 * @cfg {String} type
29103 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29108 menuClassTarget: 'tr',
29111 * @cfg {String} clickEvent
29112 * The type of event to map to the button's event handler (defaults to 'click')
29114 clickEvent : 'click',
29117 * @cfg {Boolean} handleMouseEvents
29118 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29120 handleMouseEvents : true,
29123 * @cfg {String} tooltipType
29124 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29126 tooltipType : 'qtip',
29129 * @cfg {String} cls
29130 * A CSS class to apply to the button's main element.
29134 * @cfg {Roo.Template} template (Optional)
29135 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29136 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29137 * require code modifications if required elements (e.g. a button) aren't present.
29141 render : function(renderTo){
29143 if(this.hideParent){
29144 this.parentEl = Roo.get(renderTo);
29146 if(!this.dhconfig){
29147 if(!this.template){
29148 if(!Roo.Button.buttonTemplate){
29149 // hideous table template
29150 Roo.Button.buttonTemplate = new Roo.Template(
29151 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29152 '<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>',
29153 "</tr></tbody></table>");
29155 this.template = Roo.Button.buttonTemplate;
29157 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29158 var btnEl = btn.child("button:first");
29159 btnEl.on('focus', this.onFocus, this);
29160 btnEl.on('blur', this.onBlur, this);
29162 btn.addClass(this.cls);
29165 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29168 btnEl.addClass(this.iconCls);
29170 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29173 if(this.tabIndex !== undefined){
29174 btnEl.dom.tabIndex = this.tabIndex;
29177 if(typeof this.tooltip == 'object'){
29178 Roo.QuickTips.tips(Roo.apply({
29182 btnEl.dom[this.tooltipType] = this.tooltip;
29186 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29190 this.el.dom.id = this.el.id = this.id;
29193 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29194 this.menu.on("show", this.onMenuShow, this);
29195 this.menu.on("hide", this.onMenuHide, this);
29197 btn.addClass("x-btn");
29198 if(Roo.isIE && !Roo.isIE7){
29199 this.autoWidth.defer(1, this);
29203 if(this.handleMouseEvents){
29204 btn.on("mouseover", this.onMouseOver, this);
29205 btn.on("mouseout", this.onMouseOut, this);
29206 btn.on("mousedown", this.onMouseDown, this);
29208 btn.on(this.clickEvent, this.onClick, this);
29209 //btn.on("mouseup", this.onMouseUp, this);
29216 Roo.ButtonToggleMgr.register(this);
29218 this.el.addClass("x-btn-pressed");
29221 var repeater = new Roo.util.ClickRepeater(btn,
29222 typeof this.repeat == "object" ? this.repeat : {}
29224 repeater.on("click", this.onClick, this);
29227 this.fireEvent('render', this);
29231 * Returns the button's underlying element
29232 * @return {Roo.Element} The element
29234 getEl : function(){
29239 * Destroys this Button and removes any listeners.
29241 destroy : function(){
29242 Roo.ButtonToggleMgr.unregister(this);
29243 this.el.removeAllListeners();
29244 this.purgeListeners();
29249 autoWidth : function(){
29251 this.el.setWidth("auto");
29252 if(Roo.isIE7 && Roo.isStrict){
29253 var ib = this.el.child('button');
29254 if(ib && ib.getWidth() > 20){
29256 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29261 this.el.beginMeasure();
29263 if(this.el.getWidth() < this.minWidth){
29264 this.el.setWidth(this.minWidth);
29267 this.el.endMeasure();
29274 * Assigns this button's click handler
29275 * @param {Function} handler The function to call when the button is clicked
29276 * @param {Object} scope (optional) Scope for the function passed in
29278 setHandler : function(handler, scope){
29279 this.handler = handler;
29280 this.scope = scope;
29284 * Sets this button's text
29285 * @param {String} text The button text
29287 setText : function(text){
29290 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29296 * Gets the text for this button
29297 * @return {String} The button text
29299 getText : function(){
29307 this.hidden = false;
29309 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29317 this.hidden = true;
29319 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29324 * Convenience function for boolean show/hide
29325 * @param {Boolean} visible True to show, false to hide
29327 setVisible: function(visible){
29336 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29337 * @param {Boolean} state (optional) Force a particular state
29339 toggle : function(state){
29340 state = state === undefined ? !this.pressed : state;
29341 if(state != this.pressed){
29343 this.el.addClass("x-btn-pressed");
29344 this.pressed = true;
29345 this.fireEvent("toggle", this, true);
29347 this.el.removeClass("x-btn-pressed");
29348 this.pressed = false;
29349 this.fireEvent("toggle", this, false);
29351 if(this.toggleHandler){
29352 this.toggleHandler.call(this.scope || this, this, state);
29360 focus : function(){
29361 this.el.child('button:first').focus();
29365 * Disable this button
29367 disable : function(){
29369 this.el.addClass("x-btn-disabled");
29371 this.disabled = true;
29375 * Enable this button
29377 enable : function(){
29379 this.el.removeClass("x-btn-disabled");
29381 this.disabled = false;
29385 * Convenience function for boolean enable/disable
29386 * @param {Boolean} enabled True to enable, false to disable
29388 setDisabled : function(v){
29389 this[v !== true ? "enable" : "disable"]();
29393 onClick : function(e)
29396 e.preventDefault();
29401 if(!this.disabled){
29402 if(this.enableToggle){
29405 if(this.menu && !this.menu.isVisible()){
29406 this.menu.show(this.el, this.menuAlign);
29408 this.fireEvent("click", this, e);
29410 this.el.removeClass("x-btn-over");
29411 this.handler.call(this.scope || this, this, e);
29416 onMouseOver : function(e){
29417 if(!this.disabled){
29418 this.el.addClass("x-btn-over");
29419 this.fireEvent('mouseover', this, e);
29423 onMouseOut : function(e){
29424 if(!e.within(this.el, true)){
29425 this.el.removeClass("x-btn-over");
29426 this.fireEvent('mouseout', this, e);
29430 onFocus : function(e){
29431 if(!this.disabled){
29432 this.el.addClass("x-btn-focus");
29436 onBlur : function(e){
29437 this.el.removeClass("x-btn-focus");
29440 onMouseDown : function(e){
29441 if(!this.disabled && e.button == 0){
29442 this.el.addClass("x-btn-click");
29443 Roo.get(document).on('mouseup', this.onMouseUp, this);
29447 onMouseUp : function(e){
29449 this.el.removeClass("x-btn-click");
29450 Roo.get(document).un('mouseup', this.onMouseUp, this);
29454 onMenuShow : function(e){
29455 this.el.addClass("x-btn-menu-active");
29458 onMenuHide : function(e){
29459 this.el.removeClass("x-btn-menu-active");
29463 // Private utility class used by Button
29464 Roo.ButtonToggleMgr = function(){
29467 function toggleGroup(btn, state){
29469 var g = groups[btn.toggleGroup];
29470 for(var i = 0, l = g.length; i < l; i++){
29472 g[i].toggle(false);
29479 register : function(btn){
29480 if(!btn.toggleGroup){
29483 var g = groups[btn.toggleGroup];
29485 g = groups[btn.toggleGroup] = [];
29488 btn.on("toggle", toggleGroup);
29491 unregister : function(btn){
29492 if(!btn.toggleGroup){
29495 var g = groups[btn.toggleGroup];
29498 btn.un("toggle", toggleGroup);
29504 * Ext JS Library 1.1.1
29505 * Copyright(c) 2006-2007, Ext JS, LLC.
29507 * Originally Released Under LGPL - original licence link has changed is not relivant.
29510 * <script type="text/javascript">
29514 * @class Roo.SplitButton
29515 * @extends Roo.Button
29516 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29517 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29518 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29519 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29520 * @cfg {String} arrowTooltip The title attribute of the arrow
29522 * Create a new menu button
29523 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29524 * @param {Object} config The config object
29526 Roo.SplitButton = function(renderTo, config){
29527 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29529 * @event arrowclick
29530 * Fires when this button's arrow is clicked
29531 * @param {SplitButton} this
29532 * @param {EventObject} e The click event
29534 this.addEvents({"arrowclick":true});
29537 Roo.extend(Roo.SplitButton, Roo.Button, {
29538 render : function(renderTo){
29539 // this is one sweet looking template!
29540 var tpl = new Roo.Template(
29541 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29542 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29543 '<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>',
29544 "</tbody></table></td><td>",
29545 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29546 '<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>',
29547 "</tbody></table></td></tr></table>"
29549 var btn = tpl.append(renderTo, [this.text, this.type], true);
29550 var btnEl = btn.child("button");
29552 btn.addClass(this.cls);
29555 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29558 btnEl.addClass(this.iconCls);
29560 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29564 if(this.handleMouseEvents){
29565 btn.on("mouseover", this.onMouseOver, this);
29566 btn.on("mouseout", this.onMouseOut, this);
29567 btn.on("mousedown", this.onMouseDown, this);
29568 btn.on("mouseup", this.onMouseUp, this);
29570 btn.on(this.clickEvent, this.onClick, this);
29572 if(typeof this.tooltip == 'object'){
29573 Roo.QuickTips.tips(Roo.apply({
29577 btnEl.dom[this.tooltipType] = this.tooltip;
29580 if(this.arrowTooltip){
29581 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29590 this.el.addClass("x-btn-pressed");
29592 if(Roo.isIE && !Roo.isIE7){
29593 this.autoWidth.defer(1, this);
29598 this.menu.on("show", this.onMenuShow, this);
29599 this.menu.on("hide", this.onMenuHide, this);
29601 this.fireEvent('render', this);
29605 autoWidth : function(){
29607 var tbl = this.el.child("table:first");
29608 var tbl2 = this.el.child("table:last");
29609 this.el.setWidth("auto");
29610 tbl.setWidth("auto");
29611 if(Roo.isIE7 && Roo.isStrict){
29612 var ib = this.el.child('button:first');
29613 if(ib && ib.getWidth() > 20){
29615 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29620 this.el.beginMeasure();
29622 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29623 tbl.setWidth(this.minWidth-tbl2.getWidth());
29626 this.el.endMeasure();
29629 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29633 * Sets this button's click handler
29634 * @param {Function} handler The function to call when the button is clicked
29635 * @param {Object} scope (optional) Scope for the function passed above
29637 setHandler : function(handler, scope){
29638 this.handler = handler;
29639 this.scope = scope;
29643 * Sets this button's arrow click handler
29644 * @param {Function} handler The function to call when the arrow is clicked
29645 * @param {Object} scope (optional) Scope for the function passed above
29647 setArrowHandler : function(handler, scope){
29648 this.arrowHandler = handler;
29649 this.scope = scope;
29655 focus : function(){
29657 this.el.child("button:first").focus();
29662 onClick : function(e){
29663 e.preventDefault();
29664 if(!this.disabled){
29665 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29666 if(this.menu && !this.menu.isVisible()){
29667 this.menu.show(this.el, this.menuAlign);
29669 this.fireEvent("arrowclick", this, e);
29670 if(this.arrowHandler){
29671 this.arrowHandler.call(this.scope || this, this, e);
29674 this.fireEvent("click", this, e);
29676 this.handler.call(this.scope || this, this, e);
29682 onMouseDown : function(e){
29683 if(!this.disabled){
29684 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29688 onMouseUp : function(e){
29689 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29694 // backwards compat
29695 Roo.MenuButton = Roo.SplitButton;/*
29697 * Ext JS Library 1.1.1
29698 * Copyright(c) 2006-2007, Ext JS, LLC.
29700 * Originally Released Under LGPL - original licence link has changed is not relivant.
29703 * <script type="text/javascript">
29707 * @class Roo.Toolbar
29708 * Basic Toolbar class.
29710 * Creates a new Toolbar
29711 * @param {Object} container The config object
29713 Roo.Toolbar = function(container, buttons, config)
29715 /// old consturctor format still supported..
29716 if(container instanceof Array){ // omit the container for later rendering
29717 buttons = container;
29721 if (typeof(container) == 'object' && container.xtype) {
29722 config = container;
29723 container = config.container;
29724 buttons = config.buttons || []; // not really - use items!!
29727 if (config && config.items) {
29728 xitems = config.items;
29729 delete config.items;
29731 Roo.apply(this, config);
29732 this.buttons = buttons;
29735 this.render(container);
29737 this.xitems = xitems;
29738 Roo.each(xitems, function(b) {
29744 Roo.Toolbar.prototype = {
29746 * @cfg {Array} items
29747 * array of button configs or elements to add (will be converted to a MixedCollection)
29751 * @cfg {String/HTMLElement/Element} container
29752 * The id or element that will contain the toolbar
29755 render : function(ct){
29756 this.el = Roo.get(ct);
29758 this.el.addClass(this.cls);
29760 // using a table allows for vertical alignment
29761 // 100% width is needed by Safari...
29762 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29763 this.tr = this.el.child("tr", true);
29765 this.items = new Roo.util.MixedCollection(false, function(o){
29766 return o.id || ("item" + (++autoId));
29769 this.add.apply(this, this.buttons);
29770 delete this.buttons;
29775 * Adds element(s) to the toolbar -- this function takes a variable number of
29776 * arguments of mixed type and adds them to the toolbar.
29777 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29779 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29780 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29781 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29782 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29783 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29784 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29785 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29786 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29787 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29789 * @param {Mixed} arg2
29790 * @param {Mixed} etc.
29793 var a = arguments, l = a.length;
29794 for(var i = 0; i < l; i++){
29799 _add : function(el) {
29802 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29805 if (el.applyTo){ // some kind of form field
29806 return this.addField(el);
29808 if (el.render){ // some kind of Toolbar.Item
29809 return this.addItem(el);
29811 if (typeof el == "string"){ // string
29812 if(el == "separator" || el == "-"){
29813 return this.addSeparator();
29816 return this.addSpacer();
29819 return this.addFill();
29821 return this.addText(el);
29824 if(el.tagName){ // element
29825 return this.addElement(el);
29827 if(typeof el == "object"){ // must be button config?
29828 return this.addButton(el);
29830 // and now what?!?!
29836 * Add an Xtype element
29837 * @param {Object} xtype Xtype Object
29838 * @return {Object} created Object
29840 addxtype : function(e){
29841 return this.add(e);
29845 * Returns the Element for this toolbar.
29846 * @return {Roo.Element}
29848 getEl : function(){
29854 * @return {Roo.Toolbar.Item} The separator item
29856 addSeparator : function(){
29857 return this.addItem(new Roo.Toolbar.Separator());
29861 * Adds a spacer element
29862 * @return {Roo.Toolbar.Spacer} The spacer item
29864 addSpacer : function(){
29865 return this.addItem(new Roo.Toolbar.Spacer());
29869 * Adds a fill element that forces subsequent additions to the right side of the toolbar
29870 * @return {Roo.Toolbar.Fill} The fill item
29872 addFill : function(){
29873 return this.addItem(new Roo.Toolbar.Fill());
29877 * Adds any standard HTML element to the toolbar
29878 * @param {String/HTMLElement/Element} el The element or id of the element to add
29879 * @return {Roo.Toolbar.Item} The element's item
29881 addElement : function(el){
29882 return this.addItem(new Roo.Toolbar.Item(el));
29885 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
29886 * @type Roo.util.MixedCollection
29891 * Adds any Toolbar.Item or subclass
29892 * @param {Roo.Toolbar.Item} item
29893 * @return {Roo.Toolbar.Item} The item
29895 addItem : function(item){
29896 var td = this.nextBlock();
29898 this.items.add(item);
29903 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
29904 * @param {Object/Array} config A button config or array of configs
29905 * @return {Roo.Toolbar.Button/Array}
29907 addButton : function(config){
29908 if(config instanceof Array){
29910 for(var i = 0, len = config.length; i < len; i++) {
29911 buttons.push(this.addButton(config[i]));
29916 if(!(config instanceof Roo.Toolbar.Button)){
29918 new Roo.Toolbar.SplitButton(config) :
29919 new Roo.Toolbar.Button(config);
29921 var td = this.nextBlock();
29928 * Adds text to the toolbar
29929 * @param {String} text The text to add
29930 * @return {Roo.Toolbar.Item} The element's item
29932 addText : function(text){
29933 return this.addItem(new Roo.Toolbar.TextItem(text));
29937 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
29938 * @param {Number} index The index where the item is to be inserted
29939 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
29940 * @return {Roo.Toolbar.Button/Item}
29942 insertButton : function(index, item){
29943 if(item instanceof Array){
29945 for(var i = 0, len = item.length; i < len; i++) {
29946 buttons.push(this.insertButton(index + i, item[i]));
29950 if (!(item instanceof Roo.Toolbar.Button)){
29951 item = new Roo.Toolbar.Button(item);
29953 var td = document.createElement("td");
29954 this.tr.insertBefore(td, this.tr.childNodes[index]);
29956 this.items.insert(index, item);
29961 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
29962 * @param {Object} config
29963 * @return {Roo.Toolbar.Item} The element's item
29965 addDom : function(config, returnEl){
29966 var td = this.nextBlock();
29967 Roo.DomHelper.overwrite(td, config);
29968 var ti = new Roo.Toolbar.Item(td.firstChild);
29970 this.items.add(ti);
29975 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
29976 * @type Roo.util.MixedCollection
29981 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
29982 * Note: the field should not have been rendered yet. For a field that has already been
29983 * rendered, use {@link #addElement}.
29984 * @param {Roo.form.Field} field
29985 * @return {Roo.ToolbarItem}
29989 addField : function(field) {
29990 if (!this.fields) {
29992 this.fields = new Roo.util.MixedCollection(false, function(o){
29993 return o.id || ("item" + (++autoId));
29998 var td = this.nextBlock();
30000 var ti = new Roo.Toolbar.Item(td.firstChild);
30002 this.items.add(ti);
30003 this.fields.add(field);
30014 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30015 this.el.child('div').hide();
30023 this.el.child('div').show();
30027 nextBlock : function(){
30028 var td = document.createElement("td");
30029 this.tr.appendChild(td);
30034 destroy : function(){
30035 if(this.items){ // rendered?
30036 Roo.destroy.apply(Roo, this.items.items);
30038 if(this.fields){ // rendered?
30039 Roo.destroy.apply(Roo, this.fields.items);
30041 Roo.Element.uncache(this.el, this.tr);
30046 * @class Roo.Toolbar.Item
30047 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30049 * Creates a new Item
30050 * @param {HTMLElement} el
30052 Roo.Toolbar.Item = function(el){
30054 if (typeof (el.xtype) != 'undefined') {
30059 this.el = Roo.getDom(el);
30060 this.id = Roo.id(this.el);
30061 this.hidden = false;
30066 * Fires when the button is rendered
30067 * @param {Button} this
30071 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30073 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30074 //Roo.Toolbar.Item.prototype = {
30077 * Get this item's HTML Element
30078 * @return {HTMLElement}
30080 getEl : function(){
30085 render : function(td){
30088 td.appendChild(this.el);
30090 this.fireEvent('render', this);
30094 * Removes and destroys this item.
30096 destroy : function(){
30097 this.td.parentNode.removeChild(this.td);
30104 this.hidden = false;
30105 this.td.style.display = "";
30112 this.hidden = true;
30113 this.td.style.display = "none";
30117 * Convenience function for boolean show/hide.
30118 * @param {Boolean} visible true to show/false to hide
30120 setVisible: function(visible){
30129 * Try to focus this item.
30131 focus : function(){
30132 Roo.fly(this.el).focus();
30136 * Disables this item.
30138 disable : function(){
30139 Roo.fly(this.td).addClass("x-item-disabled");
30140 this.disabled = true;
30141 this.el.disabled = true;
30145 * Enables this item.
30147 enable : function(){
30148 Roo.fly(this.td).removeClass("x-item-disabled");
30149 this.disabled = false;
30150 this.el.disabled = false;
30156 * @class Roo.Toolbar.Separator
30157 * @extends Roo.Toolbar.Item
30158 * A simple toolbar separator class
30160 * Creates a new Separator
30162 Roo.Toolbar.Separator = function(cfg){
30164 var s = document.createElement("span");
30165 s.className = "ytb-sep";
30170 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30172 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30173 enable:Roo.emptyFn,
30174 disable:Roo.emptyFn,
30179 * @class Roo.Toolbar.Spacer
30180 * @extends Roo.Toolbar.Item
30181 * A simple element that adds extra horizontal space to a toolbar.
30183 * Creates a new Spacer
30185 Roo.Toolbar.Spacer = function(cfg){
30186 var s = document.createElement("div");
30187 s.className = "ytb-spacer";
30191 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30193 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30194 enable:Roo.emptyFn,
30195 disable:Roo.emptyFn,
30200 * @class Roo.Toolbar.Fill
30201 * @extends Roo.Toolbar.Spacer
30202 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30204 * Creates a new Spacer
30206 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30208 render : function(td){
30209 td.style.width = '100%';
30210 Roo.Toolbar.Fill.superclass.render.call(this, td);
30215 * @class Roo.Toolbar.TextItem
30216 * @extends Roo.Toolbar.Item
30217 * A simple class that renders text directly into a toolbar.
30219 * Creates a new TextItem
30220 * @param {String} text
30222 Roo.Toolbar.TextItem = function(cfg){
30223 var text = cfg || "";
30224 if (typeof(cfg) == 'object') {
30225 text = cfg.text || "";
30229 var s = document.createElement("span");
30230 s.className = "ytb-text";
30231 s.innerHTML = text;
30236 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30238 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30241 enable:Roo.emptyFn,
30242 disable:Roo.emptyFn,
30247 * @class Roo.Toolbar.Button
30248 * @extends Roo.Button
30249 * A button that renders into a toolbar.
30251 * Creates a new Button
30252 * @param {Object} config A standard {@link Roo.Button} config object
30254 Roo.Toolbar.Button = function(config){
30255 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30257 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30258 render : function(td){
30260 Roo.Toolbar.Button.superclass.render.call(this, td);
30264 * Removes and destroys this button
30266 destroy : function(){
30267 Roo.Toolbar.Button.superclass.destroy.call(this);
30268 this.td.parentNode.removeChild(this.td);
30272 * Shows this button
30275 this.hidden = false;
30276 this.td.style.display = "";
30280 * Hides this button
30283 this.hidden = true;
30284 this.td.style.display = "none";
30288 * Disables this item
30290 disable : function(){
30291 Roo.fly(this.td).addClass("x-item-disabled");
30292 this.disabled = true;
30296 * Enables this item
30298 enable : function(){
30299 Roo.fly(this.td).removeClass("x-item-disabled");
30300 this.disabled = false;
30303 // backwards compat
30304 Roo.ToolbarButton = Roo.Toolbar.Button;
30307 * @class Roo.Toolbar.SplitButton
30308 * @extends Roo.SplitButton
30309 * A menu button that renders into a toolbar.
30311 * Creates a new SplitButton
30312 * @param {Object} config A standard {@link Roo.SplitButton} config object
30314 Roo.Toolbar.SplitButton = function(config){
30315 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30317 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30318 render : function(td){
30320 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30324 * Removes and destroys this button
30326 destroy : function(){
30327 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30328 this.td.parentNode.removeChild(this.td);
30332 * Shows this button
30335 this.hidden = false;
30336 this.td.style.display = "";
30340 * Hides this button
30343 this.hidden = true;
30344 this.td.style.display = "none";
30348 // backwards compat
30349 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30351 * Ext JS Library 1.1.1
30352 * Copyright(c) 2006-2007, Ext JS, LLC.
30354 * Originally Released Under LGPL - original licence link has changed is not relivant.
30357 * <script type="text/javascript">
30361 * @class Roo.PagingToolbar
30362 * @extends Roo.Toolbar
30363 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30365 * Create a new PagingToolbar
30366 * @param {Object} config The config object
30368 Roo.PagingToolbar = function(el, ds, config)
30370 // old args format still supported... - xtype is prefered..
30371 if (typeof(el) == 'object' && el.xtype) {
30372 // created from xtype...
30374 ds = el.dataSource;
30375 el = config.container;
30378 if (config.items) {
30379 items = config.items;
30383 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30386 this.renderButtons(this.el);
30389 // supprot items array.
30391 Roo.each(items, function(e) {
30392 this.add(Roo.factory(e));
30397 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30399 * @cfg {Roo.data.Store} dataSource
30400 * The underlying data store providing the paged data
30403 * @cfg {String/HTMLElement/Element} container
30404 * container The id or element that will contain the toolbar
30407 * @cfg {Boolean} displayInfo
30408 * True to display the displayMsg (defaults to false)
30411 * @cfg {Number} pageSize
30412 * The number of records to display per page (defaults to 20)
30416 * @cfg {String} displayMsg
30417 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30419 displayMsg : 'Displaying {0} - {1} of {2}',
30421 * @cfg {String} emptyMsg
30422 * The message to display when no records are found (defaults to "No data to display")
30424 emptyMsg : 'No data to display',
30426 * Customizable piece of the default paging text (defaults to "Page")
30429 beforePageText : "Page",
30431 * Customizable piece of the default paging text (defaults to "of %0")
30434 afterPageText : "of {0}",
30436 * Customizable piece of the default paging text (defaults to "First Page")
30439 firstText : "First Page",
30441 * Customizable piece of the default paging text (defaults to "Previous Page")
30444 prevText : "Previous Page",
30446 * Customizable piece of the default paging text (defaults to "Next Page")
30449 nextText : "Next Page",
30451 * Customizable piece of the default paging text (defaults to "Last Page")
30454 lastText : "Last Page",
30456 * Customizable piece of the default paging text (defaults to "Refresh")
30459 refreshText : "Refresh",
30462 renderButtons : function(el){
30463 Roo.PagingToolbar.superclass.render.call(this, el);
30464 this.first = this.addButton({
30465 tooltip: this.firstText,
30466 cls: "x-btn-icon x-grid-page-first",
30468 handler: this.onClick.createDelegate(this, ["first"])
30470 this.prev = this.addButton({
30471 tooltip: this.prevText,
30472 cls: "x-btn-icon x-grid-page-prev",
30474 handler: this.onClick.createDelegate(this, ["prev"])
30476 //this.addSeparator();
30477 this.add(this.beforePageText);
30478 this.field = Roo.get(this.addDom({
30483 cls: "x-grid-page-number"
30485 this.field.on("keydown", this.onPagingKeydown, this);
30486 this.field.on("focus", function(){this.dom.select();});
30487 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30488 this.field.setHeight(18);
30489 //this.addSeparator();
30490 this.next = this.addButton({
30491 tooltip: this.nextText,
30492 cls: "x-btn-icon x-grid-page-next",
30494 handler: this.onClick.createDelegate(this, ["next"])
30496 this.last = this.addButton({
30497 tooltip: this.lastText,
30498 cls: "x-btn-icon x-grid-page-last",
30500 handler: this.onClick.createDelegate(this, ["last"])
30502 //this.addSeparator();
30503 this.loading = this.addButton({
30504 tooltip: this.refreshText,
30505 cls: "x-btn-icon x-grid-loading",
30506 handler: this.onClick.createDelegate(this, ["refresh"])
30509 if(this.displayInfo){
30510 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30515 updateInfo : function(){
30516 if(this.displayEl){
30517 var count = this.ds.getCount();
30518 var msg = count == 0 ?
30522 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30524 this.displayEl.update(msg);
30529 onLoad : function(ds, r, o){
30530 this.cursor = o.params ? o.params.start : 0;
30531 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30533 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30534 this.field.dom.value = ap;
30535 this.first.setDisabled(ap == 1);
30536 this.prev.setDisabled(ap == 1);
30537 this.next.setDisabled(ap == ps);
30538 this.last.setDisabled(ap == ps);
30539 this.loading.enable();
30544 getPageData : function(){
30545 var total = this.ds.getTotalCount();
30548 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30549 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30554 onLoadError : function(){
30555 this.loading.enable();
30559 onPagingKeydown : function(e){
30560 var k = e.getKey();
30561 var d = this.getPageData();
30563 var v = this.field.dom.value, pageNum;
30564 if(!v || isNaN(pageNum = parseInt(v, 10))){
30565 this.field.dom.value = d.activePage;
30568 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30569 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30572 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))
30574 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30575 this.field.dom.value = pageNum;
30576 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30579 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30581 var v = this.field.dom.value, pageNum;
30582 var increment = (e.shiftKey) ? 10 : 1;
30583 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30586 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30587 this.field.dom.value = d.activePage;
30590 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30592 this.field.dom.value = parseInt(v, 10) + increment;
30593 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30594 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30601 beforeLoad : function(){
30603 this.loading.disable();
30608 onClick : function(which){
30612 ds.load({params:{start: 0, limit: this.pageSize}});
30615 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30618 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30621 var total = ds.getTotalCount();
30622 var extra = total % this.pageSize;
30623 var lastStart = extra ? (total - extra) : total-this.pageSize;
30624 ds.load({params:{start: lastStart, limit: this.pageSize}});
30627 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30633 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30634 * @param {Roo.data.Store} store The data store to unbind
30636 unbind : function(ds){
30637 ds.un("beforeload", this.beforeLoad, this);
30638 ds.un("load", this.onLoad, this);
30639 ds.un("loadexception", this.onLoadError, this);
30640 ds.un("remove", this.updateInfo, this);
30641 ds.un("add", this.updateInfo, this);
30642 this.ds = undefined;
30646 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30647 * @param {Roo.data.Store} store The data store to bind
30649 bind : function(ds){
30650 ds.on("beforeload", this.beforeLoad, this);
30651 ds.on("load", this.onLoad, this);
30652 ds.on("loadexception", this.onLoadError, this);
30653 ds.on("remove", this.updateInfo, this);
30654 ds.on("add", this.updateInfo, this);
30659 * Ext JS Library 1.1.1
30660 * Copyright(c) 2006-2007, Ext JS, LLC.
30662 * Originally Released Under LGPL - original licence link has changed is not relivant.
30665 * <script type="text/javascript">
30669 * @class Roo.Resizable
30670 * @extends Roo.util.Observable
30671 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30672 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30673 * 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
30674 * the element will be wrapped for you automatically.</p>
30675 * <p>Here is the list of valid resize handles:</p>
30678 ------ -------------------
30687 'hd' horizontal drag
30690 * <p>Here's an example showing the creation of a typical Resizable:</p>
30692 var resizer = new Roo.Resizable("element-id", {
30700 resizer.on("resize", myHandler);
30702 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30703 * resizer.east.setDisplayed(false);</p>
30704 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30705 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30706 * resize operation's new size (defaults to [0, 0])
30707 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30708 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30709 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30710 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30711 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30712 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30713 * @cfg {Number} width The width of the element in pixels (defaults to null)
30714 * @cfg {Number} height The height of the element in pixels (defaults to null)
30715 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30716 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30717 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30718 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30719 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30720 * in favor of the handles config option (defaults to false)
30721 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30722 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30723 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30724 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30725 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30726 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30727 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30728 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30729 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30730 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30731 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30733 * Create a new resizable component
30734 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30735 * @param {Object} config configuration options
30737 Roo.Resizable = function(el, config)
30739 this.el = Roo.get(el);
30741 if(config && config.wrap){
30742 config.resizeChild = this.el;
30743 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30744 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30745 this.el.setStyle("overflow", "hidden");
30746 this.el.setPositioning(config.resizeChild.getPositioning());
30747 config.resizeChild.clearPositioning();
30748 if(!config.width || !config.height){
30749 var csize = config.resizeChild.getSize();
30750 this.el.setSize(csize.width, csize.height);
30752 if(config.pinned && !config.adjustments){
30753 config.adjustments = "auto";
30757 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30758 this.proxy.unselectable();
30759 this.proxy.enableDisplayMode('block');
30761 Roo.apply(this, config);
30764 this.disableTrackOver = true;
30765 this.el.addClass("x-resizable-pinned");
30767 // if the element isn't positioned, make it relative
30768 var position = this.el.getStyle("position");
30769 if(position != "absolute" && position != "fixed"){
30770 this.el.setStyle("position", "relative");
30772 if(!this.handles){ // no handles passed, must be legacy style
30773 this.handles = 's,e,se';
30774 if(this.multiDirectional){
30775 this.handles += ',n,w';
30778 if(this.handles == "all"){
30779 this.handles = "n s e w ne nw se sw";
30781 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30782 var ps = Roo.Resizable.positions;
30783 for(var i = 0, len = hs.length; i < len; i++){
30784 if(hs[i] && ps[hs[i]]){
30785 var pos = ps[hs[i]];
30786 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30790 this.corner = this.southeast;
30792 // updateBox = the box can move..
30793 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30794 this.updateBox = true;
30797 this.activeHandle = null;
30799 if(this.resizeChild){
30800 if(typeof this.resizeChild == "boolean"){
30801 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30803 this.resizeChild = Roo.get(this.resizeChild, true);
30807 if(this.adjustments == "auto"){
30808 var rc = this.resizeChild;
30809 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30810 if(rc && (hw || hn)){
30811 rc.position("relative");
30812 rc.setLeft(hw ? hw.el.getWidth() : 0);
30813 rc.setTop(hn ? hn.el.getHeight() : 0);
30815 this.adjustments = [
30816 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30817 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30821 if(this.draggable){
30822 this.dd = this.dynamic ?
30823 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30824 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30830 * @event beforeresize
30831 * Fired before resize is allowed. Set enabled to false to cancel resize.
30832 * @param {Roo.Resizable} this
30833 * @param {Roo.EventObject} e The mousedown event
30835 "beforeresize" : true,
30838 * Fired a resizing.
30839 * @param {Roo.Resizable} this
30840 * @param {Number} x The new x position
30841 * @param {Number} y The new y position
30842 * @param {Number} w The new w width
30843 * @param {Number} h The new h hight
30844 * @param {Roo.EventObject} e The mouseup event
30849 * Fired after a resize.
30850 * @param {Roo.Resizable} this
30851 * @param {Number} width The new width
30852 * @param {Number} height The new height
30853 * @param {Roo.EventObject} e The mouseup event
30858 if(this.width !== null && this.height !== null){
30859 this.resizeTo(this.width, this.height);
30861 this.updateChildSize();
30864 this.el.dom.style.zoom = 1;
30866 Roo.Resizable.superclass.constructor.call(this);
30869 Roo.extend(Roo.Resizable, Roo.util.Observable, {
30870 resizeChild : false,
30871 adjustments : [0, 0],
30881 multiDirectional : false,
30882 disableTrackOver : false,
30883 easing : 'easeOutStrong',
30884 widthIncrement : 0,
30885 heightIncrement : 0,
30889 preserveRatio : false,
30890 transparent: false,
30896 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
30898 constrainTo: undefined,
30900 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
30902 resizeRegion: undefined,
30906 * Perform a manual resize
30907 * @param {Number} width
30908 * @param {Number} height
30910 resizeTo : function(width, height){
30911 this.el.setSize(width, height);
30912 this.updateChildSize();
30913 this.fireEvent("resize", this, width, height, null);
30917 startSizing : function(e, handle){
30918 this.fireEvent("beforeresize", this, e);
30919 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
30922 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
30923 this.overlay.unselectable();
30924 this.overlay.enableDisplayMode("block");
30925 this.overlay.on("mousemove", this.onMouseMove, this);
30926 this.overlay.on("mouseup", this.onMouseUp, this);
30928 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
30930 this.resizing = true;
30931 this.startBox = this.el.getBox();
30932 this.startPoint = e.getXY();
30933 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
30934 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
30936 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30937 this.overlay.show();
30939 if(this.constrainTo) {
30940 var ct = Roo.get(this.constrainTo);
30941 this.resizeRegion = ct.getRegion().adjust(
30942 ct.getFrameWidth('t'),
30943 ct.getFrameWidth('l'),
30944 -ct.getFrameWidth('b'),
30945 -ct.getFrameWidth('r')
30949 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
30951 this.proxy.setBox(this.startBox);
30953 this.proxy.setStyle('visibility', 'visible');
30959 onMouseDown : function(handle, e){
30962 this.activeHandle = handle;
30963 this.startSizing(e, handle);
30968 onMouseUp : function(e){
30969 var size = this.resizeElement();
30970 this.resizing = false;
30972 this.overlay.hide();
30974 this.fireEvent("resize", this, size.width, size.height, e);
30978 updateChildSize : function(){
30980 if(this.resizeChild){
30982 var child = this.resizeChild;
30983 var adj = this.adjustments;
30984 if(el.dom.offsetWidth){
30985 var b = el.getSize(true);
30986 child.setSize(b.width+adj[0], b.height+adj[1]);
30988 // Second call here for IE
30989 // The first call enables instant resizing and
30990 // the second call corrects scroll bars if they
30993 setTimeout(function(){
30994 if(el.dom.offsetWidth){
30995 var b = el.getSize(true);
30996 child.setSize(b.width+adj[0], b.height+adj[1]);
31004 snap : function(value, inc, min){
31005 if(!inc || !value) {
31008 var newValue = value;
31009 var m = value % inc;
31012 newValue = value + (inc-m);
31014 newValue = value - m;
31017 return Math.max(min, newValue);
31021 resizeElement : function(){
31022 var box = this.proxy.getBox();
31023 if(this.updateBox){
31024 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31026 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31028 this.updateChildSize();
31036 constrain : function(v, diff, m, mx){
31039 }else if(v - diff > mx){
31046 onMouseMove : function(e){
31049 try{// try catch so if something goes wrong the user doesn't get hung
31051 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31055 //var curXY = this.startPoint;
31056 var curSize = this.curSize || this.startBox;
31057 var x = this.startBox.x, y = this.startBox.y;
31058 var ox = x, oy = y;
31059 var w = curSize.width, h = curSize.height;
31060 var ow = w, oh = h;
31061 var mw = this.minWidth, mh = this.minHeight;
31062 var mxw = this.maxWidth, mxh = this.maxHeight;
31063 var wi = this.widthIncrement;
31064 var hi = this.heightIncrement;
31066 var eventXY = e.getXY();
31067 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31068 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31070 var pos = this.activeHandle.position;
31075 w = Math.min(Math.max(mw, w), mxw);
31080 h = Math.min(Math.max(mh, h), mxh);
31085 w = Math.min(Math.max(mw, w), mxw);
31086 h = Math.min(Math.max(mh, h), mxh);
31089 diffY = this.constrain(h, diffY, mh, mxh);
31096 var adiffX = Math.abs(diffX);
31097 var sub = (adiffX % wi); // how much
31098 if (sub > (wi/2)) { // far enough to snap
31099 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31101 // remove difference..
31102 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31106 x = Math.max(this.minX, x);
31109 diffX = this.constrain(w, diffX, mw, mxw);
31115 w = Math.min(Math.max(mw, w), mxw);
31116 diffY = this.constrain(h, diffY, mh, mxh);
31121 diffX = this.constrain(w, diffX, mw, mxw);
31122 diffY = this.constrain(h, diffY, mh, mxh);
31129 diffX = this.constrain(w, diffX, mw, mxw);
31131 h = Math.min(Math.max(mh, h), mxh);
31137 var sw = this.snap(w, wi, mw);
31138 var sh = this.snap(h, hi, mh);
31139 if(sw != w || sh != h){
31162 if(this.preserveRatio){
31167 h = Math.min(Math.max(mh, h), mxh);
31172 w = Math.min(Math.max(mw, w), mxw);
31177 w = Math.min(Math.max(mw, w), mxw);
31183 w = Math.min(Math.max(mw, w), mxw);
31189 h = Math.min(Math.max(mh, h), mxh);
31197 h = Math.min(Math.max(mh, h), mxh);
31207 h = Math.min(Math.max(mh, h), mxh);
31215 if (pos == 'hdrag') {
31218 this.proxy.setBounds(x, y, w, h);
31220 this.resizeElement();
31224 this.fireEvent("resizing", this, x, y, w, h, e);
31228 handleOver : function(){
31230 this.el.addClass("x-resizable-over");
31235 handleOut : function(){
31236 if(!this.resizing){
31237 this.el.removeClass("x-resizable-over");
31242 * Returns the element this component is bound to.
31243 * @return {Roo.Element}
31245 getEl : function(){
31250 * Returns the resizeChild element (or null).
31251 * @return {Roo.Element}
31253 getResizeChild : function(){
31254 return this.resizeChild;
31256 groupHandler : function()
31261 * Destroys this resizable. If the element was wrapped and
31262 * removeEl is not true then the element remains.
31263 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31265 destroy : function(removeEl){
31266 this.proxy.remove();
31268 this.overlay.removeAllListeners();
31269 this.overlay.remove();
31271 var ps = Roo.Resizable.positions;
31273 if(typeof ps[k] != "function" && this[ps[k]]){
31274 var h = this[ps[k]];
31275 h.el.removeAllListeners();
31280 this.el.update("");
31287 // hash to map config positions to true positions
31288 Roo.Resizable.positions = {
31289 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31294 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31296 // only initialize the template if resizable is used
31297 var tpl = Roo.DomHelper.createTemplate(
31298 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31301 Roo.Resizable.Handle.prototype.tpl = tpl;
31303 this.position = pos;
31305 // show north drag fro topdra
31306 var handlepos = pos == 'hdrag' ? 'north' : pos;
31308 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31309 if (pos == 'hdrag') {
31310 this.el.setStyle('cursor', 'pointer');
31312 this.el.unselectable();
31314 this.el.setOpacity(0);
31316 this.el.on("mousedown", this.onMouseDown, this);
31317 if(!disableTrackOver){
31318 this.el.on("mouseover", this.onMouseOver, this);
31319 this.el.on("mouseout", this.onMouseOut, this);
31324 Roo.Resizable.Handle.prototype = {
31325 afterResize : function(rz){
31330 onMouseDown : function(e){
31331 this.rz.onMouseDown(this, e);
31334 onMouseOver : function(e){
31335 this.rz.handleOver(this, e);
31338 onMouseOut : function(e){
31339 this.rz.handleOut(this, e);
31343 * Ext JS Library 1.1.1
31344 * Copyright(c) 2006-2007, Ext JS, LLC.
31346 * Originally Released Under LGPL - original licence link has changed is not relivant.
31349 * <script type="text/javascript">
31353 * @class Roo.Editor
31354 * @extends Roo.Component
31355 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31357 * Create a new Editor
31358 * @param {Roo.form.Field} field The Field object (or descendant)
31359 * @param {Object} config The config object
31361 Roo.Editor = function(field, config){
31362 Roo.Editor.superclass.constructor.call(this, config);
31363 this.field = field;
31366 * @event beforestartedit
31367 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31368 * false from the handler of this event.
31369 * @param {Editor} this
31370 * @param {Roo.Element} boundEl The underlying element bound to this editor
31371 * @param {Mixed} value The field value being set
31373 "beforestartedit" : true,
31376 * Fires when this editor is displayed
31377 * @param {Roo.Element} boundEl The underlying element bound to this editor
31378 * @param {Mixed} value The starting field value
31380 "startedit" : true,
31382 * @event beforecomplete
31383 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31384 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31385 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31386 * event will not fire since no edit actually occurred.
31387 * @param {Editor} this
31388 * @param {Mixed} value The current field value
31389 * @param {Mixed} startValue The original field value
31391 "beforecomplete" : true,
31394 * Fires after editing is complete and any changed value has been written to the underlying field.
31395 * @param {Editor} this
31396 * @param {Mixed} value The current field value
31397 * @param {Mixed} startValue The original field value
31401 * @event specialkey
31402 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31403 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31404 * @param {Roo.form.Field} this
31405 * @param {Roo.EventObject} e The event object
31407 "specialkey" : true
31411 Roo.extend(Roo.Editor, Roo.Component, {
31413 * @cfg {Boolean/String} autosize
31414 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31415 * or "height" to adopt the height only (defaults to false)
31418 * @cfg {Boolean} revertInvalid
31419 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31420 * validation fails (defaults to true)
31423 * @cfg {Boolean} ignoreNoChange
31424 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31425 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31426 * will never be ignored.
31429 * @cfg {Boolean} hideEl
31430 * False to keep the bound element visible while the editor is displayed (defaults to true)
31433 * @cfg {Mixed} value
31434 * The data value of the underlying field (defaults to "")
31438 * @cfg {String} alignment
31439 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31443 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31444 * for bottom-right shadow (defaults to "frame")
31448 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31452 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31454 completeOnEnter : false,
31456 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31458 cancelOnEsc : false,
31460 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31465 onRender : function(ct, position){
31466 this.el = new Roo.Layer({
31467 shadow: this.shadow,
31473 constrain: this.constrain
31475 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31476 if(this.field.msgTarget != 'title'){
31477 this.field.msgTarget = 'qtip';
31479 this.field.render(this.el);
31481 this.field.el.dom.setAttribute('autocomplete', 'off');
31483 this.field.on("specialkey", this.onSpecialKey, this);
31484 if(this.swallowKeys){
31485 this.field.el.swallowEvent(['keydown','keypress']);
31488 this.field.on("blur", this.onBlur, this);
31489 if(this.field.grow){
31490 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31494 onSpecialKey : function(field, e)
31496 //Roo.log('editor onSpecialKey');
31497 if(this.completeOnEnter && e.getKey() == e.ENTER){
31499 this.completeEdit();
31502 // do not fire special key otherwise it might hide close the editor...
31503 if(e.getKey() == e.ENTER){
31506 if(this.cancelOnEsc && e.getKey() == e.ESC){
31510 this.fireEvent('specialkey', field, e);
31515 * Starts the editing process and shows the editor.
31516 * @param {String/HTMLElement/Element} el The element to edit
31517 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31518 * to the innerHTML of el.
31520 startEdit : function(el, value){
31522 this.completeEdit();
31524 this.boundEl = Roo.get(el);
31525 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31526 if(!this.rendered){
31527 this.render(this.parentEl || document.body);
31529 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31532 this.startValue = v;
31533 this.field.setValue(v);
31535 var sz = this.boundEl.getSize();
31536 switch(this.autoSize){
31538 this.setSize(sz.width, "");
31541 this.setSize("", sz.height);
31544 this.setSize(sz.width, sz.height);
31547 this.el.alignTo(this.boundEl, this.alignment);
31548 this.editing = true;
31550 Roo.QuickTips.disable();
31556 * Sets the height and width of this editor.
31557 * @param {Number} width The new width
31558 * @param {Number} height The new height
31560 setSize : function(w, h){
31561 this.field.setSize(w, h);
31568 * Realigns the editor to the bound field based on the current alignment config value.
31570 realign : function(){
31571 this.el.alignTo(this.boundEl, this.alignment);
31575 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31576 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31578 completeEdit : function(remainVisible){
31582 var v = this.getValue();
31583 if(this.revertInvalid !== false && !this.field.isValid()){
31584 v = this.startValue;
31585 this.cancelEdit(true);
31587 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31588 this.editing = false;
31592 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31593 this.editing = false;
31594 if(this.updateEl && this.boundEl){
31595 this.boundEl.update(v);
31597 if(remainVisible !== true){
31600 this.fireEvent("complete", this, v, this.startValue);
31605 onShow : function(){
31607 if(this.hideEl !== false){
31608 this.boundEl.hide();
31611 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31612 this.fixIEFocus = true;
31613 this.deferredFocus.defer(50, this);
31615 this.field.focus();
31617 this.fireEvent("startedit", this.boundEl, this.startValue);
31620 deferredFocus : function(){
31622 this.field.focus();
31627 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31628 * reverted to the original starting value.
31629 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31630 * cancel (defaults to false)
31632 cancelEdit : function(remainVisible){
31634 this.setValue(this.startValue);
31635 if(remainVisible !== true){
31642 onBlur : function(){
31643 if(this.allowBlur !== true && this.editing){
31644 this.completeEdit();
31649 onHide : function(){
31651 this.completeEdit();
31655 if(this.field.collapse){
31656 this.field.collapse();
31659 if(this.hideEl !== false){
31660 this.boundEl.show();
31663 Roo.QuickTips.enable();
31668 * Sets the data value of the editor
31669 * @param {Mixed} value Any valid value supported by the underlying field
31671 setValue : function(v){
31672 this.field.setValue(v);
31676 * Gets the data value of the editor
31677 * @return {Mixed} The data value
31679 getValue : function(){
31680 return this.field.getValue();
31684 * Ext JS Library 1.1.1
31685 * Copyright(c) 2006-2007, Ext JS, LLC.
31687 * Originally Released Under LGPL - original licence link has changed is not relivant.
31690 * <script type="text/javascript">
31694 * @class Roo.BasicDialog
31695 * @extends Roo.util.Observable
31696 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31698 var dlg = new Roo.BasicDialog("my-dlg", {
31707 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31708 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31709 dlg.addButton('Cancel', dlg.hide, dlg);
31712 <b>A Dialog should always be a direct child of the body element.</b>
31713 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31714 * @cfg {String} title Default text to display in the title bar (defaults to null)
31715 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31716 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31717 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31718 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31719 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31720 * (defaults to null with no animation)
31721 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31722 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31723 * property for valid values (defaults to 'all')
31724 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31725 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31726 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31727 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31728 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31729 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31730 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31731 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31732 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31733 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31734 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31735 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31736 * draggable = true (defaults to false)
31737 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31738 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31739 * shadow (defaults to false)
31740 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31741 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31742 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31743 * @cfg {Array} buttons Array of buttons
31744 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31746 * Create a new BasicDialog.
31747 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31748 * @param {Object} config Configuration options
31750 Roo.BasicDialog = function(el, config){
31751 this.el = Roo.get(el);
31752 var dh = Roo.DomHelper;
31753 if(!this.el && config && config.autoCreate){
31754 if(typeof config.autoCreate == "object"){
31755 if(!config.autoCreate.id){
31756 config.autoCreate.id = el;
31758 this.el = dh.append(document.body,
31759 config.autoCreate, true);
31761 this.el = dh.append(document.body,
31762 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31766 el.setDisplayed(true);
31767 el.hide = this.hideAction;
31769 el.addClass("x-dlg");
31771 Roo.apply(this, config);
31773 this.proxy = el.createProxy("x-dlg-proxy");
31774 this.proxy.hide = this.hideAction;
31775 this.proxy.setOpacity(.5);
31779 el.setWidth(config.width);
31782 el.setHeight(config.height);
31784 this.size = el.getSize();
31785 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31786 this.xy = [config.x,config.y];
31788 this.xy = el.getCenterXY(true);
31790 /** The header element @type Roo.Element */
31791 this.header = el.child("> .x-dlg-hd");
31792 /** The body element @type Roo.Element */
31793 this.body = el.child("> .x-dlg-bd");
31794 /** The footer element @type Roo.Element */
31795 this.footer = el.child("> .x-dlg-ft");
31798 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31801 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31804 this.header.unselectable();
31806 this.header.update(this.title);
31808 // this element allows the dialog to be focused for keyboard event
31809 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31810 this.focusEl.swallowEvent("click", true);
31812 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31814 // wrap the body and footer for special rendering
31815 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31817 this.bwrap.dom.appendChild(this.footer.dom);
31820 this.bg = this.el.createChild({
31821 tag: "div", cls:"x-dlg-bg",
31822 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31824 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31827 if(this.autoScroll !== false && !this.autoTabs){
31828 this.body.setStyle("overflow", "auto");
31831 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31833 if(this.closable !== false){
31834 this.el.addClass("x-dlg-closable");
31835 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31836 this.close.on("click", this.closeClick, this);
31837 this.close.addClassOnOver("x-dlg-close-over");
31839 if(this.collapsible !== false){
31840 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31841 this.collapseBtn.on("click", this.collapseClick, this);
31842 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31843 this.header.on("dblclick", this.collapseClick, this);
31845 if(this.resizable !== false){
31846 this.el.addClass("x-dlg-resizable");
31847 this.resizer = new Roo.Resizable(el, {
31848 minWidth: this.minWidth || 80,
31849 minHeight:this.minHeight || 80,
31850 handles: this.resizeHandles || "all",
31853 this.resizer.on("beforeresize", this.beforeResize, this);
31854 this.resizer.on("resize", this.onResize, this);
31856 if(this.draggable !== false){
31857 el.addClass("x-dlg-draggable");
31858 if (!this.proxyDrag) {
31859 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
31862 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
31864 dd.setHandleElId(this.header.id);
31865 dd.endDrag = this.endMove.createDelegate(this);
31866 dd.startDrag = this.startMove.createDelegate(this);
31867 dd.onDrag = this.onDrag.createDelegate(this);
31872 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
31873 this.mask.enableDisplayMode("block");
31875 this.el.addClass("x-dlg-modal");
31878 this.shadow = new Roo.Shadow({
31879 mode : typeof this.shadow == "string" ? this.shadow : "sides",
31880 offset : this.shadowOffset
31883 this.shadowOffset = 0;
31885 if(Roo.useShims && this.shim !== false){
31886 this.shim = this.el.createShim();
31887 this.shim.hide = this.hideAction;
31895 if (this.buttons) {
31896 var bts= this.buttons;
31898 Roo.each(bts, function(b) {
31907 * Fires when a key is pressed
31908 * @param {Roo.BasicDialog} this
31909 * @param {Roo.EventObject} e
31914 * Fires when this dialog is moved by the user.
31915 * @param {Roo.BasicDialog} this
31916 * @param {Number} x The new page X
31917 * @param {Number} y The new page Y
31922 * Fires when this dialog is resized by the user.
31923 * @param {Roo.BasicDialog} this
31924 * @param {Number} width The new width
31925 * @param {Number} height The new height
31929 * @event beforehide
31930 * Fires before this dialog is hidden.
31931 * @param {Roo.BasicDialog} this
31933 "beforehide" : true,
31936 * Fires when this dialog is hidden.
31937 * @param {Roo.BasicDialog} this
31941 * @event beforeshow
31942 * Fires before this dialog is shown.
31943 * @param {Roo.BasicDialog} this
31945 "beforeshow" : true,
31948 * Fires when this dialog is shown.
31949 * @param {Roo.BasicDialog} this
31953 el.on("keydown", this.onKeyDown, this);
31954 el.on("mousedown", this.toFront, this);
31955 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
31957 Roo.DialogManager.register(this);
31958 Roo.BasicDialog.superclass.constructor.call(this);
31961 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
31962 shadowOffset: Roo.isIE ? 6 : 5,
31965 minButtonWidth: 75,
31966 defaultButton: null,
31967 buttonAlign: "right",
31972 * Sets the dialog title text
31973 * @param {String} text The title text to display
31974 * @return {Roo.BasicDialog} this
31976 setTitle : function(text){
31977 this.header.update(text);
31982 closeClick : function(){
31987 collapseClick : function(){
31988 this[this.collapsed ? "expand" : "collapse"]();
31992 * Collapses the dialog to its minimized state (only the title bar is visible).
31993 * Equivalent to the user clicking the collapse dialog button.
31995 collapse : function(){
31996 if(!this.collapsed){
31997 this.collapsed = true;
31998 this.el.addClass("x-dlg-collapsed");
31999 this.restoreHeight = this.el.getHeight();
32000 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32005 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32006 * clicking the expand dialog button.
32008 expand : function(){
32009 if(this.collapsed){
32010 this.collapsed = false;
32011 this.el.removeClass("x-dlg-collapsed");
32012 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32017 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32018 * @return {Roo.TabPanel} The tabs component
32020 initTabs : function(){
32021 var tabs = this.getTabs();
32022 while(tabs.getTab(0)){
32025 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32027 tabs.addTab(Roo.id(dom), dom.title);
32035 beforeResize : function(){
32036 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32040 onResize : function(){
32041 this.refreshSize();
32042 this.syncBodyHeight();
32043 this.adjustAssets();
32045 this.fireEvent("resize", this, this.size.width, this.size.height);
32049 onKeyDown : function(e){
32050 if(this.isVisible()){
32051 this.fireEvent("keydown", this, e);
32056 * Resizes the dialog.
32057 * @param {Number} width
32058 * @param {Number} height
32059 * @return {Roo.BasicDialog} this
32061 resizeTo : function(width, height){
32062 this.el.setSize(width, height);
32063 this.size = {width: width, height: height};
32064 this.syncBodyHeight();
32065 if(this.fixedcenter){
32068 if(this.isVisible()){
32069 this.constrainXY();
32070 this.adjustAssets();
32072 this.fireEvent("resize", this, width, height);
32078 * Resizes the dialog to fit the specified content size.
32079 * @param {Number} width
32080 * @param {Number} height
32081 * @return {Roo.BasicDialog} this
32083 setContentSize : function(w, h){
32084 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32085 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32086 //if(!this.el.isBorderBox()){
32087 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32088 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32091 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32092 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32094 this.resizeTo(w, h);
32099 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32100 * executed in response to a particular key being pressed while the dialog is active.
32101 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32102 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32103 * @param {Function} fn The function to call
32104 * @param {Object} scope (optional) The scope of the function
32105 * @return {Roo.BasicDialog} this
32107 addKeyListener : function(key, fn, scope){
32108 var keyCode, shift, ctrl, alt;
32109 if(typeof key == "object" && !(key instanceof Array)){
32110 keyCode = key["key"];
32111 shift = key["shift"];
32112 ctrl = key["ctrl"];
32117 var handler = function(dlg, e){
32118 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32119 var k = e.getKey();
32120 if(keyCode instanceof Array){
32121 for(var i = 0, len = keyCode.length; i < len; i++){
32122 if(keyCode[i] == k){
32123 fn.call(scope || window, dlg, k, e);
32129 fn.call(scope || window, dlg, k, e);
32134 this.on("keydown", handler);
32139 * Returns the TabPanel component (creates it if it doesn't exist).
32140 * Note: If you wish to simply check for the existence of tabs without creating them,
32141 * check for a null 'tabs' property.
32142 * @return {Roo.TabPanel} The tabs component
32144 getTabs : function(){
32146 this.el.addClass("x-dlg-auto-tabs");
32147 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32148 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32154 * Adds a button to the footer section of the dialog.
32155 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32156 * object or a valid Roo.DomHelper element config
32157 * @param {Function} handler The function called when the button is clicked
32158 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32159 * @return {Roo.Button} The new button
32161 addButton : function(config, handler, scope){
32162 var dh = Roo.DomHelper;
32164 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32166 if(!this.btnContainer){
32167 var tb = this.footer.createChild({
32169 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32170 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32172 this.btnContainer = tb.firstChild.firstChild.firstChild;
32177 minWidth: this.minButtonWidth,
32180 if(typeof config == "string"){
32181 bconfig.text = config;
32184 bconfig.dhconfig = config;
32186 Roo.apply(bconfig, config);
32190 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32191 bconfig.position = Math.max(0, bconfig.position);
32192 fc = this.btnContainer.childNodes[bconfig.position];
32195 var btn = new Roo.Button(
32197 this.btnContainer.insertBefore(document.createElement("td"),fc)
32198 : this.btnContainer.appendChild(document.createElement("td")),
32199 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32202 this.syncBodyHeight();
32205 * Array of all the buttons that have been added to this dialog via addButton
32210 this.buttons.push(btn);
32215 * Sets the default button to be focused when the dialog is displayed.
32216 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32217 * @return {Roo.BasicDialog} this
32219 setDefaultButton : function(btn){
32220 this.defaultButton = btn;
32225 getHeaderFooterHeight : function(safe){
32228 height += this.header.getHeight();
32231 var fm = this.footer.getMargins();
32232 height += (this.footer.getHeight()+fm.top+fm.bottom);
32234 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32235 height += this.centerBg.getPadding("tb");
32240 syncBodyHeight : function()
32242 var bd = this.body, // the text
32243 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32245 var height = this.size.height - this.getHeaderFooterHeight(false);
32246 bd.setHeight(height-bd.getMargins("tb"));
32247 var hh = this.header.getHeight();
32248 var h = this.size.height-hh;
32251 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32252 bw.setHeight(h-cb.getPadding("tb"));
32254 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32255 bd.setWidth(bw.getWidth(true));
32257 this.tabs.syncHeight();
32259 this.tabs.el.repaint();
32265 * Restores the previous state of the dialog if Roo.state is configured.
32266 * @return {Roo.BasicDialog} this
32268 restoreState : function(){
32269 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32270 if(box && box.width){
32271 this.xy = [box.x, box.y];
32272 this.resizeTo(box.width, box.height);
32278 beforeShow : function(){
32280 if(this.fixedcenter){
32281 this.xy = this.el.getCenterXY(true);
32284 Roo.get(document.body).addClass("x-body-masked");
32285 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32288 this.constrainXY();
32292 animShow : function(){
32293 var b = Roo.get(this.animateTarget).getBox();
32294 this.proxy.setSize(b.width, b.height);
32295 this.proxy.setLocation(b.x, b.y);
32297 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32298 true, .35, this.showEl.createDelegate(this));
32302 * Shows the dialog.
32303 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32304 * @return {Roo.BasicDialog} this
32306 show : function(animateTarget){
32307 if (this.fireEvent("beforeshow", this) === false){
32310 if(this.syncHeightBeforeShow){
32311 this.syncBodyHeight();
32312 }else if(this.firstShow){
32313 this.firstShow = false;
32314 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32316 this.animateTarget = animateTarget || this.animateTarget;
32317 if(!this.el.isVisible()){
32319 if(this.animateTarget && Roo.get(this.animateTarget)){
32329 showEl : function(){
32331 this.el.setXY(this.xy);
32333 this.adjustAssets(true);
32336 // IE peekaboo bug - fix found by Dave Fenwick
32340 this.fireEvent("show", this);
32344 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32345 * dialog itself will receive focus.
32347 focus : function(){
32348 if(this.defaultButton){
32349 this.defaultButton.focus();
32351 this.focusEl.focus();
32356 constrainXY : function(){
32357 if(this.constraintoviewport !== false){
32358 if(!this.viewSize){
32359 if(this.container){
32360 var s = this.container.getSize();
32361 this.viewSize = [s.width, s.height];
32363 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32366 var s = Roo.get(this.container||document).getScroll();
32368 var x = this.xy[0], y = this.xy[1];
32369 var w = this.size.width, h = this.size.height;
32370 var vw = this.viewSize[0], vh = this.viewSize[1];
32371 // only move it if it needs it
32373 // first validate right/bottom
32374 if(x + w > vw+s.left){
32378 if(y + h > vh+s.top){
32382 // then make sure top/left isn't negative
32394 if(this.isVisible()){
32395 this.el.setLocation(x, y);
32396 this.adjustAssets();
32403 onDrag : function(){
32404 if(!this.proxyDrag){
32405 this.xy = this.el.getXY();
32406 this.adjustAssets();
32411 adjustAssets : function(doShow){
32412 var x = this.xy[0], y = this.xy[1];
32413 var w = this.size.width, h = this.size.height;
32414 if(doShow === true){
32416 this.shadow.show(this.el);
32422 if(this.shadow && this.shadow.isVisible()){
32423 this.shadow.show(this.el);
32425 if(this.shim && this.shim.isVisible()){
32426 this.shim.setBounds(x, y, w, h);
32431 adjustViewport : function(w, h){
32433 w = Roo.lib.Dom.getViewWidth();
32434 h = Roo.lib.Dom.getViewHeight();
32437 this.viewSize = [w, h];
32438 if(this.modal && this.mask.isVisible()){
32439 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32440 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32442 if(this.isVisible()){
32443 this.constrainXY();
32448 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32449 * shadow, proxy, mask, etc.) Also removes all event listeners.
32450 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32452 destroy : function(removeEl){
32453 if(this.isVisible()){
32454 this.animateTarget = null;
32457 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32459 this.tabs.destroy(removeEl);
32472 for(var i = 0, len = this.buttons.length; i < len; i++){
32473 this.buttons[i].destroy();
32476 this.el.removeAllListeners();
32477 if(removeEl === true){
32478 this.el.update("");
32481 Roo.DialogManager.unregister(this);
32485 startMove : function(){
32486 if(this.proxyDrag){
32489 if(this.constraintoviewport !== false){
32490 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32495 endMove : function(){
32496 if(!this.proxyDrag){
32497 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32499 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32502 this.refreshSize();
32503 this.adjustAssets();
32505 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32509 * Brings this dialog to the front of any other visible dialogs
32510 * @return {Roo.BasicDialog} this
32512 toFront : function(){
32513 Roo.DialogManager.bringToFront(this);
32518 * Sends this dialog to the back (under) of any other visible dialogs
32519 * @return {Roo.BasicDialog} this
32521 toBack : function(){
32522 Roo.DialogManager.sendToBack(this);
32527 * Centers this dialog in the viewport
32528 * @return {Roo.BasicDialog} this
32530 center : function(){
32531 var xy = this.el.getCenterXY(true);
32532 this.moveTo(xy[0], xy[1]);
32537 * Moves the dialog's top-left corner to the specified point
32538 * @param {Number} x
32539 * @param {Number} y
32540 * @return {Roo.BasicDialog} this
32542 moveTo : function(x, y){
32544 if(this.isVisible()){
32545 this.el.setXY(this.xy);
32546 this.adjustAssets();
32552 * Aligns the dialog to the specified element
32553 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32554 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32555 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32556 * @return {Roo.BasicDialog} this
32558 alignTo : function(element, position, offsets){
32559 this.xy = this.el.getAlignToXY(element, position, offsets);
32560 if(this.isVisible()){
32561 this.el.setXY(this.xy);
32562 this.adjustAssets();
32568 * Anchors an element to another element and realigns it when the window is resized.
32569 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32570 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32571 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32572 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32573 * is a number, it is used as the buffer delay (defaults to 50ms).
32574 * @return {Roo.BasicDialog} this
32576 anchorTo : function(el, alignment, offsets, monitorScroll){
32577 var action = function(){
32578 this.alignTo(el, alignment, offsets);
32580 Roo.EventManager.onWindowResize(action, this);
32581 var tm = typeof monitorScroll;
32582 if(tm != 'undefined'){
32583 Roo.EventManager.on(window, 'scroll', action, this,
32584 {buffer: tm == 'number' ? monitorScroll : 50});
32591 * Returns true if the dialog is visible
32592 * @return {Boolean}
32594 isVisible : function(){
32595 return this.el.isVisible();
32599 animHide : function(callback){
32600 var b = Roo.get(this.animateTarget).getBox();
32602 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32604 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32605 this.hideEl.createDelegate(this, [callback]));
32609 * Hides the dialog.
32610 * @param {Function} callback (optional) Function to call when the dialog is hidden
32611 * @return {Roo.BasicDialog} this
32613 hide : function(callback){
32614 if (this.fireEvent("beforehide", this) === false){
32618 this.shadow.hide();
32623 // sometimes animateTarget seems to get set.. causing problems...
32624 // this just double checks..
32625 if(this.animateTarget && Roo.get(this.animateTarget)) {
32626 this.animHide(callback);
32629 this.hideEl(callback);
32635 hideEl : function(callback){
32639 Roo.get(document.body).removeClass("x-body-masked");
32641 this.fireEvent("hide", this);
32642 if(typeof callback == "function"){
32648 hideAction : function(){
32649 this.setLeft("-10000px");
32650 this.setTop("-10000px");
32651 this.setStyle("visibility", "hidden");
32655 refreshSize : function(){
32656 this.size = this.el.getSize();
32657 this.xy = this.el.getXY();
32658 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32662 // z-index is managed by the DialogManager and may be overwritten at any time
32663 setZIndex : function(index){
32665 this.mask.setStyle("z-index", index);
32668 this.shim.setStyle("z-index", ++index);
32671 this.shadow.setZIndex(++index);
32673 this.el.setStyle("z-index", ++index);
32675 this.proxy.setStyle("z-index", ++index);
32678 this.resizer.proxy.setStyle("z-index", ++index);
32681 this.lastZIndex = index;
32685 * Returns the element for this dialog
32686 * @return {Roo.Element} The underlying dialog Element
32688 getEl : function(){
32694 * @class Roo.DialogManager
32695 * Provides global access to BasicDialogs that have been created and
32696 * support for z-indexing (layering) multiple open dialogs.
32698 Roo.DialogManager = function(){
32700 var accessList = [];
32704 var sortDialogs = function(d1, d2){
32705 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32709 var orderDialogs = function(){
32710 accessList.sort(sortDialogs);
32711 var seed = Roo.DialogManager.zseed;
32712 for(var i = 0, len = accessList.length; i < len; i++){
32713 var dlg = accessList[i];
32715 dlg.setZIndex(seed + (i*10));
32722 * The starting z-index for BasicDialogs (defaults to 9000)
32723 * @type Number The z-index value
32728 register : function(dlg){
32729 list[dlg.id] = dlg;
32730 accessList.push(dlg);
32734 unregister : function(dlg){
32735 delete list[dlg.id];
32738 if(!accessList.indexOf){
32739 for( i = 0, len = accessList.length; i < len; i++){
32740 if(accessList[i] == dlg){
32741 accessList.splice(i, 1);
32746 i = accessList.indexOf(dlg);
32748 accessList.splice(i, 1);
32754 * Gets a registered dialog by id
32755 * @param {String/Object} id The id of the dialog or a dialog
32756 * @return {Roo.BasicDialog} this
32758 get : function(id){
32759 return typeof id == "object" ? id : list[id];
32763 * Brings the specified dialog to the front
32764 * @param {String/Object} dlg The id of the dialog or a dialog
32765 * @return {Roo.BasicDialog} this
32767 bringToFront : function(dlg){
32768 dlg = this.get(dlg);
32771 dlg._lastAccess = new Date().getTime();
32778 * Sends the specified dialog to the back
32779 * @param {String/Object} dlg The id of the dialog or a dialog
32780 * @return {Roo.BasicDialog} this
32782 sendToBack : function(dlg){
32783 dlg = this.get(dlg);
32784 dlg._lastAccess = -(new Date().getTime());
32790 * Hides all dialogs
32792 hideAll : function(){
32793 for(var id in list){
32794 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32803 * @class Roo.LayoutDialog
32804 * @extends Roo.BasicDialog
32805 * Dialog which provides adjustments for working with a layout in a Dialog.
32806 * Add your necessary layout config options to the dialog's config.<br>
32807 * Example usage (including a nested layout):
32810 dialog = new Roo.LayoutDialog("download-dlg", {
32819 // layout config merges with the dialog config
32821 tabPosition: "top",
32822 alwaysShowTabs: true
32825 dialog.addKeyListener(27, dialog.hide, dialog);
32826 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32827 dialog.addButton("Build It!", this.getDownload, this);
32829 // we can even add nested layouts
32830 var innerLayout = new Roo.BorderLayout("dl-inner", {
32840 innerLayout.beginUpdate();
32841 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32842 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32843 innerLayout.endUpdate(true);
32845 var layout = dialog.getLayout();
32846 layout.beginUpdate();
32847 layout.add("center", new Roo.ContentPanel("standard-panel",
32848 {title: "Download the Source", fitToFrame:true}));
32849 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32850 {title: "Build your own roo.js"}));
32851 layout.getRegion("center").showPanel(sp);
32852 layout.endUpdate();
32856 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32857 * @param {Object} config configuration options
32859 Roo.LayoutDialog = function(el, cfg){
32862 if (typeof(cfg) == 'undefined') {
32863 config = Roo.apply({}, el);
32864 // not sure why we use documentElement here.. - it should always be body.
32865 // IE7 borks horribly if we use documentElement.
32866 // webkit also does not like documentElement - it creates a body element...
32867 el = Roo.get( document.body || document.documentElement ).createChild();
32868 //config.autoCreate = true;
32872 config.autoTabs = false;
32873 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
32874 this.body.setStyle({overflow:"hidden", position:"relative"});
32875 this.layout = new Roo.BorderLayout(this.body.dom, config);
32876 this.layout.monitorWindowResize = false;
32877 this.el.addClass("x-dlg-auto-layout");
32878 // fix case when center region overwrites center function
32879 this.center = Roo.BasicDialog.prototype.center;
32880 this.on("show", this.layout.layout, this.layout, true);
32881 if (config.items) {
32882 var xitems = config.items;
32883 delete config.items;
32884 Roo.each(xitems, this.addxtype, this);
32889 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
32891 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
32894 endUpdate : function(){
32895 this.layout.endUpdate();
32899 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
32902 beginUpdate : function(){
32903 this.layout.beginUpdate();
32907 * Get the BorderLayout for this dialog
32908 * @return {Roo.BorderLayout}
32910 getLayout : function(){
32911 return this.layout;
32914 showEl : function(){
32915 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
32917 this.layout.layout();
32922 // Use the syncHeightBeforeShow config option to control this automatically
32923 syncBodyHeight : function(){
32924 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
32925 if(this.layout){this.layout.layout();}
32929 * Add an xtype element (actually adds to the layout.)
32930 * @return {Object} xdata xtype object data.
32933 addxtype : function(c) {
32934 return this.layout.addxtype(c);
32938 * Ext JS Library 1.1.1
32939 * Copyright(c) 2006-2007, Ext JS, LLC.
32941 * Originally Released Under LGPL - original licence link has changed is not relivant.
32944 * <script type="text/javascript">
32948 * @class Roo.MessageBox
32949 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
32953 Roo.Msg.alert('Status', 'Changes saved successfully.');
32955 // Prompt for user data:
32956 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
32958 // process text value...
32962 // Show a dialog using config options:
32964 title:'Save Changes?',
32965 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
32966 buttons: Roo.Msg.YESNOCANCEL,
32973 Roo.MessageBox = function(){
32974 var dlg, opt, mask, waitTimer;
32975 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
32976 var buttons, activeTextEl, bwidth;
32979 var handleButton = function(button){
32981 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
32985 var handleHide = function(){
32986 if(opt && opt.cls){
32987 dlg.el.removeClass(opt.cls);
32990 Roo.TaskMgr.stop(waitTimer);
32996 var updateButtons = function(b){
32999 buttons["ok"].hide();
33000 buttons["cancel"].hide();
33001 buttons["yes"].hide();
33002 buttons["no"].hide();
33003 dlg.footer.dom.style.display = 'none';
33006 dlg.footer.dom.style.display = '';
33007 for(var k in buttons){
33008 if(typeof buttons[k] != "function"){
33011 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33012 width += buttons[k].el.getWidth()+15;
33022 var handleEsc = function(d, k, e){
33023 if(opt && opt.closable !== false){
33033 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33034 * @return {Roo.BasicDialog} The BasicDialog element
33036 getDialog : function(){
33038 dlg = new Roo.BasicDialog("x-msg-box", {
33043 constraintoviewport:false,
33045 collapsible : false,
33048 width:400, height:100,
33049 buttonAlign:"center",
33050 closeClick : function(){
33051 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33052 handleButton("no");
33054 handleButton("cancel");
33058 dlg.on("hide", handleHide);
33060 dlg.addKeyListener(27, handleEsc);
33062 var bt = this.buttonText;
33063 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33064 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33065 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33066 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33067 bodyEl = dlg.body.createChild({
33069 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>'
33071 msgEl = bodyEl.dom.firstChild;
33072 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33073 textboxEl.enableDisplayMode();
33074 textboxEl.addKeyListener([10,13], function(){
33075 if(dlg.isVisible() && opt && opt.buttons){
33076 if(opt.buttons.ok){
33077 handleButton("ok");
33078 }else if(opt.buttons.yes){
33079 handleButton("yes");
33083 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33084 textareaEl.enableDisplayMode();
33085 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33086 progressEl.enableDisplayMode();
33087 var pf = progressEl.dom.firstChild;
33089 pp = Roo.get(pf.firstChild);
33090 pp.setHeight(pf.offsetHeight);
33098 * Updates the message box body text
33099 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33100 * the XHTML-compliant non-breaking space character '&#160;')
33101 * @return {Roo.MessageBox} This message box
33103 updateText : function(text){
33104 if(!dlg.isVisible() && !opt.width){
33105 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33107 msgEl.innerHTML = text || ' ';
33109 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33110 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33112 Math.min(opt.width || cw , this.maxWidth),
33113 Math.max(opt.minWidth || this.minWidth, bwidth)
33116 activeTextEl.setWidth(w);
33118 if(dlg.isVisible()){
33119 dlg.fixedcenter = false;
33121 // to big, make it scroll. = But as usual stupid IE does not support
33124 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33125 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33126 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33128 bodyEl.dom.style.height = '';
33129 bodyEl.dom.style.overflowY = '';
33132 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33134 bodyEl.dom.style.overflowX = '';
33137 dlg.setContentSize(w, bodyEl.getHeight());
33138 if(dlg.isVisible()){
33139 dlg.fixedcenter = true;
33145 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33146 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33147 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33148 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33149 * @return {Roo.MessageBox} This message box
33151 updateProgress : function(value, text){
33153 this.updateText(text);
33155 if (pp) { // weird bug on my firefox - for some reason this is not defined
33156 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33162 * Returns true if the message box is currently displayed
33163 * @return {Boolean} True if the message box is visible, else false
33165 isVisible : function(){
33166 return dlg && dlg.isVisible();
33170 * Hides the message box if it is displayed
33173 if(this.isVisible()){
33179 * Displays a new message box, or reinitializes an existing message box, based on the config options
33180 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33181 * The following config object properties are supported:
33183 Property Type Description
33184 ---------- --------------- ------------------------------------------------------------------------------------
33185 animEl String/Element An id or Element from which the message box should animate as it opens and
33186 closes (defaults to undefined)
33187 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33188 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33189 closable Boolean False to hide the top-right close button (defaults to true). Note that
33190 progress and wait dialogs will ignore this property and always hide the
33191 close button as they can only be closed programmatically.
33192 cls String A custom CSS class to apply to the message box element
33193 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33194 displayed (defaults to 75)
33195 fn Function A callback function to execute after closing the dialog. The arguments to the
33196 function will be btn (the name of the button that was clicked, if applicable,
33197 e.g. "ok"), and text (the value of the active text field, if applicable).
33198 Progress and wait dialogs will ignore this option since they do not respond to
33199 user actions and can only be closed programmatically, so any required function
33200 should be called by the same code after it closes the dialog.
33201 icon String A CSS class that provides a background image to be used as an icon for
33202 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33203 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33204 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33205 modal Boolean False to allow user interaction with the page while the message box is
33206 displayed (defaults to true)
33207 msg String A string that will replace the existing message box body text (defaults
33208 to the XHTML-compliant non-breaking space character ' ')
33209 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33210 progress Boolean True to display a progress bar (defaults to false)
33211 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33212 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33213 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33214 title String The title text
33215 value String The string value to set into the active textbox element if displayed
33216 wait Boolean True to display a progress bar (defaults to false)
33217 width Number The width of the dialog in pixels
33224 msg: 'Please enter your address:',
33226 buttons: Roo.MessageBox.OKCANCEL,
33229 animEl: 'addAddressBtn'
33232 * @param {Object} config Configuration options
33233 * @return {Roo.MessageBox} This message box
33235 show : function(options)
33238 // this causes nightmares if you show one dialog after another
33239 // especially on callbacks..
33241 if(this.isVisible()){
33244 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33245 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33246 Roo.log("New Dialog Message:" + options.msg )
33247 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33248 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33251 var d = this.getDialog();
33253 d.setTitle(opt.title || " ");
33254 d.close.setDisplayed(opt.closable !== false);
33255 activeTextEl = textboxEl;
33256 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33261 textareaEl.setHeight(typeof opt.multiline == "number" ?
33262 opt.multiline : this.defaultTextHeight);
33263 activeTextEl = textareaEl;
33272 progressEl.setDisplayed(opt.progress === true);
33273 this.updateProgress(0);
33274 activeTextEl.dom.value = opt.value || "";
33276 dlg.setDefaultButton(activeTextEl);
33278 var bs = opt.buttons;
33281 db = buttons["ok"];
33282 }else if(bs && bs.yes){
33283 db = buttons["yes"];
33285 dlg.setDefaultButton(db);
33287 bwidth = updateButtons(opt.buttons);
33288 this.updateText(opt.msg);
33290 d.el.addClass(opt.cls);
33292 d.proxyDrag = opt.proxyDrag === true;
33293 d.modal = opt.modal !== false;
33294 d.mask = opt.modal !== false ? mask : false;
33295 if(!d.isVisible()){
33296 // force it to the end of the z-index stack so it gets a cursor in FF
33297 document.body.appendChild(dlg.el.dom);
33298 d.animateTarget = null;
33299 d.show(options.animEl);
33305 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33306 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33307 * and closing the message box when the process is complete.
33308 * @param {String} title The title bar text
33309 * @param {String} msg The message box body text
33310 * @return {Roo.MessageBox} This message box
33312 progress : function(title, msg){
33319 minWidth: this.minProgressWidth,
33326 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33327 * If a callback function is passed it will be called after the user clicks the button, and the
33328 * id of the button that was clicked will be passed as the only parameter to the callback
33329 * (could also be the top-right close button).
33330 * @param {String} title The title bar text
33331 * @param {String} msg The message box body text
33332 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33333 * @param {Object} scope (optional) The scope of the callback function
33334 * @return {Roo.MessageBox} This message box
33336 alert : function(title, msg, fn, scope){
33349 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33350 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33351 * You are responsible for closing the message box when the process is complete.
33352 * @param {String} msg The message box body text
33353 * @param {String} title (optional) The title bar text
33354 * @return {Roo.MessageBox} This message box
33356 wait : function(msg, title){
33367 waitTimer = Roo.TaskMgr.start({
33369 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33377 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33378 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33379 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33380 * @param {String} title The title bar text
33381 * @param {String} msg The message box body text
33382 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33383 * @param {Object} scope (optional) The scope of the callback function
33384 * @return {Roo.MessageBox} This message box
33386 confirm : function(title, msg, fn, scope){
33390 buttons: this.YESNO,
33399 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33400 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33401 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33402 * (could also be the top-right close button) and the text that was entered will be passed as the two
33403 * parameters to the callback.
33404 * @param {String} title The title bar text
33405 * @param {String} msg The message box body text
33406 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33407 * @param {Object} scope (optional) The scope of the callback function
33408 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33409 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33410 * @return {Roo.MessageBox} This message box
33412 prompt : function(title, msg, fn, scope, multiline){
33416 buttons: this.OKCANCEL,
33421 multiline: multiline,
33428 * Button config that displays a single OK button
33433 * Button config that displays Yes and No buttons
33436 YESNO : {yes:true, no:true},
33438 * Button config that displays OK and Cancel buttons
33441 OKCANCEL : {ok:true, cancel:true},
33443 * Button config that displays Yes, No and Cancel buttons
33446 YESNOCANCEL : {yes:true, no:true, cancel:true},
33449 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33452 defaultTextHeight : 75,
33454 * The maximum width in pixels of the message box (defaults to 600)
33459 * The minimum width in pixels of the message box (defaults to 100)
33464 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33465 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33468 minProgressWidth : 250,
33470 * An object containing the default button text strings that can be overriden for localized language support.
33471 * Supported properties are: ok, cancel, yes and no.
33472 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33485 * Shorthand for {@link Roo.MessageBox}
33487 Roo.Msg = Roo.MessageBox;/*
33489 * Ext JS Library 1.1.1
33490 * Copyright(c) 2006-2007, Ext JS, LLC.
33492 * Originally Released Under LGPL - original licence link has changed is not relivant.
33495 * <script type="text/javascript">
33498 * @class Roo.QuickTips
33499 * Provides attractive and customizable tooltips for any element.
33502 Roo.QuickTips = function(){
33503 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33504 var ce, bd, xy, dd;
33505 var visible = false, disabled = true, inited = false;
33506 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33508 var onOver = function(e){
33512 var t = e.getTarget();
33513 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33516 if(ce && t == ce.el){
33517 clearTimeout(hideProc);
33520 if(t && tagEls[t.id]){
33521 tagEls[t.id].el = t;
33522 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33525 var ttp, et = Roo.fly(t);
33526 var ns = cfg.namespace;
33527 if(tm.interceptTitles && t.title){
33530 t.removeAttribute("title");
33531 e.preventDefault();
33533 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33536 showProc = show.defer(tm.showDelay, tm, [{
33539 width: et.getAttributeNS(ns, cfg.width),
33540 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33541 title: et.getAttributeNS(ns, cfg.title),
33542 cls: et.getAttributeNS(ns, cfg.cls)
33547 var onOut = function(e){
33548 clearTimeout(showProc);
33549 var t = e.getTarget();
33550 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33551 hideProc = setTimeout(hide, tm.hideDelay);
33555 var onMove = function(e){
33561 if(tm.trackMouse && ce){
33566 var onDown = function(e){
33567 clearTimeout(showProc);
33568 clearTimeout(hideProc);
33570 if(tm.hideOnClick){
33573 tm.enable.defer(100, tm);
33578 var getPad = function(){
33579 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33582 var show = function(o){
33586 clearTimeout(dismissProc);
33588 if(removeCls){ // in case manually hidden
33589 el.removeClass(removeCls);
33593 el.addClass(ce.cls);
33594 removeCls = ce.cls;
33597 tipTitle.update(ce.title);
33600 tipTitle.update('');
33603 el.dom.style.width = tm.maxWidth+'px';
33604 //tipBody.dom.style.width = '';
33605 tipBodyText.update(o.text);
33606 var p = getPad(), w = ce.width;
33608 var td = tipBodyText.dom;
33609 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33610 if(aw > tm.maxWidth){
33612 }else if(aw < tm.minWidth){
33618 //tipBody.setWidth(w);
33619 el.setWidth(parseInt(w, 10) + p);
33620 if(ce.autoHide === false){
33621 close.setDisplayed(true);
33626 close.setDisplayed(false);
33632 el.avoidY = xy[1]-18;
33637 el.setStyle("visibility", "visible");
33638 el.fadeIn({callback: afterShow});
33644 var afterShow = function(){
33648 if(tm.autoDismiss && ce.autoHide !== false){
33649 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33654 var hide = function(noanim){
33655 clearTimeout(dismissProc);
33656 clearTimeout(hideProc);
33658 if(el.isVisible()){
33660 if(noanim !== true && tm.animate){
33661 el.fadeOut({callback: afterHide});
33668 var afterHide = function(){
33671 el.removeClass(removeCls);
33678 * @cfg {Number} minWidth
33679 * The minimum width of the quick tip (defaults to 40)
33683 * @cfg {Number} maxWidth
33684 * The maximum width of the quick tip (defaults to 300)
33688 * @cfg {Boolean} interceptTitles
33689 * True to automatically use the element's DOM title value if available (defaults to false)
33691 interceptTitles : false,
33693 * @cfg {Boolean} trackMouse
33694 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33696 trackMouse : false,
33698 * @cfg {Boolean} hideOnClick
33699 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33701 hideOnClick : true,
33703 * @cfg {Number} showDelay
33704 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33708 * @cfg {Number} hideDelay
33709 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33713 * @cfg {Boolean} autoHide
33714 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33715 * Used in conjunction with hideDelay.
33720 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33721 * (defaults to true). Used in conjunction with autoDismissDelay.
33723 autoDismiss : true,
33726 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33728 autoDismissDelay : 5000,
33730 * @cfg {Boolean} animate
33731 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33736 * @cfg {String} title
33737 * Title text to display (defaults to ''). This can be any valid HTML markup.
33741 * @cfg {String} text
33742 * Body text to display (defaults to ''). This can be any valid HTML markup.
33746 * @cfg {String} cls
33747 * A CSS class to apply to the base quick tip element (defaults to '').
33751 * @cfg {Number} width
33752 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33753 * minWidth or maxWidth.
33758 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33759 * or display QuickTips in a page.
33762 tm = Roo.QuickTips;
33763 cfg = tm.tagConfig;
33765 if(!Roo.isReady){ // allow calling of init() before onReady
33766 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33769 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33770 el.fxDefaults = {stopFx: true};
33771 // maximum custom styling
33772 //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>');
33773 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>');
33774 tipTitle = el.child('h3');
33775 tipTitle.enableDisplayMode("block");
33776 tipBody = el.child('div.x-tip-bd');
33777 tipBodyText = el.child('div.x-tip-bd-inner');
33778 //bdLeft = el.child('div.x-tip-bd-left');
33779 //bdRight = el.child('div.x-tip-bd-right');
33780 close = el.child('div.x-tip-close');
33781 close.enableDisplayMode("block");
33782 close.on("click", hide);
33783 var d = Roo.get(document);
33784 d.on("mousedown", onDown);
33785 d.on("mouseover", onOver);
33786 d.on("mouseout", onOut);
33787 d.on("mousemove", onMove);
33788 esc = d.addKeyListener(27, hide);
33791 dd = el.initDD("default", null, {
33792 onDrag : function(){
33796 dd.setHandleElId(tipTitle.id);
33805 * Configures a new quick tip instance and assigns it to a target element. The following config options
33808 Property Type Description
33809 ---------- --------------------- ------------------------------------------------------------------------
33810 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33812 * @param {Object} config The config object
33814 register : function(config){
33815 var cs = config instanceof Array ? config : arguments;
33816 for(var i = 0, len = cs.length; i < len; i++) {
33818 var target = c.target;
33820 if(target instanceof Array){
33821 for(var j = 0, jlen = target.length; j < jlen; j++){
33822 tagEls[target[j]] = c;
33825 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33832 * Removes this quick tip from its element and destroys it.
33833 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33835 unregister : function(el){
33836 delete tagEls[Roo.id(el)];
33840 * Enable this quick tip.
33842 enable : function(){
33843 if(inited && disabled){
33845 if(locks.length < 1){
33852 * Disable this quick tip.
33854 disable : function(){
33856 clearTimeout(showProc);
33857 clearTimeout(hideProc);
33858 clearTimeout(dismissProc);
33866 * Returns true if the quick tip is enabled, else false.
33868 isEnabled : function(){
33874 namespace : "roo", // was ext?? this may break..
33875 alt_namespace : "ext",
33876 attribute : "qtip",
33886 // backwards compat
33887 Roo.QuickTips.tips = Roo.QuickTips.register;/*
33889 * Ext JS Library 1.1.1
33890 * Copyright(c) 2006-2007, Ext JS, LLC.
33892 * Originally Released Under LGPL - original licence link has changed is not relivant.
33895 * <script type="text/javascript">
33900 * @class Roo.tree.TreePanel
33901 * @extends Roo.data.Tree
33903 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
33904 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
33905 * @cfg {Boolean} enableDD true to enable drag and drop
33906 * @cfg {Boolean} enableDrag true to enable just drag
33907 * @cfg {Boolean} enableDrop true to enable just drop
33908 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
33909 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
33910 * @cfg {String} ddGroup The DD group this TreePanel belongs to
33911 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
33912 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
33913 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
33914 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
33915 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
33916 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
33917 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
33918 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
33919 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
33920 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
33921 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
33922 * @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>
33923 * @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>
33926 * @param {String/HTMLElement/Element} el The container element
33927 * @param {Object} config
33929 Roo.tree.TreePanel = function(el, config){
33931 var loader = false;
33933 root = config.root;
33934 delete config.root;
33936 if (config.loader) {
33937 loader = config.loader;
33938 delete config.loader;
33941 Roo.apply(this, config);
33942 Roo.tree.TreePanel.superclass.constructor.call(this);
33943 this.el = Roo.get(el);
33944 this.el.addClass('x-tree');
33945 //console.log(root);
33947 this.setRootNode( Roo.factory(root, Roo.tree));
33950 this.loader = Roo.factory(loader, Roo.tree);
33953 * Read-only. The id of the container element becomes this TreePanel's id.
33955 this.id = this.el.id;
33958 * @event beforeload
33959 * Fires before a node is loaded, return false to cancel
33960 * @param {Node} node The node being loaded
33962 "beforeload" : true,
33965 * Fires when a node is loaded
33966 * @param {Node} node The node that was loaded
33970 * @event textchange
33971 * Fires when the text for a node is changed
33972 * @param {Node} node The node
33973 * @param {String} text The new text
33974 * @param {String} oldText The old text
33976 "textchange" : true,
33978 * @event beforeexpand
33979 * Fires before a node is expanded, return false to cancel.
33980 * @param {Node} node The node
33981 * @param {Boolean} deep
33982 * @param {Boolean} anim
33984 "beforeexpand" : true,
33986 * @event beforecollapse
33987 * Fires before a node is collapsed, return false to cancel.
33988 * @param {Node} node The node
33989 * @param {Boolean} deep
33990 * @param {Boolean} anim
33992 "beforecollapse" : true,
33995 * Fires when a node is expanded
33996 * @param {Node} node The node
34000 * @event disabledchange
34001 * Fires when the disabled status of a node changes
34002 * @param {Node} node The node
34003 * @param {Boolean} disabled
34005 "disabledchange" : true,
34008 * Fires when a node is collapsed
34009 * @param {Node} node The node
34013 * @event beforeclick
34014 * Fires before click processing on a node. Return false to cancel the default action.
34015 * @param {Node} node The node
34016 * @param {Roo.EventObject} e The event object
34018 "beforeclick":true,
34020 * @event checkchange
34021 * Fires when a node with a checkbox's checked property changes
34022 * @param {Node} this This node
34023 * @param {Boolean} checked
34025 "checkchange":true,
34028 * Fires when a node is clicked
34029 * @param {Node} node The node
34030 * @param {Roo.EventObject} e The event object
34035 * Fires when a node is double clicked
34036 * @param {Node} node The node
34037 * @param {Roo.EventObject} e The event object
34041 * @event contextmenu
34042 * Fires when a node is right clicked
34043 * @param {Node} node The node
34044 * @param {Roo.EventObject} e The event object
34046 "contextmenu":true,
34048 * @event beforechildrenrendered
34049 * Fires right before the child nodes for a node are rendered
34050 * @param {Node} node The node
34052 "beforechildrenrendered":true,
34055 * Fires when a node starts being dragged
34056 * @param {Roo.tree.TreePanel} this
34057 * @param {Roo.tree.TreeNode} node
34058 * @param {event} e The raw browser event
34060 "startdrag" : true,
34063 * Fires when a drag operation is complete
34064 * @param {Roo.tree.TreePanel} this
34065 * @param {Roo.tree.TreeNode} node
34066 * @param {event} e The raw browser event
34071 * Fires when a dragged node is dropped on a valid DD target
34072 * @param {Roo.tree.TreePanel} this
34073 * @param {Roo.tree.TreeNode} node
34074 * @param {DD} dd The dd it was dropped on
34075 * @param {event} e The raw browser event
34079 * @event beforenodedrop
34080 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34081 * passed to handlers has the following properties:<br />
34082 * <ul style="padding:5px;padding-left:16px;">
34083 * <li>tree - The TreePanel</li>
34084 * <li>target - The node being targeted for the drop</li>
34085 * <li>data - The drag data from the drag source</li>
34086 * <li>point - The point of the drop - append, above or below</li>
34087 * <li>source - The drag source</li>
34088 * <li>rawEvent - Raw mouse event</li>
34089 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34090 * to be inserted by setting them on this object.</li>
34091 * <li>cancel - Set this to true to cancel the drop.</li>
34093 * @param {Object} dropEvent
34095 "beforenodedrop" : true,
34098 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34099 * passed to handlers has the following properties:<br />
34100 * <ul style="padding:5px;padding-left:16px;">
34101 * <li>tree - The TreePanel</li>
34102 * <li>target - The node being targeted for the drop</li>
34103 * <li>data - The drag data from the drag source</li>
34104 * <li>point - The point of the drop - append, above or below</li>
34105 * <li>source - The drag source</li>
34106 * <li>rawEvent - Raw mouse event</li>
34107 * <li>dropNode - Dropped node(s).</li>
34109 * @param {Object} dropEvent
34113 * @event nodedragover
34114 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34115 * passed to handlers has the following properties:<br />
34116 * <ul style="padding:5px;padding-left:16px;">
34117 * <li>tree - The TreePanel</li>
34118 * <li>target - The node being targeted for the drop</li>
34119 * <li>data - The drag data from the drag source</li>
34120 * <li>point - The point of the drop - append, above or below</li>
34121 * <li>source - The drag source</li>
34122 * <li>rawEvent - Raw mouse event</li>
34123 * <li>dropNode - Drop node(s) provided by the source.</li>
34124 * <li>cancel - Set this to true to signal drop not allowed.</li>
34126 * @param {Object} dragOverEvent
34128 "nodedragover" : true
34131 if(this.singleExpand){
34132 this.on("beforeexpand", this.restrictExpand, this);
34135 this.editor.tree = this;
34136 this.editor = Roo.factory(this.editor, Roo.tree);
34139 if (this.selModel) {
34140 this.selModel = Roo.factory(this.selModel, Roo.tree);
34144 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34145 rootVisible : true,
34146 animate: Roo.enableFx,
34149 hlDrop : Roo.enableFx,
34153 rendererTip: false,
34155 restrictExpand : function(node){
34156 var p = node.parentNode;
34158 if(p.expandedChild && p.expandedChild.parentNode == p){
34159 p.expandedChild.collapse();
34161 p.expandedChild = node;
34165 // private override
34166 setRootNode : function(node){
34167 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34168 if(!this.rootVisible){
34169 node.ui = new Roo.tree.RootTreeNodeUI(node);
34175 * Returns the container element for this TreePanel
34177 getEl : function(){
34182 * Returns the default TreeLoader for this TreePanel
34184 getLoader : function(){
34185 return this.loader;
34191 expandAll : function(){
34192 this.root.expand(true);
34196 * Collapse all nodes
34198 collapseAll : function(){
34199 this.root.collapse(true);
34203 * Returns the selection model used by this TreePanel
34205 getSelectionModel : function(){
34206 if(!this.selModel){
34207 this.selModel = new Roo.tree.DefaultSelectionModel();
34209 return this.selModel;
34213 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34214 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34215 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34218 getChecked : function(a, startNode){
34219 startNode = startNode || this.root;
34221 var f = function(){
34222 if(this.attributes.checked){
34223 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34226 startNode.cascade(f);
34231 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34232 * @param {String} path
34233 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34234 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34235 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34237 expandPath : function(path, attr, callback){
34238 attr = attr || "id";
34239 var keys = path.split(this.pathSeparator);
34240 var curNode = this.root;
34241 if(curNode.attributes[attr] != keys[1]){ // invalid root
34243 callback(false, null);
34248 var f = function(){
34249 if(++index == keys.length){
34251 callback(true, curNode);
34255 var c = curNode.findChild(attr, keys[index]);
34258 callback(false, curNode);
34263 c.expand(false, false, f);
34265 curNode.expand(false, false, f);
34269 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34270 * @param {String} path
34271 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34272 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34273 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34275 selectPath : function(path, attr, callback){
34276 attr = attr || "id";
34277 var keys = path.split(this.pathSeparator);
34278 var v = keys.pop();
34279 if(keys.length > 0){
34280 var f = function(success, node){
34281 if(success && node){
34282 var n = node.findChild(attr, v);
34288 }else if(callback){
34289 callback(false, n);
34293 callback(false, n);
34297 this.expandPath(keys.join(this.pathSeparator), attr, f);
34299 this.root.select();
34301 callback(true, this.root);
34306 getTreeEl : function(){
34311 * Trigger rendering of this TreePanel
34313 render : function(){
34314 if (this.innerCt) {
34315 return this; // stop it rendering more than once!!
34318 this.innerCt = this.el.createChild({tag:"ul",
34319 cls:"x-tree-root-ct " +
34320 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34322 if(this.containerScroll){
34323 Roo.dd.ScrollManager.register(this.el);
34325 if((this.enableDD || this.enableDrop) && !this.dropZone){
34327 * The dropZone used by this tree if drop is enabled
34328 * @type Roo.tree.TreeDropZone
34330 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34331 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34334 if((this.enableDD || this.enableDrag) && !this.dragZone){
34336 * The dragZone used by this tree if drag is enabled
34337 * @type Roo.tree.TreeDragZone
34339 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34340 ddGroup: this.ddGroup || "TreeDD",
34341 scroll: this.ddScroll
34344 this.getSelectionModel().init(this);
34346 Roo.log("ROOT not set in tree");
34349 this.root.render();
34350 if(!this.rootVisible){
34351 this.root.renderChildren();
34357 * Ext JS Library 1.1.1
34358 * Copyright(c) 2006-2007, Ext JS, LLC.
34360 * Originally Released Under LGPL - original licence link has changed is not relivant.
34363 * <script type="text/javascript">
34368 * @class Roo.tree.DefaultSelectionModel
34369 * @extends Roo.util.Observable
34370 * The default single selection for a TreePanel.
34371 * @param {Object} cfg Configuration
34373 Roo.tree.DefaultSelectionModel = function(cfg){
34374 this.selNode = null;
34380 * @event selectionchange
34381 * Fires when the selected node changes
34382 * @param {DefaultSelectionModel} this
34383 * @param {TreeNode} node the new selection
34385 "selectionchange" : true,
34388 * @event beforeselect
34389 * Fires before the selected node changes, return false to cancel the change
34390 * @param {DefaultSelectionModel} this
34391 * @param {TreeNode} node the new selection
34392 * @param {TreeNode} node the old selection
34394 "beforeselect" : true
34397 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34400 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34401 init : function(tree){
34403 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34404 tree.on("click", this.onNodeClick, this);
34407 onNodeClick : function(node, e){
34408 if (e.ctrlKey && this.selNode == node) {
34409 this.unselect(node);
34417 * @param {TreeNode} node The node to select
34418 * @return {TreeNode} The selected node
34420 select : function(node){
34421 var last = this.selNode;
34422 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34424 last.ui.onSelectedChange(false);
34426 this.selNode = node;
34427 node.ui.onSelectedChange(true);
34428 this.fireEvent("selectionchange", this, node, last);
34435 * @param {TreeNode} node The node to unselect
34437 unselect : function(node){
34438 if(this.selNode == node){
34439 this.clearSelections();
34444 * Clear all selections
34446 clearSelections : function(){
34447 var n = this.selNode;
34449 n.ui.onSelectedChange(false);
34450 this.selNode = null;
34451 this.fireEvent("selectionchange", this, null);
34457 * Get the selected node
34458 * @return {TreeNode} The selected node
34460 getSelectedNode : function(){
34461 return this.selNode;
34465 * Returns true if the node is selected
34466 * @param {TreeNode} node The node to check
34467 * @return {Boolean}
34469 isSelected : function(node){
34470 return this.selNode == node;
34474 * Selects the node above the selected node in the tree, intelligently walking the nodes
34475 * @return TreeNode The new selection
34477 selectPrevious : function(){
34478 var s = this.selNode || this.lastSelNode;
34482 var ps = s.previousSibling;
34484 if(!ps.isExpanded() || ps.childNodes.length < 1){
34485 return this.select(ps);
34487 var lc = ps.lastChild;
34488 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34491 return this.select(lc);
34493 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34494 return this.select(s.parentNode);
34500 * Selects the node above the selected node in the tree, intelligently walking the nodes
34501 * @return TreeNode The new selection
34503 selectNext : function(){
34504 var s = this.selNode || this.lastSelNode;
34508 if(s.firstChild && s.isExpanded()){
34509 return this.select(s.firstChild);
34510 }else if(s.nextSibling){
34511 return this.select(s.nextSibling);
34512 }else if(s.parentNode){
34514 s.parentNode.bubble(function(){
34515 if(this.nextSibling){
34516 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34525 onKeyDown : function(e){
34526 var s = this.selNode || this.lastSelNode;
34527 // undesirable, but required
34532 var k = e.getKey();
34540 this.selectPrevious();
34543 e.preventDefault();
34544 if(s.hasChildNodes()){
34545 if(!s.isExpanded()){
34547 }else if(s.firstChild){
34548 this.select(s.firstChild, e);
34553 e.preventDefault();
34554 if(s.hasChildNodes() && s.isExpanded()){
34556 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34557 this.select(s.parentNode, e);
34565 * @class Roo.tree.MultiSelectionModel
34566 * @extends Roo.util.Observable
34567 * Multi selection for a TreePanel.
34568 * @param {Object} cfg Configuration
34570 Roo.tree.MultiSelectionModel = function(){
34571 this.selNodes = [];
34575 * @event selectionchange
34576 * Fires when the selected nodes change
34577 * @param {MultiSelectionModel} this
34578 * @param {Array} nodes Array of the selected nodes
34580 "selectionchange" : true
34582 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34586 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34587 init : function(tree){
34589 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34590 tree.on("click", this.onNodeClick, this);
34593 onNodeClick : function(node, e){
34594 this.select(node, e, e.ctrlKey);
34599 * @param {TreeNode} node The node to select
34600 * @param {EventObject} e (optional) An event associated with the selection
34601 * @param {Boolean} keepExisting True to retain existing selections
34602 * @return {TreeNode} The selected node
34604 select : function(node, e, keepExisting){
34605 if(keepExisting !== true){
34606 this.clearSelections(true);
34608 if(this.isSelected(node)){
34609 this.lastSelNode = node;
34612 this.selNodes.push(node);
34613 this.selMap[node.id] = node;
34614 this.lastSelNode = node;
34615 node.ui.onSelectedChange(true);
34616 this.fireEvent("selectionchange", this, this.selNodes);
34622 * @param {TreeNode} node The node to unselect
34624 unselect : function(node){
34625 if(this.selMap[node.id]){
34626 node.ui.onSelectedChange(false);
34627 var sn = this.selNodes;
34630 index = sn.indexOf(node);
34632 for(var i = 0, len = sn.length; i < len; i++){
34640 this.selNodes.splice(index, 1);
34642 delete this.selMap[node.id];
34643 this.fireEvent("selectionchange", this, this.selNodes);
34648 * Clear all selections
34650 clearSelections : function(suppressEvent){
34651 var sn = this.selNodes;
34653 for(var i = 0, len = sn.length; i < len; i++){
34654 sn[i].ui.onSelectedChange(false);
34656 this.selNodes = [];
34658 if(suppressEvent !== true){
34659 this.fireEvent("selectionchange", this, this.selNodes);
34665 * Returns true if the node is selected
34666 * @param {TreeNode} node The node to check
34667 * @return {Boolean}
34669 isSelected : function(node){
34670 return this.selMap[node.id] ? true : false;
34674 * Returns an array of the selected nodes
34677 getSelectedNodes : function(){
34678 return this.selNodes;
34681 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34683 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34685 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34688 * Ext JS Library 1.1.1
34689 * Copyright(c) 2006-2007, Ext JS, LLC.
34691 * Originally Released Under LGPL - original licence link has changed is not relivant.
34694 * <script type="text/javascript">
34698 * @class Roo.tree.TreeNode
34699 * @extends Roo.data.Node
34700 * @cfg {String} text The text for this node
34701 * @cfg {Boolean} expanded true to start the node expanded
34702 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34703 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34704 * @cfg {Boolean} disabled true to start the node disabled
34705 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34706 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34707 * @cfg {String} cls A css class to be added to the node
34708 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34709 * @cfg {String} href URL of the link used for the node (defaults to #)
34710 * @cfg {String} hrefTarget target frame for the link
34711 * @cfg {String} qtip An Ext QuickTip for the node
34712 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34713 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34714 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34715 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34716 * (defaults to undefined with no checkbox rendered)
34718 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34720 Roo.tree.TreeNode = function(attributes){
34721 attributes = attributes || {};
34722 if(typeof attributes == "string"){
34723 attributes = {text: attributes};
34725 this.childrenRendered = false;
34726 this.rendered = false;
34727 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34728 this.expanded = attributes.expanded === true;
34729 this.isTarget = attributes.isTarget !== false;
34730 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34731 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34734 * Read-only. The text for this node. To change it use setText().
34737 this.text = attributes.text;
34739 * True if this node is disabled.
34742 this.disabled = attributes.disabled === true;
34746 * @event textchange
34747 * Fires when the text for this node is changed
34748 * @param {Node} this This node
34749 * @param {String} text The new text
34750 * @param {String} oldText The old text
34752 "textchange" : true,
34754 * @event beforeexpand
34755 * Fires before this node is expanded, return false to cancel.
34756 * @param {Node} this This node
34757 * @param {Boolean} deep
34758 * @param {Boolean} anim
34760 "beforeexpand" : true,
34762 * @event beforecollapse
34763 * Fires before this node is collapsed, return false to cancel.
34764 * @param {Node} this This node
34765 * @param {Boolean} deep
34766 * @param {Boolean} anim
34768 "beforecollapse" : true,
34771 * Fires when this node is expanded
34772 * @param {Node} this This node
34776 * @event disabledchange
34777 * Fires when the disabled status of this node changes
34778 * @param {Node} this This node
34779 * @param {Boolean} disabled
34781 "disabledchange" : true,
34784 * Fires when this node is collapsed
34785 * @param {Node} this This node
34789 * @event beforeclick
34790 * Fires before click processing. Return false to cancel the default action.
34791 * @param {Node} this This node
34792 * @param {Roo.EventObject} e The event object
34794 "beforeclick":true,
34796 * @event checkchange
34797 * Fires when a node with a checkbox's checked property changes
34798 * @param {Node} this This node
34799 * @param {Boolean} checked
34801 "checkchange":true,
34804 * Fires when this node is clicked
34805 * @param {Node} this This node
34806 * @param {Roo.EventObject} e The event object
34811 * Fires when this node is double clicked
34812 * @param {Node} this This node
34813 * @param {Roo.EventObject} e The event object
34817 * @event contextmenu
34818 * Fires when this node is right clicked
34819 * @param {Node} this This node
34820 * @param {Roo.EventObject} e The event object
34822 "contextmenu":true,
34824 * @event beforechildrenrendered
34825 * Fires right before the child nodes for this node are rendered
34826 * @param {Node} this This node
34828 "beforechildrenrendered":true
34831 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34834 * Read-only. The UI for this node
34837 this.ui = new uiClass(this);
34839 // finally support items[]
34840 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34845 Roo.each(this.attributes.items, function(c) {
34846 this.appendChild(Roo.factory(c,Roo.Tree));
34848 delete this.attributes.items;
34853 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34854 preventHScroll: true,
34856 * Returns true if this node is expanded
34857 * @return {Boolean}
34859 isExpanded : function(){
34860 return this.expanded;
34864 * Returns the UI object for this node
34865 * @return {TreeNodeUI}
34867 getUI : function(){
34871 // private override
34872 setFirstChild : function(node){
34873 var of = this.firstChild;
34874 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
34875 if(this.childrenRendered && of && node != of){
34876 of.renderIndent(true, true);
34879 this.renderIndent(true, true);
34883 // private override
34884 setLastChild : function(node){
34885 var ol = this.lastChild;
34886 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
34887 if(this.childrenRendered && ol && node != ol){
34888 ol.renderIndent(true, true);
34891 this.renderIndent(true, true);
34895 // these methods are overridden to provide lazy rendering support
34896 // private override
34897 appendChild : function()
34899 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
34900 if(node && this.childrenRendered){
34903 this.ui.updateExpandIcon();
34907 // private override
34908 removeChild : function(node){
34909 this.ownerTree.getSelectionModel().unselect(node);
34910 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
34911 // if it's been rendered remove dom node
34912 if(this.childrenRendered){
34915 if(this.childNodes.length < 1){
34916 this.collapse(false, false);
34918 this.ui.updateExpandIcon();
34920 if(!this.firstChild) {
34921 this.childrenRendered = false;
34926 // private override
34927 insertBefore : function(node, refNode){
34928 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
34929 if(newNode && refNode && this.childrenRendered){
34932 this.ui.updateExpandIcon();
34937 * Sets the text for this node
34938 * @param {String} text
34940 setText : function(text){
34941 var oldText = this.text;
34943 this.attributes.text = text;
34944 if(this.rendered){ // event without subscribing
34945 this.ui.onTextChange(this, text, oldText);
34947 this.fireEvent("textchange", this, text, oldText);
34951 * Triggers selection of this node
34953 select : function(){
34954 this.getOwnerTree().getSelectionModel().select(this);
34958 * Triggers deselection of this node
34960 unselect : function(){
34961 this.getOwnerTree().getSelectionModel().unselect(this);
34965 * Returns true if this node is selected
34966 * @return {Boolean}
34968 isSelected : function(){
34969 return this.getOwnerTree().getSelectionModel().isSelected(this);
34973 * Expand this node.
34974 * @param {Boolean} deep (optional) True to expand all children as well
34975 * @param {Boolean} anim (optional) false to cancel the default animation
34976 * @param {Function} callback (optional) A callback to be called when
34977 * expanding this node completes (does not wait for deep expand to complete).
34978 * Called with 1 parameter, this node.
34980 expand : function(deep, anim, callback){
34981 if(!this.expanded){
34982 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
34985 if(!this.childrenRendered){
34986 this.renderChildren();
34988 this.expanded = true;
34989 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
34990 this.ui.animExpand(function(){
34991 this.fireEvent("expand", this);
34992 if(typeof callback == "function"){
34996 this.expandChildNodes(true);
34998 }.createDelegate(this));
35002 this.fireEvent("expand", this);
35003 if(typeof callback == "function"){
35008 if(typeof callback == "function"){
35013 this.expandChildNodes(true);
35017 isHiddenRoot : function(){
35018 return this.isRoot && !this.getOwnerTree().rootVisible;
35022 * Collapse this node.
35023 * @param {Boolean} deep (optional) True to collapse all children as well
35024 * @param {Boolean} anim (optional) false to cancel the default animation
35026 collapse : function(deep, anim){
35027 if(this.expanded && !this.isHiddenRoot()){
35028 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35031 this.expanded = false;
35032 if((this.getOwnerTree().animate && anim !== false) || anim){
35033 this.ui.animCollapse(function(){
35034 this.fireEvent("collapse", this);
35036 this.collapseChildNodes(true);
35038 }.createDelegate(this));
35041 this.ui.collapse();
35042 this.fireEvent("collapse", this);
35046 var cs = this.childNodes;
35047 for(var i = 0, len = cs.length; i < len; i++) {
35048 cs[i].collapse(true, false);
35054 delayedExpand : function(delay){
35055 if(!this.expandProcId){
35056 this.expandProcId = this.expand.defer(delay, this);
35061 cancelExpand : function(){
35062 if(this.expandProcId){
35063 clearTimeout(this.expandProcId);
35065 this.expandProcId = false;
35069 * Toggles expanded/collapsed state of the node
35071 toggle : function(){
35080 * Ensures all parent nodes are expanded
35082 ensureVisible : function(callback){
35083 var tree = this.getOwnerTree();
35084 tree.expandPath(this.parentNode.getPath(), false, function(){
35085 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35086 Roo.callback(callback);
35087 }.createDelegate(this));
35091 * Expand all child nodes
35092 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35094 expandChildNodes : function(deep){
35095 var cs = this.childNodes;
35096 for(var i = 0, len = cs.length; i < len; i++) {
35097 cs[i].expand(deep);
35102 * Collapse all child nodes
35103 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35105 collapseChildNodes : function(deep){
35106 var cs = this.childNodes;
35107 for(var i = 0, len = cs.length; i < len; i++) {
35108 cs[i].collapse(deep);
35113 * Disables this node
35115 disable : function(){
35116 this.disabled = true;
35118 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35119 this.ui.onDisableChange(this, true);
35121 this.fireEvent("disabledchange", this, true);
35125 * Enables this node
35127 enable : function(){
35128 this.disabled = false;
35129 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35130 this.ui.onDisableChange(this, false);
35132 this.fireEvent("disabledchange", this, false);
35136 renderChildren : function(suppressEvent){
35137 if(suppressEvent !== false){
35138 this.fireEvent("beforechildrenrendered", this);
35140 var cs = this.childNodes;
35141 for(var i = 0, len = cs.length; i < len; i++){
35142 cs[i].render(true);
35144 this.childrenRendered = true;
35148 sort : function(fn, scope){
35149 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35150 if(this.childrenRendered){
35151 var cs = this.childNodes;
35152 for(var i = 0, len = cs.length; i < len; i++){
35153 cs[i].render(true);
35159 render : function(bulkRender){
35160 this.ui.render(bulkRender);
35161 if(!this.rendered){
35162 this.rendered = true;
35164 this.expanded = false;
35165 this.expand(false, false);
35171 renderIndent : function(deep, refresh){
35173 this.ui.childIndent = null;
35175 this.ui.renderIndent();
35176 if(deep === true && this.childrenRendered){
35177 var cs = this.childNodes;
35178 for(var i = 0, len = cs.length; i < len; i++){
35179 cs[i].renderIndent(true, refresh);
35185 * Ext JS Library 1.1.1
35186 * Copyright(c) 2006-2007, Ext JS, LLC.
35188 * Originally Released Under LGPL - original licence link has changed is not relivant.
35191 * <script type="text/javascript">
35195 * @class Roo.tree.AsyncTreeNode
35196 * @extends Roo.tree.TreeNode
35197 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35199 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35201 Roo.tree.AsyncTreeNode = function(config){
35202 this.loaded = false;
35203 this.loading = false;
35204 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35206 * @event beforeload
35207 * Fires before this node is loaded, return false to cancel
35208 * @param {Node} this This node
35210 this.addEvents({'beforeload':true, 'load': true});
35213 * Fires when this node is loaded
35214 * @param {Node} this This node
35217 * The loader used by this node (defaults to using the tree's defined loader)
35222 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35223 expand : function(deep, anim, callback){
35224 if(this.loading){ // if an async load is already running, waiting til it's done
35226 var f = function(){
35227 if(!this.loading){ // done loading
35228 clearInterval(timer);
35229 this.expand(deep, anim, callback);
35231 }.createDelegate(this);
35232 timer = setInterval(f, 200);
35236 if(this.fireEvent("beforeload", this) === false){
35239 this.loading = true;
35240 this.ui.beforeLoad(this);
35241 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35243 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35247 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35251 * Returns true if this node is currently loading
35252 * @return {Boolean}
35254 isLoading : function(){
35255 return this.loading;
35258 loadComplete : function(deep, anim, callback){
35259 this.loading = false;
35260 this.loaded = true;
35261 this.ui.afterLoad(this);
35262 this.fireEvent("load", this);
35263 this.expand(deep, anim, callback);
35267 * Returns true if this node has been loaded
35268 * @return {Boolean}
35270 isLoaded : function(){
35271 return this.loaded;
35274 hasChildNodes : function(){
35275 if(!this.isLeaf() && !this.loaded){
35278 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35283 * Trigger a reload for this node
35284 * @param {Function} callback
35286 reload : function(callback){
35287 this.collapse(false, false);
35288 while(this.firstChild){
35289 this.removeChild(this.firstChild);
35291 this.childrenRendered = false;
35292 this.loaded = false;
35293 if(this.isHiddenRoot()){
35294 this.expanded = false;
35296 this.expand(false, false, callback);
35300 * Ext JS Library 1.1.1
35301 * Copyright(c) 2006-2007, Ext JS, LLC.
35303 * Originally Released Under LGPL - original licence link has changed is not relivant.
35306 * <script type="text/javascript">
35310 * @class Roo.tree.TreeNodeUI
35312 * @param {Object} node The node to render
35313 * The TreeNode UI implementation is separate from the
35314 * tree implementation. Unless you are customizing the tree UI,
35315 * you should never have to use this directly.
35317 Roo.tree.TreeNodeUI = function(node){
35319 this.rendered = false;
35320 this.animating = false;
35321 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35324 Roo.tree.TreeNodeUI.prototype = {
35325 removeChild : function(node){
35327 this.ctNode.removeChild(node.ui.getEl());
35331 beforeLoad : function(){
35332 this.addClass("x-tree-node-loading");
35335 afterLoad : function(){
35336 this.removeClass("x-tree-node-loading");
35339 onTextChange : function(node, text, oldText){
35341 this.textNode.innerHTML = text;
35345 onDisableChange : function(node, state){
35346 this.disabled = state;
35348 this.addClass("x-tree-node-disabled");
35350 this.removeClass("x-tree-node-disabled");
35354 onSelectedChange : function(state){
35357 this.addClass("x-tree-selected");
35360 this.removeClass("x-tree-selected");
35364 onMove : function(tree, node, oldParent, newParent, index, refNode){
35365 this.childIndent = null;
35367 var targetNode = newParent.ui.getContainer();
35368 if(!targetNode){//target not rendered
35369 this.holder = document.createElement("div");
35370 this.holder.appendChild(this.wrap);
35373 var insertBefore = refNode ? refNode.ui.getEl() : null;
35375 targetNode.insertBefore(this.wrap, insertBefore);
35377 targetNode.appendChild(this.wrap);
35379 this.node.renderIndent(true);
35383 addClass : function(cls){
35385 Roo.fly(this.elNode).addClass(cls);
35389 removeClass : function(cls){
35391 Roo.fly(this.elNode).removeClass(cls);
35395 remove : function(){
35397 this.holder = document.createElement("div");
35398 this.holder.appendChild(this.wrap);
35402 fireEvent : function(){
35403 return this.node.fireEvent.apply(this.node, arguments);
35406 initEvents : function(){
35407 this.node.on("move", this.onMove, this);
35408 var E = Roo.EventManager;
35409 var a = this.anchor;
35411 var el = Roo.fly(a, '_treeui');
35413 if(Roo.isOpera){ // opera render bug ignores the CSS
35414 el.setStyle("text-decoration", "none");
35417 el.on("click", this.onClick, this);
35418 el.on("dblclick", this.onDblClick, this);
35421 Roo.EventManager.on(this.checkbox,
35422 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35425 el.on("contextmenu", this.onContextMenu, this);
35427 var icon = Roo.fly(this.iconNode);
35428 icon.on("click", this.onClick, this);
35429 icon.on("dblclick", this.onDblClick, this);
35430 icon.on("contextmenu", this.onContextMenu, this);
35431 E.on(this.ecNode, "click", this.ecClick, this, true);
35433 if(this.node.disabled){
35434 this.addClass("x-tree-node-disabled");
35436 if(this.node.hidden){
35437 this.addClass("x-tree-node-disabled");
35439 var ot = this.node.getOwnerTree();
35440 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35441 if(dd && (!this.node.isRoot || ot.rootVisible)){
35442 Roo.dd.Registry.register(this.elNode, {
35444 handles: this.getDDHandles(),
35450 getDDHandles : function(){
35451 return [this.iconNode, this.textNode];
35456 this.wrap.style.display = "none";
35462 this.wrap.style.display = "";
35466 onContextMenu : function(e){
35467 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35468 e.preventDefault();
35470 this.fireEvent("contextmenu", this.node, e);
35474 onClick : function(e){
35479 if(this.fireEvent("beforeclick", this.node, e) !== false){
35480 if(!this.disabled && this.node.attributes.href){
35481 this.fireEvent("click", this.node, e);
35484 e.preventDefault();
35489 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35490 this.node.toggle();
35493 this.fireEvent("click", this.node, e);
35499 onDblClick : function(e){
35500 e.preventDefault();
35505 this.toggleCheck();
35507 if(!this.animating && this.node.hasChildNodes()){
35508 this.node.toggle();
35510 this.fireEvent("dblclick", this.node, e);
35513 onCheckChange : function(){
35514 var checked = this.checkbox.checked;
35515 this.node.attributes.checked = checked;
35516 this.fireEvent('checkchange', this.node, checked);
35519 ecClick : function(e){
35520 if(!this.animating && this.node.hasChildNodes()){
35521 this.node.toggle();
35525 startDrop : function(){
35526 this.dropping = true;
35529 // delayed drop so the click event doesn't get fired on a drop
35530 endDrop : function(){
35531 setTimeout(function(){
35532 this.dropping = false;
35533 }.createDelegate(this), 50);
35536 expand : function(){
35537 this.updateExpandIcon();
35538 this.ctNode.style.display = "";
35541 focus : function(){
35542 if(!this.node.preventHScroll){
35543 try{this.anchor.focus();
35545 }else if(!Roo.isIE){
35547 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35548 var l = noscroll.scrollLeft;
35549 this.anchor.focus();
35550 noscroll.scrollLeft = l;
35555 toggleCheck : function(value){
35556 var cb = this.checkbox;
35558 cb.checked = (value === undefined ? !cb.checked : value);
35564 this.anchor.blur();
35568 animExpand : function(callback){
35569 var ct = Roo.get(this.ctNode);
35571 if(!this.node.hasChildNodes()){
35572 this.updateExpandIcon();
35573 this.ctNode.style.display = "";
35574 Roo.callback(callback);
35577 this.animating = true;
35578 this.updateExpandIcon();
35581 callback : function(){
35582 this.animating = false;
35583 Roo.callback(callback);
35586 duration: this.node.ownerTree.duration || .25
35590 highlight : function(){
35591 var tree = this.node.getOwnerTree();
35592 Roo.fly(this.wrap).highlight(
35593 tree.hlColor || "C3DAF9",
35594 {endColor: tree.hlBaseColor}
35598 collapse : function(){
35599 this.updateExpandIcon();
35600 this.ctNode.style.display = "none";
35603 animCollapse : function(callback){
35604 var ct = Roo.get(this.ctNode);
35605 ct.enableDisplayMode('block');
35608 this.animating = true;
35609 this.updateExpandIcon();
35612 callback : function(){
35613 this.animating = false;
35614 Roo.callback(callback);
35617 duration: this.node.ownerTree.duration || .25
35621 getContainer : function(){
35622 return this.ctNode;
35625 getEl : function(){
35629 appendDDGhost : function(ghostNode){
35630 ghostNode.appendChild(this.elNode.cloneNode(true));
35633 getDDRepairXY : function(){
35634 return Roo.lib.Dom.getXY(this.iconNode);
35637 onRender : function(){
35641 render : function(bulkRender){
35642 var n = this.node, a = n.attributes;
35643 var targetNode = n.parentNode ?
35644 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35646 if(!this.rendered){
35647 this.rendered = true;
35649 this.renderElements(n, a, targetNode, bulkRender);
35652 if(this.textNode.setAttributeNS){
35653 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35655 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35658 this.textNode.setAttribute("ext:qtip", a.qtip);
35660 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35663 }else if(a.qtipCfg){
35664 a.qtipCfg.target = Roo.id(this.textNode);
35665 Roo.QuickTips.register(a.qtipCfg);
35668 if(!this.node.expanded){
35669 this.updateExpandIcon();
35672 if(bulkRender === true) {
35673 targetNode.appendChild(this.wrap);
35678 renderElements : function(n, a, targetNode, bulkRender)
35680 // add some indent caching, this helps performance when rendering a large tree
35681 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35682 var t = n.getOwnerTree();
35683 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35684 if (typeof(n.attributes.html) != 'undefined') {
35685 txt = n.attributes.html;
35687 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35688 var cb = typeof a.checked == 'boolean';
35689 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35690 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35691 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35692 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35693 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35694 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35695 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35696 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35697 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35698 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35701 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35702 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35703 n.nextSibling.ui.getEl(), buf.join(""));
35705 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35708 this.elNode = this.wrap.childNodes[0];
35709 this.ctNode = this.wrap.childNodes[1];
35710 var cs = this.elNode.childNodes;
35711 this.indentNode = cs[0];
35712 this.ecNode = cs[1];
35713 this.iconNode = cs[2];
35716 this.checkbox = cs[3];
35719 this.anchor = cs[index];
35720 this.textNode = cs[index].firstChild;
35723 getAnchor : function(){
35724 return this.anchor;
35727 getTextEl : function(){
35728 return this.textNode;
35731 getIconEl : function(){
35732 return this.iconNode;
35735 isChecked : function(){
35736 return this.checkbox ? this.checkbox.checked : false;
35739 updateExpandIcon : function(){
35741 var n = this.node, c1, c2;
35742 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35743 var hasChild = n.hasChildNodes();
35747 c1 = "x-tree-node-collapsed";
35748 c2 = "x-tree-node-expanded";
35751 c1 = "x-tree-node-expanded";
35752 c2 = "x-tree-node-collapsed";
35755 this.removeClass("x-tree-node-leaf");
35756 this.wasLeaf = false;
35758 if(this.c1 != c1 || this.c2 != c2){
35759 Roo.fly(this.elNode).replaceClass(c1, c2);
35760 this.c1 = c1; this.c2 = c2;
35763 // this changes non-leafs into leafs if they have no children.
35764 // it's not very rational behaviour..
35766 if(!this.wasLeaf && this.node.leaf){
35767 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35770 this.wasLeaf = true;
35773 var ecc = "x-tree-ec-icon "+cls;
35774 if(this.ecc != ecc){
35775 this.ecNode.className = ecc;
35781 getChildIndent : function(){
35782 if(!this.childIndent){
35786 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35788 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35790 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35795 this.childIndent = buf.join("");
35797 return this.childIndent;
35800 renderIndent : function(){
35803 var p = this.node.parentNode;
35805 indent = p.ui.getChildIndent();
35807 if(this.indentMarkup != indent){ // don't rerender if not required
35808 this.indentNode.innerHTML = indent;
35809 this.indentMarkup = indent;
35811 this.updateExpandIcon();
35816 Roo.tree.RootTreeNodeUI = function(){
35817 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35819 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35820 render : function(){
35821 if(!this.rendered){
35822 var targetNode = this.node.ownerTree.innerCt.dom;
35823 this.node.expanded = true;
35824 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35825 this.wrap = this.ctNode = targetNode.firstChild;
35828 collapse : function(){
35830 expand : function(){
35834 * Ext JS Library 1.1.1
35835 * Copyright(c) 2006-2007, Ext JS, LLC.
35837 * Originally Released Under LGPL - original licence link has changed is not relivant.
35840 * <script type="text/javascript">
35843 * @class Roo.tree.TreeLoader
35844 * @extends Roo.util.Observable
35845 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35846 * nodes from a specified URL. The response must be a javascript Array definition
35847 * who's elements are node definition objects. eg:
35852 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35853 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
35860 * The old style respose with just an array is still supported, but not recommended.
35863 * A server request is sent, and child nodes are loaded only when a node is expanded.
35864 * The loading node's id is passed to the server under the parameter name "node" to
35865 * enable the server to produce the correct child nodes.
35867 * To pass extra parameters, an event handler may be attached to the "beforeload"
35868 * event, and the parameters specified in the TreeLoader's baseParams property:
35870 myTreeLoader.on("beforeload", function(treeLoader, node) {
35871 this.baseParams.category = node.attributes.category;
35874 * This would pass an HTTP parameter called "category" to the server containing
35875 * the value of the Node's "category" attribute.
35877 * Creates a new Treeloader.
35878 * @param {Object} config A config object containing config properties.
35880 Roo.tree.TreeLoader = function(config){
35881 this.baseParams = {};
35882 this.requestMethod = "POST";
35883 Roo.apply(this, config);
35888 * @event beforeload
35889 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
35890 * @param {Object} This TreeLoader object.
35891 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35892 * @param {Object} callback The callback function specified in the {@link #load} call.
35897 * Fires when the node has been successfuly loaded.
35898 * @param {Object} This TreeLoader object.
35899 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35900 * @param {Object} response The response object containing the data from the server.
35904 * @event loadexception
35905 * Fires if the network request failed.
35906 * @param {Object} This TreeLoader object.
35907 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35908 * @param {Object} response The response object containing the data from the server.
35910 loadexception : true,
35913 * Fires before a node is created, enabling you to return custom Node types
35914 * @param {Object} This TreeLoader object.
35915 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
35920 Roo.tree.TreeLoader.superclass.constructor.call(this);
35923 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
35925 * @cfg {String} dataUrl The URL from which to request a Json string which
35926 * specifies an array of node definition object representing the child nodes
35930 * @cfg {String} requestMethod either GET or POST
35931 * defaults to POST (due to BC)
35935 * @cfg {Object} baseParams (optional) An object containing properties which
35936 * specify HTTP parameters to be passed to each request for child nodes.
35939 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
35940 * created by this loader. If the attributes sent by the server have an attribute in this object,
35941 * they take priority.
35944 * @cfg {Object} uiProviders (optional) An object containing properties which
35946 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
35947 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
35948 * <i>uiProvider</i> attribute of a returned child node is a string rather
35949 * than a reference to a TreeNodeUI implementation, this that string value
35950 * is used as a property name in the uiProviders object. You can define the provider named
35951 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
35956 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
35957 * child nodes before loading.
35959 clearOnLoad : true,
35962 * @cfg {String} root (optional) Default to false. Use this to read data from an object
35963 * property on loading, rather than expecting an array. (eg. more compatible to a standard
35964 * Grid query { data : [ .....] }
35969 * @cfg {String} queryParam (optional)
35970 * Name of the query as it will be passed on the querystring (defaults to 'node')
35971 * eg. the request will be ?node=[id]
35978 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
35979 * This is called automatically when a node is expanded, but may be used to reload
35980 * a node (or append new children if the {@link #clearOnLoad} option is false.)
35981 * @param {Roo.tree.TreeNode} node
35982 * @param {Function} callback
35984 load : function(node, callback){
35985 if(this.clearOnLoad){
35986 while(node.firstChild){
35987 node.removeChild(node.firstChild);
35990 if(node.attributes.children){ // preloaded json children
35991 var cs = node.attributes.children;
35992 for(var i = 0, len = cs.length; i < len; i++){
35993 node.appendChild(this.createNode(cs[i]));
35995 if(typeof callback == "function"){
35998 }else if(this.dataUrl){
35999 this.requestData(node, callback);
36003 getParams: function(node){
36004 var buf = [], bp = this.baseParams;
36005 for(var key in bp){
36006 if(typeof bp[key] != "function"){
36007 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36010 var n = this.queryParam === false ? 'node' : this.queryParam;
36011 buf.push(n + "=", encodeURIComponent(node.id));
36012 return buf.join("");
36015 requestData : function(node, callback){
36016 if(this.fireEvent("beforeload", this, node, callback) !== false){
36017 this.transId = Roo.Ajax.request({
36018 method:this.requestMethod,
36019 url: this.dataUrl||this.url,
36020 success: this.handleResponse,
36021 failure: this.handleFailure,
36023 argument: {callback: callback, node: node},
36024 params: this.getParams(node)
36027 // if the load is cancelled, make sure we notify
36028 // the node that we are done
36029 if(typeof callback == "function"){
36035 isLoading : function(){
36036 return this.transId ? true : false;
36039 abort : function(){
36040 if(this.isLoading()){
36041 Roo.Ajax.abort(this.transId);
36046 createNode : function(attr)
36048 // apply baseAttrs, nice idea Corey!
36049 if(this.baseAttrs){
36050 Roo.applyIf(attr, this.baseAttrs);
36052 if(this.applyLoader !== false){
36053 attr.loader = this;
36055 // uiProvider = depreciated..
36057 if(typeof(attr.uiProvider) == 'string'){
36058 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36059 /** eval:var:attr */ eval(attr.uiProvider);
36061 if(typeof(this.uiProviders['default']) != 'undefined') {
36062 attr.uiProvider = this.uiProviders['default'];
36065 this.fireEvent('create', this, attr);
36067 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36069 new Roo.tree.TreeNode(attr) :
36070 new Roo.tree.AsyncTreeNode(attr));
36073 processResponse : function(response, node, callback)
36075 var json = response.responseText;
36078 var o = Roo.decode(json);
36080 if (this.root === false && typeof(o.success) != undefined) {
36081 this.root = 'data'; // the default behaviour for list like data..
36084 if (this.root !== false && !o.success) {
36085 // it's a failure condition.
36086 var a = response.argument;
36087 this.fireEvent("loadexception", this, a.node, response);
36088 Roo.log("Load failed - should have a handler really");
36094 if (this.root !== false) {
36098 for(var i = 0, len = o.length; i < len; i++){
36099 var n = this.createNode(o[i]);
36101 node.appendChild(n);
36104 if(typeof callback == "function"){
36105 callback(this, node);
36108 this.handleFailure(response);
36112 handleResponse : function(response){
36113 this.transId = false;
36114 var a = response.argument;
36115 this.processResponse(response, a.node, a.callback);
36116 this.fireEvent("load", this, a.node, response);
36119 handleFailure : function(response)
36121 // should handle failure better..
36122 this.transId = false;
36123 var a = response.argument;
36124 this.fireEvent("loadexception", this, a.node, response);
36125 if(typeof a.callback == "function"){
36126 a.callback(this, a.node);
36131 * Ext JS Library 1.1.1
36132 * Copyright(c) 2006-2007, Ext JS, LLC.
36134 * Originally Released Under LGPL - original licence link has changed is not relivant.
36137 * <script type="text/javascript">
36141 * @class Roo.tree.TreeFilter
36142 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36143 * @param {TreePanel} tree
36144 * @param {Object} config (optional)
36146 Roo.tree.TreeFilter = function(tree, config){
36148 this.filtered = {};
36149 Roo.apply(this, config);
36152 Roo.tree.TreeFilter.prototype = {
36159 * Filter the data by a specific attribute.
36160 * @param {String/RegExp} value Either string that the attribute value
36161 * should start with or a RegExp to test against the attribute
36162 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36163 * @param {TreeNode} startNode (optional) The node to start the filter at.
36165 filter : function(value, attr, startNode){
36166 attr = attr || "text";
36168 if(typeof value == "string"){
36169 var vlen = value.length;
36170 // auto clear empty filter
36171 if(vlen == 0 && this.clearBlank){
36175 value = value.toLowerCase();
36177 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36179 }else if(value.exec){ // regex?
36181 return value.test(n.attributes[attr]);
36184 throw 'Illegal filter type, must be string or regex';
36186 this.filterBy(f, null, startNode);
36190 * Filter by a function. The passed function will be called with each
36191 * node in the tree (or from the startNode). If the function returns true, the node is kept
36192 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36193 * @param {Function} fn The filter function
36194 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36196 filterBy : function(fn, scope, startNode){
36197 startNode = startNode || this.tree.root;
36198 if(this.autoClear){
36201 var af = this.filtered, rv = this.reverse;
36202 var f = function(n){
36203 if(n == startNode){
36209 var m = fn.call(scope || n, n);
36217 startNode.cascade(f);
36220 if(typeof id != "function"){
36222 if(n && n.parentNode){
36223 n.parentNode.removeChild(n);
36231 * Clears the current filter. Note: with the "remove" option
36232 * set a filter cannot be cleared.
36234 clear : function(){
36236 var af = this.filtered;
36238 if(typeof id != "function"){
36245 this.filtered = {};
36250 * Ext JS Library 1.1.1
36251 * Copyright(c) 2006-2007, Ext JS, LLC.
36253 * Originally Released Under LGPL - original licence link has changed is not relivant.
36256 * <script type="text/javascript">
36261 * @class Roo.tree.TreeSorter
36262 * Provides sorting of nodes in a TreePanel
36264 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36265 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36266 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36267 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36268 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36269 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36271 * @param {TreePanel} tree
36272 * @param {Object} config
36274 Roo.tree.TreeSorter = function(tree, config){
36275 Roo.apply(this, config);
36276 tree.on("beforechildrenrendered", this.doSort, this);
36277 tree.on("append", this.updateSort, this);
36278 tree.on("insert", this.updateSort, this);
36280 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36281 var p = this.property || "text";
36282 var sortType = this.sortType;
36283 var fs = this.folderSort;
36284 var cs = this.caseSensitive === true;
36285 var leafAttr = this.leafAttr || 'leaf';
36287 this.sortFn = function(n1, n2){
36289 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36292 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36296 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36297 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36299 return dsc ? +1 : -1;
36301 return dsc ? -1 : +1;
36308 Roo.tree.TreeSorter.prototype = {
36309 doSort : function(node){
36310 node.sort(this.sortFn);
36313 compareNodes : function(n1, n2){
36314 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36317 updateSort : function(tree, node){
36318 if(node.childrenRendered){
36319 this.doSort.defer(1, this, [node]);
36324 * Ext JS Library 1.1.1
36325 * Copyright(c) 2006-2007, Ext JS, LLC.
36327 * Originally Released Under LGPL - original licence link has changed is not relivant.
36330 * <script type="text/javascript">
36333 if(Roo.dd.DropZone){
36335 Roo.tree.TreeDropZone = function(tree, config){
36336 this.allowParentInsert = false;
36337 this.allowContainerDrop = false;
36338 this.appendOnly = false;
36339 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36341 this.lastInsertClass = "x-tree-no-status";
36342 this.dragOverData = {};
36345 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36346 ddGroup : "TreeDD",
36349 expandDelay : 1000,
36351 expandNode : function(node){
36352 if(node.hasChildNodes() && !node.isExpanded()){
36353 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36357 queueExpand : function(node){
36358 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36361 cancelExpand : function(){
36362 if(this.expandProcId){
36363 clearTimeout(this.expandProcId);
36364 this.expandProcId = false;
36368 isValidDropPoint : function(n, pt, dd, e, data){
36369 if(!n || !data){ return false; }
36370 var targetNode = n.node;
36371 var dropNode = data.node;
36372 // default drop rules
36373 if(!(targetNode && targetNode.isTarget && pt)){
36376 if(pt == "append" && targetNode.allowChildren === false){
36379 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36382 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36385 // reuse the object
36386 var overEvent = this.dragOverData;
36387 overEvent.tree = this.tree;
36388 overEvent.target = targetNode;
36389 overEvent.data = data;
36390 overEvent.point = pt;
36391 overEvent.source = dd;
36392 overEvent.rawEvent = e;
36393 overEvent.dropNode = dropNode;
36394 overEvent.cancel = false;
36395 var result = this.tree.fireEvent("nodedragover", overEvent);
36396 return overEvent.cancel === false && result !== false;
36399 getDropPoint : function(e, n, dd)
36403 return tn.allowChildren !== false ? "append" : false; // always append for root
36405 var dragEl = n.ddel;
36406 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36407 var y = Roo.lib.Event.getPageY(e);
36408 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36410 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36411 var noAppend = tn.allowChildren === false;
36412 if(this.appendOnly || tn.parentNode.allowChildren === false){
36413 return noAppend ? false : "append";
36415 var noBelow = false;
36416 if(!this.allowParentInsert){
36417 noBelow = tn.hasChildNodes() && tn.isExpanded();
36419 var q = (b - t) / (noAppend ? 2 : 3);
36420 if(y >= t && y < (t + q)){
36422 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36429 onNodeEnter : function(n, dd, e, data)
36431 this.cancelExpand();
36434 onNodeOver : function(n, dd, e, data)
36437 var pt = this.getDropPoint(e, n, dd);
36440 // auto node expand check
36441 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36442 this.queueExpand(node);
36443 }else if(pt != "append"){
36444 this.cancelExpand();
36447 // set the insert point style on the target node
36448 var returnCls = this.dropNotAllowed;
36449 if(this.isValidDropPoint(n, pt, dd, e, data)){
36454 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36455 cls = "x-tree-drag-insert-above";
36456 }else if(pt == "below"){
36457 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36458 cls = "x-tree-drag-insert-below";
36460 returnCls = "x-tree-drop-ok-append";
36461 cls = "x-tree-drag-append";
36463 if(this.lastInsertClass != cls){
36464 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36465 this.lastInsertClass = cls;
36472 onNodeOut : function(n, dd, e, data){
36474 this.cancelExpand();
36475 this.removeDropIndicators(n);
36478 onNodeDrop : function(n, dd, e, data){
36479 var point = this.getDropPoint(e, n, dd);
36480 var targetNode = n.node;
36481 targetNode.ui.startDrop();
36482 if(!this.isValidDropPoint(n, point, dd, e, data)){
36483 targetNode.ui.endDrop();
36486 // first try to find the drop node
36487 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36490 target: targetNode,
36495 dropNode: dropNode,
36498 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36499 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36500 targetNode.ui.endDrop();
36503 // allow target changing
36504 targetNode = dropEvent.target;
36505 if(point == "append" && !targetNode.isExpanded()){
36506 targetNode.expand(false, null, function(){
36507 this.completeDrop(dropEvent);
36508 }.createDelegate(this));
36510 this.completeDrop(dropEvent);
36515 completeDrop : function(de){
36516 var ns = de.dropNode, p = de.point, t = de.target;
36517 if(!(ns instanceof Array)){
36521 for(var i = 0, len = ns.length; i < len; i++){
36524 t.parentNode.insertBefore(n, t);
36525 }else if(p == "below"){
36526 t.parentNode.insertBefore(n, t.nextSibling);
36532 if(this.tree.hlDrop){
36536 this.tree.fireEvent("nodedrop", de);
36539 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36540 if(this.tree.hlDrop){
36541 dropNode.ui.focus();
36542 dropNode.ui.highlight();
36544 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36547 getTree : function(){
36551 removeDropIndicators : function(n){
36554 Roo.fly(el).removeClass([
36555 "x-tree-drag-insert-above",
36556 "x-tree-drag-insert-below",
36557 "x-tree-drag-append"]);
36558 this.lastInsertClass = "_noclass";
36562 beforeDragDrop : function(target, e, id){
36563 this.cancelExpand();
36567 afterRepair : function(data){
36568 if(data && Roo.enableFx){
36569 data.node.ui.highlight();
36579 * Ext JS Library 1.1.1
36580 * Copyright(c) 2006-2007, Ext JS, LLC.
36582 * Originally Released Under LGPL - original licence link has changed is not relivant.
36585 * <script type="text/javascript">
36589 if(Roo.dd.DragZone){
36590 Roo.tree.TreeDragZone = function(tree, config){
36591 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36595 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36596 ddGroup : "TreeDD",
36598 onBeforeDrag : function(data, e){
36600 return n && n.draggable && !n.disabled;
36604 onInitDrag : function(e){
36605 var data = this.dragData;
36606 this.tree.getSelectionModel().select(data.node);
36607 this.proxy.update("");
36608 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36609 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36612 getRepairXY : function(e, data){
36613 return data.node.ui.getDDRepairXY();
36616 onEndDrag : function(data, e){
36617 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36622 onValidDrop : function(dd, e, id){
36623 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36627 beforeInvalidDrop : function(e, id){
36628 // this scrolls the original position back into view
36629 var sm = this.tree.getSelectionModel();
36630 sm.clearSelections();
36631 sm.select(this.dragData.node);
36636 * Ext JS Library 1.1.1
36637 * Copyright(c) 2006-2007, Ext JS, LLC.
36639 * Originally Released Under LGPL - original licence link has changed is not relivant.
36642 * <script type="text/javascript">
36645 * @class Roo.tree.TreeEditor
36646 * @extends Roo.Editor
36647 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36648 * as the editor field.
36650 * @param {Object} config (used to be the tree panel.)
36651 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36653 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36654 * @cfg {Roo.form.TextField|Object} field The field configuration
36658 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36661 if (oldconfig) { // old style..
36662 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36665 tree = config.tree;
36666 config.field = config.field || {};
36667 config.field.xtype = 'TextField';
36668 field = Roo.factory(config.field, Roo.form);
36670 config = config || {};
36675 * @event beforenodeedit
36676 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36677 * false from the handler of this event.
36678 * @param {Editor} this
36679 * @param {Roo.tree.Node} node
36681 "beforenodeedit" : true
36685 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36689 tree.on('beforeclick', this.beforeNodeClick, this);
36690 tree.getTreeEl().on('mousedown', this.hide, this);
36691 this.on('complete', this.updateNode, this);
36692 this.on('beforestartedit', this.fitToTree, this);
36693 this.on('startedit', this.bindScroll, this, {delay:10});
36694 this.on('specialkey', this.onSpecialKey, this);
36697 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36699 * @cfg {String} alignment
36700 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36706 * @cfg {Boolean} hideEl
36707 * True to hide the bound element while the editor is displayed (defaults to false)
36711 * @cfg {String} cls
36712 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36714 cls: "x-small-editor x-tree-editor",
36716 * @cfg {Boolean} shim
36717 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36723 * @cfg {Number} maxWidth
36724 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36725 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36726 * scroll and client offsets into account prior to each edit.
36733 fitToTree : function(ed, el){
36734 var td = this.tree.getTreeEl().dom, nd = el.dom;
36735 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36736 td.scrollLeft = nd.offsetLeft;
36740 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36741 this.setSize(w, '');
36743 return this.fireEvent('beforenodeedit', this, this.editNode);
36748 triggerEdit : function(node){
36749 this.completeEdit();
36750 this.editNode = node;
36751 this.startEdit(node.ui.textNode, node.text);
36755 bindScroll : function(){
36756 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36760 beforeNodeClick : function(node, e){
36761 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36762 this.lastClick = new Date();
36763 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36765 this.triggerEdit(node);
36772 updateNode : function(ed, value){
36773 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36774 this.editNode.setText(value);
36778 onHide : function(){
36779 Roo.tree.TreeEditor.superclass.onHide.call(this);
36781 this.editNode.ui.focus();
36786 onSpecialKey : function(field, e){
36787 var k = e.getKey();
36791 }else if(k == e.ENTER && !e.hasModifier()){
36793 this.completeEdit();
36796 });//<Script type="text/javascript">
36799 * Ext JS Library 1.1.1
36800 * Copyright(c) 2006-2007, Ext JS, LLC.
36802 * Originally Released Under LGPL - original licence link has changed is not relivant.
36805 * <script type="text/javascript">
36809 * Not documented??? - probably should be...
36812 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36813 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36815 renderElements : function(n, a, targetNode, bulkRender){
36816 //consel.log("renderElements?");
36817 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36819 var t = n.getOwnerTree();
36820 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36822 var cols = t.columns;
36823 var bw = t.borderWidth;
36825 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36826 var cb = typeof a.checked == "boolean";
36827 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36828 var colcls = 'x-t-' + tid + '-c0';
36830 '<li class="x-tree-node">',
36833 '<div class="x-tree-node-el ', a.cls,'">',
36835 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36838 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36839 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36840 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36841 (a.icon ? ' x-tree-node-inline-icon' : ''),
36842 (a.iconCls ? ' '+a.iconCls : ''),
36843 '" unselectable="on" />',
36844 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36845 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36847 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36848 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36849 '<span unselectable="on" qtip="' + tx + '">',
36853 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36854 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36856 for(var i = 1, len = cols.length; i < len; i++){
36858 colcls = 'x-t-' + tid + '-c' +i;
36859 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36860 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
36861 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
36867 '<div class="x-clear"></div></div>',
36868 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36871 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36872 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36873 n.nextSibling.ui.getEl(), buf.join(""));
36875 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36877 var el = this.wrap.firstChild;
36879 this.elNode = el.firstChild;
36880 this.ranchor = el.childNodes[1];
36881 this.ctNode = this.wrap.childNodes[1];
36882 var cs = el.firstChild.childNodes;
36883 this.indentNode = cs[0];
36884 this.ecNode = cs[1];
36885 this.iconNode = cs[2];
36888 this.checkbox = cs[3];
36891 this.anchor = cs[index];
36893 this.textNode = cs[index].firstChild;
36895 //el.on("click", this.onClick, this);
36896 //el.on("dblclick", this.onDblClick, this);
36899 // console.log(this);
36901 initEvents : function(){
36902 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
36905 var a = this.ranchor;
36907 var el = Roo.get(a);
36909 if(Roo.isOpera){ // opera render bug ignores the CSS
36910 el.setStyle("text-decoration", "none");
36913 el.on("click", this.onClick, this);
36914 el.on("dblclick", this.onDblClick, this);
36915 el.on("contextmenu", this.onContextMenu, this);
36919 /*onSelectedChange : function(state){
36922 this.addClass("x-tree-selected");
36925 this.removeClass("x-tree-selected");
36928 addClass : function(cls){
36930 Roo.fly(this.elRow).addClass(cls);
36936 removeClass : function(cls){
36938 Roo.fly(this.elRow).removeClass(cls);
36944 });//<Script type="text/javascript">
36948 * Ext JS Library 1.1.1
36949 * Copyright(c) 2006-2007, Ext JS, LLC.
36951 * Originally Released Under LGPL - original licence link has changed is not relivant.
36954 * <script type="text/javascript">
36959 * @class Roo.tree.ColumnTree
36960 * @extends Roo.data.TreePanel
36961 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
36962 * @cfg {int} borderWidth compined right/left border allowance
36964 * @param {String/HTMLElement/Element} el The container element
36965 * @param {Object} config
36967 Roo.tree.ColumnTree = function(el, config)
36969 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
36973 * Fire this event on a container when it resizes
36974 * @param {int} w Width
36975 * @param {int} h Height
36979 this.on('resize', this.onResize, this);
36982 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
36986 borderWidth: Roo.isBorderBox ? 0 : 2,
36989 render : function(){
36990 // add the header.....
36992 Roo.tree.ColumnTree.superclass.render.apply(this);
36994 this.el.addClass('x-column-tree');
36996 this.headers = this.el.createChild(
36997 {cls:'x-tree-headers'},this.innerCt.dom);
36999 var cols = this.columns, c;
37000 var totalWidth = 0;
37002 var len = cols.length;
37003 for(var i = 0; i < len; i++){
37005 totalWidth += c.width;
37006 this.headEls.push(this.headers.createChild({
37007 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37009 cls:'x-tree-hd-text',
37012 style:'width:'+(c.width-this.borderWidth)+'px;'
37015 this.headers.createChild({cls:'x-clear'});
37016 // prevent floats from wrapping when clipped
37017 this.headers.setWidth(totalWidth);
37018 //this.innerCt.setWidth(totalWidth);
37019 this.innerCt.setStyle({ overflow: 'auto' });
37020 this.onResize(this.width, this.height);
37024 onResize : function(w,h)
37029 this.innerCt.setWidth(this.width);
37030 this.innerCt.setHeight(this.height-20);
37033 var cols = this.columns, c;
37034 var totalWidth = 0;
37036 var len = cols.length;
37037 for(var i = 0; i < len; i++){
37039 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37040 // it's the expander..
37041 expEl = this.headEls[i];
37044 totalWidth += c.width;
37048 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37050 this.headers.setWidth(w-20);
37059 * Ext JS Library 1.1.1
37060 * Copyright(c) 2006-2007, Ext JS, LLC.
37062 * Originally Released Under LGPL - original licence link has changed is not relivant.
37065 * <script type="text/javascript">
37069 * @class Roo.menu.Menu
37070 * @extends Roo.util.Observable
37071 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37072 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37074 * Creates a new Menu
37075 * @param {Object} config Configuration options
37077 Roo.menu.Menu = function(config){
37078 Roo.apply(this, config);
37079 this.id = this.id || Roo.id();
37082 * @event beforeshow
37083 * Fires before this menu is displayed
37084 * @param {Roo.menu.Menu} this
37088 * @event beforehide
37089 * Fires before this menu is hidden
37090 * @param {Roo.menu.Menu} this
37095 * Fires after this menu is displayed
37096 * @param {Roo.menu.Menu} this
37101 * Fires after this menu is hidden
37102 * @param {Roo.menu.Menu} this
37107 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37108 * @param {Roo.menu.Menu} this
37109 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37110 * @param {Roo.EventObject} e
37115 * Fires when the mouse is hovering over this menu
37116 * @param {Roo.menu.Menu} this
37117 * @param {Roo.EventObject} e
37118 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37123 * Fires when the mouse exits this menu
37124 * @param {Roo.menu.Menu} this
37125 * @param {Roo.EventObject} e
37126 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37131 * Fires when a menu item contained in this menu is clicked
37132 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37133 * @param {Roo.EventObject} e
37137 if (this.registerMenu) {
37138 Roo.menu.MenuMgr.register(this);
37141 var mis = this.items;
37142 this.items = new Roo.util.MixedCollection();
37144 this.add.apply(this, mis);
37148 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37150 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37154 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37155 * for bottom-right shadow (defaults to "sides")
37159 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37160 * this menu (defaults to "tl-tr?")
37162 subMenuAlign : "tl-tr?",
37164 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37165 * relative to its element of origin (defaults to "tl-bl?")
37167 defaultAlign : "tl-bl?",
37169 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37171 allowOtherMenus : false,
37173 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37175 registerMenu : true,
37180 render : function(){
37184 var el = this.el = new Roo.Layer({
37186 shadow:this.shadow,
37188 parentEl: this.parentEl || document.body,
37192 this.keyNav = new Roo.menu.MenuNav(this);
37195 el.addClass("x-menu-plain");
37198 el.addClass(this.cls);
37200 // generic focus element
37201 this.focusEl = el.createChild({
37202 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37204 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37205 //disabling touch- as it's causing issues ..
37206 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37207 ul.on('click' , this.onClick, this);
37210 ul.on("mouseover", this.onMouseOver, this);
37211 ul.on("mouseout", this.onMouseOut, this);
37212 this.items.each(function(item){
37217 var li = document.createElement("li");
37218 li.className = "x-menu-list-item";
37219 ul.dom.appendChild(li);
37220 item.render(li, this);
37227 autoWidth : function(){
37228 var el = this.el, ul = this.ul;
37232 var w = this.width;
37235 }else if(Roo.isIE){
37236 el.setWidth(this.minWidth);
37237 var t = el.dom.offsetWidth; // force recalc
37238 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37243 delayAutoWidth : function(){
37246 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37248 this.awTask.delay(20);
37253 findTargetItem : function(e){
37254 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37255 if(t && t.menuItemId){
37256 return this.items.get(t.menuItemId);
37261 onClick : function(e){
37262 Roo.log("menu.onClick");
37263 var t = this.findTargetItem(e);
37268 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37269 if(t == this.activeItem && t.shouldDeactivate(e)){
37270 this.activeItem.deactivate();
37271 delete this.activeItem;
37275 this.setActiveItem(t, true);
37283 this.fireEvent("click", this, t, e);
37287 setActiveItem : function(item, autoExpand){
37288 if(item != this.activeItem){
37289 if(this.activeItem){
37290 this.activeItem.deactivate();
37292 this.activeItem = item;
37293 item.activate(autoExpand);
37294 }else if(autoExpand){
37300 tryActivate : function(start, step){
37301 var items = this.items;
37302 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37303 var item = items.get(i);
37304 if(!item.disabled && item.canActivate){
37305 this.setActiveItem(item, false);
37313 onMouseOver : function(e){
37315 if(t = this.findTargetItem(e)){
37316 if(t.canActivate && !t.disabled){
37317 this.setActiveItem(t, true);
37320 this.fireEvent("mouseover", this, e, t);
37324 onMouseOut : function(e){
37326 if(t = this.findTargetItem(e)){
37327 if(t == this.activeItem && t.shouldDeactivate(e)){
37328 this.activeItem.deactivate();
37329 delete this.activeItem;
37332 this.fireEvent("mouseout", this, e, t);
37336 * Read-only. Returns true if the menu is currently displayed, else false.
37339 isVisible : function(){
37340 return this.el && !this.hidden;
37344 * Displays this menu relative to another element
37345 * @param {String/HTMLElement/Roo.Element} element The element to align to
37346 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37347 * the element (defaults to this.defaultAlign)
37348 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37350 show : function(el, pos, parentMenu){
37351 this.parentMenu = parentMenu;
37355 this.fireEvent("beforeshow", this);
37356 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37360 * Displays this menu at a specific xy position
37361 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37362 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37364 showAt : function(xy, parentMenu, /* private: */_e){
37365 this.parentMenu = parentMenu;
37370 this.fireEvent("beforeshow", this);
37371 xy = this.el.adjustForConstraints(xy);
37375 this.hidden = false;
37377 this.fireEvent("show", this);
37380 focus : function(){
37382 this.doFocus.defer(50, this);
37386 doFocus : function(){
37388 this.focusEl.focus();
37393 * Hides this menu and optionally all parent menus
37394 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37396 hide : function(deep){
37397 if(this.el && this.isVisible()){
37398 this.fireEvent("beforehide", this);
37399 if(this.activeItem){
37400 this.activeItem.deactivate();
37401 this.activeItem = null;
37404 this.hidden = true;
37405 this.fireEvent("hide", this);
37407 if(deep === true && this.parentMenu){
37408 this.parentMenu.hide(true);
37413 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37414 * Any of the following are valid:
37416 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37417 * <li>An HTMLElement object which will be converted to a menu item</li>
37418 * <li>A menu item config object that will be created as a new menu item</li>
37419 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37420 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37425 var menu = new Roo.menu.Menu();
37427 // Create a menu item to add by reference
37428 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37430 // Add a bunch of items at once using different methods.
37431 // Only the last item added will be returned.
37432 var item = menu.add(
37433 menuItem, // add existing item by ref
37434 'Dynamic Item', // new TextItem
37435 '-', // new separator
37436 { text: 'Config Item' } // new item by config
37439 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37440 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37443 var a = arguments, l = a.length, item;
37444 for(var i = 0; i < l; i++){
37446 if ((typeof(el) == "object") && el.xtype && el.xns) {
37447 el = Roo.factory(el, Roo.menu);
37450 if(el.render){ // some kind of Item
37451 item = this.addItem(el);
37452 }else if(typeof el == "string"){ // string
37453 if(el == "separator" || el == "-"){
37454 item = this.addSeparator();
37456 item = this.addText(el);
37458 }else if(el.tagName || el.el){ // element
37459 item = this.addElement(el);
37460 }else if(typeof el == "object"){ // must be menu item config?
37461 item = this.addMenuItem(el);
37468 * Returns this menu's underlying {@link Roo.Element} object
37469 * @return {Roo.Element} The element
37471 getEl : function(){
37479 * Adds a separator bar to the menu
37480 * @return {Roo.menu.Item} The menu item that was added
37482 addSeparator : function(){
37483 return this.addItem(new Roo.menu.Separator());
37487 * Adds an {@link Roo.Element} object to the menu
37488 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37489 * @return {Roo.menu.Item} The menu item that was added
37491 addElement : function(el){
37492 return this.addItem(new Roo.menu.BaseItem(el));
37496 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37497 * @param {Roo.menu.Item} item The menu item to add
37498 * @return {Roo.menu.Item} The menu item that was added
37500 addItem : function(item){
37501 this.items.add(item);
37503 var li = document.createElement("li");
37504 li.className = "x-menu-list-item";
37505 this.ul.dom.appendChild(li);
37506 item.render(li, this);
37507 this.delayAutoWidth();
37513 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37514 * @param {Object} config A MenuItem config object
37515 * @return {Roo.menu.Item} The menu item that was added
37517 addMenuItem : function(config){
37518 if(!(config instanceof Roo.menu.Item)){
37519 if(typeof config.checked == "boolean"){ // must be check menu item config?
37520 config = new Roo.menu.CheckItem(config);
37522 config = new Roo.menu.Item(config);
37525 return this.addItem(config);
37529 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37530 * @param {String} text The text to display in the menu item
37531 * @return {Roo.menu.Item} The menu item that was added
37533 addText : function(text){
37534 return this.addItem(new Roo.menu.TextItem({ text : text }));
37538 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37539 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37540 * @param {Roo.menu.Item} item The menu item to add
37541 * @return {Roo.menu.Item} The menu item that was added
37543 insert : function(index, item){
37544 this.items.insert(index, item);
37546 var li = document.createElement("li");
37547 li.className = "x-menu-list-item";
37548 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37549 item.render(li, this);
37550 this.delayAutoWidth();
37556 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37557 * @param {Roo.menu.Item} item The menu item to remove
37559 remove : function(item){
37560 this.items.removeKey(item.id);
37565 * Removes and destroys all items in the menu
37567 removeAll : function(){
37569 while(f = this.items.first()){
37575 // MenuNav is a private utility class used internally by the Menu
37576 Roo.menu.MenuNav = function(menu){
37577 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37578 this.scope = this.menu = menu;
37581 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37582 doRelay : function(e, h){
37583 var k = e.getKey();
37584 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37585 this.menu.tryActivate(0, 1);
37588 return h.call(this.scope || this, e, this.menu);
37591 up : function(e, m){
37592 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37593 m.tryActivate(m.items.length-1, -1);
37597 down : function(e, m){
37598 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37599 m.tryActivate(0, 1);
37603 right : function(e, m){
37605 m.activeItem.expandMenu(true);
37609 left : function(e, m){
37611 if(m.parentMenu && m.parentMenu.activeItem){
37612 m.parentMenu.activeItem.activate();
37616 enter : function(e, m){
37618 e.stopPropagation();
37619 m.activeItem.onClick(e);
37620 m.fireEvent("click", this, m.activeItem);
37626 * Ext JS Library 1.1.1
37627 * Copyright(c) 2006-2007, Ext JS, LLC.
37629 * Originally Released Under LGPL - original licence link has changed is not relivant.
37632 * <script type="text/javascript">
37636 * @class Roo.menu.MenuMgr
37637 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37640 Roo.menu.MenuMgr = function(){
37641 var menus, active, groups = {}, attached = false, lastShow = new Date();
37643 // private - called when first menu is created
37646 active = new Roo.util.MixedCollection();
37647 Roo.get(document).addKeyListener(27, function(){
37648 if(active.length > 0){
37655 function hideAll(){
37656 if(active && active.length > 0){
37657 var c = active.clone();
37658 c.each(function(m){
37665 function onHide(m){
37667 if(active.length < 1){
37668 Roo.get(document).un("mousedown", onMouseDown);
37674 function onShow(m){
37675 var last = active.last();
37676 lastShow = new Date();
37679 Roo.get(document).on("mousedown", onMouseDown);
37683 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37684 m.parentMenu.activeChild = m;
37685 }else if(last && last.isVisible()){
37686 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37691 function onBeforeHide(m){
37693 m.activeChild.hide();
37695 if(m.autoHideTimer){
37696 clearTimeout(m.autoHideTimer);
37697 delete m.autoHideTimer;
37702 function onBeforeShow(m){
37703 var pm = m.parentMenu;
37704 if(!pm && !m.allowOtherMenus){
37706 }else if(pm && pm.activeChild && active != m){
37707 pm.activeChild.hide();
37712 function onMouseDown(e){
37713 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37719 function onBeforeCheck(mi, state){
37721 var g = groups[mi.group];
37722 for(var i = 0, l = g.length; i < l; i++){
37724 g[i].setChecked(false);
37733 * Hides all menus that are currently visible
37735 hideAll : function(){
37740 register : function(menu){
37744 menus[menu.id] = menu;
37745 menu.on("beforehide", onBeforeHide);
37746 menu.on("hide", onHide);
37747 menu.on("beforeshow", onBeforeShow);
37748 menu.on("show", onShow);
37749 var g = menu.group;
37750 if(g && menu.events["checkchange"]){
37754 groups[g].push(menu);
37755 menu.on("checkchange", onCheck);
37760 * Returns a {@link Roo.menu.Menu} object
37761 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37762 * be used to generate and return a new Menu instance.
37764 get : function(menu){
37765 if(typeof menu == "string"){ // menu id
37766 return menus[menu];
37767 }else if(menu.events){ // menu instance
37769 }else if(typeof menu.length == 'number'){ // array of menu items?
37770 return new Roo.menu.Menu({items:menu});
37771 }else{ // otherwise, must be a config
37772 return new Roo.menu.Menu(menu);
37777 unregister : function(menu){
37778 delete menus[menu.id];
37779 menu.un("beforehide", onBeforeHide);
37780 menu.un("hide", onHide);
37781 menu.un("beforeshow", onBeforeShow);
37782 menu.un("show", onShow);
37783 var g = menu.group;
37784 if(g && menu.events["checkchange"]){
37785 groups[g].remove(menu);
37786 menu.un("checkchange", onCheck);
37791 registerCheckable : function(menuItem){
37792 var g = menuItem.group;
37797 groups[g].push(menuItem);
37798 menuItem.on("beforecheckchange", onBeforeCheck);
37803 unregisterCheckable : function(menuItem){
37804 var g = menuItem.group;
37806 groups[g].remove(menuItem);
37807 menuItem.un("beforecheckchange", onBeforeCheck);
37813 * Ext JS Library 1.1.1
37814 * Copyright(c) 2006-2007, Ext JS, LLC.
37816 * Originally Released Under LGPL - original licence link has changed is not relivant.
37819 * <script type="text/javascript">
37824 * @class Roo.menu.BaseItem
37825 * @extends Roo.Component
37826 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37827 * management and base configuration options shared by all menu components.
37829 * Creates a new BaseItem
37830 * @param {Object} config Configuration options
37832 Roo.menu.BaseItem = function(config){
37833 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37838 * Fires when this item is clicked
37839 * @param {Roo.menu.BaseItem} this
37840 * @param {Roo.EventObject} e
37845 * Fires when this item is activated
37846 * @param {Roo.menu.BaseItem} this
37850 * @event deactivate
37851 * Fires when this item is deactivated
37852 * @param {Roo.menu.BaseItem} this
37858 this.on("click", this.handler, this.scope, true);
37862 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
37864 * @cfg {Function} handler
37865 * A function that will handle the click event of this menu item (defaults to undefined)
37868 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
37870 canActivate : false,
37873 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
37878 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
37880 activeClass : "x-menu-item-active",
37882 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
37884 hideOnClick : true,
37886 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
37891 ctype: "Roo.menu.BaseItem",
37894 actionMode : "container",
37897 render : function(container, parentMenu){
37898 this.parentMenu = parentMenu;
37899 Roo.menu.BaseItem.superclass.render.call(this, container);
37900 this.container.menuItemId = this.id;
37904 onRender : function(container, position){
37905 this.el = Roo.get(this.el);
37906 container.dom.appendChild(this.el.dom);
37910 onClick : function(e){
37911 if(!this.disabled && this.fireEvent("click", this, e) !== false
37912 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
37913 this.handleClick(e);
37920 activate : function(){
37924 var li = this.container;
37925 li.addClass(this.activeClass);
37926 this.region = li.getRegion().adjust(2, 2, -2, -2);
37927 this.fireEvent("activate", this);
37932 deactivate : function(){
37933 this.container.removeClass(this.activeClass);
37934 this.fireEvent("deactivate", this);
37938 shouldDeactivate : function(e){
37939 return !this.region || !this.region.contains(e.getPoint());
37943 handleClick : function(e){
37944 if(this.hideOnClick){
37945 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
37950 expandMenu : function(autoActivate){
37955 hideMenu : function(){
37960 * Ext JS Library 1.1.1
37961 * Copyright(c) 2006-2007, Ext JS, LLC.
37963 * Originally Released Under LGPL - original licence link has changed is not relivant.
37966 * <script type="text/javascript">
37970 * @class Roo.menu.Adapter
37971 * @extends Roo.menu.BaseItem
37972 * 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.
37973 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
37975 * Creates a new Adapter
37976 * @param {Object} config Configuration options
37978 Roo.menu.Adapter = function(component, config){
37979 Roo.menu.Adapter.superclass.constructor.call(this, config);
37980 this.component = component;
37982 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
37984 canActivate : true,
37987 onRender : function(container, position){
37988 this.component.render(container);
37989 this.el = this.component.getEl();
37993 activate : function(){
37997 this.component.focus();
37998 this.fireEvent("activate", this);
38003 deactivate : function(){
38004 this.fireEvent("deactivate", this);
38008 disable : function(){
38009 this.component.disable();
38010 Roo.menu.Adapter.superclass.disable.call(this);
38014 enable : function(){
38015 this.component.enable();
38016 Roo.menu.Adapter.superclass.enable.call(this);
38020 * Ext JS Library 1.1.1
38021 * Copyright(c) 2006-2007, Ext JS, LLC.
38023 * Originally Released Under LGPL - original licence link has changed is not relivant.
38026 * <script type="text/javascript">
38030 * @class Roo.menu.TextItem
38031 * @extends Roo.menu.BaseItem
38032 * Adds a static text string to a menu, usually used as either a heading or group separator.
38033 * Note: old style constructor with text is still supported.
38036 * Creates a new TextItem
38037 * @param {Object} cfg Configuration
38039 Roo.menu.TextItem = function(cfg){
38040 if (typeof(cfg) == 'string') {
38043 Roo.apply(this,cfg);
38046 Roo.menu.TextItem.superclass.constructor.call(this);
38049 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38051 * @cfg {Boolean} text Text to show on item.
38056 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38058 hideOnClick : false,
38060 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38062 itemCls : "x-menu-text",
38065 onRender : function(){
38066 var s = document.createElement("span");
38067 s.className = this.itemCls;
38068 s.innerHTML = this.text;
38070 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38074 * Ext JS Library 1.1.1
38075 * Copyright(c) 2006-2007, Ext JS, LLC.
38077 * Originally Released Under LGPL - original licence link has changed is not relivant.
38080 * <script type="text/javascript">
38084 * @class Roo.menu.Separator
38085 * @extends Roo.menu.BaseItem
38086 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38087 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38089 * @param {Object} config Configuration options
38091 Roo.menu.Separator = function(config){
38092 Roo.menu.Separator.superclass.constructor.call(this, config);
38095 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38097 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38099 itemCls : "x-menu-sep",
38101 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38103 hideOnClick : false,
38106 onRender : function(li){
38107 var s = document.createElement("span");
38108 s.className = this.itemCls;
38109 s.innerHTML = " ";
38111 li.addClass("x-menu-sep-li");
38112 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38116 * Ext JS Library 1.1.1
38117 * Copyright(c) 2006-2007, Ext JS, LLC.
38119 * Originally Released Under LGPL - original licence link has changed is not relivant.
38122 * <script type="text/javascript">
38125 * @class Roo.menu.Item
38126 * @extends Roo.menu.BaseItem
38127 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38128 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38129 * activation and click handling.
38131 * Creates a new Item
38132 * @param {Object} config Configuration options
38134 Roo.menu.Item = function(config){
38135 Roo.menu.Item.superclass.constructor.call(this, config);
38137 this.menu = Roo.menu.MenuMgr.get(this.menu);
38140 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38143 * @cfg {String} text
38144 * The text to show on the menu item.
38148 * @cfg {String} HTML to render in menu
38149 * The text to show on the menu item (HTML version).
38153 * @cfg {String} icon
38154 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38158 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38160 itemCls : "x-menu-item",
38162 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38164 canActivate : true,
38166 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38169 // doc'd in BaseItem
38173 ctype: "Roo.menu.Item",
38176 onRender : function(container, position){
38177 var el = document.createElement("a");
38178 el.hideFocus = true;
38179 el.unselectable = "on";
38180 el.href = this.href || "#";
38181 if(this.hrefTarget){
38182 el.target = this.hrefTarget;
38184 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38186 var html = this.html.length ? this.html : String.format('{0}',this.text);
38188 el.innerHTML = String.format(
38189 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38190 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38192 Roo.menu.Item.superclass.onRender.call(this, container, position);
38196 * Sets the text to display in this menu item
38197 * @param {String} text The text to display
38198 * @param {Boolean} isHTML true to indicate text is pure html.
38200 setText : function(text, isHTML){
38208 var html = this.html.length ? this.html : String.format('{0}',this.text);
38210 this.el.update(String.format(
38211 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38212 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38213 this.parentMenu.autoWidth();
38218 handleClick : function(e){
38219 if(!this.href){ // if no link defined, stop the event automatically
38222 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38226 activate : function(autoExpand){
38227 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38237 shouldDeactivate : function(e){
38238 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38239 if(this.menu && this.menu.isVisible()){
38240 return !this.menu.getEl().getRegion().contains(e.getPoint());
38248 deactivate : function(){
38249 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38254 expandMenu : function(autoActivate){
38255 if(!this.disabled && this.menu){
38256 clearTimeout(this.hideTimer);
38257 delete this.hideTimer;
38258 if(!this.menu.isVisible() && !this.showTimer){
38259 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38260 }else if (this.menu.isVisible() && autoActivate){
38261 this.menu.tryActivate(0, 1);
38267 deferExpand : function(autoActivate){
38268 delete this.showTimer;
38269 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38271 this.menu.tryActivate(0, 1);
38276 hideMenu : function(){
38277 clearTimeout(this.showTimer);
38278 delete this.showTimer;
38279 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38280 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38285 deferHide : function(){
38286 delete this.hideTimer;
38291 * Ext JS Library 1.1.1
38292 * Copyright(c) 2006-2007, Ext JS, LLC.
38294 * Originally Released Under LGPL - original licence link has changed is not relivant.
38297 * <script type="text/javascript">
38301 * @class Roo.menu.CheckItem
38302 * @extends Roo.menu.Item
38303 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38305 * Creates a new CheckItem
38306 * @param {Object} config Configuration options
38308 Roo.menu.CheckItem = function(config){
38309 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38312 * @event beforecheckchange
38313 * Fires before the checked value is set, providing an opportunity to cancel if needed
38314 * @param {Roo.menu.CheckItem} this
38315 * @param {Boolean} checked The new checked value that will be set
38317 "beforecheckchange" : true,
38319 * @event checkchange
38320 * Fires after the checked value has been set
38321 * @param {Roo.menu.CheckItem} this
38322 * @param {Boolean} checked The checked value that was set
38324 "checkchange" : true
38326 if(this.checkHandler){
38327 this.on('checkchange', this.checkHandler, this.scope);
38330 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38332 * @cfg {String} group
38333 * All check items with the same group name will automatically be grouped into a single-select
38334 * radio button group (defaults to '')
38337 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38339 itemCls : "x-menu-item x-menu-check-item",
38341 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38343 groupClass : "x-menu-group-item",
38346 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38347 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38348 * initialized with checked = true will be rendered as checked.
38353 ctype: "Roo.menu.CheckItem",
38356 onRender : function(c){
38357 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38359 this.el.addClass(this.groupClass);
38361 Roo.menu.MenuMgr.registerCheckable(this);
38363 this.checked = false;
38364 this.setChecked(true, true);
38369 destroy : function(){
38371 Roo.menu.MenuMgr.unregisterCheckable(this);
38373 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38377 * Set the checked state of this item
38378 * @param {Boolean} checked The new checked value
38379 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38381 setChecked : function(state, suppressEvent){
38382 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38383 if(this.container){
38384 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38386 this.checked = state;
38387 if(suppressEvent !== true){
38388 this.fireEvent("checkchange", this, state);
38394 handleClick : function(e){
38395 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38396 this.setChecked(!this.checked);
38398 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38402 * Ext JS Library 1.1.1
38403 * Copyright(c) 2006-2007, Ext JS, LLC.
38405 * Originally Released Under LGPL - original licence link has changed is not relivant.
38408 * <script type="text/javascript">
38412 * @class Roo.menu.DateItem
38413 * @extends Roo.menu.Adapter
38414 * A menu item that wraps the {@link Roo.DatPicker} component.
38416 * Creates a new DateItem
38417 * @param {Object} config Configuration options
38419 Roo.menu.DateItem = function(config){
38420 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38421 /** The Roo.DatePicker object @type Roo.DatePicker */
38422 this.picker = this.component;
38423 this.addEvents({select: true});
38425 this.picker.on("render", function(picker){
38426 picker.getEl().swallowEvent("click");
38427 picker.container.addClass("x-menu-date-item");
38430 this.picker.on("select", this.onSelect, this);
38433 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38435 onSelect : function(picker, date){
38436 this.fireEvent("select", this, date, picker);
38437 Roo.menu.DateItem.superclass.handleClick.call(this);
38441 * Ext JS Library 1.1.1
38442 * Copyright(c) 2006-2007, Ext JS, LLC.
38444 * Originally Released Under LGPL - original licence link has changed is not relivant.
38447 * <script type="text/javascript">
38451 * @class Roo.menu.ColorItem
38452 * @extends Roo.menu.Adapter
38453 * A menu item that wraps the {@link Roo.ColorPalette} component.
38455 * Creates a new ColorItem
38456 * @param {Object} config Configuration options
38458 Roo.menu.ColorItem = function(config){
38459 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38460 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38461 this.palette = this.component;
38462 this.relayEvents(this.palette, ["select"]);
38463 if(this.selectHandler){
38464 this.on('select', this.selectHandler, this.scope);
38467 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38469 * Ext JS Library 1.1.1
38470 * Copyright(c) 2006-2007, Ext JS, LLC.
38472 * Originally Released Under LGPL - original licence link has changed is not relivant.
38475 * <script type="text/javascript">
38480 * @class Roo.menu.DateMenu
38481 * @extends Roo.menu.Menu
38482 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38484 * Creates a new DateMenu
38485 * @param {Object} config Configuration options
38487 Roo.menu.DateMenu = function(config){
38488 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38490 var di = new Roo.menu.DateItem(config);
38493 * The {@link Roo.DatePicker} instance for this DateMenu
38496 this.picker = di.picker;
38499 * @param {DatePicker} picker
38500 * @param {Date} date
38502 this.relayEvents(di, ["select"]);
38503 this.on('beforeshow', function(){
38505 this.picker.hideMonthPicker(false);
38509 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38513 * Ext JS Library 1.1.1
38514 * Copyright(c) 2006-2007, Ext JS, LLC.
38516 * Originally Released Under LGPL - original licence link has changed is not relivant.
38519 * <script type="text/javascript">
38524 * @class Roo.menu.ColorMenu
38525 * @extends Roo.menu.Menu
38526 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38528 * Creates a new ColorMenu
38529 * @param {Object} config Configuration options
38531 Roo.menu.ColorMenu = function(config){
38532 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38534 var ci = new Roo.menu.ColorItem(config);
38537 * The {@link Roo.ColorPalette} instance for this ColorMenu
38538 * @type ColorPalette
38540 this.palette = ci.palette;
38543 * @param {ColorPalette} palette
38544 * @param {String} color
38546 this.relayEvents(ci, ["select"]);
38548 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38550 * Ext JS Library 1.1.1
38551 * Copyright(c) 2006-2007, Ext JS, LLC.
38553 * Originally Released Under LGPL - original licence link has changed is not relivant.
38556 * <script type="text/javascript">
38560 * @class Roo.form.Field
38561 * @extends Roo.BoxComponent
38562 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38564 * Creates a new Field
38565 * @param {Object} config Configuration options
38567 Roo.form.Field = function(config){
38568 Roo.form.Field.superclass.constructor.call(this, config);
38571 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38573 * @cfg {String} fieldLabel Label to use when rendering a form.
38576 * @cfg {String} qtip Mouse over tip
38580 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38582 invalidClass : "x-form-invalid",
38584 * @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")
38586 invalidText : "The value in this field is invalid",
38588 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38590 focusClass : "x-form-focus",
38592 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38593 automatic validation (defaults to "keyup").
38595 validationEvent : "keyup",
38597 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38599 validateOnBlur : true,
38601 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38603 validationDelay : 250,
38605 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38606 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38608 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38610 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38612 fieldClass : "x-form-field",
38614 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38617 ----------- ----------------------------------------------------------------------
38618 qtip Display a quick tip when the user hovers over the field
38619 title Display a default browser title attribute popup
38620 under Add a block div beneath the field containing the error text
38621 side Add an error icon to the right of the field with a popup on hover
38622 [element id] Add the error text directly to the innerHTML of the specified element
38625 msgTarget : 'qtip',
38627 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38632 * @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.
38637 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38642 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38644 inputType : undefined,
38647 * @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).
38649 tabIndex : undefined,
38652 isFormField : true,
38657 * @property {Roo.Element} fieldEl
38658 * Element Containing the rendered Field (with label etc.)
38661 * @cfg {Mixed} value A value to initialize this field with.
38666 * @cfg {String} name The field's HTML name attribute.
38669 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38672 loadedValue : false,
38676 initComponent : function(){
38677 Roo.form.Field.superclass.initComponent.call(this);
38681 * Fires when this field receives input focus.
38682 * @param {Roo.form.Field} this
38687 * Fires when this field loses input focus.
38688 * @param {Roo.form.Field} this
38692 * @event specialkey
38693 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38694 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38695 * @param {Roo.form.Field} this
38696 * @param {Roo.EventObject} e The event object
38701 * Fires just before the field blurs if the field value has changed.
38702 * @param {Roo.form.Field} this
38703 * @param {Mixed} newValue The new value
38704 * @param {Mixed} oldValue The original value
38709 * Fires after the field has been marked as invalid.
38710 * @param {Roo.form.Field} this
38711 * @param {String} msg The validation message
38716 * Fires after the field has been validated with no errors.
38717 * @param {Roo.form.Field} this
38722 * Fires after the key up
38723 * @param {Roo.form.Field} this
38724 * @param {Roo.EventObject} e The event Object
38731 * Returns the name attribute of the field if available
38732 * @return {String} name The field name
38734 getName: function(){
38735 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38739 onRender : function(ct, position){
38740 Roo.form.Field.superclass.onRender.call(this, ct, position);
38742 var cfg = this.getAutoCreate();
38744 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38746 if (!cfg.name.length) {
38749 if(this.inputType){
38750 cfg.type = this.inputType;
38752 this.el = ct.createChild(cfg, position);
38754 var type = this.el.dom.type;
38756 if(type == 'password'){
38759 this.el.addClass('x-form-'+type);
38762 this.el.dom.readOnly = true;
38764 if(this.tabIndex !== undefined){
38765 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38768 this.el.addClass([this.fieldClass, this.cls]);
38773 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38774 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38775 * @return {Roo.form.Field} this
38777 applyTo : function(target){
38778 this.allowDomMove = false;
38779 this.el = Roo.get(target);
38780 this.render(this.el.dom.parentNode);
38785 initValue : function(){
38786 if(this.value !== undefined){
38787 this.setValue(this.value);
38788 }else if(this.el.dom.value.length > 0){
38789 this.setValue(this.el.dom.value);
38794 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38795 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38797 isDirty : function() {
38798 if(this.disabled) {
38801 return String(this.getValue()) !== String(this.originalValue);
38805 * stores the current value in loadedValue
38807 resetHasChanged : function()
38809 this.loadedValue = String(this.getValue());
38812 * checks the current value against the 'loaded' value.
38813 * Note - will return false if 'resetHasChanged' has not been called first.
38815 hasChanged : function()
38817 if(this.disabled || this.readOnly) {
38820 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38826 afterRender : function(){
38827 Roo.form.Field.superclass.afterRender.call(this);
38832 fireKey : function(e){
38833 //Roo.log('field ' + e.getKey());
38834 if(e.isNavKeyPress()){
38835 this.fireEvent("specialkey", this, e);
38840 * Resets the current field value to the originally loaded value and clears any validation messages
38842 reset : function(){
38843 this.setValue(this.resetValue);
38844 this.clearInvalid();
38848 initEvents : function(){
38849 // safari killled keypress - so keydown is now used..
38850 this.el.on("keydown" , this.fireKey, this);
38851 this.el.on("focus", this.onFocus, this);
38852 this.el.on("blur", this.onBlur, this);
38853 this.el.relayEvent('keyup', this);
38855 // reference to original value for reset
38856 this.originalValue = this.getValue();
38857 this.resetValue = this.getValue();
38861 onFocus : function(){
38862 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38863 this.el.addClass(this.focusClass);
38865 if(!this.hasFocus){
38866 this.hasFocus = true;
38867 this.startValue = this.getValue();
38868 this.fireEvent("focus", this);
38872 beforeBlur : Roo.emptyFn,
38875 onBlur : function(){
38877 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38878 this.el.removeClass(this.focusClass);
38880 this.hasFocus = false;
38881 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
38884 var v = this.getValue();
38885 if(String(v) !== String(this.startValue)){
38886 this.fireEvent('change', this, v, this.startValue);
38888 this.fireEvent("blur", this);
38892 * Returns whether or not the field value is currently valid
38893 * @param {Boolean} preventMark True to disable marking the field invalid
38894 * @return {Boolean} True if the value is valid, else false
38896 isValid : function(preventMark){
38900 var restore = this.preventMark;
38901 this.preventMark = preventMark === true;
38902 var v = this.validateValue(this.processValue(this.getRawValue()));
38903 this.preventMark = restore;
38908 * Validates the field value
38909 * @return {Boolean} True if the value is valid, else false
38911 validate : function(){
38912 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
38913 this.clearInvalid();
38919 processValue : function(value){
38924 // Subclasses should provide the validation implementation by overriding this
38925 validateValue : function(value){
38930 * Mark this field as invalid
38931 * @param {String} msg The validation message
38933 markInvalid : function(msg){
38934 if(!this.rendered || this.preventMark){ // not rendered
38938 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38940 obj.el.addClass(this.invalidClass);
38941 msg = msg || this.invalidText;
38942 switch(this.msgTarget){
38944 obj.el.dom.qtip = msg;
38945 obj.el.dom.qclass = 'x-form-invalid-tip';
38946 if(Roo.QuickTips){ // fix for floating editors interacting with DND
38947 Roo.QuickTips.enable();
38951 this.el.dom.title = msg;
38955 var elp = this.el.findParent('.x-form-element', 5, true);
38956 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
38957 this.errorEl.setWidth(elp.getWidth(true)-20);
38959 this.errorEl.update(msg);
38960 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
38963 if(!this.errorIcon){
38964 var elp = this.el.findParent('.x-form-element', 5, true);
38965 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
38967 this.alignErrorIcon();
38968 this.errorIcon.dom.qtip = msg;
38969 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
38970 this.errorIcon.show();
38971 this.on('resize', this.alignErrorIcon, this);
38974 var t = Roo.getDom(this.msgTarget);
38976 t.style.display = this.msgDisplay;
38979 this.fireEvent('invalid', this, msg);
38983 alignErrorIcon : function(){
38984 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
38988 * Clear any invalid styles/messages for this field
38990 clearInvalid : function(){
38991 if(!this.rendered || this.preventMark){ // not rendered
38994 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38996 obj.el.removeClass(this.invalidClass);
38997 switch(this.msgTarget){
38999 obj.el.dom.qtip = '';
39002 this.el.dom.title = '';
39006 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39010 if(this.errorIcon){
39011 this.errorIcon.dom.qtip = '';
39012 this.errorIcon.hide();
39013 this.un('resize', this.alignErrorIcon, this);
39017 var t = Roo.getDom(this.msgTarget);
39019 t.style.display = 'none';
39022 this.fireEvent('valid', this);
39026 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39027 * @return {Mixed} value The field value
39029 getRawValue : function(){
39030 var v = this.el.getValue();
39036 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39037 * @return {Mixed} value The field value
39039 getValue : function(){
39040 var v = this.el.getValue();
39046 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39047 * @param {Mixed} value The value to set
39049 setRawValue : function(v){
39050 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39054 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39055 * @param {Mixed} value The value to set
39057 setValue : function(v){
39060 this.el.dom.value = (v === null || v === undefined ? '' : v);
39065 adjustSize : function(w, h){
39066 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39067 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39071 adjustWidth : function(tag, w){
39072 tag = tag.toLowerCase();
39073 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39074 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39075 if(tag == 'input'){
39078 if(tag == 'textarea'){
39081 }else if(Roo.isOpera){
39082 if(tag == 'input'){
39085 if(tag == 'textarea'){
39095 // anything other than normal should be considered experimental
39096 Roo.form.Field.msgFx = {
39098 show: function(msgEl, f){
39099 msgEl.setDisplayed('block');
39102 hide : function(msgEl, f){
39103 msgEl.setDisplayed(false).update('');
39108 show: function(msgEl, f){
39109 msgEl.slideIn('t', {stopFx:true});
39112 hide : function(msgEl, f){
39113 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39118 show: function(msgEl, f){
39119 msgEl.fixDisplay();
39120 msgEl.alignTo(f.el, 'tl-tr');
39121 msgEl.slideIn('l', {stopFx:true});
39124 hide : function(msgEl, f){
39125 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39130 * Ext JS Library 1.1.1
39131 * Copyright(c) 2006-2007, Ext JS, LLC.
39133 * Originally Released Under LGPL - original licence link has changed is not relivant.
39136 * <script type="text/javascript">
39141 * @class Roo.form.TextField
39142 * @extends Roo.form.Field
39143 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39144 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39146 * Creates a new TextField
39147 * @param {Object} config Configuration options
39149 Roo.form.TextField = function(config){
39150 Roo.form.TextField.superclass.constructor.call(this, config);
39154 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39155 * according to the default logic, but this event provides a hook for the developer to apply additional
39156 * logic at runtime to resize the field if needed.
39157 * @param {Roo.form.Field} this This text field
39158 * @param {Number} width The new field width
39164 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39166 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39170 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39174 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39178 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39182 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39186 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39188 disableKeyFilter : false,
39190 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39194 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39198 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39200 maxLength : Number.MAX_VALUE,
39202 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39204 minLengthText : "The minimum length for this field is {0}",
39206 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39208 maxLengthText : "The maximum length for this field is {0}",
39210 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39212 selectOnFocus : false,
39214 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39216 blankText : "This field is required",
39218 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39219 * If available, this function will be called only after the basic validators all return true, and will be passed the
39220 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39224 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39225 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39226 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39230 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39234 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39240 initEvents : function()
39242 if (this.emptyText) {
39243 this.el.attr('placeholder', this.emptyText);
39246 Roo.form.TextField.superclass.initEvents.call(this);
39247 if(this.validationEvent == 'keyup'){
39248 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39249 this.el.on('keyup', this.filterValidation, this);
39251 else if(this.validationEvent !== false){
39252 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39255 if(this.selectOnFocus){
39256 this.on("focus", this.preFocus, this);
39259 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39260 this.el.on("keypress", this.filterKeys, this);
39263 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39264 this.el.on("click", this.autoSize, this);
39266 if(this.el.is('input[type=password]') && Roo.isSafari){
39267 this.el.on('keydown', this.SafariOnKeyDown, this);
39271 processValue : function(value){
39272 if(this.stripCharsRe){
39273 var newValue = value.replace(this.stripCharsRe, '');
39274 if(newValue !== value){
39275 this.setRawValue(newValue);
39282 filterValidation : function(e){
39283 if(!e.isNavKeyPress()){
39284 this.validationTask.delay(this.validationDelay);
39289 onKeyUp : function(e){
39290 if(!e.isNavKeyPress()){
39296 * Resets the current field value to the originally-loaded value and clears any validation messages.
39299 reset : function(){
39300 Roo.form.TextField.superclass.reset.call(this);
39306 preFocus : function(){
39308 if(this.selectOnFocus){
39309 this.el.dom.select();
39315 filterKeys : function(e){
39316 var k = e.getKey();
39317 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39320 var c = e.getCharCode(), cc = String.fromCharCode(c);
39321 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39324 if(!this.maskRe.test(cc)){
39329 setValue : function(v){
39331 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39337 * Validates a value according to the field's validation rules and marks the field as invalid
39338 * if the validation fails
39339 * @param {Mixed} value The value to validate
39340 * @return {Boolean} True if the value is valid, else false
39342 validateValue : function(value){
39343 if(value.length < 1) { // if it's blank
39344 if(this.allowBlank){
39345 this.clearInvalid();
39348 this.markInvalid(this.blankText);
39352 if(value.length < this.minLength){
39353 this.markInvalid(String.format(this.minLengthText, this.minLength));
39356 if(value.length > this.maxLength){
39357 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39361 var vt = Roo.form.VTypes;
39362 if(!vt[this.vtype](value, this)){
39363 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39367 if(typeof this.validator == "function"){
39368 var msg = this.validator(value);
39370 this.markInvalid(msg);
39374 if(this.regex && !this.regex.test(value)){
39375 this.markInvalid(this.regexText);
39382 * Selects text in this field
39383 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39384 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39386 selectText : function(start, end){
39387 var v = this.getRawValue();
39389 start = start === undefined ? 0 : start;
39390 end = end === undefined ? v.length : end;
39391 var d = this.el.dom;
39392 if(d.setSelectionRange){
39393 d.setSelectionRange(start, end);
39394 }else if(d.createTextRange){
39395 var range = d.createTextRange();
39396 range.moveStart("character", start);
39397 range.moveEnd("character", v.length-end);
39404 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39405 * This only takes effect if grow = true, and fires the autosize event.
39407 autoSize : function(){
39408 if(!this.grow || !this.rendered){
39412 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39415 var v = el.dom.value;
39416 var d = document.createElement('div');
39417 d.appendChild(document.createTextNode(v));
39421 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39422 this.el.setWidth(w);
39423 this.fireEvent("autosize", this, w);
39427 SafariOnKeyDown : function(event)
39429 // this is a workaround for a password hang bug on chrome/ webkit.
39431 var isSelectAll = false;
39433 if(this.el.dom.selectionEnd > 0){
39434 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39436 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39437 event.preventDefault();
39442 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39444 event.preventDefault();
39445 // this is very hacky as keydown always get's upper case.
39447 var cc = String.fromCharCode(event.getCharCode());
39450 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39458 * Ext JS Library 1.1.1
39459 * Copyright(c) 2006-2007, Ext JS, LLC.
39461 * Originally Released Under LGPL - original licence link has changed is not relivant.
39464 * <script type="text/javascript">
39468 * @class Roo.form.Hidden
39469 * @extends Roo.form.TextField
39470 * Simple Hidden element used on forms
39472 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39475 * Creates a new Hidden form element.
39476 * @param {Object} config Configuration options
39481 // easy hidden field...
39482 Roo.form.Hidden = function(config){
39483 Roo.form.Hidden.superclass.constructor.call(this, config);
39486 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39488 inputType: 'hidden',
39491 labelSeparator: '',
39493 itemCls : 'x-form-item-display-none'
39501 * Ext JS Library 1.1.1
39502 * Copyright(c) 2006-2007, Ext JS, LLC.
39504 * Originally Released Under LGPL - original licence link has changed is not relivant.
39507 * <script type="text/javascript">
39511 * @class Roo.form.TriggerField
39512 * @extends Roo.form.TextField
39513 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39514 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39515 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39516 * for which you can provide a custom implementation. For example:
39518 var trigger = new Roo.form.TriggerField();
39519 trigger.onTriggerClick = myTriggerFn;
39520 trigger.applyTo('my-field');
39523 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39524 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39525 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39526 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39528 * Create a new TriggerField.
39529 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39530 * to the base TextField)
39532 Roo.form.TriggerField = function(config){
39533 this.mimicing = false;
39534 Roo.form.TriggerField.superclass.constructor.call(this, config);
39537 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39539 * @cfg {String} triggerClass A CSS class to apply to the trigger
39542 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39543 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39545 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39547 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39551 /** @cfg {Boolean} grow @hide */
39552 /** @cfg {Number} growMin @hide */
39553 /** @cfg {Number} growMax @hide */
39559 autoSize: Roo.emptyFn,
39563 deferHeight : true,
39566 actionMode : 'wrap',
39568 onResize : function(w, h){
39569 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39570 if(typeof w == 'number'){
39571 var x = w - this.trigger.getWidth();
39572 this.el.setWidth(this.adjustWidth('input', x));
39573 this.trigger.setStyle('left', x+'px');
39578 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39581 getResizeEl : function(){
39586 getPositionEl : function(){
39591 alignErrorIcon : function(){
39592 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39596 onRender : function(ct, position){
39597 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39598 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39599 this.trigger = this.wrap.createChild(this.triggerConfig ||
39600 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39601 if(this.hideTrigger){
39602 this.trigger.setDisplayed(false);
39604 this.initTrigger();
39606 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39611 initTrigger : function(){
39612 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39613 this.trigger.addClassOnOver('x-form-trigger-over');
39614 this.trigger.addClassOnClick('x-form-trigger-click');
39618 onDestroy : function(){
39620 this.trigger.removeAllListeners();
39621 this.trigger.remove();
39624 this.wrap.remove();
39626 Roo.form.TriggerField.superclass.onDestroy.call(this);
39630 onFocus : function(){
39631 Roo.form.TriggerField.superclass.onFocus.call(this);
39632 if(!this.mimicing){
39633 this.wrap.addClass('x-trigger-wrap-focus');
39634 this.mimicing = true;
39635 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39636 if(this.monitorTab){
39637 this.el.on("keydown", this.checkTab, this);
39643 checkTab : function(e){
39644 if(e.getKey() == e.TAB){
39645 this.triggerBlur();
39650 onBlur : function(){
39655 mimicBlur : function(e, t){
39656 if(!this.wrap.contains(t) && this.validateBlur()){
39657 this.triggerBlur();
39662 triggerBlur : function(){
39663 this.mimicing = false;
39664 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39665 if(this.monitorTab){
39666 this.el.un("keydown", this.checkTab, this);
39668 this.wrap.removeClass('x-trigger-wrap-focus');
39669 Roo.form.TriggerField.superclass.onBlur.call(this);
39673 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39674 validateBlur : function(e, t){
39679 onDisable : function(){
39680 Roo.form.TriggerField.superclass.onDisable.call(this);
39682 this.wrap.addClass('x-item-disabled');
39687 onEnable : function(){
39688 Roo.form.TriggerField.superclass.onEnable.call(this);
39690 this.wrap.removeClass('x-item-disabled');
39695 onShow : function(){
39696 var ae = this.getActionEl();
39699 ae.dom.style.display = '';
39700 ae.dom.style.visibility = 'visible';
39706 onHide : function(){
39707 var ae = this.getActionEl();
39708 ae.dom.style.display = 'none';
39712 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39713 * by an implementing function.
39715 * @param {EventObject} e
39717 onTriggerClick : Roo.emptyFn
39720 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39721 // to be extended by an implementing class. For an example of implementing this class, see the custom
39722 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39723 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39724 initComponent : function(){
39725 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39727 this.triggerConfig = {
39728 tag:'span', cls:'x-form-twin-triggers', cn:[
39729 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39730 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39734 getTrigger : function(index){
39735 return this.triggers[index];
39738 initTrigger : function(){
39739 var ts = this.trigger.select('.x-form-trigger', true);
39740 this.wrap.setStyle('overflow', 'hidden');
39741 var triggerField = this;
39742 ts.each(function(t, all, index){
39743 t.hide = function(){
39744 var w = triggerField.wrap.getWidth();
39745 this.dom.style.display = 'none';
39746 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39748 t.show = function(){
39749 var w = triggerField.wrap.getWidth();
39750 this.dom.style.display = '';
39751 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39753 var triggerIndex = 'Trigger'+(index+1);
39755 if(this['hide'+triggerIndex]){
39756 t.dom.style.display = 'none';
39758 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39759 t.addClassOnOver('x-form-trigger-over');
39760 t.addClassOnClick('x-form-trigger-click');
39762 this.triggers = ts.elements;
39765 onTrigger1Click : Roo.emptyFn,
39766 onTrigger2Click : Roo.emptyFn
39769 * Ext JS Library 1.1.1
39770 * Copyright(c) 2006-2007, Ext JS, LLC.
39772 * Originally Released Under LGPL - original licence link has changed is not relivant.
39775 * <script type="text/javascript">
39779 * @class Roo.form.TextArea
39780 * @extends Roo.form.TextField
39781 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39782 * support for auto-sizing.
39784 * Creates a new TextArea
39785 * @param {Object} config Configuration options
39787 Roo.form.TextArea = function(config){
39788 Roo.form.TextArea.superclass.constructor.call(this, config);
39789 // these are provided exchanges for backwards compat
39790 // minHeight/maxHeight were replaced by growMin/growMax to be
39791 // compatible with TextField growing config values
39792 if(this.minHeight !== undefined){
39793 this.growMin = this.minHeight;
39795 if(this.maxHeight !== undefined){
39796 this.growMax = this.maxHeight;
39800 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39802 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39806 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39810 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39811 * in the field (equivalent to setting overflow: hidden, defaults to false)
39813 preventScrollbars: false,
39815 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39816 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39820 onRender : function(ct, position){
39822 this.defaultAutoCreate = {
39824 style:"width:300px;height:60px;",
39825 autocomplete: "new-password"
39828 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39830 this.textSizeEl = Roo.DomHelper.append(document.body, {
39831 tag: "pre", cls: "x-form-grow-sizer"
39833 if(this.preventScrollbars){
39834 this.el.setStyle("overflow", "hidden");
39836 this.el.setHeight(this.growMin);
39840 onDestroy : function(){
39841 if(this.textSizeEl){
39842 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39844 Roo.form.TextArea.superclass.onDestroy.call(this);
39848 onKeyUp : function(e){
39849 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39855 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39856 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39858 autoSize : function(){
39859 if(!this.grow || !this.textSizeEl){
39863 var v = el.dom.value;
39864 var ts = this.textSizeEl;
39867 ts.appendChild(document.createTextNode(v));
39870 Roo.fly(ts).setWidth(this.el.getWidth());
39872 v = "  ";
39875 v = v.replace(/\n/g, '<p> </p>');
39877 v += " \n ";
39880 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
39881 if(h != this.lastHeight){
39882 this.lastHeight = h;
39883 this.el.setHeight(h);
39884 this.fireEvent("autosize", this, h);
39889 * Ext JS Library 1.1.1
39890 * Copyright(c) 2006-2007, Ext JS, LLC.
39892 * Originally Released Under LGPL - original licence link has changed is not relivant.
39895 * <script type="text/javascript">
39900 * @class Roo.form.NumberField
39901 * @extends Roo.form.TextField
39902 * Numeric text field that provides automatic keystroke filtering and numeric validation.
39904 * Creates a new NumberField
39905 * @param {Object} config Configuration options
39907 Roo.form.NumberField = function(config){
39908 Roo.form.NumberField.superclass.constructor.call(this, config);
39911 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
39913 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
39915 fieldClass: "x-form-field x-form-num-field",
39917 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39919 allowDecimals : true,
39921 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39923 decimalSeparator : ".",
39925 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39927 decimalPrecision : 2,
39929 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39931 allowNegative : true,
39933 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39935 minValue : Number.NEGATIVE_INFINITY,
39937 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39939 maxValue : Number.MAX_VALUE,
39941 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39943 minText : "The minimum value for this field is {0}",
39945 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39947 maxText : "The maximum value for this field is {0}",
39949 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39950 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39952 nanText : "{0} is not a valid number",
39955 initEvents : function(){
39956 Roo.form.NumberField.superclass.initEvents.call(this);
39957 var allowed = "0123456789";
39958 if(this.allowDecimals){
39959 allowed += this.decimalSeparator;
39961 if(this.allowNegative){
39964 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
39965 var keyPress = function(e){
39966 var k = e.getKey();
39967 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39970 var c = e.getCharCode();
39971 if(allowed.indexOf(String.fromCharCode(c)) === -1){
39975 this.el.on("keypress", keyPress, this);
39979 validateValue : function(value){
39980 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
39983 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39986 var num = this.parseValue(value);
39988 this.markInvalid(String.format(this.nanText, value));
39991 if(num < this.minValue){
39992 this.markInvalid(String.format(this.minText, this.minValue));
39995 if(num > this.maxValue){
39996 this.markInvalid(String.format(this.maxText, this.maxValue));
40002 getValue : function(){
40003 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40007 parseValue : function(value){
40008 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40009 return isNaN(value) ? '' : value;
40013 fixPrecision : function(value){
40014 var nan = isNaN(value);
40015 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40016 return nan ? '' : value;
40018 return parseFloat(value).toFixed(this.decimalPrecision);
40021 setValue : function(v){
40022 v = this.fixPrecision(v);
40023 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40027 decimalPrecisionFcn : function(v){
40028 return Math.floor(v);
40031 beforeBlur : function(){
40032 var v = this.parseValue(this.getRawValue());
40039 * Ext JS Library 1.1.1
40040 * Copyright(c) 2006-2007, Ext JS, LLC.
40042 * Originally Released Under LGPL - original licence link has changed is not relivant.
40045 * <script type="text/javascript">
40049 * @class Roo.form.DateField
40050 * @extends Roo.form.TriggerField
40051 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40053 * Create a new DateField
40054 * @param {Object} config
40056 Roo.form.DateField = function(config){
40057 Roo.form.DateField.superclass.constructor.call(this, config);
40063 * Fires when a date is selected
40064 * @param {Roo.form.DateField} combo This combo box
40065 * @param {Date} date The date selected
40072 if(typeof this.minValue == "string") {
40073 this.minValue = this.parseDate(this.minValue);
40075 if(typeof this.maxValue == "string") {
40076 this.maxValue = this.parseDate(this.maxValue);
40078 this.ddMatch = null;
40079 if(this.disabledDates){
40080 var dd = this.disabledDates;
40082 for(var i = 0; i < dd.length; i++){
40084 if(i != dd.length-1) {
40088 this.ddMatch = new RegExp(re + ")");
40092 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40094 * @cfg {String} format
40095 * The default date format string which can be overriden for localization support. The format must be
40096 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40100 * @cfg {String} altFormats
40101 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40102 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40104 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40106 * @cfg {Array} disabledDays
40107 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40109 disabledDays : null,
40111 * @cfg {String} disabledDaysText
40112 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40114 disabledDaysText : "Disabled",
40116 * @cfg {Array} disabledDates
40117 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40118 * expression so they are very powerful. Some examples:
40120 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40121 * <li>["03/08", "09/16"] would disable those days for every year</li>
40122 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40123 * <li>["03/../2006"] would disable every day in March 2006</li>
40124 * <li>["^03"] would disable every day in every March</li>
40126 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40127 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40129 disabledDates : null,
40131 * @cfg {String} disabledDatesText
40132 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40134 disabledDatesText : "Disabled",
40136 * @cfg {Date/String} minValue
40137 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40138 * valid format (defaults to null).
40142 * @cfg {Date/String} maxValue
40143 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40144 * valid format (defaults to null).
40148 * @cfg {String} minText
40149 * The error text to display when the date in the cell is before minValue (defaults to
40150 * 'The date in this field must be after {minValue}').
40152 minText : "The date in this field must be equal to or after {0}",
40154 * @cfg {String} maxText
40155 * The error text to display when the date in the cell is after maxValue (defaults to
40156 * 'The date in this field must be before {maxValue}').
40158 maxText : "The date in this field must be equal to or before {0}",
40160 * @cfg {String} invalidText
40161 * The error text to display when the date in the field is invalid (defaults to
40162 * '{value} is not a valid date - it must be in the format {format}').
40164 invalidText : "{0} is not a valid date - it must be in the format {1}",
40166 * @cfg {String} triggerClass
40167 * An additional CSS class used to style the trigger button. The trigger will always get the
40168 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40169 * which displays a calendar icon).
40171 triggerClass : 'x-form-date-trigger',
40175 * @cfg {Boolean} useIso
40176 * if enabled, then the date field will use a hidden field to store the
40177 * real value as iso formated date. default (false)
40181 * @cfg {String/Object} autoCreate
40182 * A DomHelper element spec, or true for a default element spec (defaults to
40183 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40186 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40189 hiddenField: false,
40191 onRender : function(ct, position)
40193 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40195 //this.el.dom.removeAttribute('name');
40196 Roo.log("Changing name?");
40197 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40198 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40200 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40201 // prevent input submission
40202 this.hiddenName = this.name;
40209 validateValue : function(value)
40211 value = this.formatDate(value);
40212 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40213 Roo.log('super failed');
40216 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40219 var svalue = value;
40220 value = this.parseDate(value);
40222 Roo.log('parse date failed' + svalue);
40223 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40226 var time = value.getTime();
40227 if(this.minValue && time < this.minValue.getTime()){
40228 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40231 if(this.maxValue && time > this.maxValue.getTime()){
40232 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40235 if(this.disabledDays){
40236 var day = value.getDay();
40237 for(var i = 0; i < this.disabledDays.length; i++) {
40238 if(day === this.disabledDays[i]){
40239 this.markInvalid(this.disabledDaysText);
40244 var fvalue = this.formatDate(value);
40245 if(this.ddMatch && this.ddMatch.test(fvalue)){
40246 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40253 // Provides logic to override the default TriggerField.validateBlur which just returns true
40254 validateBlur : function(){
40255 return !this.menu || !this.menu.isVisible();
40258 getName: function()
40260 // returns hidden if it's set..
40261 if (!this.rendered) {return ''};
40262 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40267 * Returns the current date value of the date field.
40268 * @return {Date} The date value
40270 getValue : function(){
40272 return this.hiddenField ?
40273 this.hiddenField.value :
40274 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40278 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40279 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40280 * (the default format used is "m/d/y").
40283 //All of these calls set the same date value (May 4, 2006)
40285 //Pass a date object:
40286 var dt = new Date('5/4/06');
40287 dateField.setValue(dt);
40289 //Pass a date string (default format):
40290 dateField.setValue('5/4/06');
40292 //Pass a date string (custom format):
40293 dateField.format = 'Y-m-d';
40294 dateField.setValue('2006-5-4');
40296 * @param {String/Date} date The date or valid date string
40298 setValue : function(date){
40299 if (this.hiddenField) {
40300 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40302 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40303 // make sure the value field is always stored as a date..
40304 this.value = this.parseDate(date);
40310 parseDate : function(value){
40311 if(!value || value instanceof Date){
40314 var v = Date.parseDate(value, this.format);
40315 if (!v && this.useIso) {
40316 v = Date.parseDate(value, 'Y-m-d');
40318 if(!v && this.altFormats){
40319 if(!this.altFormatsArray){
40320 this.altFormatsArray = this.altFormats.split("|");
40322 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40323 v = Date.parseDate(value, this.altFormatsArray[i]);
40330 formatDate : function(date, fmt){
40331 return (!date || !(date instanceof Date)) ?
40332 date : date.dateFormat(fmt || this.format);
40337 select: function(m, d){
40340 this.fireEvent('select', this, d);
40342 show : function(){ // retain focus styling
40346 this.focus.defer(10, this);
40347 var ml = this.menuListeners;
40348 this.menu.un("select", ml.select, this);
40349 this.menu.un("show", ml.show, this);
40350 this.menu.un("hide", ml.hide, this);
40355 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40356 onTriggerClick : function(){
40360 if(this.menu == null){
40361 this.menu = new Roo.menu.DateMenu();
40363 Roo.apply(this.menu.picker, {
40364 showClear: this.allowBlank,
40365 minDate : this.minValue,
40366 maxDate : this.maxValue,
40367 disabledDatesRE : this.ddMatch,
40368 disabledDatesText : this.disabledDatesText,
40369 disabledDays : this.disabledDays,
40370 disabledDaysText : this.disabledDaysText,
40371 format : this.useIso ? 'Y-m-d' : this.format,
40372 minText : String.format(this.minText, this.formatDate(this.minValue)),
40373 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40375 this.menu.on(Roo.apply({}, this.menuListeners, {
40378 this.menu.picker.setValue(this.getValue() || new Date());
40379 this.menu.show(this.el, "tl-bl?");
40382 beforeBlur : function(){
40383 var v = this.parseDate(this.getRawValue());
40393 isDirty : function() {
40394 if(this.disabled) {
40398 if(typeof(this.startValue) === 'undefined'){
40402 return String(this.getValue()) !== String(this.startValue);
40407 * Ext JS Library 1.1.1
40408 * Copyright(c) 2006-2007, Ext JS, LLC.
40410 * Originally Released Under LGPL - original licence link has changed is not relivant.
40413 * <script type="text/javascript">
40417 * @class Roo.form.MonthField
40418 * @extends Roo.form.TriggerField
40419 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40421 * Create a new MonthField
40422 * @param {Object} config
40424 Roo.form.MonthField = function(config){
40426 Roo.form.MonthField.superclass.constructor.call(this, config);
40432 * Fires when a date is selected
40433 * @param {Roo.form.MonthFieeld} combo This combo box
40434 * @param {Date} date The date selected
40441 if(typeof this.minValue == "string") {
40442 this.minValue = this.parseDate(this.minValue);
40444 if(typeof this.maxValue == "string") {
40445 this.maxValue = this.parseDate(this.maxValue);
40447 this.ddMatch = null;
40448 if(this.disabledDates){
40449 var dd = this.disabledDates;
40451 for(var i = 0; i < dd.length; i++){
40453 if(i != dd.length-1) {
40457 this.ddMatch = new RegExp(re + ")");
40461 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40463 * @cfg {String} format
40464 * The default date format string which can be overriden for localization support. The format must be
40465 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40469 * @cfg {String} altFormats
40470 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40471 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40473 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40475 * @cfg {Array} disabledDays
40476 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40478 disabledDays : [0,1,2,3,4,5,6],
40480 * @cfg {String} disabledDaysText
40481 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40483 disabledDaysText : "Disabled",
40485 * @cfg {Array} disabledDates
40486 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40487 * expression so they are very powerful. Some examples:
40489 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40490 * <li>["03/08", "09/16"] would disable those days for every year</li>
40491 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40492 * <li>["03/../2006"] would disable every day in March 2006</li>
40493 * <li>["^03"] would disable every day in every March</li>
40495 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40496 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40498 disabledDates : null,
40500 * @cfg {String} disabledDatesText
40501 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40503 disabledDatesText : "Disabled",
40505 * @cfg {Date/String} minValue
40506 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40507 * valid format (defaults to null).
40511 * @cfg {Date/String} maxValue
40512 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40513 * valid format (defaults to null).
40517 * @cfg {String} minText
40518 * The error text to display when the date in the cell is before minValue (defaults to
40519 * 'The date in this field must be after {minValue}').
40521 minText : "The date in this field must be equal to or after {0}",
40523 * @cfg {String} maxTextf
40524 * The error text to display when the date in the cell is after maxValue (defaults to
40525 * 'The date in this field must be before {maxValue}').
40527 maxText : "The date in this field must be equal to or before {0}",
40529 * @cfg {String} invalidText
40530 * The error text to display when the date in the field is invalid (defaults to
40531 * '{value} is not a valid date - it must be in the format {format}').
40533 invalidText : "{0} is not a valid date - it must be in the format {1}",
40535 * @cfg {String} triggerClass
40536 * An additional CSS class used to style the trigger button. The trigger will always get the
40537 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40538 * which displays a calendar icon).
40540 triggerClass : 'x-form-date-trigger',
40544 * @cfg {Boolean} useIso
40545 * if enabled, then the date field will use a hidden field to store the
40546 * real value as iso formated date. default (true)
40550 * @cfg {String/Object} autoCreate
40551 * A DomHelper element spec, or true for a default element spec (defaults to
40552 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40555 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40558 hiddenField: false,
40560 hideMonthPicker : false,
40562 onRender : function(ct, position)
40564 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40566 this.el.dom.removeAttribute('name');
40567 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40569 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40570 // prevent input submission
40571 this.hiddenName = this.name;
40578 validateValue : function(value)
40580 value = this.formatDate(value);
40581 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40584 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40587 var svalue = value;
40588 value = this.parseDate(value);
40590 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40593 var time = value.getTime();
40594 if(this.minValue && time < this.minValue.getTime()){
40595 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40598 if(this.maxValue && time > this.maxValue.getTime()){
40599 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40602 /*if(this.disabledDays){
40603 var day = value.getDay();
40604 for(var i = 0; i < this.disabledDays.length; i++) {
40605 if(day === this.disabledDays[i]){
40606 this.markInvalid(this.disabledDaysText);
40612 var fvalue = this.formatDate(value);
40613 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40614 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40622 // Provides logic to override the default TriggerField.validateBlur which just returns true
40623 validateBlur : function(){
40624 return !this.menu || !this.menu.isVisible();
40628 * Returns the current date value of the date field.
40629 * @return {Date} The date value
40631 getValue : function(){
40635 return this.hiddenField ?
40636 this.hiddenField.value :
40637 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40641 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40642 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40643 * (the default format used is "m/d/y").
40646 //All of these calls set the same date value (May 4, 2006)
40648 //Pass a date object:
40649 var dt = new Date('5/4/06');
40650 monthField.setValue(dt);
40652 //Pass a date string (default format):
40653 monthField.setValue('5/4/06');
40655 //Pass a date string (custom format):
40656 monthField.format = 'Y-m-d';
40657 monthField.setValue('2006-5-4');
40659 * @param {String/Date} date The date or valid date string
40661 setValue : function(date){
40662 Roo.log('month setValue' + date);
40663 // can only be first of month..
40665 var val = this.parseDate(date);
40667 if (this.hiddenField) {
40668 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40670 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40671 this.value = this.parseDate(date);
40675 parseDate : function(value){
40676 if(!value || value instanceof Date){
40677 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40680 var v = Date.parseDate(value, this.format);
40681 if (!v && this.useIso) {
40682 v = Date.parseDate(value, 'Y-m-d');
40686 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40690 if(!v && this.altFormats){
40691 if(!this.altFormatsArray){
40692 this.altFormatsArray = this.altFormats.split("|");
40694 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40695 v = Date.parseDate(value, this.altFormatsArray[i]);
40702 formatDate : function(date, fmt){
40703 return (!date || !(date instanceof Date)) ?
40704 date : date.dateFormat(fmt || this.format);
40709 select: function(m, d){
40711 this.fireEvent('select', this, d);
40713 show : function(){ // retain focus styling
40717 this.focus.defer(10, this);
40718 var ml = this.menuListeners;
40719 this.menu.un("select", ml.select, this);
40720 this.menu.un("show", ml.show, this);
40721 this.menu.un("hide", ml.hide, this);
40725 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40726 onTriggerClick : function(){
40730 if(this.menu == null){
40731 this.menu = new Roo.menu.DateMenu();
40735 Roo.apply(this.menu.picker, {
40737 showClear: this.allowBlank,
40738 minDate : this.minValue,
40739 maxDate : this.maxValue,
40740 disabledDatesRE : this.ddMatch,
40741 disabledDatesText : this.disabledDatesText,
40743 format : this.useIso ? 'Y-m-d' : this.format,
40744 minText : String.format(this.minText, this.formatDate(this.minValue)),
40745 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40748 this.menu.on(Roo.apply({}, this.menuListeners, {
40756 // hide month picker get's called when we called by 'before hide';
40758 var ignorehide = true;
40759 p.hideMonthPicker = function(disableAnim){
40763 if(this.monthPicker){
40764 Roo.log("hideMonthPicker called");
40765 if(disableAnim === true){
40766 this.monthPicker.hide();
40768 this.monthPicker.slideOut('t', {duration:.2});
40769 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40770 p.fireEvent("select", this, this.value);
40776 Roo.log('picker set value');
40777 Roo.log(this.getValue());
40778 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40779 m.show(this.el, 'tl-bl?');
40780 ignorehide = false;
40781 // this will trigger hideMonthPicker..
40784 // hidden the day picker
40785 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40791 p.showMonthPicker.defer(100, p);
40797 beforeBlur : function(){
40798 var v = this.parseDate(this.getRawValue());
40804 /** @cfg {Boolean} grow @hide */
40805 /** @cfg {Number} growMin @hide */
40806 /** @cfg {Number} growMax @hide */
40813 * Ext JS Library 1.1.1
40814 * Copyright(c) 2006-2007, Ext JS, LLC.
40816 * Originally Released Under LGPL - original licence link has changed is not relivant.
40819 * <script type="text/javascript">
40824 * @class Roo.form.ComboBox
40825 * @extends Roo.form.TriggerField
40826 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40828 * Create a new ComboBox.
40829 * @param {Object} config Configuration options
40831 Roo.form.ComboBox = function(config){
40832 Roo.form.ComboBox.superclass.constructor.call(this, config);
40836 * Fires when the dropdown list is expanded
40837 * @param {Roo.form.ComboBox} combo This combo box
40842 * Fires when the dropdown list is collapsed
40843 * @param {Roo.form.ComboBox} combo This combo box
40847 * @event beforeselect
40848 * Fires before a list item is selected. Return false to cancel the selection.
40849 * @param {Roo.form.ComboBox} combo This combo box
40850 * @param {Roo.data.Record} record The data record returned from the underlying store
40851 * @param {Number} index The index of the selected item in the dropdown list
40853 'beforeselect' : true,
40856 * Fires when a list item is selected
40857 * @param {Roo.form.ComboBox} combo This combo box
40858 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
40859 * @param {Number} index The index of the selected item in the dropdown list
40863 * @event beforequery
40864 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
40865 * The event object passed has these properties:
40866 * @param {Roo.form.ComboBox} combo This combo box
40867 * @param {String} query The query
40868 * @param {Boolean} forceAll true to force "all" query
40869 * @param {Boolean} cancel true to cancel the query
40870 * @param {Object} e The query event object
40872 'beforequery': true,
40875 * Fires when the 'add' icon is pressed (add a listener to enable add button)
40876 * @param {Roo.form.ComboBox} combo This combo box
40881 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
40882 * @param {Roo.form.ComboBox} combo This combo box
40883 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
40889 if(this.transform){
40890 this.allowDomMove = false;
40891 var s = Roo.getDom(this.transform);
40892 if(!this.hiddenName){
40893 this.hiddenName = s.name;
40896 this.mode = 'local';
40897 var d = [], opts = s.options;
40898 for(var i = 0, len = opts.length;i < len; i++){
40900 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
40902 this.value = value;
40904 d.push([value, o.text]);
40906 this.store = new Roo.data.SimpleStore({
40908 fields: ['value', 'text'],
40911 this.valueField = 'value';
40912 this.displayField = 'text';
40914 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
40915 if(!this.lazyRender){
40916 this.target = true;
40917 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
40918 s.parentNode.removeChild(s); // remove it
40919 this.render(this.el.parentNode);
40921 s.parentNode.removeChild(s); // remove it
40926 this.store = Roo.factory(this.store, Roo.data);
40929 this.selectedIndex = -1;
40930 if(this.mode == 'local'){
40931 if(config.queryDelay === undefined){
40932 this.queryDelay = 10;
40934 if(config.minChars === undefined){
40940 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
40942 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
40945 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
40946 * rendering into an Roo.Editor, defaults to false)
40949 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
40950 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
40953 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
40956 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
40957 * the dropdown list (defaults to undefined, with no header element)
40961 * @cfg {String/Roo.Template} tpl The template to use to render the output
40965 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
40967 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
40969 listWidth: undefined,
40971 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
40972 * mode = 'remote' or 'text' if mode = 'local')
40974 displayField: undefined,
40976 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
40977 * mode = 'remote' or 'value' if mode = 'local').
40978 * Note: use of a valueField requires the user make a selection
40979 * in order for a value to be mapped.
40981 valueField: undefined,
40985 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
40986 * field's data value (defaults to the underlying DOM element's name)
40988 hiddenName: undefined,
40990 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
40994 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
40996 selectedClass: 'x-combo-selected',
40998 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40999 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41000 * which displays a downward arrow icon).
41002 triggerClass : 'x-form-arrow-trigger',
41004 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41008 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41009 * anchor positions (defaults to 'tl-bl')
41011 listAlign: 'tl-bl?',
41013 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41017 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41018 * query specified by the allQuery config option (defaults to 'query')
41020 triggerAction: 'query',
41022 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41023 * (defaults to 4, does not apply if editable = false)
41027 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41028 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41032 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41033 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41037 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41038 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41042 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41043 * when editable = true (defaults to false)
41045 selectOnFocus:false,
41047 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41049 queryParam: 'query',
41051 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41052 * when mode = 'remote' (defaults to 'Loading...')
41054 loadingText: 'Loading...',
41056 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41060 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41064 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41065 * traditional select (defaults to true)
41069 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41073 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41077 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41078 * listWidth has a higher value)
41082 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41083 * allow the user to set arbitrary text into the field (defaults to false)
41085 forceSelection:false,
41087 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41088 * if typeAhead = true (defaults to 250)
41090 typeAheadDelay : 250,
41092 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41093 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41095 valueNotFoundText : undefined,
41097 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41099 blockFocus : false,
41102 * @cfg {Boolean} disableClear Disable showing of clear button.
41104 disableClear : false,
41106 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41108 alwaysQuery : false,
41114 // element that contains real text value.. (when hidden is used..)
41117 onRender : function(ct, position){
41118 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41119 if(this.hiddenName){
41120 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41122 this.hiddenField.value =
41123 this.hiddenValue !== undefined ? this.hiddenValue :
41124 this.value !== undefined ? this.value : '';
41126 // prevent input submission
41127 this.el.dom.removeAttribute('name');
41132 this.el.dom.setAttribute('autocomplete', 'off');
41135 var cls = 'x-combo-list';
41137 this.list = new Roo.Layer({
41138 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41141 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41142 this.list.setWidth(lw);
41143 this.list.swallowEvent('mousewheel');
41144 this.assetHeight = 0;
41147 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41148 this.assetHeight += this.header.getHeight();
41151 this.innerList = this.list.createChild({cls:cls+'-inner'});
41152 this.innerList.on('mouseover', this.onViewOver, this);
41153 this.innerList.on('mousemove', this.onViewMove, this);
41154 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41156 if(this.allowBlank && !this.pageSize && !this.disableClear){
41157 this.footer = this.list.createChild({cls:cls+'-ft'});
41158 this.pageTb = new Roo.Toolbar(this.footer);
41162 this.footer = this.list.createChild({cls:cls+'-ft'});
41163 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41164 {pageSize: this.pageSize});
41168 if (this.pageTb && this.allowBlank && !this.disableClear) {
41170 this.pageTb.add(new Roo.Toolbar.Fill(), {
41171 cls: 'x-btn-icon x-btn-clear',
41173 handler: function()
41176 _this.clearValue();
41177 _this.onSelect(false, -1);
41182 this.assetHeight += this.footer.getHeight();
41187 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41190 this.view = new Roo.View(this.innerList, this.tpl, {
41191 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41194 this.view.on('click', this.onViewClick, this);
41196 this.store.on('beforeload', this.onBeforeLoad, this);
41197 this.store.on('load', this.onLoad, this);
41198 this.store.on('loadexception', this.onLoadException, this);
41200 if(this.resizable){
41201 this.resizer = new Roo.Resizable(this.list, {
41202 pinned:true, handles:'se'
41204 this.resizer.on('resize', function(r, w, h){
41205 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41206 this.listWidth = w;
41207 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41208 this.restrictHeight();
41210 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41212 if(!this.editable){
41213 this.editable = true;
41214 this.setEditable(false);
41218 if (typeof(this.events.add.listeners) != 'undefined') {
41220 this.addicon = this.wrap.createChild(
41221 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41223 this.addicon.on('click', function(e) {
41224 this.fireEvent('add', this);
41227 if (typeof(this.events.edit.listeners) != 'undefined') {
41229 this.editicon = this.wrap.createChild(
41230 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41231 if (this.addicon) {
41232 this.editicon.setStyle('margin-left', '40px');
41234 this.editicon.on('click', function(e) {
41236 // we fire even if inothing is selected..
41237 this.fireEvent('edit', this, this.lastData );
41247 initEvents : function(){
41248 Roo.form.ComboBox.superclass.initEvents.call(this);
41250 this.keyNav = new Roo.KeyNav(this.el, {
41251 "up" : function(e){
41252 this.inKeyMode = true;
41256 "down" : function(e){
41257 if(!this.isExpanded()){
41258 this.onTriggerClick();
41260 this.inKeyMode = true;
41265 "enter" : function(e){
41266 this.onViewClick();
41270 "esc" : function(e){
41274 "tab" : function(e){
41275 this.onViewClick(false);
41276 this.fireEvent("specialkey", this, e);
41282 doRelay : function(foo, bar, hname){
41283 if(hname == 'down' || this.scope.isExpanded()){
41284 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41291 this.queryDelay = Math.max(this.queryDelay || 10,
41292 this.mode == 'local' ? 10 : 250);
41293 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41294 if(this.typeAhead){
41295 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41297 if(this.editable !== false){
41298 this.el.on("keyup", this.onKeyUp, this);
41300 if(this.forceSelection){
41301 this.on('blur', this.doForce, this);
41305 onDestroy : function(){
41307 this.view.setStore(null);
41308 this.view.el.removeAllListeners();
41309 this.view.el.remove();
41310 this.view.purgeListeners();
41313 this.list.destroy();
41316 this.store.un('beforeload', this.onBeforeLoad, this);
41317 this.store.un('load', this.onLoad, this);
41318 this.store.un('loadexception', this.onLoadException, this);
41320 Roo.form.ComboBox.superclass.onDestroy.call(this);
41324 fireKey : function(e){
41325 if(e.isNavKeyPress() && !this.list.isVisible()){
41326 this.fireEvent("specialkey", this, e);
41331 onResize: function(w, h){
41332 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41334 if(typeof w != 'number'){
41335 // we do not handle it!?!?
41338 var tw = this.trigger.getWidth();
41339 tw += this.addicon ? this.addicon.getWidth() : 0;
41340 tw += this.editicon ? this.editicon.getWidth() : 0;
41342 this.el.setWidth( this.adjustWidth('input', x));
41344 this.trigger.setStyle('left', x+'px');
41346 if(this.list && this.listWidth === undefined){
41347 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41348 this.list.setWidth(lw);
41349 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41357 * Allow or prevent the user from directly editing the field text. If false is passed,
41358 * the user will only be able to select from the items defined in the dropdown list. This method
41359 * is the runtime equivalent of setting the 'editable' config option at config time.
41360 * @param {Boolean} value True to allow the user to directly edit the field text
41362 setEditable : function(value){
41363 if(value == this.editable){
41366 this.editable = value;
41368 this.el.dom.setAttribute('readOnly', true);
41369 this.el.on('mousedown', this.onTriggerClick, this);
41370 this.el.addClass('x-combo-noedit');
41372 this.el.dom.setAttribute('readOnly', false);
41373 this.el.un('mousedown', this.onTriggerClick, this);
41374 this.el.removeClass('x-combo-noedit');
41379 onBeforeLoad : function(){
41380 if(!this.hasFocus){
41383 this.innerList.update(this.loadingText ?
41384 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41385 this.restrictHeight();
41386 this.selectedIndex = -1;
41390 onLoad : function(){
41391 if(!this.hasFocus){
41394 if(this.store.getCount() > 0){
41396 this.restrictHeight();
41397 if(this.lastQuery == this.allQuery){
41399 this.el.dom.select();
41401 if(!this.selectByValue(this.value, true)){
41402 this.select(0, true);
41406 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41407 this.taTask.delay(this.typeAheadDelay);
41411 this.onEmptyResults();
41416 onLoadException : function()
41419 Roo.log(this.store.reader.jsonData);
41420 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41421 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41427 onTypeAhead : function(){
41428 if(this.store.getCount() > 0){
41429 var r = this.store.getAt(0);
41430 var newValue = r.data[this.displayField];
41431 var len = newValue.length;
41432 var selStart = this.getRawValue().length;
41433 if(selStart != len){
41434 this.setRawValue(newValue);
41435 this.selectText(selStart, newValue.length);
41441 onSelect : function(record, index){
41442 if(this.fireEvent('beforeselect', this, record, index) !== false){
41443 this.setFromData(index > -1 ? record.data : false);
41445 this.fireEvent('select', this, record, index);
41450 * Returns the currently selected field value or empty string if no value is set.
41451 * @return {String} value The selected value
41453 getValue : function(){
41454 if(this.valueField){
41455 return typeof this.value != 'undefined' ? this.value : '';
41457 return Roo.form.ComboBox.superclass.getValue.call(this);
41461 * Clears any text/value currently set in the field
41463 clearValue : function(){
41464 if(this.hiddenField){
41465 this.hiddenField.value = '';
41468 this.setRawValue('');
41469 this.lastSelectionText = '';
41474 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41475 * will be displayed in the field. If the value does not match the data value of an existing item,
41476 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41477 * Otherwise the field will be blank (although the value will still be set).
41478 * @param {String} value The value to match
41480 setValue : function(v){
41482 if(this.valueField){
41483 var r = this.findRecord(this.valueField, v);
41485 text = r.data[this.displayField];
41486 }else if(this.valueNotFoundText !== undefined){
41487 text = this.valueNotFoundText;
41490 this.lastSelectionText = text;
41491 if(this.hiddenField){
41492 this.hiddenField.value = v;
41494 Roo.form.ComboBox.superclass.setValue.call(this, text);
41498 * @property {Object} the last set data for the element
41503 * Sets the value of the field based on a object which is related to the record format for the store.
41504 * @param {Object} value the value to set as. or false on reset?
41506 setFromData : function(o){
41507 var dv = ''; // display value
41508 var vv = ''; // value value..
41510 if (this.displayField) {
41511 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41513 // this is an error condition!!!
41514 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41517 if(this.valueField){
41518 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41520 if(this.hiddenField){
41521 this.hiddenField.value = vv;
41523 this.lastSelectionText = dv;
41524 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41528 // no hidden field.. - we store the value in 'value', but still display
41529 // display field!!!!
41530 this.lastSelectionText = dv;
41531 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41537 reset : function(){
41538 // overridden so that last data is reset..
41539 this.setValue(this.resetValue);
41540 this.clearInvalid();
41541 this.lastData = false;
41543 this.view.clearSelections();
41547 findRecord : function(prop, value){
41549 if(this.store.getCount() > 0){
41550 this.store.each(function(r){
41551 if(r.data[prop] == value){
41561 getName: function()
41563 // returns hidden if it's set..
41564 if (!this.rendered) {return ''};
41565 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41569 onViewMove : function(e, t){
41570 this.inKeyMode = false;
41574 onViewOver : function(e, t){
41575 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41578 var item = this.view.findItemFromChild(t);
41580 var index = this.view.indexOf(item);
41581 this.select(index, false);
41586 onViewClick : function(doFocus)
41588 var index = this.view.getSelectedIndexes()[0];
41589 var r = this.store.getAt(index);
41591 this.onSelect(r, index);
41593 if(doFocus !== false && !this.blockFocus){
41599 restrictHeight : function(){
41600 this.innerList.dom.style.height = '';
41601 var inner = this.innerList.dom;
41602 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41603 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41604 this.list.beginUpdate();
41605 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41606 this.list.alignTo(this.el, this.listAlign);
41607 this.list.endUpdate();
41611 onEmptyResults : function(){
41616 * Returns true if the dropdown list is expanded, else false.
41618 isExpanded : function(){
41619 return this.list.isVisible();
41623 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41624 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41625 * @param {String} value The data value of the item to select
41626 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41627 * selected item if it is not currently in view (defaults to true)
41628 * @return {Boolean} True if the value matched an item in the list, else false
41630 selectByValue : function(v, scrollIntoView){
41631 if(v !== undefined && v !== null){
41632 var r = this.findRecord(this.valueField || this.displayField, v);
41634 this.select(this.store.indexOf(r), scrollIntoView);
41642 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41643 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41644 * @param {Number} index The zero-based index of the list item to select
41645 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41646 * selected item if it is not currently in view (defaults to true)
41648 select : function(index, scrollIntoView){
41649 this.selectedIndex = index;
41650 this.view.select(index);
41651 if(scrollIntoView !== false){
41652 var el = this.view.getNode(index);
41654 this.innerList.scrollChildIntoView(el, false);
41660 selectNext : function(){
41661 var ct = this.store.getCount();
41663 if(this.selectedIndex == -1){
41665 }else if(this.selectedIndex < ct-1){
41666 this.select(this.selectedIndex+1);
41672 selectPrev : function(){
41673 var ct = this.store.getCount();
41675 if(this.selectedIndex == -1){
41677 }else if(this.selectedIndex != 0){
41678 this.select(this.selectedIndex-1);
41684 onKeyUp : function(e){
41685 if(this.editable !== false && !e.isSpecialKey()){
41686 this.lastKey = e.getKey();
41687 this.dqTask.delay(this.queryDelay);
41692 validateBlur : function(){
41693 return !this.list || !this.list.isVisible();
41697 initQuery : function(){
41698 this.doQuery(this.getRawValue());
41702 doForce : function(){
41703 if(this.el.dom.value.length > 0){
41704 this.el.dom.value =
41705 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41711 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41712 * query allowing the query action to be canceled if needed.
41713 * @param {String} query The SQL query to execute
41714 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41715 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41716 * saved in the current store (defaults to false)
41718 doQuery : function(q, forceAll){
41719 if(q === undefined || q === null){
41724 forceAll: forceAll,
41728 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41732 forceAll = qe.forceAll;
41733 if(forceAll === true || (q.length >= this.minChars)){
41734 if(this.lastQuery != q || this.alwaysQuery){
41735 this.lastQuery = q;
41736 if(this.mode == 'local'){
41737 this.selectedIndex = -1;
41739 this.store.clearFilter();
41741 this.store.filter(this.displayField, q);
41745 this.store.baseParams[this.queryParam] = q;
41747 params: this.getParams(q)
41752 this.selectedIndex = -1;
41759 getParams : function(q){
41761 //p[this.queryParam] = q;
41764 p.limit = this.pageSize;
41770 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41772 collapse : function(){
41773 if(!this.isExpanded()){
41777 Roo.get(document).un('mousedown', this.collapseIf, this);
41778 Roo.get(document).un('mousewheel', this.collapseIf, this);
41779 if (!this.editable) {
41780 Roo.get(document).un('keydown', this.listKeyPress, this);
41782 this.fireEvent('collapse', this);
41786 collapseIf : function(e){
41787 if(!e.within(this.wrap) && !e.within(this.list)){
41793 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41795 expand : function(){
41796 if(this.isExpanded() || !this.hasFocus){
41799 this.list.alignTo(this.el, this.listAlign);
41801 Roo.get(document).on('mousedown', this.collapseIf, this);
41802 Roo.get(document).on('mousewheel', this.collapseIf, this);
41803 if (!this.editable) {
41804 Roo.get(document).on('keydown', this.listKeyPress, this);
41807 this.fireEvent('expand', this);
41811 // Implements the default empty TriggerField.onTriggerClick function
41812 onTriggerClick : function(){
41816 if(this.isExpanded()){
41818 if (!this.blockFocus) {
41823 this.hasFocus = true;
41824 if(this.triggerAction == 'all') {
41825 this.doQuery(this.allQuery, true);
41827 this.doQuery(this.getRawValue());
41829 if (!this.blockFocus) {
41834 listKeyPress : function(e)
41836 //Roo.log('listkeypress');
41837 // scroll to first matching element based on key pres..
41838 if (e.isSpecialKey()) {
41841 var k = String.fromCharCode(e.getKey()).toUpperCase();
41844 var csel = this.view.getSelectedNodes();
41845 var cselitem = false;
41847 var ix = this.view.indexOf(csel[0]);
41848 cselitem = this.store.getAt(ix);
41849 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41855 this.store.each(function(v) {
41857 // start at existing selection.
41858 if (cselitem.id == v.id) {
41864 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
41865 match = this.store.indexOf(v);
41870 if (match === false) {
41871 return true; // no more action?
41874 this.view.select(match);
41875 var sn = Roo.get(this.view.getSelectedNodes()[0]);
41876 sn.scrollIntoView(sn.dom.parentNode, false);
41880 * @cfg {Boolean} grow
41884 * @cfg {Number} growMin
41888 * @cfg {Number} growMax
41896 * Copyright(c) 2010-2012, Roo J Solutions Limited
41903 * @class Roo.form.ComboBoxArray
41904 * @extends Roo.form.TextField
41905 * A facebook style adder... for lists of email / people / countries etc...
41906 * pick multiple items from a combo box, and shows each one.
41908 * Fred [x] Brian [x] [Pick another |v]
41911 * For this to work: it needs various extra information
41912 * - normal combo problay has
41914 * + displayField, valueField
41916 * For our purpose...
41919 * If we change from 'extends' to wrapping...
41926 * Create a new ComboBoxArray.
41927 * @param {Object} config Configuration options
41931 Roo.form.ComboBoxArray = function(config)
41935 * @event beforeremove
41936 * Fires before remove the value from the list
41937 * @param {Roo.form.ComboBoxArray} _self This combo box array
41938 * @param {Roo.form.ComboBoxArray.Item} item removed item
41940 'beforeremove' : true,
41943 * Fires when remove the value from the list
41944 * @param {Roo.form.ComboBoxArray} _self This combo box array
41945 * @param {Roo.form.ComboBoxArray.Item} item removed item
41952 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
41954 this.items = new Roo.util.MixedCollection(false);
41956 // construct the child combo...
41966 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
41969 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
41974 // behavies liek a hiddne field
41975 inputType: 'hidden',
41977 * @cfg {Number} width The width of the box that displays the selected element
41984 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
41988 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
41990 hiddenName : false,
41993 // private the array of items that are displayed..
41995 // private - the hidden field el.
41997 // private - the filed el..
42000 //validateValue : function() { return true; }, // all values are ok!
42001 //onAddClick: function() { },
42003 onRender : function(ct, position)
42006 // create the standard hidden element
42007 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42010 // give fake names to child combo;
42011 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42012 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
42014 this.combo = Roo.factory(this.combo, Roo.form);
42015 this.combo.onRender(ct, position);
42016 if (typeof(this.combo.width) != 'undefined') {
42017 this.combo.onResize(this.combo.width,0);
42020 this.combo.initEvents();
42022 // assigned so form know we need to do this..
42023 this.store = this.combo.store;
42024 this.valueField = this.combo.valueField;
42025 this.displayField = this.combo.displayField ;
42028 this.combo.wrap.addClass('x-cbarray-grp');
42030 var cbwrap = this.combo.wrap.createChild(
42031 {tag: 'div', cls: 'x-cbarray-cb'},
42036 this.hiddenEl = this.combo.wrap.createChild({
42037 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42039 this.el = this.combo.wrap.createChild({
42040 tag: 'input', type:'hidden' , name: this.name, value : ''
42042 // this.el.dom.removeAttribute("name");
42045 this.outerWrap = this.combo.wrap;
42046 this.wrap = cbwrap;
42048 this.outerWrap.setWidth(this.width);
42049 this.outerWrap.dom.removeChild(this.el.dom);
42051 this.wrap.dom.appendChild(this.el.dom);
42052 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42053 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42055 this.combo.trigger.setStyle('position','relative');
42056 this.combo.trigger.setStyle('left', '0px');
42057 this.combo.trigger.setStyle('top', '2px');
42059 this.combo.el.setStyle('vertical-align', 'text-bottom');
42061 //this.trigger.setStyle('vertical-align', 'top');
42063 // this should use the code from combo really... on('add' ....)
42067 this.adder = this.outerWrap.createChild(
42068 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42070 this.adder.on('click', function(e) {
42071 _t.fireEvent('adderclick', this, e);
42075 //this.adder.on('click', this.onAddClick, _t);
42078 this.combo.on('select', function(cb, rec, ix) {
42079 this.addItem(rec.data);
42082 cb.el.dom.value = '';
42083 //cb.lastData = rec.data;
42092 getName: function()
42094 // returns hidden if it's set..
42095 if (!this.rendered) {return ''};
42096 return this.hiddenName ? this.hiddenName : this.name;
42101 onResize: function(w, h){
42104 // not sure if this is needed..
42105 //this.combo.onResize(w,h);
42107 if(typeof w != 'number'){
42108 // we do not handle it!?!?
42111 var tw = this.combo.trigger.getWidth();
42112 tw += this.addicon ? this.addicon.getWidth() : 0;
42113 tw += this.editicon ? this.editicon.getWidth() : 0;
42115 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42117 this.combo.trigger.setStyle('left', '0px');
42119 if(this.list && this.listWidth === undefined){
42120 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42121 this.list.setWidth(lw);
42122 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42129 addItem: function(rec)
42131 var valueField = this.combo.valueField;
42132 var displayField = this.combo.displayField;
42133 if (this.items.indexOfKey(rec[valueField]) > -1) {
42134 //console.log("GOT " + rec.data.id);
42138 var x = new Roo.form.ComboBoxArray.Item({
42139 //id : rec[this.idField],
42141 displayField : displayField ,
42142 tipField : displayField ,
42146 this.items.add(rec[valueField],x);
42147 // add it before the element..
42148 this.updateHiddenEl();
42149 x.render(this.outerWrap, this.wrap.dom);
42150 // add the image handler..
42153 updateHiddenEl : function()
42156 if (!this.hiddenEl) {
42160 var idField = this.combo.valueField;
42162 this.items.each(function(f) {
42163 ar.push(f.data[idField]);
42166 this.hiddenEl.dom.value = ar.join(',');
42172 this.items.clear();
42174 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42178 this.el.dom.value = '';
42179 if (this.hiddenEl) {
42180 this.hiddenEl.dom.value = '';
42184 getValue: function()
42186 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42188 setValue: function(v) // not a valid action - must use addItems..
42195 if (this.store.isLocal && (typeof(v) == 'string')) {
42196 // then we can use the store to find the values..
42197 // comma seperated at present.. this needs to allow JSON based encoding..
42198 this.hiddenEl.value = v;
42200 Roo.each(v.split(','), function(k) {
42201 Roo.log("CHECK " + this.valueField + ',' + k);
42202 var li = this.store.query(this.valueField, k);
42207 add[this.valueField] = k;
42208 add[this.displayField] = li.item(0).data[this.displayField];
42214 if (typeof(v) == 'object' ) {
42215 // then let's assume it's an array of objects..
42216 Roo.each(v, function(l) {
42224 setFromData: function(v)
42226 // this recieves an object, if setValues is called.
42228 this.el.dom.value = v[this.displayField];
42229 this.hiddenEl.dom.value = v[this.valueField];
42230 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42233 var kv = v[this.valueField];
42234 var dv = v[this.displayField];
42235 kv = typeof(kv) != 'string' ? '' : kv;
42236 dv = typeof(dv) != 'string' ? '' : dv;
42239 var keys = kv.split(',');
42240 var display = dv.split(',');
42241 for (var i = 0 ; i < keys.length; i++) {
42244 add[this.valueField] = keys[i];
42245 add[this.displayField] = display[i];
42253 * Validates the combox array value
42254 * @return {Boolean} True if the value is valid, else false
42256 validate : function(){
42257 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42258 this.clearInvalid();
42264 validateValue : function(value){
42265 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42273 isDirty : function() {
42274 if(this.disabled) {
42279 var d = Roo.decode(String(this.originalValue));
42281 return String(this.getValue()) !== String(this.originalValue);
42284 var originalValue = [];
42286 for (var i = 0; i < d.length; i++){
42287 originalValue.push(d[i][this.valueField]);
42290 return String(this.getValue()) !== String(originalValue.join(','));
42299 * @class Roo.form.ComboBoxArray.Item
42300 * @extends Roo.BoxComponent
42301 * A selected item in the list
42302 * Fred [x] Brian [x] [Pick another |v]
42305 * Create a new item.
42306 * @param {Object} config Configuration options
42309 Roo.form.ComboBoxArray.Item = function(config) {
42310 config.id = Roo.id();
42311 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42314 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42317 displayField : false,
42321 defaultAutoCreate : {
42323 cls: 'x-cbarray-item',
42330 src : Roo.BLANK_IMAGE_URL ,
42338 onRender : function(ct, position)
42340 Roo.form.Field.superclass.onRender.call(this, ct, position);
42343 var cfg = this.getAutoCreate();
42344 this.el = ct.createChild(cfg, position);
42347 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42349 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42350 this.cb.renderer(this.data) :
42351 String.format('{0}',this.data[this.displayField]);
42354 this.el.child('div').dom.setAttribute('qtip',
42355 String.format('{0}',this.data[this.tipField])
42358 this.el.child('img').on('click', this.remove, this);
42362 remove : function()
42364 if(this.cb.disabled){
42368 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42369 this.cb.items.remove(this);
42370 this.el.child('img').un('click', this.remove, this);
42372 this.cb.updateHiddenEl();
42374 this.cb.fireEvent('remove', this.cb, this);
42380 * Ext JS Library 1.1.1
42381 * Copyright(c) 2006-2007, Ext JS, LLC.
42383 * Originally Released Under LGPL - original licence link has changed is not relivant.
42386 * <script type="text/javascript">
42389 * @class Roo.form.Checkbox
42390 * @extends Roo.form.Field
42391 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42393 * Creates a new Checkbox
42394 * @param {Object} config Configuration options
42396 Roo.form.Checkbox = function(config){
42397 Roo.form.Checkbox.superclass.constructor.call(this, config);
42401 * Fires when the checkbox is checked or unchecked.
42402 * @param {Roo.form.Checkbox} this This checkbox
42403 * @param {Boolean} checked The new checked value
42409 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42411 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42413 focusClass : undefined,
42415 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42417 fieldClass: "x-form-field",
42419 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42423 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42424 * {tag: "input", type: "checkbox", autocomplete: "off"})
42426 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42428 * @cfg {String} boxLabel The text that appears beside the checkbox
42432 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42436 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42438 valueOff: '0', // value when not checked..
42440 actionMode : 'viewEl',
42443 itemCls : 'x-menu-check-item x-form-item',
42444 groupClass : 'x-menu-group-item',
42445 inputType : 'hidden',
42448 inSetChecked: false, // check that we are not calling self...
42450 inputElement: false, // real input element?
42451 basedOn: false, // ????
42453 isFormField: true, // not sure where this is needed!!!!
42455 onResize : function(){
42456 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42457 if(!this.boxLabel){
42458 this.el.alignTo(this.wrap, 'c-c');
42462 initEvents : function(){
42463 Roo.form.Checkbox.superclass.initEvents.call(this);
42464 this.el.on("click", this.onClick, this);
42465 this.el.on("change", this.onClick, this);
42469 getResizeEl : function(){
42473 getPositionEl : function(){
42478 onRender : function(ct, position){
42479 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42481 if(this.inputValue !== undefined){
42482 this.el.dom.value = this.inputValue;
42485 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42486 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42487 var viewEl = this.wrap.createChild({
42488 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42489 this.viewEl = viewEl;
42490 this.wrap.on('click', this.onClick, this);
42492 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42493 this.el.on('propertychange', this.setFromHidden, this); //ie
42498 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42499 // viewEl.on('click', this.onClick, this);
42501 //if(this.checked){
42502 this.setChecked(this.checked);
42504 //this.checked = this.el.dom;
42510 initValue : Roo.emptyFn,
42513 * Returns the checked state of the checkbox.
42514 * @return {Boolean} True if checked, else false
42516 getValue : function(){
42518 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42520 return this.valueOff;
42525 onClick : function(){
42526 if (this.disabled) {
42529 this.setChecked(!this.checked);
42531 //if(this.el.dom.checked != this.checked){
42532 // this.setValue(this.el.dom.checked);
42537 * Sets the checked state of the checkbox.
42538 * On is always based on a string comparison between inputValue and the param.
42539 * @param {Boolean/String} value - the value to set
42540 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42542 setValue : function(v,suppressEvent){
42545 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42546 //if(this.el && this.el.dom){
42547 // this.el.dom.checked = this.checked;
42548 // this.el.dom.defaultChecked = this.checked;
42550 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42551 //this.fireEvent("check", this, this.checked);
42554 setChecked : function(state,suppressEvent)
42556 if (this.inSetChecked) {
42557 this.checked = state;
42563 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42565 this.checked = state;
42566 if(suppressEvent !== true){
42567 this.fireEvent('check', this, state);
42569 this.inSetChecked = true;
42570 this.el.dom.value = state ? this.inputValue : this.valueOff;
42571 this.inSetChecked = false;
42574 // handle setting of hidden value by some other method!!?!?
42575 setFromHidden: function()
42580 //console.log("SET FROM HIDDEN");
42581 //alert('setFrom hidden');
42582 this.setValue(this.el.dom.value);
42585 onDestroy : function()
42588 Roo.get(this.viewEl).remove();
42591 Roo.form.Checkbox.superclass.onDestroy.call(this);
42594 setBoxLabel : function(str)
42596 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42601 * Ext JS Library 1.1.1
42602 * Copyright(c) 2006-2007, Ext JS, LLC.
42604 * Originally Released Under LGPL - original licence link has changed is not relivant.
42607 * <script type="text/javascript">
42611 * @class Roo.form.Radio
42612 * @extends Roo.form.Checkbox
42613 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42614 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42616 * Creates a new Radio
42617 * @param {Object} config Configuration options
42619 Roo.form.Radio = function(){
42620 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42622 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42623 inputType: 'radio',
42626 * If this radio is part of a group, it will return the selected value
42629 getGroupValue : function(){
42630 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42634 onRender : function(ct, position){
42635 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42637 if(this.inputValue !== undefined){
42638 this.el.dom.value = this.inputValue;
42641 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42642 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42643 //var viewEl = this.wrap.createChild({
42644 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42645 //this.viewEl = viewEl;
42646 //this.wrap.on('click', this.onClick, this);
42648 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42649 //this.el.on('propertychange', this.setFromHidden, this); //ie
42654 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42655 // viewEl.on('click', this.onClick, this);
42658 this.el.dom.checked = 'checked' ;
42664 });//<script type="text/javascript">
42667 * Based Ext JS Library 1.1.1
42668 * Copyright(c) 2006-2007, Ext JS, LLC.
42674 * @class Roo.HtmlEditorCore
42675 * @extends Roo.Component
42676 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42678 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42681 Roo.HtmlEditorCore = function(config){
42684 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42689 * @event initialize
42690 * Fires when the editor is fully initialized (including the iframe)
42691 * @param {Roo.HtmlEditorCore} this
42696 * Fires when the editor is first receives the focus. Any insertion must wait
42697 * until after this event.
42698 * @param {Roo.HtmlEditorCore} this
42702 * @event beforesync
42703 * Fires before the textarea is updated with content from the editor iframe. Return false
42704 * to cancel the sync.
42705 * @param {Roo.HtmlEditorCore} this
42706 * @param {String} html
42710 * @event beforepush
42711 * Fires before the iframe editor is updated with content from the textarea. Return false
42712 * to cancel the push.
42713 * @param {Roo.HtmlEditorCore} this
42714 * @param {String} html
42719 * Fires when the textarea is updated with content from the editor iframe.
42720 * @param {Roo.HtmlEditorCore} this
42721 * @param {String} html
42726 * Fires when the iframe editor is updated with content from the textarea.
42727 * @param {Roo.HtmlEditorCore} this
42728 * @param {String} html
42733 * @event editorevent
42734 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42735 * @param {Roo.HtmlEditorCore} this
42741 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42743 // defaults : white / black...
42744 this.applyBlacklists();
42751 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42755 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42761 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42766 * @cfg {Number} height (in pixels)
42770 * @cfg {Number} width (in pixels)
42775 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42778 stylesheets: false,
42783 // private properties
42784 validationEvent : false,
42786 initialized : false,
42788 sourceEditMode : false,
42789 onFocus : Roo.emptyFn,
42791 hideMode:'offsets',
42795 // blacklist + whitelisted elements..
42802 * Protected method that will not generally be called directly. It
42803 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42804 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42806 getDocMarkup : function(){
42810 // inherit styels from page...??
42811 if (this.stylesheets === false) {
42813 Roo.get(document.head).select('style').each(function(node) {
42814 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42817 Roo.get(document.head).select('link').each(function(node) {
42818 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42821 } else if (!this.stylesheets.length) {
42823 st = '<style type="text/css">' +
42824 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42830 st += '<style type="text/css">' +
42831 'IMG { cursor: pointer } ' +
42835 return '<html><head>' + st +
42836 //<style type="text/css">' +
42837 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42839 ' </head><body class="roo-htmleditor-body"></body></html>';
42843 onRender : function(ct, position)
42846 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42847 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42850 this.el.dom.style.border = '0 none';
42851 this.el.dom.setAttribute('tabIndex', -1);
42852 this.el.addClass('x-hidden hide');
42856 if(Roo.isIE){ // fix IE 1px bogus margin
42857 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42861 this.frameId = Roo.id();
42865 var iframe = this.owner.wrap.createChild({
42867 cls: 'form-control', // bootstrap..
42869 name: this.frameId,
42870 frameBorder : 'no',
42871 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42876 this.iframe = iframe.dom;
42878 this.assignDocWin();
42880 this.doc.designMode = 'on';
42883 this.doc.write(this.getDocMarkup());
42887 var task = { // must defer to wait for browser to be ready
42889 //console.log("run task?" + this.doc.readyState);
42890 this.assignDocWin();
42891 if(this.doc.body || this.doc.readyState == 'complete'){
42893 this.doc.designMode="on";
42897 Roo.TaskMgr.stop(task);
42898 this.initEditor.defer(10, this);
42905 Roo.TaskMgr.start(task);
42910 onResize : function(w, h)
42912 Roo.log('resize: ' +w + ',' + h );
42913 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
42917 if(typeof w == 'number'){
42919 this.iframe.style.width = w + 'px';
42921 if(typeof h == 'number'){
42923 this.iframe.style.height = h + 'px';
42925 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
42932 * Toggles the editor between standard and source edit mode.
42933 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42935 toggleSourceEdit : function(sourceEditMode){
42937 this.sourceEditMode = sourceEditMode === true;
42939 if(this.sourceEditMode){
42941 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
42944 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
42945 //this.iframe.className = '';
42948 //this.setSize(this.owner.wrap.getSize());
42949 //this.fireEvent('editmodechange', this, this.sourceEditMode);
42956 * Protected method that will not generally be called directly. If you need/want
42957 * custom HTML cleanup, this is the method you should override.
42958 * @param {String} html The HTML to be cleaned
42959 * return {String} The cleaned HTML
42961 cleanHtml : function(html){
42962 html = String(html);
42963 if(html.length > 5){
42964 if(Roo.isSafari){ // strip safari nonsense
42965 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
42968 if(html == ' '){
42975 * HTML Editor -> Textarea
42976 * Protected method that will not generally be called directly. Syncs the contents
42977 * of the editor iframe with the textarea.
42979 syncValue : function(){
42980 if(this.initialized){
42981 var bd = (this.doc.body || this.doc.documentElement);
42982 //this.cleanUpPaste(); -- this is done else where and causes havoc..
42983 var html = bd.innerHTML;
42985 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
42986 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
42988 html = '<div style="'+m[0]+'">' + html + '</div>';
42991 html = this.cleanHtml(html);
42992 // fix up the special chars.. normaly like back quotes in word...
42993 // however we do not want to do this with chinese..
42994 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
42995 var cc = b.charCodeAt();
42997 (cc >= 0x4E00 && cc < 0xA000 ) ||
42998 (cc >= 0x3400 && cc < 0x4E00 ) ||
42999 (cc >= 0xf900 && cc < 0xfb00 )
43005 if(this.owner.fireEvent('beforesync', this, html) !== false){
43006 this.el.dom.value = html;
43007 this.owner.fireEvent('sync', this, html);
43013 * Protected method that will not generally be called directly. Pushes the value of the textarea
43014 * into the iframe editor.
43016 pushValue : function(){
43017 if(this.initialized){
43018 var v = this.el.dom.value.trim();
43020 // if(v.length < 1){
43024 if(this.owner.fireEvent('beforepush', this, v) !== false){
43025 var d = (this.doc.body || this.doc.documentElement);
43027 this.cleanUpPaste();
43028 this.el.dom.value = d.innerHTML;
43029 this.owner.fireEvent('push', this, v);
43035 deferFocus : function(){
43036 this.focus.defer(10, this);
43040 focus : function(){
43041 if(this.win && !this.sourceEditMode){
43048 assignDocWin: function()
43050 var iframe = this.iframe;
43053 this.doc = iframe.contentWindow.document;
43054 this.win = iframe.contentWindow;
43056 // if (!Roo.get(this.frameId)) {
43059 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43060 // this.win = Roo.get(this.frameId).dom.contentWindow;
43062 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43066 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43067 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43072 initEditor : function(){
43073 //console.log("INIT EDITOR");
43074 this.assignDocWin();
43078 this.doc.designMode="on";
43080 this.doc.write(this.getDocMarkup());
43083 var dbody = (this.doc.body || this.doc.documentElement);
43084 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43085 // this copies styles from the containing element into thsi one..
43086 // not sure why we need all of this..
43087 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43089 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43090 //ss['background-attachment'] = 'fixed'; // w3c
43091 dbody.bgProperties = 'fixed'; // ie
43092 //Roo.DomHelper.applyStyles(dbody, ss);
43093 Roo.EventManager.on(this.doc, {
43094 //'mousedown': this.onEditorEvent,
43095 'mouseup': this.onEditorEvent,
43096 'dblclick': this.onEditorEvent,
43097 'click': this.onEditorEvent,
43098 'keyup': this.onEditorEvent,
43103 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43105 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43106 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43108 this.initialized = true;
43110 this.owner.fireEvent('initialize', this);
43115 onDestroy : function(){
43121 //for (var i =0; i < this.toolbars.length;i++) {
43122 // // fixme - ask toolbars for heights?
43123 // this.toolbars[i].onDestroy();
43126 //this.wrap.dom.innerHTML = '';
43127 //this.wrap.remove();
43132 onFirstFocus : function(){
43134 this.assignDocWin();
43137 this.activated = true;
43140 if(Roo.isGecko){ // prevent silly gecko errors
43142 var s = this.win.getSelection();
43143 if(!s.focusNode || s.focusNode.nodeType != 3){
43144 var r = s.getRangeAt(0);
43145 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43150 this.execCmd('useCSS', true);
43151 this.execCmd('styleWithCSS', false);
43154 this.owner.fireEvent('activate', this);
43158 adjustFont: function(btn){
43159 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43160 //if(Roo.isSafari){ // safari
43163 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43164 if(Roo.isSafari){ // safari
43165 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43166 v = (v < 10) ? 10 : v;
43167 v = (v > 48) ? 48 : v;
43168 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43173 v = Math.max(1, v+adjust);
43175 this.execCmd('FontSize', v );
43178 onEditorEvent : function(e)
43180 this.owner.fireEvent('editorevent', this, e);
43181 // this.updateToolbar();
43182 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43185 insertTag : function(tg)
43187 // could be a bit smarter... -> wrap the current selected tRoo..
43188 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43190 range = this.createRange(this.getSelection());
43191 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43192 wrappingNode.appendChild(range.extractContents());
43193 range.insertNode(wrappingNode);
43200 this.execCmd("formatblock", tg);
43204 insertText : function(txt)
43208 var range = this.createRange();
43209 range.deleteContents();
43210 //alert(Sender.getAttribute('label'));
43212 range.insertNode(this.doc.createTextNode(txt));
43218 * Executes a Midas editor command on the editor document and performs necessary focus and
43219 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43220 * @param {String} cmd The Midas command
43221 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43223 relayCmd : function(cmd, value){
43225 this.execCmd(cmd, value);
43226 this.owner.fireEvent('editorevent', this);
43227 //this.updateToolbar();
43228 this.owner.deferFocus();
43232 * Executes a Midas editor command directly on the editor document.
43233 * For visual commands, you should use {@link #relayCmd} instead.
43234 * <b>This should only be called after the editor is initialized.</b>
43235 * @param {String} cmd The Midas command
43236 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43238 execCmd : function(cmd, value){
43239 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43246 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43248 * @param {String} text | dom node..
43250 insertAtCursor : function(text)
43255 if(!this.activated){
43261 var r = this.doc.selection.createRange();
43272 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43276 // from jquery ui (MIT licenced)
43278 var win = this.win;
43280 if (win.getSelection && win.getSelection().getRangeAt) {
43281 range = win.getSelection().getRangeAt(0);
43282 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43283 range.insertNode(node);
43284 } else if (win.document.selection && win.document.selection.createRange) {
43285 // no firefox support
43286 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43287 win.document.selection.createRange().pasteHTML(txt);
43289 // no firefox support
43290 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43291 this.execCmd('InsertHTML', txt);
43300 mozKeyPress : function(e){
43302 var c = e.getCharCode(), cmd;
43305 c = String.fromCharCode(c).toLowerCase();
43319 this.cleanUpPaste.defer(100, this);
43327 e.preventDefault();
43335 fixKeys : function(){ // load time branching for fastest keydown performance
43337 return function(e){
43338 var k = e.getKey(), r;
43341 r = this.doc.selection.createRange();
43344 r.pasteHTML('    ');
43351 r = this.doc.selection.createRange();
43353 var target = r.parentElement();
43354 if(!target || target.tagName.toLowerCase() != 'li'){
43356 r.pasteHTML('<br />');
43362 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43363 this.cleanUpPaste.defer(100, this);
43369 }else if(Roo.isOpera){
43370 return function(e){
43371 var k = e.getKey();
43375 this.execCmd('InsertHTML','    ');
43378 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43379 this.cleanUpPaste.defer(100, this);
43384 }else if(Roo.isSafari){
43385 return function(e){
43386 var k = e.getKey();
43390 this.execCmd('InsertText','\t');
43394 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43395 this.cleanUpPaste.defer(100, this);
43403 getAllAncestors: function()
43405 var p = this.getSelectedNode();
43408 a.push(p); // push blank onto stack..
43409 p = this.getParentElement();
43413 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43417 a.push(this.doc.body);
43421 lastSelNode : false,
43424 getSelection : function()
43426 this.assignDocWin();
43427 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43430 getSelectedNode: function()
43432 // this may only work on Gecko!!!
43434 // should we cache this!!!!
43439 var range = this.createRange(this.getSelection()).cloneRange();
43442 var parent = range.parentElement();
43444 var testRange = range.duplicate();
43445 testRange.moveToElementText(parent);
43446 if (testRange.inRange(range)) {
43449 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43452 parent = parent.parentElement;
43457 // is ancestor a text element.
43458 var ac = range.commonAncestorContainer;
43459 if (ac.nodeType == 3) {
43460 ac = ac.parentNode;
43463 var ar = ac.childNodes;
43466 var other_nodes = [];
43467 var has_other_nodes = false;
43468 for (var i=0;i<ar.length;i++) {
43469 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43472 // fullly contained node.
43474 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43479 // probably selected..
43480 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43481 other_nodes.push(ar[i]);
43485 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43490 has_other_nodes = true;
43492 if (!nodes.length && other_nodes.length) {
43493 nodes= other_nodes;
43495 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43501 createRange: function(sel)
43503 // this has strange effects when using with
43504 // top toolbar - not sure if it's a great idea.
43505 //this.editor.contentWindow.focus();
43506 if (typeof sel != "undefined") {
43508 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43510 return this.doc.createRange();
43513 return this.doc.createRange();
43516 getParentElement: function()
43519 this.assignDocWin();
43520 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43522 var range = this.createRange(sel);
43525 var p = range.commonAncestorContainer;
43526 while (p.nodeType == 3) { // text node
43537 * Range intersection.. the hard stuff...
43541 * [ -- selected range --- ]
43545 * if end is before start or hits it. fail.
43546 * if start is after end or hits it fail.
43548 * if either hits (but other is outside. - then it's not
43554 // @see http://www.thismuchiknow.co.uk/?p=64.
43555 rangeIntersectsNode : function(range, node)
43557 var nodeRange = node.ownerDocument.createRange();
43559 nodeRange.selectNode(node);
43561 nodeRange.selectNodeContents(node);
43564 var rangeStartRange = range.cloneRange();
43565 rangeStartRange.collapse(true);
43567 var rangeEndRange = range.cloneRange();
43568 rangeEndRange.collapse(false);
43570 var nodeStartRange = nodeRange.cloneRange();
43571 nodeStartRange.collapse(true);
43573 var nodeEndRange = nodeRange.cloneRange();
43574 nodeEndRange.collapse(false);
43576 return rangeStartRange.compareBoundaryPoints(
43577 Range.START_TO_START, nodeEndRange) == -1 &&
43578 rangeEndRange.compareBoundaryPoints(
43579 Range.START_TO_START, nodeStartRange) == 1;
43583 rangeCompareNode : function(range, node)
43585 var nodeRange = node.ownerDocument.createRange();
43587 nodeRange.selectNode(node);
43589 nodeRange.selectNodeContents(node);
43593 range.collapse(true);
43595 nodeRange.collapse(true);
43597 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43598 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43600 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43602 var nodeIsBefore = ss == 1;
43603 var nodeIsAfter = ee == -1;
43605 if (nodeIsBefore && nodeIsAfter) {
43608 if (!nodeIsBefore && nodeIsAfter) {
43609 return 1; //right trailed.
43612 if (nodeIsBefore && !nodeIsAfter) {
43613 return 2; // left trailed.
43619 // private? - in a new class?
43620 cleanUpPaste : function()
43622 // cleans up the whole document..
43623 Roo.log('cleanuppaste');
43625 this.cleanUpChildren(this.doc.body);
43626 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43627 if (clean != this.doc.body.innerHTML) {
43628 this.doc.body.innerHTML = clean;
43633 cleanWordChars : function(input) {// change the chars to hex code
43634 var he = Roo.HtmlEditorCore;
43636 var output = input;
43637 Roo.each(he.swapCodes, function(sw) {
43638 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43640 output = output.replace(swapper, sw[1]);
43647 cleanUpChildren : function (n)
43649 if (!n.childNodes.length) {
43652 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43653 this.cleanUpChild(n.childNodes[i]);
43660 cleanUpChild : function (node)
43663 //console.log(node);
43664 if (node.nodeName == "#text") {
43665 // clean up silly Windows -- stuff?
43668 if (node.nodeName == "#comment") {
43669 node.parentNode.removeChild(node);
43670 // clean up silly Windows -- stuff?
43673 var lcname = node.tagName.toLowerCase();
43674 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43675 // whitelist of tags..
43677 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43679 node.parentNode.removeChild(node);
43684 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43686 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43687 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43689 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43690 // remove_keep_children = true;
43693 if (remove_keep_children) {
43694 this.cleanUpChildren(node);
43695 // inserts everything just before this node...
43696 while (node.childNodes.length) {
43697 var cn = node.childNodes[0];
43698 node.removeChild(cn);
43699 node.parentNode.insertBefore(cn, node);
43701 node.parentNode.removeChild(node);
43705 if (!node.attributes || !node.attributes.length) {
43706 this.cleanUpChildren(node);
43710 function cleanAttr(n,v)
43713 if (v.match(/^\./) || v.match(/^\//)) {
43716 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
43719 if (v.match(/^#/)) {
43722 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43723 node.removeAttribute(n);
43727 var cwhite = this.cwhite;
43728 var cblack = this.cblack;
43730 function cleanStyle(n,v)
43732 if (v.match(/expression/)) { //XSS?? should we even bother..
43733 node.removeAttribute(n);
43737 var parts = v.split(/;/);
43740 Roo.each(parts, function(p) {
43741 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43745 var l = p.split(':').shift().replace(/\s+/g,'');
43746 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43748 if ( cwhite.length && cblack.indexOf(l) > -1) {
43749 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43750 //node.removeAttribute(n);
43754 // only allow 'c whitelisted system attributes'
43755 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43756 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43757 //node.removeAttribute(n);
43767 if (clean.length) {
43768 node.setAttribute(n, clean.join(';'));
43770 node.removeAttribute(n);
43776 for (var i = node.attributes.length-1; i > -1 ; i--) {
43777 var a = node.attributes[i];
43780 if (a.name.toLowerCase().substr(0,2)=='on') {
43781 node.removeAttribute(a.name);
43784 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43785 node.removeAttribute(a.name);
43788 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43789 cleanAttr(a.name,a.value); // fixme..
43792 if (a.name == 'style') {
43793 cleanStyle(a.name,a.value);
43796 /// clean up MS crap..
43797 // tecnically this should be a list of valid class'es..
43800 if (a.name == 'class') {
43801 if (a.value.match(/^Mso/)) {
43802 node.className = '';
43805 if (a.value.match(/body/)) {
43806 node.className = '';
43817 this.cleanUpChildren(node);
43823 * Clean up MS wordisms...
43825 cleanWord : function(node)
43830 this.cleanWord(this.doc.body);
43833 if (node.nodeName == "#text") {
43834 // clean up silly Windows -- stuff?
43837 if (node.nodeName == "#comment") {
43838 node.parentNode.removeChild(node);
43839 // clean up silly Windows -- stuff?
43843 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43844 node.parentNode.removeChild(node);
43848 // remove - but keep children..
43849 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43850 while (node.childNodes.length) {
43851 var cn = node.childNodes[0];
43852 node.removeChild(cn);
43853 node.parentNode.insertBefore(cn, node);
43855 node.parentNode.removeChild(node);
43856 this.iterateChildren(node, this.cleanWord);
43860 if (node.className.length) {
43862 var cn = node.className.split(/\W+/);
43864 Roo.each(cn, function(cls) {
43865 if (cls.match(/Mso[a-zA-Z]+/)) {
43870 node.className = cna.length ? cna.join(' ') : '';
43872 node.removeAttribute("class");
43876 if (node.hasAttribute("lang")) {
43877 node.removeAttribute("lang");
43880 if (node.hasAttribute("style")) {
43882 var styles = node.getAttribute("style").split(";");
43884 Roo.each(styles, function(s) {
43885 if (!s.match(/:/)) {
43888 var kv = s.split(":");
43889 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
43892 // what ever is left... we allow.
43895 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43896 if (!nstyle.length) {
43897 node.removeAttribute('style');
43900 this.iterateChildren(node, this.cleanWord);
43906 * iterateChildren of a Node, calling fn each time, using this as the scole..
43907 * @param {DomNode} node node to iterate children of.
43908 * @param {Function} fn method of this class to call on each item.
43910 iterateChildren : function(node, fn)
43912 if (!node.childNodes.length) {
43915 for (var i = node.childNodes.length-1; i > -1 ; i--) {
43916 fn.call(this, node.childNodes[i])
43922 * cleanTableWidths.
43924 * Quite often pasting from word etc.. results in tables with column and widths.
43925 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
43928 cleanTableWidths : function(node)
43933 this.cleanTableWidths(this.doc.body);
43938 if (node.nodeName == "#text" || node.nodeName == "#comment") {
43941 Roo.log(node.tagName);
43942 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
43943 this.iterateChildren(node, this.cleanTableWidths);
43946 if (node.hasAttribute('width')) {
43947 node.removeAttribute('width');
43951 if (node.hasAttribute("style")) {
43954 var styles = node.getAttribute("style").split(";");
43956 Roo.each(styles, function(s) {
43957 if (!s.match(/:/)) {
43960 var kv = s.split(":");
43961 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
43964 // what ever is left... we allow.
43967 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43968 if (!nstyle.length) {
43969 node.removeAttribute('style');
43973 this.iterateChildren(node, this.cleanTableWidths);
43981 domToHTML : function(currentElement, depth, nopadtext) {
43983 depth = depth || 0;
43984 nopadtext = nopadtext || false;
43986 if (!currentElement) {
43987 return this.domToHTML(this.doc.body);
43990 //Roo.log(currentElement);
43992 var allText = false;
43993 var nodeName = currentElement.nodeName;
43994 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
43996 if (nodeName == '#text') {
43998 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44003 if (nodeName != 'BODY') {
44006 // Prints the node tagName, such as <A>, <IMG>, etc
44009 for(i = 0; i < currentElement.attributes.length;i++) {
44011 var aname = currentElement.attributes.item(i).name;
44012 if (!currentElement.attributes.item(i).value.length) {
44015 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44018 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44027 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44030 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44035 // Traverse the tree
44037 var currentElementChild = currentElement.childNodes.item(i);
44038 var allText = true;
44039 var innerHTML = '';
44041 while (currentElementChild) {
44042 // Formatting code (indent the tree so it looks nice on the screen)
44043 var nopad = nopadtext;
44044 if (lastnode == 'SPAN') {
44048 if (currentElementChild.nodeName == '#text') {
44049 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44050 toadd = nopadtext ? toadd : toadd.trim();
44051 if (!nopad && toadd.length > 80) {
44052 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44054 innerHTML += toadd;
44057 currentElementChild = currentElement.childNodes.item(i);
44063 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44065 // Recursively traverse the tree structure of the child node
44066 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44067 lastnode = currentElementChild.nodeName;
44069 currentElementChild=currentElement.childNodes.item(i);
44075 // The remaining code is mostly for formatting the tree
44076 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44081 ret+= "</"+tagName+">";
44087 applyBlacklists : function()
44089 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44090 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44094 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44095 if (b.indexOf(tag) > -1) {
44098 this.white.push(tag);
44102 Roo.each(w, function(tag) {
44103 if (b.indexOf(tag) > -1) {
44106 if (this.white.indexOf(tag) > -1) {
44109 this.white.push(tag);
44114 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44115 if (w.indexOf(tag) > -1) {
44118 this.black.push(tag);
44122 Roo.each(b, function(tag) {
44123 if (w.indexOf(tag) > -1) {
44126 if (this.black.indexOf(tag) > -1) {
44129 this.black.push(tag);
44134 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44135 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44139 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44140 if (b.indexOf(tag) > -1) {
44143 this.cwhite.push(tag);
44147 Roo.each(w, function(tag) {
44148 if (b.indexOf(tag) > -1) {
44151 if (this.cwhite.indexOf(tag) > -1) {
44154 this.cwhite.push(tag);
44159 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44160 if (w.indexOf(tag) > -1) {
44163 this.cblack.push(tag);
44167 Roo.each(b, function(tag) {
44168 if (w.indexOf(tag) > -1) {
44171 if (this.cblack.indexOf(tag) > -1) {
44174 this.cblack.push(tag);
44179 setStylesheets : function(stylesheets)
44181 if(typeof(stylesheets) == 'string'){
44182 Roo.get(this.iframe.contentDocument.head).createChild({
44184 rel : 'stylesheet',
44193 Roo.each(stylesheets, function(s) {
44198 Roo.get(_this.iframe.contentDocument.head).createChild({
44200 rel : 'stylesheet',
44209 removeStylesheets : function()
44213 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44218 // hide stuff that is not compatible
44232 * @event specialkey
44236 * @cfg {String} fieldClass @hide
44239 * @cfg {String} focusClass @hide
44242 * @cfg {String} autoCreate @hide
44245 * @cfg {String} inputType @hide
44248 * @cfg {String} invalidClass @hide
44251 * @cfg {String} invalidText @hide
44254 * @cfg {String} msgFx @hide
44257 * @cfg {String} validateOnBlur @hide
44261 Roo.HtmlEditorCore.white = [
44262 'area', 'br', 'img', 'input', 'hr', 'wbr',
44264 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44265 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44266 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44267 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44268 'table', 'ul', 'xmp',
44270 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44273 'dir', 'menu', 'ol', 'ul', 'dl',
44279 Roo.HtmlEditorCore.black = [
44280 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44282 'base', 'basefont', 'bgsound', 'blink', 'body',
44283 'frame', 'frameset', 'head', 'html', 'ilayer',
44284 'iframe', 'layer', 'link', 'meta', 'object',
44285 'script', 'style' ,'title', 'xml' // clean later..
44287 Roo.HtmlEditorCore.clean = [
44288 'script', 'style', 'title', 'xml'
44290 Roo.HtmlEditorCore.remove = [
44295 Roo.HtmlEditorCore.ablack = [
44299 Roo.HtmlEditorCore.aclean = [
44300 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44304 Roo.HtmlEditorCore.pwhite= [
44305 'http', 'https', 'mailto'
44308 // white listed style attributes.
44309 Roo.HtmlEditorCore.cwhite= [
44310 // 'text-align', /// default is to allow most things..
44316 // black listed style attributes.
44317 Roo.HtmlEditorCore.cblack= [
44318 // 'font-size' -- this can be set by the project
44322 Roo.HtmlEditorCore.swapCodes =[
44333 //<script type="text/javascript">
44336 * Ext JS Library 1.1.1
44337 * Copyright(c) 2006-2007, Ext JS, LLC.
44343 Roo.form.HtmlEditor = function(config){
44347 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44349 if (!this.toolbars) {
44350 this.toolbars = [];
44352 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44358 * @class Roo.form.HtmlEditor
44359 * @extends Roo.form.Field
44360 * Provides a lightweight HTML Editor component.
44362 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44364 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44365 * supported by this editor.</b><br/><br/>
44366 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44367 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44369 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44371 * @cfg {Boolean} clearUp
44375 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44380 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44385 * @cfg {Number} height (in pixels)
44389 * @cfg {Number} width (in pixels)
44394 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44397 stylesheets: false,
44401 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44406 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44412 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44417 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44425 // private properties
44426 validationEvent : false,
44428 initialized : false,
44431 onFocus : Roo.emptyFn,
44433 hideMode:'offsets',
44435 actionMode : 'container', // defaults to hiding it...
44437 defaultAutoCreate : { // modified by initCompnoent..
44439 style:"width:500px;height:300px;",
44440 autocomplete: "new-password"
44444 initComponent : function(){
44447 * @event initialize
44448 * Fires when the editor is fully initialized (including the iframe)
44449 * @param {HtmlEditor} this
44454 * Fires when the editor is first receives the focus. Any insertion must wait
44455 * until after this event.
44456 * @param {HtmlEditor} this
44460 * @event beforesync
44461 * Fires before the textarea is updated with content from the editor iframe. Return false
44462 * to cancel the sync.
44463 * @param {HtmlEditor} this
44464 * @param {String} html
44468 * @event beforepush
44469 * Fires before the iframe editor is updated with content from the textarea. Return false
44470 * to cancel the push.
44471 * @param {HtmlEditor} this
44472 * @param {String} html
44477 * Fires when the textarea is updated with content from the editor iframe.
44478 * @param {HtmlEditor} this
44479 * @param {String} html
44484 * Fires when the iframe editor is updated with content from the textarea.
44485 * @param {HtmlEditor} this
44486 * @param {String} html
44490 * @event editmodechange
44491 * Fires when the editor switches edit modes
44492 * @param {HtmlEditor} this
44493 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44495 editmodechange: true,
44497 * @event editorevent
44498 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44499 * @param {HtmlEditor} this
44503 * @event firstfocus
44504 * Fires when on first focus - needed by toolbars..
44505 * @param {HtmlEditor} this
44510 * Auto save the htmlEditor value as a file into Events
44511 * @param {HtmlEditor} this
44515 * @event savedpreview
44516 * preview the saved version of htmlEditor
44517 * @param {HtmlEditor} this
44519 savedpreview: true,
44522 * @event stylesheetsclick
44523 * Fires when press the Sytlesheets button
44524 * @param {Roo.HtmlEditorCore} this
44526 stylesheetsclick: true
44528 this.defaultAutoCreate = {
44530 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44531 autocomplete: "new-password"
44536 * Protected method that will not generally be called directly. It
44537 * is called when the editor creates its toolbar. Override this method if you need to
44538 * add custom toolbar buttons.
44539 * @param {HtmlEditor} editor
44541 createToolbar : function(editor){
44542 Roo.log("create toolbars");
44543 if (!editor.toolbars || !editor.toolbars.length) {
44544 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44547 for (var i =0 ; i < editor.toolbars.length;i++) {
44548 editor.toolbars[i] = Roo.factory(
44549 typeof(editor.toolbars[i]) == 'string' ?
44550 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44551 Roo.form.HtmlEditor);
44552 editor.toolbars[i].init(editor);
44560 onRender : function(ct, position)
44563 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44565 this.wrap = this.el.wrap({
44566 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44569 this.editorcore.onRender(ct, position);
44571 if (this.resizable) {
44572 this.resizeEl = new Roo.Resizable(this.wrap, {
44576 minHeight : this.height,
44577 height: this.height,
44578 handles : this.resizable,
44581 resize : function(r, w, h) {
44582 _t.onResize(w,h); // -something
44588 this.createToolbar(this);
44592 this.setSize(this.wrap.getSize());
44594 if (this.resizeEl) {
44595 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44596 // should trigger onReize..
44599 this.keyNav = new Roo.KeyNav(this.el, {
44601 "tab" : function(e){
44602 e.preventDefault();
44604 var value = this.getValue();
44606 var start = this.el.dom.selectionStart;
44607 var end = this.el.dom.selectionEnd;
44611 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44612 this.el.dom.setSelectionRange(end + 1, end + 1);
44616 var f = value.substring(0, start).split("\t");
44618 if(f.pop().length != 0){
44622 this.setValue(f.join("\t") + value.substring(end));
44623 this.el.dom.setSelectionRange(start - 1, start - 1);
44627 "home" : function(e){
44628 e.preventDefault();
44630 var curr = this.el.dom.selectionStart;
44631 var lines = this.getValue().split("\n");
44638 this.el.dom.setSelectionRange(0, 0);
44644 for (var i = 0; i < lines.length;i++) {
44645 pos += lines[i].length;
44655 pos -= lines[i].length;
44661 this.el.dom.setSelectionRange(pos, pos);
44665 this.el.dom.selectionStart = pos;
44666 this.el.dom.selectionEnd = curr;
44669 "end" : function(e){
44670 e.preventDefault();
44672 var curr = this.el.dom.selectionStart;
44673 var lines = this.getValue().split("\n");
44680 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44686 for (var i = 0; i < lines.length;i++) {
44688 pos += lines[i].length;
44702 this.el.dom.setSelectionRange(pos, pos);
44706 this.el.dom.selectionStart = curr;
44707 this.el.dom.selectionEnd = pos;
44712 doRelay : function(foo, bar, hname){
44713 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44719 // if(this.autosave && this.w){
44720 // this.autoSaveFn = setInterval(this.autosave, 1000);
44725 onResize : function(w, h)
44727 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44732 if(typeof w == 'number'){
44733 var aw = w - this.wrap.getFrameWidth('lr');
44734 this.el.setWidth(this.adjustWidth('textarea', aw));
44737 if(typeof h == 'number'){
44739 for (var i =0; i < this.toolbars.length;i++) {
44740 // fixme - ask toolbars for heights?
44741 tbh += this.toolbars[i].tb.el.getHeight();
44742 if (this.toolbars[i].footer) {
44743 tbh += this.toolbars[i].footer.el.getHeight();
44750 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44751 ah -= 5; // knock a few pixes off for look..
44753 this.el.setHeight(this.adjustWidth('textarea', ah));
44757 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44758 this.editorcore.onResize(ew,eh);
44763 * Toggles the editor between standard and source edit mode.
44764 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44766 toggleSourceEdit : function(sourceEditMode)
44768 this.editorcore.toggleSourceEdit(sourceEditMode);
44770 if(this.editorcore.sourceEditMode){
44771 Roo.log('editor - showing textarea');
44774 // Roo.log(this.syncValue());
44775 this.editorcore.syncValue();
44776 this.el.removeClass('x-hidden');
44777 this.el.dom.removeAttribute('tabIndex');
44780 for (var i = 0; i < this.toolbars.length; i++) {
44781 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44782 this.toolbars[i].tb.hide();
44783 this.toolbars[i].footer.hide();
44788 Roo.log('editor - hiding textarea');
44790 // Roo.log(this.pushValue());
44791 this.editorcore.pushValue();
44793 this.el.addClass('x-hidden');
44794 this.el.dom.setAttribute('tabIndex', -1);
44796 for (var i = 0; i < this.toolbars.length; i++) {
44797 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44798 this.toolbars[i].tb.show();
44799 this.toolbars[i].footer.show();
44803 //this.deferFocus();
44806 this.setSize(this.wrap.getSize());
44807 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44809 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44812 // private (for BoxComponent)
44813 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44815 // private (for BoxComponent)
44816 getResizeEl : function(){
44820 // private (for BoxComponent)
44821 getPositionEl : function(){
44826 initEvents : function(){
44827 this.originalValue = this.getValue();
44831 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44834 markInvalid : Roo.emptyFn,
44836 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44839 clearInvalid : Roo.emptyFn,
44841 setValue : function(v){
44842 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44843 this.editorcore.pushValue();
44848 deferFocus : function(){
44849 this.focus.defer(10, this);
44853 focus : function(){
44854 this.editorcore.focus();
44860 onDestroy : function(){
44866 for (var i =0; i < this.toolbars.length;i++) {
44867 // fixme - ask toolbars for heights?
44868 this.toolbars[i].onDestroy();
44871 this.wrap.dom.innerHTML = '';
44872 this.wrap.remove();
44877 onFirstFocus : function(){
44878 //Roo.log("onFirstFocus");
44879 this.editorcore.onFirstFocus();
44880 for (var i =0; i < this.toolbars.length;i++) {
44881 this.toolbars[i].onFirstFocus();
44887 syncValue : function()
44889 this.editorcore.syncValue();
44892 pushValue : function()
44894 this.editorcore.pushValue();
44897 setStylesheets : function(stylesheets)
44899 this.editorcore.setStylesheets(stylesheets);
44902 removeStylesheets : function()
44904 this.editorcore.removeStylesheets();
44908 // hide stuff that is not compatible
44922 * @event specialkey
44926 * @cfg {String} fieldClass @hide
44929 * @cfg {String} focusClass @hide
44932 * @cfg {String} autoCreate @hide
44935 * @cfg {String} inputType @hide
44938 * @cfg {String} invalidClass @hide
44941 * @cfg {String} invalidText @hide
44944 * @cfg {String} msgFx @hide
44947 * @cfg {String} validateOnBlur @hide
44951 // <script type="text/javascript">
44954 * Ext JS Library 1.1.1
44955 * Copyright(c) 2006-2007, Ext JS, LLC.
44961 * @class Roo.form.HtmlEditorToolbar1
44966 new Roo.form.HtmlEditor({
44969 new Roo.form.HtmlEditorToolbar1({
44970 disable : { fonts: 1 , format: 1, ..., ... , ...],
44976 * @cfg {Object} disable List of elements to disable..
44977 * @cfg {Array} btns List of additional buttons.
44981 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
44984 Roo.form.HtmlEditor.ToolbarStandard = function(config)
44987 Roo.apply(this, config);
44989 // default disabled, based on 'good practice'..
44990 this.disable = this.disable || {};
44991 Roo.applyIf(this.disable, {
44994 specialElements : true
44998 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44999 // dont call parent... till later.
45002 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45009 editorcore : false,
45011 * @cfg {Object} disable List of toolbar elements to disable
45018 * @cfg {String} createLinkText The default text for the create link prompt
45020 createLinkText : 'Please enter the URL for the link:',
45022 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45024 defaultLinkValue : 'http:/'+'/',
45028 * @cfg {Array} fontFamilies An array of available font families
45046 // "á" , ?? a acute?
45051 "°" // , // degrees
45053 // "é" , // e ecute
45054 // "ú" , // u ecute?
45057 specialElements : [
45059 text: "Insert Table",
45062 ihtml : '<table><tr><td>Cell</td></tr></table>'
45066 text: "Insert Image",
45069 ihtml : '<img src="about:blank"/>'
45078 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45079 "input:submit", "input:button", "select", "textarea", "label" ],
45082 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45084 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45092 * @cfg {String} defaultFont default font to use.
45094 defaultFont: 'tahoma',
45096 fontSelect : false,
45099 formatCombo : false,
45101 init : function(editor)
45103 this.editor = editor;
45104 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45105 var editorcore = this.editorcore;
45109 var fid = editorcore.frameId;
45111 function btn(id, toggle, handler){
45112 var xid = fid + '-'+ id ;
45116 cls : 'x-btn-icon x-edit-'+id,
45117 enableToggle:toggle !== false,
45118 scope: _t, // was editor...
45119 handler:handler||_t.relayBtnCmd,
45120 clickEvent:'mousedown',
45121 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45128 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45130 // stop form submits
45131 tb.el.on('click', function(e){
45132 e.preventDefault(); // what does this do?
45135 if(!this.disable.font) { // && !Roo.isSafari){
45136 /* why no safari for fonts
45137 editor.fontSelect = tb.el.createChild({
45140 cls:'x-font-select',
45141 html: this.createFontOptions()
45144 editor.fontSelect.on('change', function(){
45145 var font = editor.fontSelect.dom.value;
45146 editor.relayCmd('fontname', font);
45147 editor.deferFocus();
45151 editor.fontSelect.dom,
45157 if(!this.disable.formats){
45158 this.formatCombo = new Roo.form.ComboBox({
45159 store: new Roo.data.SimpleStore({
45162 data : this.formats // from states.js
45166 //autoCreate : {tag: "div", size: "20"},
45167 displayField:'tag',
45171 triggerAction: 'all',
45172 emptyText:'Add tag',
45173 selectOnFocus:true,
45176 'select': function(c, r, i) {
45177 editorcore.insertTag(r.get('tag'));
45183 tb.addField(this.formatCombo);
45187 if(!this.disable.format){
45192 btn('strikethrough')
45195 if(!this.disable.fontSize){
45200 btn('increasefontsize', false, editorcore.adjustFont),
45201 btn('decreasefontsize', false, editorcore.adjustFont)
45206 if(!this.disable.colors){
45209 id:editorcore.frameId +'-forecolor',
45210 cls:'x-btn-icon x-edit-forecolor',
45211 clickEvent:'mousedown',
45212 tooltip: this.buttonTips['forecolor'] || undefined,
45214 menu : new Roo.menu.ColorMenu({
45215 allowReselect: true,
45216 focus: Roo.emptyFn,
45219 selectHandler: function(cp, color){
45220 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45221 editor.deferFocus();
45224 clickEvent:'mousedown'
45227 id:editorcore.frameId +'backcolor',
45228 cls:'x-btn-icon x-edit-backcolor',
45229 clickEvent:'mousedown',
45230 tooltip: this.buttonTips['backcolor'] || undefined,
45232 menu : new Roo.menu.ColorMenu({
45233 focus: Roo.emptyFn,
45236 allowReselect: true,
45237 selectHandler: function(cp, color){
45239 editorcore.execCmd('useCSS', false);
45240 editorcore.execCmd('hilitecolor', color);
45241 editorcore.execCmd('useCSS', true);
45242 editor.deferFocus();
45244 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45245 Roo.isSafari || Roo.isIE ? '#'+color : color);
45246 editor.deferFocus();
45250 clickEvent:'mousedown'
45255 // now add all the items...
45258 if(!this.disable.alignments){
45261 btn('justifyleft'),
45262 btn('justifycenter'),
45263 btn('justifyright')
45267 //if(!Roo.isSafari){
45268 if(!this.disable.links){
45271 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45275 if(!this.disable.lists){
45278 btn('insertorderedlist'),
45279 btn('insertunorderedlist')
45282 if(!this.disable.sourceEdit){
45285 btn('sourceedit', true, function(btn){
45286 this.toggleSourceEdit(btn.pressed);
45293 // special menu.. - needs to be tidied up..
45294 if (!this.disable.special) {
45297 cls: 'x-edit-none',
45303 for (var i =0; i < this.specialChars.length; i++) {
45304 smenu.menu.items.push({
45306 html: this.specialChars[i],
45307 handler: function(a,b) {
45308 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45309 //editor.insertAtCursor(a.html);
45323 if (!this.disable.cleanStyles) {
45325 cls: 'x-btn-icon x-btn-clear',
45331 for (var i =0; i < this.cleanStyles.length; i++) {
45332 cmenu.menu.items.push({
45333 actiontype : this.cleanStyles[i],
45334 html: 'Remove ' + this.cleanStyles[i],
45335 handler: function(a,b) {
45338 var c = Roo.get(editorcore.doc.body);
45339 c.select('[style]').each(function(s) {
45340 s.dom.style.removeProperty(a.actiontype);
45342 editorcore.syncValue();
45347 cmenu.menu.items.push({
45348 actiontype : 'tablewidths',
45349 html: 'Remove Table Widths',
45350 handler: function(a,b) {
45351 editorcore.cleanTableWidths();
45352 editorcore.syncValue();
45356 cmenu.menu.items.push({
45357 actiontype : 'word',
45358 html: 'Remove MS Word Formating',
45359 handler: function(a,b) {
45360 editorcore.cleanWord();
45361 editorcore.syncValue();
45366 cmenu.menu.items.push({
45367 actiontype : 'all',
45368 html: 'Remove All Styles',
45369 handler: function(a,b) {
45371 var c = Roo.get(editorcore.doc.body);
45372 c.select('[style]').each(function(s) {
45373 s.dom.removeAttribute('style');
45375 editorcore.syncValue();
45380 cmenu.menu.items.push({
45381 actiontype : 'all',
45382 html: 'Remove All CSS Classes',
45383 handler: function(a,b) {
45385 var c = Roo.get(editorcore.doc.body);
45386 c.select('[class]').each(function(s) {
45387 s.dom.className = '';
45389 editorcore.syncValue();
45394 cmenu.menu.items.push({
45395 actiontype : 'tidy',
45396 html: 'Tidy HTML Source',
45397 handler: function(a,b) {
45398 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45399 editorcore.syncValue();
45408 if (!this.disable.specialElements) {
45411 cls: 'x-edit-none',
45416 for (var i =0; i < this.specialElements.length; i++) {
45417 semenu.menu.items.push(
45419 handler: function(a,b) {
45420 editor.insertAtCursor(this.ihtml);
45422 }, this.specialElements[i])
45434 for(var i =0; i< this.btns.length;i++) {
45435 var b = Roo.factory(this.btns[i],Roo.form);
45436 b.cls = 'x-edit-none';
45438 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45439 b.cls += ' x-init-enable';
45442 b.scope = editorcore;
45450 // disable everything...
45452 this.tb.items.each(function(item){
45455 item.id != editorcore.frameId+ '-sourceedit' &&
45456 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45462 this.rendered = true;
45464 // the all the btns;
45465 editor.on('editorevent', this.updateToolbar, this);
45466 // other toolbars need to implement this..
45467 //editor.on('editmodechange', this.updateToolbar, this);
45471 relayBtnCmd : function(btn) {
45472 this.editorcore.relayCmd(btn.cmd);
45474 // private used internally
45475 createLink : function(){
45476 Roo.log("create link?");
45477 var url = prompt(this.createLinkText, this.defaultLinkValue);
45478 if(url && url != 'http:/'+'/'){
45479 this.editorcore.relayCmd('createlink', url);
45485 * Protected method that will not generally be called directly. It triggers
45486 * a toolbar update by reading the markup state of the current selection in the editor.
45488 updateToolbar: function(){
45490 if(!this.editorcore.activated){
45491 this.editor.onFirstFocus();
45495 var btns = this.tb.items.map,
45496 doc = this.editorcore.doc,
45497 frameId = this.editorcore.frameId;
45499 if(!this.disable.font && !Roo.isSafari){
45501 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45502 if(name != this.fontSelect.dom.value){
45503 this.fontSelect.dom.value = name;
45507 if(!this.disable.format){
45508 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45509 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45510 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45511 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45513 if(!this.disable.alignments){
45514 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45515 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45516 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45518 if(!Roo.isSafari && !this.disable.lists){
45519 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45520 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45523 var ans = this.editorcore.getAllAncestors();
45524 if (this.formatCombo) {
45527 var store = this.formatCombo.store;
45528 this.formatCombo.setValue("");
45529 for (var i =0; i < ans.length;i++) {
45530 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45532 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45540 // hides menus... - so this cant be on a menu...
45541 Roo.menu.MenuMgr.hideAll();
45543 //this.editorsyncValue();
45547 createFontOptions : function(){
45548 var buf = [], fs = this.fontFamilies, ff, lc;
45552 for(var i = 0, len = fs.length; i< len; i++){
45554 lc = ff.toLowerCase();
45556 '<option value="',lc,'" style="font-family:',ff,';"',
45557 (this.defaultFont == lc ? ' selected="true">' : '>'),
45562 return buf.join('');
45565 toggleSourceEdit : function(sourceEditMode){
45567 Roo.log("toolbar toogle");
45568 if(sourceEditMode === undefined){
45569 sourceEditMode = !this.sourceEditMode;
45571 this.sourceEditMode = sourceEditMode === true;
45572 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45573 // just toggle the button?
45574 if(btn.pressed !== this.sourceEditMode){
45575 btn.toggle(this.sourceEditMode);
45579 if(sourceEditMode){
45580 Roo.log("disabling buttons");
45581 this.tb.items.each(function(item){
45582 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45588 Roo.log("enabling buttons");
45589 if(this.editorcore.initialized){
45590 this.tb.items.each(function(item){
45596 Roo.log("calling toggole on editor");
45597 // tell the editor that it's been pressed..
45598 this.editor.toggleSourceEdit(sourceEditMode);
45602 * Object collection of toolbar tooltips for the buttons in the editor. The key
45603 * is the command id associated with that button and the value is a valid QuickTips object.
45608 title: 'Bold (Ctrl+B)',
45609 text: 'Make the selected text bold.',
45610 cls: 'x-html-editor-tip'
45613 title: 'Italic (Ctrl+I)',
45614 text: 'Make the selected text italic.',
45615 cls: 'x-html-editor-tip'
45623 title: 'Bold (Ctrl+B)',
45624 text: 'Make the selected text bold.',
45625 cls: 'x-html-editor-tip'
45628 title: 'Italic (Ctrl+I)',
45629 text: 'Make the selected text italic.',
45630 cls: 'x-html-editor-tip'
45633 title: 'Underline (Ctrl+U)',
45634 text: 'Underline the selected text.',
45635 cls: 'x-html-editor-tip'
45638 title: 'Strikethrough',
45639 text: 'Strikethrough the selected text.',
45640 cls: 'x-html-editor-tip'
45642 increasefontsize : {
45643 title: 'Grow Text',
45644 text: 'Increase the font size.',
45645 cls: 'x-html-editor-tip'
45647 decreasefontsize : {
45648 title: 'Shrink Text',
45649 text: 'Decrease the font size.',
45650 cls: 'x-html-editor-tip'
45653 title: 'Text Highlight Color',
45654 text: 'Change the background color of the selected text.',
45655 cls: 'x-html-editor-tip'
45658 title: 'Font Color',
45659 text: 'Change the color of the selected text.',
45660 cls: 'x-html-editor-tip'
45663 title: 'Align Text Left',
45664 text: 'Align text to the left.',
45665 cls: 'x-html-editor-tip'
45668 title: 'Center Text',
45669 text: 'Center text in the editor.',
45670 cls: 'x-html-editor-tip'
45673 title: 'Align Text Right',
45674 text: 'Align text to the right.',
45675 cls: 'x-html-editor-tip'
45677 insertunorderedlist : {
45678 title: 'Bullet List',
45679 text: 'Start a bulleted list.',
45680 cls: 'x-html-editor-tip'
45682 insertorderedlist : {
45683 title: 'Numbered List',
45684 text: 'Start a numbered list.',
45685 cls: 'x-html-editor-tip'
45688 title: 'Hyperlink',
45689 text: 'Make the selected text a hyperlink.',
45690 cls: 'x-html-editor-tip'
45693 title: 'Source Edit',
45694 text: 'Switch to source editing mode.',
45695 cls: 'x-html-editor-tip'
45699 onDestroy : function(){
45702 this.tb.items.each(function(item){
45704 item.menu.removeAll();
45706 item.menu.el.destroy();
45714 onFirstFocus: function() {
45715 this.tb.items.each(function(item){
45724 // <script type="text/javascript">
45727 * Ext JS Library 1.1.1
45728 * Copyright(c) 2006-2007, Ext JS, LLC.
45735 * @class Roo.form.HtmlEditor.ToolbarContext
45740 new Roo.form.HtmlEditor({
45743 { xtype: 'ToolbarStandard', styles : {} }
45744 { xtype: 'ToolbarContext', disable : {} }
45750 * @config : {Object} disable List of elements to disable.. (not done yet.)
45751 * @config : {Object} styles Map of styles available.
45755 Roo.form.HtmlEditor.ToolbarContext = function(config)
45758 Roo.apply(this, config);
45759 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45760 // dont call parent... till later.
45761 this.styles = this.styles || {};
45766 Roo.form.HtmlEditor.ToolbarContext.types = {
45778 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45844 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45849 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45859 style : 'fontFamily',
45860 displayField: 'display',
45861 optname : 'font-family',
45910 // should we really allow this??
45911 // should this just be
45922 style : 'fontFamily',
45923 displayField: 'display',
45924 optname : 'font-family',
45931 style : 'fontFamily',
45932 displayField: 'display',
45933 optname : 'font-family',
45940 style : 'fontFamily',
45941 displayField: 'display',
45942 optname : 'font-family',
45953 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
45954 Roo.form.HtmlEditor.ToolbarContext.stores = false;
45956 Roo.form.HtmlEditor.ToolbarContext.options = {
45958 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
45959 [ 'Courier New', 'Courier New'],
45960 [ 'Tahoma', 'Tahoma'],
45961 [ 'Times New Roman,serif', 'Times'],
45962 [ 'Verdana','Verdana' ]
45966 // fixme - these need to be configurable..
45969 //Roo.form.HtmlEditor.ToolbarContext.types
45972 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
45979 editorcore : false,
45981 * @cfg {Object} disable List of toolbar elements to disable
45986 * @cfg {Object} styles List of styles
45987 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
45989 * These must be defined in the page, so they get rendered correctly..
46000 init : function(editor)
46002 this.editor = editor;
46003 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46004 var editorcore = this.editorcore;
46006 var fid = editorcore.frameId;
46008 function btn(id, toggle, handler){
46009 var xid = fid + '-'+ id ;
46013 cls : 'x-btn-icon x-edit-'+id,
46014 enableToggle:toggle !== false,
46015 scope: editorcore, // was editor...
46016 handler:handler||editorcore.relayBtnCmd,
46017 clickEvent:'mousedown',
46018 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46022 // create a new element.
46023 var wdiv = editor.wrap.createChild({
46025 }, editor.wrap.dom.firstChild.nextSibling, true);
46027 // can we do this more than once??
46029 // stop form submits
46032 // disable everything...
46033 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46034 this.toolbars = {};
46036 for (var i in ty) {
46038 this.toolbars[i] = this.buildToolbar(ty[i],i);
46040 this.tb = this.toolbars.BODY;
46042 this.buildFooter();
46043 this.footer.show();
46044 editor.on('hide', function( ) { this.footer.hide() }, this);
46045 editor.on('show', function( ) { this.footer.show() }, this);
46048 this.rendered = true;
46050 // the all the btns;
46051 editor.on('editorevent', this.updateToolbar, this);
46052 // other toolbars need to implement this..
46053 //editor.on('editmodechange', this.updateToolbar, this);
46059 * Protected method that will not generally be called directly. It triggers
46060 * a toolbar update by reading the markup state of the current selection in the editor.
46062 * Note you can force an update by calling on('editorevent', scope, false)
46064 updateToolbar: function(editor,ev,sel){
46067 // capture mouse up - this is handy for selecting images..
46068 // perhaps should go somewhere else...
46069 if(!this.editorcore.activated){
46070 this.editor.onFirstFocus();
46076 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46077 // selectNode - might want to handle IE?
46079 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46080 ev.target && ev.target.tagName == 'IMG') {
46081 // they have click on an image...
46082 // let's see if we can change the selection...
46085 var nodeRange = sel.ownerDocument.createRange();
46087 nodeRange.selectNode(sel);
46089 nodeRange.selectNodeContents(sel);
46091 //nodeRange.collapse(true);
46092 var s = this.editorcore.win.getSelection();
46093 s.removeAllRanges();
46094 s.addRange(nodeRange);
46098 var updateFooter = sel ? false : true;
46101 var ans = this.editorcore.getAllAncestors();
46104 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46107 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46108 sel = sel ? sel : this.editorcore.doc.body;
46109 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46112 // pick a menu that exists..
46113 var tn = sel.tagName.toUpperCase();
46114 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46116 tn = sel.tagName.toUpperCase();
46118 var lastSel = this.tb.selectedNode;
46120 this.tb.selectedNode = sel;
46122 // if current menu does not match..
46124 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46127 ///console.log("show: " + tn);
46128 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46131 this.tb.items.first().el.innerHTML = tn + ': ';
46134 // update attributes
46135 if (this.tb.fields) {
46136 this.tb.fields.each(function(e) {
46138 e.setValue(sel.style[e.stylename]);
46141 e.setValue(sel.getAttribute(e.attrname));
46145 var hasStyles = false;
46146 for(var i in this.styles) {
46153 var st = this.tb.fields.item(0);
46155 st.store.removeAll();
46158 var cn = sel.className.split(/\s+/);
46161 if (this.styles['*']) {
46163 Roo.each(this.styles['*'], function(v) {
46164 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46167 if (this.styles[tn]) {
46168 Roo.each(this.styles[tn], function(v) {
46169 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46173 st.store.loadData(avs);
46177 // flag our selected Node.
46178 this.tb.selectedNode = sel;
46181 Roo.menu.MenuMgr.hideAll();
46185 if (!updateFooter) {
46186 //this.footDisp.dom.innerHTML = '';
46189 // update the footer
46193 this.footerEls = ans.reverse();
46194 Roo.each(this.footerEls, function(a,i) {
46195 if (!a) { return; }
46196 html += html.length ? ' > ' : '';
46198 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46203 var sz = this.footDisp.up('td').getSize();
46204 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46205 this.footDisp.dom.style.marginLeft = '5px';
46207 this.footDisp.dom.style.overflow = 'hidden';
46209 this.footDisp.dom.innerHTML = html;
46211 //this.editorsyncValue();
46218 onDestroy : function(){
46221 this.tb.items.each(function(item){
46223 item.menu.removeAll();
46225 item.menu.el.destroy();
46233 onFirstFocus: function() {
46234 // need to do this for all the toolbars..
46235 this.tb.items.each(function(item){
46239 buildToolbar: function(tlist, nm)
46241 var editor = this.editor;
46242 var editorcore = this.editorcore;
46243 // create a new element.
46244 var wdiv = editor.wrap.createChild({
46246 }, editor.wrap.dom.firstChild.nextSibling, true);
46249 var tb = new Roo.Toolbar(wdiv);
46252 tb.add(nm+ ": ");
46255 for(var i in this.styles) {
46260 if (styles && styles.length) {
46262 // this needs a multi-select checkbox...
46263 tb.addField( new Roo.form.ComboBox({
46264 store: new Roo.data.SimpleStore({
46266 fields: ['val', 'selected'],
46269 name : '-roo-edit-className',
46270 attrname : 'className',
46271 displayField: 'val',
46275 triggerAction: 'all',
46276 emptyText:'Select Style',
46277 selectOnFocus:true,
46280 'select': function(c, r, i) {
46281 // initial support only for on class per el..
46282 tb.selectedNode.className = r ? r.get('val') : '';
46283 editorcore.syncValue();
46290 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46291 var tbops = tbc.options;
46293 for (var i in tlist) {
46295 var item = tlist[i];
46296 tb.add(item.title + ": ");
46299 //optname == used so you can configure the options available..
46300 var opts = item.opts ? item.opts : false;
46301 if (item.optname) {
46302 opts = tbops[item.optname];
46307 // opts == pulldown..
46308 tb.addField( new Roo.form.ComboBox({
46309 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46311 fields: ['val', 'display'],
46314 name : '-roo-edit-' + i,
46316 stylename : item.style ? item.style : false,
46317 displayField: item.displayField ? item.displayField : 'val',
46318 valueField : 'val',
46320 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46322 triggerAction: 'all',
46323 emptyText:'Select',
46324 selectOnFocus:true,
46325 width: item.width ? item.width : 130,
46327 'select': function(c, r, i) {
46329 tb.selectedNode.style[c.stylename] = r.get('val');
46332 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46341 tb.addField( new Roo.form.TextField({
46344 //allowBlank:false,
46349 tb.addField( new Roo.form.TextField({
46350 name: '-roo-edit-' + i,
46357 'change' : function(f, nv, ov) {
46358 tb.selectedNode.setAttribute(f.attrname, nv);
46359 editorcore.syncValue();
46372 text: 'Stylesheets',
46375 click : function ()
46377 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46385 text: 'Remove Tag',
46388 click : function ()
46391 // undo does not work.
46393 var sn = tb.selectedNode;
46395 var pn = sn.parentNode;
46397 var stn = sn.childNodes[0];
46398 var en = sn.childNodes[sn.childNodes.length - 1 ];
46399 while (sn.childNodes.length) {
46400 var node = sn.childNodes[0];
46401 sn.removeChild(node);
46403 pn.insertBefore(node, sn);
46406 pn.removeChild(sn);
46407 var range = editorcore.createRange();
46409 range.setStart(stn,0);
46410 range.setEnd(en,0); //????
46411 //range.selectNode(sel);
46414 var selection = editorcore.getSelection();
46415 selection.removeAllRanges();
46416 selection.addRange(range);
46420 //_this.updateToolbar(null, null, pn);
46421 _this.updateToolbar(null, null, null);
46422 _this.footDisp.dom.innerHTML = '';
46432 tb.el.on('click', function(e){
46433 e.preventDefault(); // what does this do?
46435 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46438 // dont need to disable them... as they will get hidden
46443 buildFooter : function()
46446 var fel = this.editor.wrap.createChild();
46447 this.footer = new Roo.Toolbar(fel);
46448 // toolbar has scrolly on left / right?
46449 var footDisp= new Roo.Toolbar.Fill();
46455 handler : function() {
46456 _t.footDisp.scrollTo('left',0,true)
46460 this.footer.add( footDisp );
46465 handler : function() {
46467 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46471 var fel = Roo.get(footDisp.el);
46472 fel.addClass('x-editor-context');
46473 this.footDispWrap = fel;
46474 this.footDispWrap.overflow = 'hidden';
46476 this.footDisp = fel.createChild();
46477 this.footDispWrap.on('click', this.onContextClick, this)
46481 onContextClick : function (ev,dom)
46483 ev.preventDefault();
46484 var cn = dom.className;
46486 if (!cn.match(/x-ed-loc-/)) {
46489 var n = cn.split('-').pop();
46490 var ans = this.footerEls;
46494 var range = this.editorcore.createRange();
46496 range.selectNodeContents(sel);
46497 //range.selectNode(sel);
46500 var selection = this.editorcore.getSelection();
46501 selection.removeAllRanges();
46502 selection.addRange(range);
46506 this.updateToolbar(null, null, sel);
46523 * Ext JS Library 1.1.1
46524 * Copyright(c) 2006-2007, Ext JS, LLC.
46526 * Originally Released Under LGPL - original licence link has changed is not relivant.
46529 * <script type="text/javascript">
46533 * @class Roo.form.BasicForm
46534 * @extends Roo.util.Observable
46535 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46537 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46538 * @param {Object} config Configuration options
46540 Roo.form.BasicForm = function(el, config){
46541 this.allItems = [];
46542 this.childForms = [];
46543 Roo.apply(this, config);
46545 * The Roo.form.Field items in this form.
46546 * @type MixedCollection
46550 this.items = new Roo.util.MixedCollection(false, function(o){
46551 return o.id || (o.id = Roo.id());
46555 * @event beforeaction
46556 * Fires before any action is performed. Return false to cancel the action.
46557 * @param {Form} this
46558 * @param {Action} action The action to be performed
46560 beforeaction: true,
46562 * @event actionfailed
46563 * Fires when an action fails.
46564 * @param {Form} this
46565 * @param {Action} action The action that failed
46567 actionfailed : true,
46569 * @event actioncomplete
46570 * Fires when an action is completed.
46571 * @param {Form} this
46572 * @param {Action} action The action that completed
46574 actioncomplete : true
46579 Roo.form.BasicForm.superclass.constructor.call(this);
46582 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46584 * @cfg {String} method
46585 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46588 * @cfg {DataReader} reader
46589 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46590 * This is optional as there is built-in support for processing JSON.
46593 * @cfg {DataReader} errorReader
46594 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46595 * This is completely optional as there is built-in support for processing JSON.
46598 * @cfg {String} url
46599 * The URL to use for form actions if one isn't supplied in the action options.
46602 * @cfg {Boolean} fileUpload
46603 * Set to true if this form is a file upload.
46607 * @cfg {Object} baseParams
46608 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46613 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46618 activeAction : null,
46621 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46622 * or setValues() data instead of when the form was first created.
46624 trackResetOnLoad : false,
46628 * childForms - used for multi-tab forms
46631 childForms : false,
46634 * allItems - full list of fields.
46640 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46641 * element by passing it or its id or mask the form itself by passing in true.
46644 waitMsgTarget : false,
46647 initEl : function(el){
46648 this.el = Roo.get(el);
46649 this.id = this.el.id || Roo.id();
46650 this.el.on('submit', this.onSubmit, this);
46651 this.el.addClass('x-form');
46655 onSubmit : function(e){
46660 * Returns true if client-side validation on the form is successful.
46663 isValid : function(){
46665 this.items.each(function(f){
46674 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46677 isDirty : function(){
46679 this.items.each(function(f){
46689 * Returns true if any fields in this form have changed since their original load. (New version)
46693 hasChanged : function()
46696 this.items.each(function(f){
46697 if(f.hasChanged()){
46706 * Resets all hasChanged to 'false' -
46707 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46708 * So hasChanged storage is only to be used for this purpose
46711 resetHasChanged : function()
46713 this.items.each(function(f){
46714 f.resetHasChanged();
46721 * Performs a predefined action (submit or load) or custom actions you define on this form.
46722 * @param {String} actionName The name of the action type
46723 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46724 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46725 * accept other config options):
46727 Property Type Description
46728 ---------------- --------------- ----------------------------------------------------------------------------------
46729 url String The url for the action (defaults to the form's url)
46730 method String The form method to use (defaults to the form's method, or POST if not defined)
46731 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46732 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46733 validate the form on the client (defaults to false)
46735 * @return {BasicForm} this
46737 doAction : function(action, options){
46738 if(typeof action == 'string'){
46739 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46741 if(this.fireEvent('beforeaction', this, action) !== false){
46742 this.beforeAction(action);
46743 action.run.defer(100, action);
46749 * Shortcut to do a submit action.
46750 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46751 * @return {BasicForm} this
46753 submit : function(options){
46754 this.doAction('submit', options);
46759 * Shortcut to do a load action.
46760 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46761 * @return {BasicForm} this
46763 load : function(options){
46764 this.doAction('load', options);
46769 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46770 * @param {Record} record The record to edit
46771 * @return {BasicForm} this
46773 updateRecord : function(record){
46774 record.beginEdit();
46775 var fs = record.fields;
46776 fs.each(function(f){
46777 var field = this.findField(f.name);
46779 record.set(f.name, field.getValue());
46787 * Loads an Roo.data.Record into this form.
46788 * @param {Record} record The record to load
46789 * @return {BasicForm} this
46791 loadRecord : function(record){
46792 this.setValues(record.data);
46797 beforeAction : function(action){
46798 var o = action.options;
46801 if(this.waitMsgTarget === true){
46802 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46803 }else if(this.waitMsgTarget){
46804 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46805 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46807 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46813 afterAction : function(action, success){
46814 this.activeAction = null;
46815 var o = action.options;
46817 if(this.waitMsgTarget === true){
46819 }else if(this.waitMsgTarget){
46820 this.waitMsgTarget.unmask();
46822 Roo.MessageBox.updateProgress(1);
46823 Roo.MessageBox.hide();
46830 Roo.callback(o.success, o.scope, [this, action]);
46831 this.fireEvent('actioncomplete', this, action);
46835 // failure condition..
46836 // we have a scenario where updates need confirming.
46837 // eg. if a locking scenario exists..
46838 // we look for { errors : { needs_confirm : true }} in the response.
46840 (typeof(action.result) != 'undefined') &&
46841 (typeof(action.result.errors) != 'undefined') &&
46842 (typeof(action.result.errors.needs_confirm) != 'undefined')
46845 Roo.MessageBox.confirm(
46846 "Change requires confirmation",
46847 action.result.errorMsg,
46852 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46862 Roo.callback(o.failure, o.scope, [this, action]);
46863 // show an error message if no failed handler is set..
46864 if (!this.hasListener('actionfailed')) {
46865 Roo.MessageBox.alert("Error",
46866 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46867 action.result.errorMsg :
46868 "Saving Failed, please check your entries or try again"
46872 this.fireEvent('actionfailed', this, action);
46878 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46879 * @param {String} id The value to search for
46882 findField : function(id){
46883 var field = this.items.get(id);
46885 this.items.each(function(f){
46886 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
46892 return field || null;
46896 * Add a secondary form to this one,
46897 * Used to provide tabbed forms. One form is primary, with hidden values
46898 * which mirror the elements from the other forms.
46900 * @param {Roo.form.Form} form to add.
46903 addForm : function(form)
46906 if (this.childForms.indexOf(form) > -1) {
46910 this.childForms.push(form);
46912 Roo.each(form.allItems, function (fe) {
46914 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
46915 if (this.findField(n)) { // already added..
46918 var add = new Roo.form.Hidden({
46921 add.render(this.el);
46928 * Mark fields in this form invalid in bulk.
46929 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
46930 * @return {BasicForm} this
46932 markInvalid : function(errors){
46933 if(errors instanceof Array){
46934 for(var i = 0, len = errors.length; i < len; i++){
46935 var fieldError = errors[i];
46936 var f = this.findField(fieldError.id);
46938 f.markInvalid(fieldError.msg);
46944 if(typeof errors[id] != 'function' && (field = this.findField(id))){
46945 field.markInvalid(errors[id]);
46949 Roo.each(this.childForms || [], function (f) {
46950 f.markInvalid(errors);
46957 * Set values for fields in this form in bulk.
46958 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
46959 * @return {BasicForm} this
46961 setValues : function(values){
46962 if(values instanceof Array){ // array of objects
46963 for(var i = 0, len = values.length; i < len; i++){
46965 var f = this.findField(v.id);
46967 f.setValue(v.value);
46968 if(this.trackResetOnLoad){
46969 f.originalValue = f.getValue();
46973 }else{ // object hash
46976 if(typeof values[id] != 'function' && (field = this.findField(id))){
46978 if (field.setFromData &&
46979 field.valueField &&
46980 field.displayField &&
46981 // combos' with local stores can
46982 // be queried via setValue()
46983 // to set their value..
46984 (field.store && !field.store.isLocal)
46988 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
46989 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
46990 field.setFromData(sd);
46993 field.setValue(values[id]);
46997 if(this.trackResetOnLoad){
46998 field.originalValue = field.getValue();
47003 this.resetHasChanged();
47006 Roo.each(this.childForms || [], function (f) {
47007 f.setValues(values);
47008 f.resetHasChanged();
47015 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47016 * they are returned as an array.
47017 * @param {Boolean} asString
47020 getValues : function(asString){
47021 if (this.childForms) {
47022 // copy values from the child forms
47023 Roo.each(this.childForms, function (f) {
47024 this.setValues(f.getValues());
47030 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47031 if(asString === true){
47034 return Roo.urlDecode(fs);
47038 * Returns the fields in this form as an object with key/value pairs.
47039 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47042 getFieldValues : function(with_hidden)
47044 if (this.childForms) {
47045 // copy values from the child forms
47046 // should this call getFieldValues - probably not as we do not currently copy
47047 // hidden fields when we generate..
47048 Roo.each(this.childForms, function (f) {
47049 this.setValues(f.getValues());
47054 this.items.each(function(f){
47055 if (!f.getName()) {
47058 var v = f.getValue();
47059 if (f.inputType =='radio') {
47060 if (typeof(ret[f.getName()]) == 'undefined') {
47061 ret[f.getName()] = ''; // empty..
47064 if (!f.el.dom.checked) {
47068 v = f.el.dom.value;
47072 // not sure if this supported any more..
47073 if ((typeof(v) == 'object') && f.getRawValue) {
47074 v = f.getRawValue() ; // dates..
47076 // combo boxes where name != hiddenName...
47077 if (f.name != f.getName()) {
47078 ret[f.name] = f.getRawValue();
47080 ret[f.getName()] = v;
47087 * Clears all invalid messages in this form.
47088 * @return {BasicForm} this
47090 clearInvalid : function(){
47091 this.items.each(function(f){
47095 Roo.each(this.childForms || [], function (f) {
47104 * Resets this form.
47105 * @return {BasicForm} this
47107 reset : function(){
47108 this.items.each(function(f){
47112 Roo.each(this.childForms || [], function (f) {
47115 this.resetHasChanged();
47121 * Add Roo.form components to this form.
47122 * @param {Field} field1
47123 * @param {Field} field2 (optional)
47124 * @param {Field} etc (optional)
47125 * @return {BasicForm} this
47128 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47134 * Removes a field from the items collection (does NOT remove its markup).
47135 * @param {Field} field
47136 * @return {BasicForm} this
47138 remove : function(field){
47139 this.items.remove(field);
47144 * Looks at the fields in this form, checks them for an id attribute,
47145 * and calls applyTo on the existing dom element with that id.
47146 * @return {BasicForm} this
47148 render : function(){
47149 this.items.each(function(f){
47150 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47158 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47159 * @param {Object} values
47160 * @return {BasicForm} this
47162 applyToFields : function(o){
47163 this.items.each(function(f){
47170 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47171 * @param {Object} values
47172 * @return {BasicForm} this
47174 applyIfToFields : function(o){
47175 this.items.each(function(f){
47183 Roo.BasicForm = Roo.form.BasicForm;/*
47185 * Ext JS Library 1.1.1
47186 * Copyright(c) 2006-2007, Ext JS, LLC.
47188 * Originally Released Under LGPL - original licence link has changed is not relivant.
47191 * <script type="text/javascript">
47195 * @class Roo.form.Form
47196 * @extends Roo.form.BasicForm
47197 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47199 * @param {Object} config Configuration options
47201 Roo.form.Form = function(config){
47203 if (config.items) {
47204 xitems = config.items;
47205 delete config.items;
47209 Roo.form.Form.superclass.constructor.call(this, null, config);
47210 this.url = this.url || this.action;
47212 this.root = new Roo.form.Layout(Roo.applyIf({
47216 this.active = this.root;
47218 * Array of all the buttons that have been added to this form via {@link addButton}
47222 this.allItems = [];
47225 * @event clientvalidation
47226 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47227 * @param {Form} this
47228 * @param {Boolean} valid true if the form has passed client-side validation
47230 clientvalidation: true,
47233 * Fires when the form is rendered
47234 * @param {Roo.form.Form} form
47239 if (this.progressUrl) {
47240 // push a hidden field onto the list of fields..
47244 name : 'UPLOAD_IDENTIFIER'
47249 Roo.each(xitems, this.addxtype, this);
47255 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47257 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47260 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47263 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47265 buttonAlign:'center',
47268 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47273 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47274 * This property cascades to child containers if not set.
47279 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47280 * fires a looping event with that state. This is required to bind buttons to the valid
47281 * state using the config value formBind:true on the button.
47283 monitorValid : false,
47286 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47291 * @cfg {String} progressUrl - Url to return progress data
47294 progressUrl : false,
47297 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47298 * fields are added and the column is closed. If no fields are passed the column remains open
47299 * until end() is called.
47300 * @param {Object} config The config to pass to the column
47301 * @param {Field} field1 (optional)
47302 * @param {Field} field2 (optional)
47303 * @param {Field} etc (optional)
47304 * @return Column The column container object
47306 column : function(c){
47307 var col = new Roo.form.Column(c);
47309 if(arguments.length > 1){ // duplicate code required because of Opera
47310 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47317 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47318 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47319 * until end() is called.
47320 * @param {Object} config The config to pass to the fieldset
47321 * @param {Field} field1 (optional)
47322 * @param {Field} field2 (optional)
47323 * @param {Field} etc (optional)
47324 * @return FieldSet The fieldset container object
47326 fieldset : function(c){
47327 var fs = new Roo.form.FieldSet(c);
47329 if(arguments.length > 1){ // duplicate code required because of Opera
47330 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47337 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47338 * fields are added and the container is closed. If no fields are passed the container remains open
47339 * until end() is called.
47340 * @param {Object} config The config to pass to the Layout
47341 * @param {Field} field1 (optional)
47342 * @param {Field} field2 (optional)
47343 * @param {Field} etc (optional)
47344 * @return Layout The container object
47346 container : function(c){
47347 var l = new Roo.form.Layout(c);
47349 if(arguments.length > 1){ // duplicate code required because of Opera
47350 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47357 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47358 * @param {Object} container A Roo.form.Layout or subclass of Layout
47359 * @return {Form} this
47361 start : function(c){
47362 // cascade label info
47363 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47364 this.active.stack.push(c);
47365 c.ownerCt = this.active;
47371 * Closes the current open container
47372 * @return {Form} this
47375 if(this.active == this.root){
47378 this.active = this.active.ownerCt;
47383 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47384 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47385 * as the label of the field.
47386 * @param {Field} field1
47387 * @param {Field} field2 (optional)
47388 * @param {Field} etc. (optional)
47389 * @return {Form} this
47392 this.active.stack.push.apply(this.active.stack, arguments);
47393 this.allItems.push.apply(this.allItems,arguments);
47395 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47396 if(a[i].isFormField){
47401 Roo.form.Form.superclass.add.apply(this, r);
47411 * Find any element that has been added to a form, using it's ID or name
47412 * This can include framesets, columns etc. along with regular fields..
47413 * @param {String} id - id or name to find.
47415 * @return {Element} e - or false if nothing found.
47417 findbyId : function(id)
47423 Roo.each(this.allItems, function(f){
47424 if (f.id == id || f.name == id ){
47435 * Render this form into the passed container. This should only be called once!
47436 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47437 * @return {Form} this
47439 render : function(ct)
47445 var o = this.autoCreate || {
47447 method : this.method || 'POST',
47448 id : this.id || Roo.id()
47450 this.initEl(ct.createChild(o));
47452 this.root.render(this.el);
47456 this.items.each(function(f){
47457 f.render('x-form-el-'+f.id);
47460 if(this.buttons.length > 0){
47461 // tables are required to maintain order and for correct IE layout
47462 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47463 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47464 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47466 var tr = tb.getElementsByTagName('tr')[0];
47467 for(var i = 0, len = this.buttons.length; i < len; i++) {
47468 var b = this.buttons[i];
47469 var td = document.createElement('td');
47470 td.className = 'x-form-btn-td';
47471 b.render(tr.appendChild(td));
47474 if(this.monitorValid){ // initialize after render
47475 this.startMonitoring();
47477 this.fireEvent('rendered', this);
47482 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47483 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47484 * object or a valid Roo.DomHelper element config
47485 * @param {Function} handler The function called when the button is clicked
47486 * @param {Object} scope (optional) The scope of the handler function
47487 * @return {Roo.Button}
47489 addButton : function(config, handler, scope){
47493 minWidth: this.minButtonWidth,
47496 if(typeof config == "string"){
47499 Roo.apply(bc, config);
47501 var btn = new Roo.Button(null, bc);
47502 this.buttons.push(btn);
47507 * Adds a series of form elements (using the xtype property as the factory method.
47508 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47509 * @param {Object} config
47512 addxtype : function()
47514 var ar = Array.prototype.slice.call(arguments, 0);
47516 for(var i = 0; i < ar.length; i++) {
47518 continue; // skip -- if this happends something invalid got sent, we
47519 // should ignore it, as basically that interface element will not show up
47520 // and that should be pretty obvious!!
47523 if (Roo.form[ar[i].xtype]) {
47525 var fe = Roo.factory(ar[i], Roo.form);
47531 fe.store.form = this;
47536 this.allItems.push(fe);
47537 if (fe.items && fe.addxtype) {
47538 fe.addxtype.apply(fe, fe.items);
47548 // console.log('adding ' + ar[i].xtype);
47550 if (ar[i].xtype == 'Button') {
47551 //console.log('adding button');
47552 //console.log(ar[i]);
47553 this.addButton(ar[i]);
47554 this.allItems.push(fe);
47558 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47559 alert('end is not supported on xtype any more, use items');
47561 // //console.log('adding end');
47569 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47570 * option "monitorValid"
47572 startMonitoring : function(){
47575 Roo.TaskMgr.start({
47576 run : this.bindHandler,
47577 interval : this.monitorPoll || 200,
47584 * Stops monitoring of the valid state of this form
47586 stopMonitoring : function(){
47587 this.bound = false;
47591 bindHandler : function(){
47593 return false; // stops binding
47596 this.items.each(function(f){
47597 if(!f.isValid(true)){
47602 for(var i = 0, len = this.buttons.length; i < len; i++){
47603 var btn = this.buttons[i];
47604 if(btn.formBind === true && btn.disabled === valid){
47605 btn.setDisabled(!valid);
47608 this.fireEvent('clientvalidation', this, valid);
47622 Roo.Form = Roo.form.Form;
47625 * Ext JS Library 1.1.1
47626 * Copyright(c) 2006-2007, Ext JS, LLC.
47628 * Originally Released Under LGPL - original licence link has changed is not relivant.
47631 * <script type="text/javascript">
47634 // as we use this in bootstrap.
47635 Roo.namespace('Roo.form');
47637 * @class Roo.form.Action
47638 * Internal Class used to handle form actions
47640 * @param {Roo.form.BasicForm} el The form element or its id
47641 * @param {Object} config Configuration options
47646 // define the action interface
47647 Roo.form.Action = function(form, options){
47649 this.options = options || {};
47652 * Client Validation Failed
47655 Roo.form.Action.CLIENT_INVALID = 'client';
47657 * Server Validation Failed
47660 Roo.form.Action.SERVER_INVALID = 'server';
47662 * Connect to Server Failed
47665 Roo.form.Action.CONNECT_FAILURE = 'connect';
47667 * Reading Data from Server Failed
47670 Roo.form.Action.LOAD_FAILURE = 'load';
47672 Roo.form.Action.prototype = {
47674 failureType : undefined,
47675 response : undefined,
47676 result : undefined,
47678 // interface method
47679 run : function(options){
47683 // interface method
47684 success : function(response){
47688 // interface method
47689 handleResponse : function(response){
47693 // default connection failure
47694 failure : function(response){
47696 this.response = response;
47697 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47698 this.form.afterAction(this, false);
47701 processResponse : function(response){
47702 this.response = response;
47703 if(!response.responseText){
47706 this.result = this.handleResponse(response);
47707 return this.result;
47710 // utility functions used internally
47711 getUrl : function(appendParams){
47712 var url = this.options.url || this.form.url || this.form.el.dom.action;
47714 var p = this.getParams();
47716 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47722 getMethod : function(){
47723 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47726 getParams : function(){
47727 var bp = this.form.baseParams;
47728 var p = this.options.params;
47730 if(typeof p == "object"){
47731 p = Roo.urlEncode(Roo.applyIf(p, bp));
47732 }else if(typeof p == 'string' && bp){
47733 p += '&' + Roo.urlEncode(bp);
47736 p = Roo.urlEncode(bp);
47741 createCallback : function(){
47743 success: this.success,
47744 failure: this.failure,
47746 timeout: (this.form.timeout*1000),
47747 upload: this.form.fileUpload ? this.success : undefined
47752 Roo.form.Action.Submit = function(form, options){
47753 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47756 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47759 haveProgress : false,
47760 uploadComplete : false,
47762 // uploadProgress indicator.
47763 uploadProgress : function()
47765 if (!this.form.progressUrl) {
47769 if (!this.haveProgress) {
47770 Roo.MessageBox.progress("Uploading", "Uploading");
47772 if (this.uploadComplete) {
47773 Roo.MessageBox.hide();
47777 this.haveProgress = true;
47779 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47781 var c = new Roo.data.Connection();
47783 url : this.form.progressUrl,
47788 success : function(req){
47789 //console.log(data);
47793 rdata = Roo.decode(req.responseText)
47795 Roo.log("Invalid data from server..");
47799 if (!rdata || !rdata.success) {
47801 Roo.MessageBox.alert(Roo.encode(rdata));
47804 var data = rdata.data;
47806 if (this.uploadComplete) {
47807 Roo.MessageBox.hide();
47812 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47813 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47816 this.uploadProgress.defer(2000,this);
47819 failure: function(data) {
47820 Roo.log('progress url failed ');
47831 // run get Values on the form, so it syncs any secondary forms.
47832 this.form.getValues();
47834 var o = this.options;
47835 var method = this.getMethod();
47836 var isPost = method == 'POST';
47837 if(o.clientValidation === false || this.form.isValid()){
47839 if (this.form.progressUrl) {
47840 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47841 (new Date() * 1) + '' + Math.random());
47846 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47847 form:this.form.el.dom,
47848 url:this.getUrl(!isPost),
47850 params:isPost ? this.getParams() : null,
47851 isUpload: this.form.fileUpload
47854 this.uploadProgress();
47856 }else if (o.clientValidation !== false){ // client validation failed
47857 this.failureType = Roo.form.Action.CLIENT_INVALID;
47858 this.form.afterAction(this, false);
47862 success : function(response)
47864 this.uploadComplete= true;
47865 if (this.haveProgress) {
47866 Roo.MessageBox.hide();
47870 var result = this.processResponse(response);
47871 if(result === true || result.success){
47872 this.form.afterAction(this, true);
47876 this.form.markInvalid(result.errors);
47877 this.failureType = Roo.form.Action.SERVER_INVALID;
47879 this.form.afterAction(this, false);
47881 failure : function(response)
47883 this.uploadComplete= true;
47884 if (this.haveProgress) {
47885 Roo.MessageBox.hide();
47888 this.response = response;
47889 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47890 this.form.afterAction(this, false);
47893 handleResponse : function(response){
47894 if(this.form.errorReader){
47895 var rs = this.form.errorReader.read(response);
47898 for(var i = 0, len = rs.records.length; i < len; i++) {
47899 var r = rs.records[i];
47900 errors[i] = r.data;
47903 if(errors.length < 1){
47907 success : rs.success,
47913 ret = Roo.decode(response.responseText);
47917 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
47927 Roo.form.Action.Load = function(form, options){
47928 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
47929 this.reader = this.form.reader;
47932 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
47937 Roo.Ajax.request(Roo.apply(
47938 this.createCallback(), {
47939 method:this.getMethod(),
47940 url:this.getUrl(false),
47941 params:this.getParams()
47945 success : function(response){
47947 var result = this.processResponse(response);
47948 if(result === true || !result.success || !result.data){
47949 this.failureType = Roo.form.Action.LOAD_FAILURE;
47950 this.form.afterAction(this, false);
47953 this.form.clearInvalid();
47954 this.form.setValues(result.data);
47955 this.form.afterAction(this, true);
47958 handleResponse : function(response){
47959 if(this.form.reader){
47960 var rs = this.form.reader.read(response);
47961 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
47963 success : rs.success,
47967 return Roo.decode(response.responseText);
47971 Roo.form.Action.ACTION_TYPES = {
47972 'load' : Roo.form.Action.Load,
47973 'submit' : Roo.form.Action.Submit
47976 * Ext JS Library 1.1.1
47977 * Copyright(c) 2006-2007, Ext JS, LLC.
47979 * Originally Released Under LGPL - original licence link has changed is not relivant.
47982 * <script type="text/javascript">
47986 * @class Roo.form.Layout
47987 * @extends Roo.Component
47988 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
47990 * @param {Object} config Configuration options
47992 Roo.form.Layout = function(config){
47994 if (config.items) {
47995 xitems = config.items;
47996 delete config.items;
47998 Roo.form.Layout.superclass.constructor.call(this, config);
48000 Roo.each(xitems, this.addxtype, this);
48004 Roo.extend(Roo.form.Layout, Roo.Component, {
48006 * @cfg {String/Object} autoCreate
48007 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
48010 * @cfg {String/Object/Function} style
48011 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
48012 * a function which returns such a specification.
48015 * @cfg {String} labelAlign
48016 * Valid values are "left," "top" and "right" (defaults to "left")
48019 * @cfg {Number} labelWidth
48020 * Fixed width in pixels of all field labels (defaults to undefined)
48023 * @cfg {Boolean} clear
48024 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
48028 * @cfg {String} labelSeparator
48029 * The separator to use after field labels (defaults to ':')
48031 labelSeparator : ':',
48033 * @cfg {Boolean} hideLabels
48034 * True to suppress the display of field labels in this layout (defaults to false)
48036 hideLabels : false,
48039 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48044 onRender : function(ct, position){
48045 if(this.el){ // from markup
48046 this.el = Roo.get(this.el);
48047 }else { // generate
48048 var cfg = this.getAutoCreate();
48049 this.el = ct.createChild(cfg, position);
48052 this.el.applyStyles(this.style);
48054 if(this.labelAlign){
48055 this.el.addClass('x-form-label-'+this.labelAlign);
48057 if(this.hideLabels){
48058 this.labelStyle = "display:none";
48059 this.elementStyle = "padding-left:0;";
48061 if(typeof this.labelWidth == 'number'){
48062 this.labelStyle = "width:"+this.labelWidth+"px;";
48063 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48065 if(this.labelAlign == 'top'){
48066 this.labelStyle = "width:auto;";
48067 this.elementStyle = "padding-left:0;";
48070 var stack = this.stack;
48071 var slen = stack.length;
48073 if(!this.fieldTpl){
48074 var t = new Roo.Template(
48075 '<div class="x-form-item {5}">',
48076 '<label for="{0}" style="{2}">{1}{4}</label>',
48077 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48079 '</div><div class="x-form-clear-left"></div>'
48081 t.disableFormats = true;
48083 Roo.form.Layout.prototype.fieldTpl = t;
48085 for(var i = 0; i < slen; i++) {
48086 if(stack[i].isFormField){
48087 this.renderField(stack[i]);
48089 this.renderComponent(stack[i]);
48094 this.el.createChild({cls:'x-form-clear'});
48099 renderField : function(f){
48100 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48103 f.labelStyle||this.labelStyle||'', //2
48104 this.elementStyle||'', //3
48105 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48106 f.itemCls||this.itemCls||'' //5
48107 ], true).getPrevSibling());
48111 renderComponent : function(c){
48112 c.render(c.isLayout ? this.el : this.el.createChild());
48115 * Adds a object form elements (using the xtype property as the factory method.)
48116 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48117 * @param {Object} config
48119 addxtype : function(o)
48121 // create the lement.
48122 o.form = this.form;
48123 var fe = Roo.factory(o, Roo.form);
48124 this.form.allItems.push(fe);
48125 this.stack.push(fe);
48127 if (fe.isFormField) {
48128 this.form.items.add(fe);
48136 * @class Roo.form.Column
48137 * @extends Roo.form.Layout
48138 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48140 * @param {Object} config Configuration options
48142 Roo.form.Column = function(config){
48143 Roo.form.Column.superclass.constructor.call(this, config);
48146 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48148 * @cfg {Number/String} width
48149 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48152 * @cfg {String/Object} autoCreate
48153 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48157 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48160 onRender : function(ct, position){
48161 Roo.form.Column.superclass.onRender.call(this, ct, position);
48163 this.el.setWidth(this.width);
48170 * @class Roo.form.Row
48171 * @extends Roo.form.Layout
48172 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48174 * @param {Object} config Configuration options
48178 Roo.form.Row = function(config){
48179 Roo.form.Row.superclass.constructor.call(this, config);
48182 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48184 * @cfg {Number/String} width
48185 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48188 * @cfg {Number/String} height
48189 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48191 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48195 onRender : function(ct, position){
48196 //console.log('row render');
48198 var t = new Roo.Template(
48199 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48200 '<label for="{0}" style="{2}">{1}{4}</label>',
48201 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48205 t.disableFormats = true;
48207 Roo.form.Layout.prototype.rowTpl = t;
48209 this.fieldTpl = this.rowTpl;
48211 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48212 var labelWidth = 100;
48214 if ((this.labelAlign != 'top')) {
48215 if (typeof this.labelWidth == 'number') {
48216 labelWidth = this.labelWidth
48218 this.padWidth = 20 + labelWidth;
48222 Roo.form.Column.superclass.onRender.call(this, ct, position);
48224 this.el.setWidth(this.width);
48227 this.el.setHeight(this.height);
48232 renderField : function(f){
48233 f.fieldEl = this.fieldTpl.append(this.el, [
48234 f.id, f.fieldLabel,
48235 f.labelStyle||this.labelStyle||'',
48236 this.elementStyle||'',
48237 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48238 f.itemCls||this.itemCls||'',
48239 f.width ? f.width + this.padWidth : 160 + this.padWidth
48246 * @class Roo.form.FieldSet
48247 * @extends Roo.form.Layout
48248 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48250 * @param {Object} config Configuration options
48252 Roo.form.FieldSet = function(config){
48253 Roo.form.FieldSet.superclass.constructor.call(this, config);
48256 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48258 * @cfg {String} legend
48259 * The text to display as the legend for the FieldSet (defaults to '')
48262 * @cfg {String/Object} autoCreate
48263 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48267 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48270 onRender : function(ct, position){
48271 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48273 this.setLegend(this.legend);
48278 setLegend : function(text){
48280 this.el.child('legend').update(text);
48285 * Ext JS Library 1.1.1
48286 * Copyright(c) 2006-2007, Ext JS, LLC.
48288 * Originally Released Under LGPL - original licence link has changed is not relivant.
48291 * <script type="text/javascript">
48294 * @class Roo.form.VTypes
48295 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48298 Roo.form.VTypes = function(){
48299 // closure these in so they are only created once.
48300 var alpha = /^[a-zA-Z_]+$/;
48301 var alphanum = /^[a-zA-Z0-9_]+$/;
48302 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48303 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48305 // All these messages and functions are configurable
48308 * The function used to validate email addresses
48309 * @param {String} value The email address
48311 'email' : function(v){
48312 return email.test(v);
48315 * The error text to display when the email validation function returns false
48318 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48320 * The keystroke filter mask to be applied on email input
48323 'emailMask' : /[a-z0-9_\.\-@]/i,
48326 * The function used to validate URLs
48327 * @param {String} value The URL
48329 'url' : function(v){
48330 return url.test(v);
48333 * The error text to display when the url validation function returns false
48336 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48339 * The function used to validate alpha values
48340 * @param {String} value The value
48342 'alpha' : function(v){
48343 return alpha.test(v);
48346 * The error text to display when the alpha validation function returns false
48349 'alphaText' : 'This field should only contain letters and _',
48351 * The keystroke filter mask to be applied on alpha input
48354 'alphaMask' : /[a-z_]/i,
48357 * The function used to validate alphanumeric values
48358 * @param {String} value The value
48360 'alphanum' : function(v){
48361 return alphanum.test(v);
48364 * The error text to display when the alphanumeric validation function returns false
48367 'alphanumText' : 'This field should only contain letters, numbers and _',
48369 * The keystroke filter mask to be applied on alphanumeric input
48372 'alphanumMask' : /[a-z0-9_]/i
48374 }();//<script type="text/javascript">
48377 * @class Roo.form.FCKeditor
48378 * @extends Roo.form.TextArea
48379 * Wrapper around the FCKEditor http://www.fckeditor.net
48381 * Creates a new FCKeditor
48382 * @param {Object} config Configuration options
48384 Roo.form.FCKeditor = function(config){
48385 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48388 * @event editorinit
48389 * Fired when the editor is initialized - you can add extra handlers here..
48390 * @param {FCKeditor} this
48391 * @param {Object} the FCK object.
48398 Roo.form.FCKeditor.editors = { };
48399 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48401 //defaultAutoCreate : {
48402 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48406 * @cfg {Object} fck options - see fck manual for details.
48411 * @cfg {Object} fck toolbar set (Basic or Default)
48413 toolbarSet : 'Basic',
48415 * @cfg {Object} fck BasePath
48417 basePath : '/fckeditor/',
48425 onRender : function(ct, position)
48428 this.defaultAutoCreate = {
48430 style:"width:300px;height:60px;",
48431 autocomplete: "new-password"
48434 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48437 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48438 if(this.preventScrollbars){
48439 this.el.setStyle("overflow", "hidden");
48441 this.el.setHeight(this.growMin);
48444 //console.log('onrender' + this.getId() );
48445 Roo.form.FCKeditor.editors[this.getId()] = this;
48448 this.replaceTextarea() ;
48452 getEditor : function() {
48453 return this.fckEditor;
48456 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48457 * @param {Mixed} value The value to set
48461 setValue : function(value)
48463 //console.log('setValue: ' + value);
48465 if(typeof(value) == 'undefined') { // not sure why this is happending...
48468 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48470 //if(!this.el || !this.getEditor()) {
48471 // this.value = value;
48472 //this.setValue.defer(100,this,[value]);
48476 if(!this.getEditor()) {
48480 this.getEditor().SetData(value);
48487 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48488 * @return {Mixed} value The field value
48490 getValue : function()
48493 if (this.frame && this.frame.dom.style.display == 'none') {
48494 return Roo.form.FCKeditor.superclass.getValue.call(this);
48497 if(!this.el || !this.getEditor()) {
48499 // this.getValue.defer(100,this);
48504 var value=this.getEditor().GetData();
48505 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48506 return Roo.form.FCKeditor.superclass.getValue.call(this);
48512 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48513 * @return {Mixed} value The field value
48515 getRawValue : function()
48517 if (this.frame && this.frame.dom.style.display == 'none') {
48518 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48521 if(!this.el || !this.getEditor()) {
48522 //this.getRawValue.defer(100,this);
48529 var value=this.getEditor().GetData();
48530 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48531 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48535 setSize : function(w,h) {
48539 //if (this.frame && this.frame.dom.style.display == 'none') {
48540 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48543 //if(!this.el || !this.getEditor()) {
48544 // this.setSize.defer(100,this, [w,h]);
48550 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48552 this.frame.dom.setAttribute('width', w);
48553 this.frame.dom.setAttribute('height', h);
48554 this.frame.setSize(w,h);
48558 toggleSourceEdit : function(value) {
48562 this.el.dom.style.display = value ? '' : 'none';
48563 this.frame.dom.style.display = value ? 'none' : '';
48568 focus: function(tag)
48570 if (this.frame.dom.style.display == 'none') {
48571 return Roo.form.FCKeditor.superclass.focus.call(this);
48573 if(!this.el || !this.getEditor()) {
48574 this.focus.defer(100,this, [tag]);
48581 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48582 this.getEditor().Focus();
48584 if (!this.getEditor().Selection.GetSelection()) {
48585 this.focus.defer(100,this, [tag]);
48590 var r = this.getEditor().EditorDocument.createRange();
48591 r.setStart(tgs[0],0);
48592 r.setEnd(tgs[0],0);
48593 this.getEditor().Selection.GetSelection().removeAllRanges();
48594 this.getEditor().Selection.GetSelection().addRange(r);
48595 this.getEditor().Focus();
48602 replaceTextarea : function()
48604 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48607 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48609 // We must check the elements firstly using the Id and then the name.
48610 var oTextarea = document.getElementById( this.getId() );
48612 var colElementsByName = document.getElementsByName( this.getId() ) ;
48614 oTextarea.style.display = 'none' ;
48616 if ( oTextarea.tabIndex ) {
48617 this.TabIndex = oTextarea.tabIndex ;
48620 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48621 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48622 this.frame = Roo.get(this.getId() + '___Frame')
48625 _getConfigHtml : function()
48629 for ( var o in this.fckconfig ) {
48630 sConfig += sConfig.length > 0 ? '&' : '';
48631 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48634 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48638 _getIFrameHtml : function()
48640 var sFile = 'fckeditor.html' ;
48641 /* no idea what this is about..
48644 if ( (/fcksource=true/i).test( window.top.location.search ) )
48645 sFile = 'fckeditor.original.html' ;
48650 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48651 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48654 var html = '<iframe id="' + this.getId() +
48655 '___Frame" src="' + sLink +
48656 '" width="' + this.width +
48657 '" height="' + this.height + '"' +
48658 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48659 ' frameborder="0" scrolling="no"></iframe>' ;
48664 _insertHtmlBefore : function( html, element )
48666 if ( element.insertAdjacentHTML ) {
48668 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48670 var oRange = document.createRange() ;
48671 oRange.setStartBefore( element ) ;
48672 var oFragment = oRange.createContextualFragment( html );
48673 element.parentNode.insertBefore( oFragment, element ) ;
48686 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48688 function FCKeditor_OnComplete(editorInstance){
48689 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48690 f.fckEditor = editorInstance;
48691 //console.log("loaded");
48692 f.fireEvent('editorinit', f, editorInstance);
48712 //<script type="text/javascript">
48714 * @class Roo.form.GridField
48715 * @extends Roo.form.Field
48716 * Embed a grid (or editable grid into a form)
48719 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48721 * xgrid.store = Roo.data.Store
48722 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48723 * xgrid.store.reader = Roo.data.JsonReader
48727 * Creates a new GridField
48728 * @param {Object} config Configuration options
48730 Roo.form.GridField = function(config){
48731 Roo.form.GridField.superclass.constructor.call(this, config);
48735 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48737 * @cfg {Number} width - used to restrict width of grid..
48741 * @cfg {Number} height - used to restrict height of grid..
48745 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48751 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48752 * {tag: "input", type: "checkbox", autocomplete: "off"})
48754 // defaultAutoCreate : { tag: 'div' },
48755 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48757 * @cfg {String} addTitle Text to include for adding a title.
48761 onResize : function(){
48762 Roo.form.Field.superclass.onResize.apply(this, arguments);
48765 initEvents : function(){
48766 // Roo.form.Checkbox.superclass.initEvents.call(this);
48767 // has no events...
48772 getResizeEl : function(){
48776 getPositionEl : function(){
48781 onRender : function(ct, position){
48783 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48784 var style = this.style;
48787 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48788 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48789 this.viewEl = this.wrap.createChild({ tag: 'div' });
48791 this.viewEl.applyStyles(style);
48794 this.viewEl.setWidth(this.width);
48797 this.viewEl.setHeight(this.height);
48799 //if(this.inputValue !== undefined){
48800 //this.setValue(this.value);
48803 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48806 this.grid.render();
48807 this.grid.getDataSource().on('remove', this.refreshValue, this);
48808 this.grid.getDataSource().on('update', this.refreshValue, this);
48809 this.grid.on('afteredit', this.refreshValue, this);
48815 * Sets the value of the item.
48816 * @param {String} either an object or a string..
48818 setValue : function(v){
48820 v = v || []; // empty set..
48821 // this does not seem smart - it really only affects memoryproxy grids..
48822 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48823 var ds = this.grid.getDataSource();
48824 // assumes a json reader..
48826 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48827 ds.loadData( data);
48829 // clear selection so it does not get stale.
48830 if (this.grid.sm) {
48831 this.grid.sm.clearSelections();
48834 Roo.form.GridField.superclass.setValue.call(this, v);
48835 this.refreshValue();
48836 // should load data in the grid really....
48840 refreshValue: function() {
48842 this.grid.getDataSource().each(function(r) {
48845 this.el.dom.value = Roo.encode(val);
48853 * Ext JS Library 1.1.1
48854 * Copyright(c) 2006-2007, Ext JS, LLC.
48856 * Originally Released Under LGPL - original licence link has changed is not relivant.
48859 * <script type="text/javascript">
48862 * @class Roo.form.DisplayField
48863 * @extends Roo.form.Field
48864 * A generic Field to display non-editable data.
48865 * @cfg {Boolean} closable (true|false) default false
48867 * Creates a new Display Field item.
48868 * @param {Object} config Configuration options
48870 Roo.form.DisplayField = function(config){
48871 Roo.form.DisplayField.superclass.constructor.call(this, config);
48876 * Fires after the click the close btn
48877 * @param {Roo.form.DisplayField} this
48883 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
48884 inputType: 'hidden',
48890 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48892 focusClass : undefined,
48894 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48896 fieldClass: 'x-form-field',
48899 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
48901 valueRenderer: undefined,
48905 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48906 * {tag: "input", type: "checkbox", autocomplete: "off"})
48909 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
48913 onResize : function(){
48914 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
48918 initEvents : function(){
48919 // Roo.form.Checkbox.superclass.initEvents.call(this);
48920 // has no events...
48923 this.closeEl.on('click', this.onClose, this);
48929 getResizeEl : function(){
48933 getPositionEl : function(){
48938 onRender : function(ct, position){
48940 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
48941 //if(this.inputValue !== undefined){
48942 this.wrap = this.el.wrap();
48944 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
48947 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
48950 if (this.bodyStyle) {
48951 this.viewEl.applyStyles(this.bodyStyle);
48953 //this.viewEl.setStyle('padding', '2px');
48955 this.setValue(this.value);
48960 initValue : Roo.emptyFn,
48965 onClick : function(){
48970 * Sets the checked state of the checkbox.
48971 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
48973 setValue : function(v){
48975 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
48976 // this might be called before we have a dom element..
48977 if (!this.viewEl) {
48980 this.viewEl.dom.innerHTML = html;
48981 Roo.form.DisplayField.superclass.setValue.call(this, v);
48985 onClose : function(e)
48987 e.preventDefault();
48989 this.fireEvent('close', this);
48998 * @class Roo.form.DayPicker
48999 * @extends Roo.form.Field
49000 * A Day picker show [M] [T] [W] ....
49002 * Creates a new Day Picker
49003 * @param {Object} config Configuration options
49005 Roo.form.DayPicker= function(config){
49006 Roo.form.DayPicker.superclass.constructor.call(this, config);
49010 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
49012 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49014 focusClass : undefined,
49016 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49018 fieldClass: "x-form-field",
49021 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49022 * {tag: "input", type: "checkbox", autocomplete: "off"})
49024 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
49027 actionMode : 'viewEl',
49031 inputType : 'hidden',
49034 inputElement: false, // real input element?
49035 basedOn: false, // ????
49037 isFormField: true, // not sure where this is needed!!!!
49039 onResize : function(){
49040 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49041 if(!this.boxLabel){
49042 this.el.alignTo(this.wrap, 'c-c');
49046 initEvents : function(){
49047 Roo.form.Checkbox.superclass.initEvents.call(this);
49048 this.el.on("click", this.onClick, this);
49049 this.el.on("change", this.onClick, this);
49053 getResizeEl : function(){
49057 getPositionEl : function(){
49063 onRender : function(ct, position){
49064 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49066 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49068 var r1 = '<table><tr>';
49069 var r2 = '<tr class="x-form-daypick-icons">';
49070 for (var i=0; i < 7; i++) {
49071 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49072 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49075 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49076 viewEl.select('img').on('click', this.onClick, this);
49077 this.viewEl = viewEl;
49080 // this will not work on Chrome!!!
49081 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49082 this.el.on('propertychange', this.setFromHidden, this); //ie
49090 initValue : Roo.emptyFn,
49093 * Returns the checked state of the checkbox.
49094 * @return {Boolean} True if checked, else false
49096 getValue : function(){
49097 return this.el.dom.value;
49102 onClick : function(e){
49103 //this.setChecked(!this.checked);
49104 Roo.get(e.target).toggleClass('x-menu-item-checked');
49105 this.refreshValue();
49106 //if(this.el.dom.checked != this.checked){
49107 // this.setValue(this.el.dom.checked);
49112 refreshValue : function()
49115 this.viewEl.select('img',true).each(function(e,i,n) {
49116 val += e.is(".x-menu-item-checked") ? String(n) : '';
49118 this.setValue(val, true);
49122 * Sets the checked state of the checkbox.
49123 * On is always based on a string comparison between inputValue and the param.
49124 * @param {Boolean/String} value - the value to set
49125 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49127 setValue : function(v,suppressEvent){
49128 if (!this.el.dom) {
49131 var old = this.el.dom.value ;
49132 this.el.dom.value = v;
49133 if (suppressEvent) {
49137 // update display..
49138 this.viewEl.select('img',true).each(function(e,i,n) {
49140 var on = e.is(".x-menu-item-checked");
49141 var newv = v.indexOf(String(n)) > -1;
49143 e.toggleClass('x-menu-item-checked');
49149 this.fireEvent('change', this, v, old);
49154 // handle setting of hidden value by some other method!!?!?
49155 setFromHidden: function()
49160 //console.log("SET FROM HIDDEN");
49161 //alert('setFrom hidden');
49162 this.setValue(this.el.dom.value);
49165 onDestroy : function()
49168 Roo.get(this.viewEl).remove();
49171 Roo.form.DayPicker.superclass.onDestroy.call(this);
49175 * RooJS Library 1.1.1
49176 * Copyright(c) 2008-2011 Alan Knowles
49183 * @class Roo.form.ComboCheck
49184 * @extends Roo.form.ComboBox
49185 * A combobox for multiple select items.
49187 * FIXME - could do with a reset button..
49190 * Create a new ComboCheck
49191 * @param {Object} config Configuration options
49193 Roo.form.ComboCheck = function(config){
49194 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49195 // should verify some data...
49197 // hiddenName = required..
49198 // displayField = required
49199 // valudField == required
49200 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49202 Roo.each(req, function(e) {
49203 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49204 throw "Roo.form.ComboCheck : missing value for: " + e;
49211 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49216 selectedClass: 'x-menu-item-checked',
49219 onRender : function(ct, position){
49225 var cls = 'x-combo-list';
49228 this.tpl = new Roo.Template({
49229 html : '<div class="'+cls+'-item x-menu-check-item">' +
49230 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49231 '<span>{' + this.displayField + '}</span>' +
49238 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49239 this.view.singleSelect = false;
49240 this.view.multiSelect = true;
49241 this.view.toggleSelect = true;
49242 this.pageTb.add(new Roo.Toolbar.Fill(), {
49245 handler: function()
49252 onViewOver : function(e, t){
49258 onViewClick : function(doFocus,index){
49262 select: function () {
49263 //Roo.log("SELECT CALLED");
49266 selectByValue : function(xv, scrollIntoView){
49267 var ar = this.getValueArray();
49270 Roo.each(ar, function(v) {
49271 if(v === undefined || v === null){
49274 var r = this.findRecord(this.valueField, v);
49276 sels.push(this.store.indexOf(r))
49280 this.view.select(sels);
49286 onSelect : function(record, index){
49287 // Roo.log("onselect Called");
49288 // this is only called by the clear button now..
49289 this.view.clearSelections();
49290 this.setValue('[]');
49291 if (this.value != this.valueBefore) {
49292 this.fireEvent('change', this, this.value, this.valueBefore);
49293 this.valueBefore = this.value;
49296 getValueArray : function()
49301 //Roo.log(this.value);
49302 if (typeof(this.value) == 'undefined') {
49305 var ar = Roo.decode(this.value);
49306 return ar instanceof Array ? ar : []; //?? valid?
49309 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49314 expand : function ()
49317 Roo.form.ComboCheck.superclass.expand.call(this);
49318 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49319 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49324 collapse : function(){
49325 Roo.form.ComboCheck.superclass.collapse.call(this);
49326 var sl = this.view.getSelectedIndexes();
49327 var st = this.store;
49331 Roo.each(sl, function(i) {
49333 nv.push(r.get(this.valueField));
49335 this.setValue(Roo.encode(nv));
49336 if (this.value != this.valueBefore) {
49338 this.fireEvent('change', this, this.value, this.valueBefore);
49339 this.valueBefore = this.value;
49344 setValue : function(v){
49348 var vals = this.getValueArray();
49350 Roo.each(vals, function(k) {
49351 var r = this.findRecord(this.valueField, k);
49353 tv.push(r.data[this.displayField]);
49354 }else if(this.valueNotFoundText !== undefined){
49355 tv.push( this.valueNotFoundText );
49360 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49361 this.hiddenField.value = v;
49367 * Ext JS Library 1.1.1
49368 * Copyright(c) 2006-2007, Ext JS, LLC.
49370 * Originally Released Under LGPL - original licence link has changed is not relivant.
49373 * <script type="text/javascript">
49377 * @class Roo.form.Signature
49378 * @extends Roo.form.Field
49382 * @param {Object} config Configuration options
49385 Roo.form.Signature = function(config){
49386 Roo.form.Signature.superclass.constructor.call(this, config);
49388 this.addEvents({// not in used??
49391 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49392 * @param {Roo.form.Signature} combo This combo box
49397 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49398 * @param {Roo.form.ComboBox} combo This combo box
49399 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49405 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49407 * @cfg {Object} labels Label to use when rendering a form.
49411 * confirm : "Confirm"
49416 confirm : "Confirm"
49419 * @cfg {Number} width The signature panel width (defaults to 300)
49423 * @cfg {Number} height The signature panel height (defaults to 100)
49427 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49429 allowBlank : false,
49432 // {Object} signPanel The signature SVG panel element (defaults to {})
49434 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49435 isMouseDown : false,
49436 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49437 isConfirmed : false,
49438 // {String} signatureTmp SVG mapping string (defaults to empty string)
49442 defaultAutoCreate : { // modified by initCompnoent..
49448 onRender : function(ct, position){
49450 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49452 this.wrap = this.el.wrap({
49453 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49456 this.createToolbar(this);
49457 this.signPanel = this.wrap.createChild({
49459 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49463 this.svgID = Roo.id();
49464 this.svgEl = this.signPanel.createChild({
49465 xmlns : 'http://www.w3.org/2000/svg',
49467 id : this.svgID + "-svg",
49469 height: this.height,
49470 viewBox: '0 0 '+this.width+' '+this.height,
49474 id: this.svgID + "-svg-r",
49476 height: this.height,
49481 id: this.svgID + "-svg-l",
49483 y1: (this.height*0.8), // start set the line in 80% of height
49484 x2: this.width, // end
49485 y2: (this.height*0.8), // end set the line in 80% of height
49487 'stroke-width': "1",
49488 'stroke-dasharray': "3",
49489 'shape-rendering': "crispEdges",
49490 'pointer-events': "none"
49494 id: this.svgID + "-svg-p",
49496 'stroke-width': "3",
49498 'pointer-events': 'none'
49503 this.svgBox = this.svgEl.dom.getScreenCTM();
49505 createSVG : function(){
49506 var svg = this.signPanel;
49507 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49510 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49511 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49512 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49513 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49514 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49515 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49516 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49519 isTouchEvent : function(e){
49520 return e.type.match(/^touch/);
49522 getCoords : function (e) {
49523 var pt = this.svgEl.dom.createSVGPoint();
49526 if (this.isTouchEvent(e)) {
49527 pt.x = e.targetTouches[0].clientX;
49528 pt.y = e.targetTouches[0].clientY;
49530 var a = this.svgEl.dom.getScreenCTM();
49531 var b = a.inverse();
49532 var mx = pt.matrixTransform(b);
49533 return mx.x + ',' + mx.y;
49535 //mouse event headler
49536 down : function (e) {
49537 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49538 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49540 this.isMouseDown = true;
49542 e.preventDefault();
49544 move : function (e) {
49545 if (this.isMouseDown) {
49546 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49547 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49550 e.preventDefault();
49552 up : function (e) {
49553 this.isMouseDown = false;
49554 var sp = this.signatureTmp.split(' ');
49557 if(!sp[sp.length-2].match(/^L/)){
49561 this.signatureTmp = sp.join(" ");
49564 if(this.getValue() != this.signatureTmp){
49565 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49566 this.isConfirmed = false;
49568 e.preventDefault();
49572 * Protected method that will not generally be called directly. It
49573 * is called when the editor creates its toolbar. Override this method if you need to
49574 * add custom toolbar buttons.
49575 * @param {HtmlEditor} editor
49577 createToolbar : function(editor){
49578 function btn(id, toggle, handler){
49579 var xid = fid + '-'+ id ;
49583 cls : 'x-btn-icon x-edit-'+id,
49584 enableToggle:toggle !== false,
49585 scope: editor, // was editor...
49586 handler:handler||editor.relayBtnCmd,
49587 clickEvent:'mousedown',
49588 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49594 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49598 cls : ' x-signature-btn x-signature-'+id,
49599 scope: editor, // was editor...
49600 handler: this.reset,
49601 clickEvent:'mousedown',
49602 text: this.labels.clear
49609 cls : ' x-signature-btn x-signature-'+id,
49610 scope: editor, // was editor...
49611 handler: this.confirmHandler,
49612 clickEvent:'mousedown',
49613 text: this.labels.confirm
49620 * when user is clicked confirm then show this image.....
49622 * @return {String} Image Data URI
49624 getImageDataURI : function(){
49625 var svg = this.svgEl.dom.parentNode.innerHTML;
49626 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49631 * @return {Boolean} this.isConfirmed
49633 getConfirmed : function(){
49634 return this.isConfirmed;
49638 * @return {Number} this.width
49640 getWidth : function(){
49645 * @return {Number} this.height
49647 getHeight : function(){
49648 return this.height;
49651 getSignature : function(){
49652 return this.signatureTmp;
49655 reset : function(){
49656 this.signatureTmp = '';
49657 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49658 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49659 this.isConfirmed = false;
49660 Roo.form.Signature.superclass.reset.call(this);
49662 setSignature : function(s){
49663 this.signatureTmp = s;
49664 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49665 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49667 this.isConfirmed = false;
49668 Roo.form.Signature.superclass.reset.call(this);
49671 // Roo.log(this.signPanel.dom.contentWindow.up())
49674 setConfirmed : function(){
49678 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49681 confirmHandler : function(){
49682 if(!this.getSignature()){
49686 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49687 this.setValue(this.getSignature());
49688 this.isConfirmed = true;
49690 this.fireEvent('confirm', this);
49693 // Subclasses should provide the validation implementation by overriding this
49694 validateValue : function(value){
49695 if(this.allowBlank){
49699 if(this.isConfirmed){
49706 * Ext JS Library 1.1.1
49707 * Copyright(c) 2006-2007, Ext JS, LLC.
49709 * Originally Released Under LGPL - original licence link has changed is not relivant.
49712 * <script type="text/javascript">
49717 * @class Roo.form.ComboBox
49718 * @extends Roo.form.TriggerField
49719 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49721 * Create a new ComboBox.
49722 * @param {Object} config Configuration options
49724 Roo.form.Select = function(config){
49725 Roo.form.Select.superclass.constructor.call(this, config);
49729 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49731 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49734 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49735 * rendering into an Roo.Editor, defaults to false)
49738 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49739 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49742 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49745 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49746 * the dropdown list (defaults to undefined, with no header element)
49750 * @cfg {String/Roo.Template} tpl The template to use to render the output
49754 defaultAutoCreate : {tag: "select" },
49756 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49758 listWidth: undefined,
49760 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49761 * mode = 'remote' or 'text' if mode = 'local')
49763 displayField: undefined,
49765 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49766 * mode = 'remote' or 'value' if mode = 'local').
49767 * Note: use of a valueField requires the user make a selection
49768 * in order for a value to be mapped.
49770 valueField: undefined,
49774 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49775 * field's data value (defaults to the underlying DOM element's name)
49777 hiddenName: undefined,
49779 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49783 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49785 selectedClass: 'x-combo-selected',
49787 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49788 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49789 * which displays a downward arrow icon).
49791 triggerClass : 'x-form-arrow-trigger',
49793 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49797 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49798 * anchor positions (defaults to 'tl-bl')
49800 listAlign: 'tl-bl?',
49802 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49806 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49807 * query specified by the allQuery config option (defaults to 'query')
49809 triggerAction: 'query',
49811 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49812 * (defaults to 4, does not apply if editable = false)
49816 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49817 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49821 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49822 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49826 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49827 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49831 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49832 * when editable = true (defaults to false)
49834 selectOnFocus:false,
49836 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49838 queryParam: 'query',
49840 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49841 * when mode = 'remote' (defaults to 'Loading...')
49843 loadingText: 'Loading...',
49845 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49849 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49853 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49854 * traditional select (defaults to true)
49858 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49862 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49866 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49867 * listWidth has a higher value)
49871 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49872 * allow the user to set arbitrary text into the field (defaults to false)
49874 forceSelection:false,
49876 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49877 * if typeAhead = true (defaults to 250)
49879 typeAheadDelay : 250,
49881 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
49882 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
49884 valueNotFoundText : undefined,
49887 * @cfg {String} defaultValue The value displayed after loading the store.
49892 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
49894 blockFocus : false,
49897 * @cfg {Boolean} disableClear Disable showing of clear button.
49899 disableClear : false,
49901 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
49903 alwaysQuery : false,
49909 // element that contains real text value.. (when hidden is used..)
49912 onRender : function(ct, position){
49913 Roo.form.Field.prototype.onRender.call(this, ct, position);
49916 this.store.on('beforeload', this.onBeforeLoad, this);
49917 this.store.on('load', this.onLoad, this);
49918 this.store.on('loadexception', this.onLoadException, this);
49919 this.store.load({});
49927 initEvents : function(){
49928 //Roo.form.ComboBox.superclass.initEvents.call(this);
49932 onDestroy : function(){
49935 this.store.un('beforeload', this.onBeforeLoad, this);
49936 this.store.un('load', this.onLoad, this);
49937 this.store.un('loadexception', this.onLoadException, this);
49939 //Roo.form.ComboBox.superclass.onDestroy.call(this);
49943 fireKey : function(e){
49944 if(e.isNavKeyPress() && !this.list.isVisible()){
49945 this.fireEvent("specialkey", this, e);
49950 onResize: function(w, h){
49958 * Allow or prevent the user from directly editing the field text. If false is passed,
49959 * the user will only be able to select from the items defined in the dropdown list. This method
49960 * is the runtime equivalent of setting the 'editable' config option at config time.
49961 * @param {Boolean} value True to allow the user to directly edit the field text
49963 setEditable : function(value){
49968 onBeforeLoad : function(){
49970 Roo.log("Select before load");
49973 this.innerList.update(this.loadingText ?
49974 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
49975 //this.restrictHeight();
49976 this.selectedIndex = -1;
49980 onLoad : function(){
49983 var dom = this.el.dom;
49984 dom.innerHTML = '';
49985 var od = dom.ownerDocument;
49987 if (this.emptyText) {
49988 var op = od.createElement('option');
49989 op.setAttribute('value', '');
49990 op.innerHTML = String.format('{0}', this.emptyText);
49991 dom.appendChild(op);
49993 if(this.store.getCount() > 0){
49995 var vf = this.valueField;
49996 var df = this.displayField;
49997 this.store.data.each(function(r) {
49998 // which colmsn to use... testing - cdoe / title..
49999 var op = od.createElement('option');
50000 op.setAttribute('value', r.data[vf]);
50001 op.innerHTML = String.format('{0}', r.data[df]);
50002 dom.appendChild(op);
50004 if (typeof(this.defaultValue != 'undefined')) {
50005 this.setValue(this.defaultValue);
50010 //this.onEmptyResults();
50015 onLoadException : function()
50017 dom.innerHTML = '';
50019 Roo.log("Select on load exception");
50023 Roo.log(this.store.reader.jsonData);
50024 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
50025 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50031 onTypeAhead : function(){
50036 onSelect : function(record, index){
50037 Roo.log('on select?');
50039 if(this.fireEvent('beforeselect', this, record, index) !== false){
50040 this.setFromData(index > -1 ? record.data : false);
50042 this.fireEvent('select', this, record, index);
50047 * Returns the currently selected field value or empty string if no value is set.
50048 * @return {String} value The selected value
50050 getValue : function(){
50051 var dom = this.el.dom;
50052 this.value = dom.options[dom.selectedIndex].value;
50058 * Clears any text/value currently set in the field
50060 clearValue : function(){
50062 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50067 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50068 * will be displayed in the field. If the value does not match the data value of an existing item,
50069 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50070 * Otherwise the field will be blank (although the value will still be set).
50071 * @param {String} value The value to match
50073 setValue : function(v){
50074 var d = this.el.dom;
50075 for (var i =0; i < d.options.length;i++) {
50076 if (v == d.options[i].value) {
50077 d.selectedIndex = i;
50085 * @property {Object} the last set data for the element
50090 * Sets the value of the field based on a object which is related to the record format for the store.
50091 * @param {Object} value the value to set as. or false on reset?
50093 setFromData : function(o){
50094 Roo.log('setfrom data?');
50100 reset : function(){
50104 findRecord : function(prop, value){
50109 if(this.store.getCount() > 0){
50110 this.store.each(function(r){
50111 if(r.data[prop] == value){
50121 getName: function()
50123 // returns hidden if it's set..
50124 if (!this.rendered) {return ''};
50125 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50133 onEmptyResults : function(){
50134 Roo.log('empty results');
50139 * Returns true if the dropdown list is expanded, else false.
50141 isExpanded : function(){
50146 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50147 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50148 * @param {String} value The data value of the item to select
50149 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50150 * selected item if it is not currently in view (defaults to true)
50151 * @return {Boolean} True if the value matched an item in the list, else false
50153 selectByValue : function(v, scrollIntoView){
50154 Roo.log('select By Value');
50157 if(v !== undefined && v !== null){
50158 var r = this.findRecord(this.valueField || this.displayField, v);
50160 this.select(this.store.indexOf(r), scrollIntoView);
50168 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50169 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50170 * @param {Number} index The zero-based index of the list item to select
50171 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50172 * selected item if it is not currently in view (defaults to true)
50174 select : function(index, scrollIntoView){
50175 Roo.log('select ');
50178 this.selectedIndex = index;
50179 this.view.select(index);
50180 if(scrollIntoView !== false){
50181 var el = this.view.getNode(index);
50183 this.innerList.scrollChildIntoView(el, false);
50191 validateBlur : function(){
50198 initQuery : function(){
50199 this.doQuery(this.getRawValue());
50203 doForce : function(){
50204 if(this.el.dom.value.length > 0){
50205 this.el.dom.value =
50206 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50212 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50213 * query allowing the query action to be canceled if needed.
50214 * @param {String} query The SQL query to execute
50215 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50216 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50217 * saved in the current store (defaults to false)
50219 doQuery : function(q, forceAll){
50221 Roo.log('doQuery?');
50222 if(q === undefined || q === null){
50227 forceAll: forceAll,
50231 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50235 forceAll = qe.forceAll;
50236 if(forceAll === true || (q.length >= this.minChars)){
50237 if(this.lastQuery != q || this.alwaysQuery){
50238 this.lastQuery = q;
50239 if(this.mode == 'local'){
50240 this.selectedIndex = -1;
50242 this.store.clearFilter();
50244 this.store.filter(this.displayField, q);
50248 this.store.baseParams[this.queryParam] = q;
50250 params: this.getParams(q)
50255 this.selectedIndex = -1;
50262 getParams : function(q){
50264 //p[this.queryParam] = q;
50267 p.limit = this.pageSize;
50273 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50275 collapse : function(){
50280 collapseIf : function(e){
50285 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50287 expand : function(){
50295 * @cfg {Boolean} grow
50299 * @cfg {Number} growMin
50303 * @cfg {Number} growMax
50311 setWidth : function()
50315 getResizeEl : function(){
50318 });//<script type="text/javasscript">
50322 * @class Roo.DDView
50323 * A DnD enabled version of Roo.View.
50324 * @param {Element/String} container The Element in which to create the View.
50325 * @param {String} tpl The template string used to create the markup for each element of the View
50326 * @param {Object} config The configuration properties. These include all the config options of
50327 * {@link Roo.View} plus some specific to this class.<br>
50329 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50330 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50332 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50333 .x-view-drag-insert-above {
50334 border-top:1px dotted #3366cc;
50336 .x-view-drag-insert-below {
50337 border-bottom:1px dotted #3366cc;
50343 Roo.DDView = function(container, tpl, config) {
50344 Roo.DDView.superclass.constructor.apply(this, arguments);
50345 this.getEl().setStyle("outline", "0px none");
50346 this.getEl().unselectable();
50347 if (this.dragGroup) {
50348 this.setDraggable(this.dragGroup.split(","));
50350 if (this.dropGroup) {
50351 this.setDroppable(this.dropGroup.split(","));
50353 if (this.deletable) {
50354 this.setDeletable();
50356 this.isDirtyFlag = false;
50362 Roo.extend(Roo.DDView, Roo.View, {
50363 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50364 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50365 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50366 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50370 reset: Roo.emptyFn,
50372 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50374 validate: function() {
50378 destroy: function() {
50379 this.purgeListeners();
50380 this.getEl.removeAllListeners();
50381 this.getEl().remove();
50382 if (this.dragZone) {
50383 if (this.dragZone.destroy) {
50384 this.dragZone.destroy();
50387 if (this.dropZone) {
50388 if (this.dropZone.destroy) {
50389 this.dropZone.destroy();
50394 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50395 getName: function() {
50399 /** Loads the View from a JSON string representing the Records to put into the Store. */
50400 setValue: function(v) {
50402 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50405 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50406 this.store.proxy = new Roo.data.MemoryProxy(data);
50410 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50411 getValue: function() {
50413 this.store.each(function(rec) {
50414 result += rec.id + ',';
50416 return result.substr(0, result.length - 1) + ')';
50419 getIds: function() {
50420 var i = 0, result = new Array(this.store.getCount());
50421 this.store.each(function(rec) {
50422 result[i++] = rec.id;
50427 isDirty: function() {
50428 return this.isDirtyFlag;
50432 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50433 * whole Element becomes the target, and this causes the drop gesture to append.
50435 getTargetFromEvent : function(e) {
50436 var target = e.getTarget();
50437 while ((target !== null) && (target.parentNode != this.el.dom)) {
50438 target = target.parentNode;
50441 target = this.el.dom.lastChild || this.el.dom;
50447 * Create the drag data which consists of an object which has the property "ddel" as
50448 * the drag proxy element.
50450 getDragData : function(e) {
50451 var target = this.findItemFromChild(e.getTarget());
50453 this.handleSelection(e);
50454 var selNodes = this.getSelectedNodes();
50457 copy: this.copy || (this.allowCopy && e.ctrlKey),
50461 var selectedIndices = this.getSelectedIndexes();
50462 for (var i = 0; i < selectedIndices.length; i++) {
50463 dragData.records.push(this.store.getAt(selectedIndices[i]));
50465 if (selNodes.length == 1) {
50466 dragData.ddel = target.cloneNode(true); // the div element
50468 var div = document.createElement('div'); // create the multi element drag "ghost"
50469 div.className = 'multi-proxy';
50470 for (var i = 0, len = selNodes.length; i < len; i++) {
50471 div.appendChild(selNodes[i].cloneNode(true));
50473 dragData.ddel = div;
50475 //console.log(dragData)
50476 //console.log(dragData.ddel.innerHTML)
50479 //console.log('nodragData')
50483 /** Specify to which ddGroup items in this DDView may be dragged. */
50484 setDraggable: function(ddGroup) {
50485 if (ddGroup instanceof Array) {
50486 Roo.each(ddGroup, this.setDraggable, this);
50489 if (this.dragZone) {
50490 this.dragZone.addToGroup(ddGroup);
50492 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50493 containerScroll: true,
50497 // Draggability implies selection. DragZone's mousedown selects the element.
50498 if (!this.multiSelect) { this.singleSelect = true; }
50500 // Wire the DragZone's handlers up to methods in *this*
50501 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50505 /** Specify from which ddGroup this DDView accepts drops. */
50506 setDroppable: function(ddGroup) {
50507 if (ddGroup instanceof Array) {
50508 Roo.each(ddGroup, this.setDroppable, this);
50511 if (this.dropZone) {
50512 this.dropZone.addToGroup(ddGroup);
50514 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50515 containerScroll: true,
50519 // Wire the DropZone's handlers up to methods in *this*
50520 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50521 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50522 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50523 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50524 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50528 /** Decide whether to drop above or below a View node. */
50529 getDropPoint : function(e, n, dd){
50530 if (n == this.el.dom) { return "above"; }
50531 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50532 var c = t + (b - t) / 2;
50533 var y = Roo.lib.Event.getPageY(e);
50541 onNodeEnter : function(n, dd, e, data){
50545 onNodeOver : function(n, dd, e, data){
50546 var pt = this.getDropPoint(e, n, dd);
50547 // set the insert point style on the target node
50548 var dragElClass = this.dropNotAllowed;
50551 if (pt == "above"){
50552 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50553 targetElClass = "x-view-drag-insert-above";
50555 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50556 targetElClass = "x-view-drag-insert-below";
50558 if (this.lastInsertClass != targetElClass){
50559 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50560 this.lastInsertClass = targetElClass;
50563 return dragElClass;
50566 onNodeOut : function(n, dd, e, data){
50567 this.removeDropIndicators(n);
50570 onNodeDrop : function(n, dd, e, data){
50571 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50574 var pt = this.getDropPoint(e, n, dd);
50575 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50576 if (pt == "below") { insertAt++; }
50577 for (var i = 0; i < data.records.length; i++) {
50578 var r = data.records[i];
50579 var dup = this.store.getById(r.id);
50580 if (dup && (dd != this.dragZone)) {
50581 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50584 this.store.insert(insertAt++, r.copy());
50586 data.source.isDirtyFlag = true;
50588 this.store.insert(insertAt++, r);
50590 this.isDirtyFlag = true;
50593 this.dragZone.cachedTarget = null;
50597 removeDropIndicators : function(n){
50599 Roo.fly(n).removeClass([
50600 "x-view-drag-insert-above",
50601 "x-view-drag-insert-below"]);
50602 this.lastInsertClass = "_noclass";
50607 * Utility method. Add a delete option to the DDView's context menu.
50608 * @param {String} imageUrl The URL of the "delete" icon image.
50610 setDeletable: function(imageUrl) {
50611 if (!this.singleSelect && !this.multiSelect) {
50612 this.singleSelect = true;
50614 var c = this.getContextMenu();
50615 this.contextMenu.on("itemclick", function(item) {
50618 this.remove(this.getSelectedIndexes());
50622 this.contextMenu.add({
50629 /** Return the context menu for this DDView. */
50630 getContextMenu: function() {
50631 if (!this.contextMenu) {
50632 // Create the View's context menu
50633 this.contextMenu = new Roo.menu.Menu({
50634 id: this.id + "-contextmenu"
50636 this.el.on("contextmenu", this.showContextMenu, this);
50638 return this.contextMenu;
50641 disableContextMenu: function() {
50642 if (this.contextMenu) {
50643 this.el.un("contextmenu", this.showContextMenu, this);
50647 showContextMenu: function(e, item) {
50648 item = this.findItemFromChild(e.getTarget());
50651 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50652 this.contextMenu.showAt(e.getXY());
50657 * Remove {@link Roo.data.Record}s at the specified indices.
50658 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50660 remove: function(selectedIndices) {
50661 selectedIndices = [].concat(selectedIndices);
50662 for (var i = 0; i < selectedIndices.length; i++) {
50663 var rec = this.store.getAt(selectedIndices[i]);
50664 this.store.remove(rec);
50669 * Double click fires the event, but also, if this is draggable, and there is only one other
50670 * related DropZone, it transfers the selected node.
50672 onDblClick : function(e){
50673 var item = this.findItemFromChild(e.getTarget());
50675 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50678 if (this.dragGroup) {
50679 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50680 while (targets.indexOf(this.dropZone) > -1) {
50681 targets.remove(this.dropZone);
50683 if (targets.length == 1) {
50684 this.dragZone.cachedTarget = null;
50685 var el = Roo.get(targets[0].getEl());
50686 var box = el.getBox(true);
50687 targets[0].onNodeDrop(el.dom, {
50689 xy: [box.x, box.y + box.height - 1]
50690 }, null, this.getDragData(e));
50696 handleSelection: function(e) {
50697 this.dragZone.cachedTarget = null;
50698 var item = this.findItemFromChild(e.getTarget());
50700 this.clearSelections(true);
50703 if (item && (this.multiSelect || this.singleSelect)){
50704 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50705 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50706 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50707 this.unselect(item);
50709 this.select(item, this.multiSelect && e.ctrlKey);
50710 this.lastSelection = item;
50715 onItemClick : function(item, index, e){
50716 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50722 unselect : function(nodeInfo, suppressEvent){
50723 var node = this.getNode(nodeInfo);
50724 if(node && this.isSelected(node)){
50725 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50726 Roo.fly(node).removeClass(this.selectedClass);
50727 this.selections.remove(node);
50728 if(!suppressEvent){
50729 this.fireEvent("selectionchange", this, this.selections);
50737 * Ext JS Library 1.1.1
50738 * Copyright(c) 2006-2007, Ext JS, LLC.
50740 * Originally Released Under LGPL - original licence link has changed is not relivant.
50743 * <script type="text/javascript">
50747 * @class Roo.LayoutManager
50748 * @extends Roo.util.Observable
50749 * Base class for layout managers.
50751 Roo.LayoutManager = function(container, config){
50752 Roo.LayoutManager.superclass.constructor.call(this);
50753 this.el = Roo.get(container);
50754 // ie scrollbar fix
50755 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50756 document.body.scroll = "no";
50757 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50758 this.el.position('relative');
50760 this.id = this.el.id;
50761 this.el.addClass("x-layout-container");
50762 /** false to disable window resize monitoring @type Boolean */
50763 this.monitorWindowResize = true;
50768 * Fires when a layout is performed.
50769 * @param {Roo.LayoutManager} this
50773 * @event regionresized
50774 * Fires when the user resizes a region.
50775 * @param {Roo.LayoutRegion} region The resized region
50776 * @param {Number} newSize The new size (width for east/west, height for north/south)
50778 "regionresized" : true,
50780 * @event regioncollapsed
50781 * Fires when a region is collapsed.
50782 * @param {Roo.LayoutRegion} region The collapsed region
50784 "regioncollapsed" : true,
50786 * @event regionexpanded
50787 * Fires when a region is expanded.
50788 * @param {Roo.LayoutRegion} region The expanded region
50790 "regionexpanded" : true
50792 this.updating = false;
50793 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50796 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50798 * Returns true if this layout is currently being updated
50799 * @return {Boolean}
50801 isUpdating : function(){
50802 return this.updating;
50806 * Suspend the LayoutManager from doing auto-layouts while
50807 * making multiple add or remove calls
50809 beginUpdate : function(){
50810 this.updating = true;
50814 * Restore auto-layouts and optionally disable the manager from performing a layout
50815 * @param {Boolean} noLayout true to disable a layout update
50817 endUpdate : function(noLayout){
50818 this.updating = false;
50824 layout: function(){
50828 onRegionResized : function(region, newSize){
50829 this.fireEvent("regionresized", region, newSize);
50833 onRegionCollapsed : function(region){
50834 this.fireEvent("regioncollapsed", region);
50837 onRegionExpanded : function(region){
50838 this.fireEvent("regionexpanded", region);
50842 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50843 * performs box-model adjustments.
50844 * @return {Object} The size as an object {width: (the width), height: (the height)}
50846 getViewSize : function(){
50848 if(this.el.dom != document.body){
50849 size = this.el.getSize();
50851 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50853 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50854 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50859 * Returns the Element this layout is bound to.
50860 * @return {Roo.Element}
50862 getEl : function(){
50867 * Returns the specified region.
50868 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50869 * @return {Roo.LayoutRegion}
50871 getRegion : function(target){
50872 return this.regions[target.toLowerCase()];
50875 onWindowResize : function(){
50876 if(this.monitorWindowResize){
50882 * Ext JS Library 1.1.1
50883 * Copyright(c) 2006-2007, Ext JS, LLC.
50885 * Originally Released Under LGPL - original licence link has changed is not relivant.
50888 * <script type="text/javascript">
50891 * @class Roo.BorderLayout
50892 * @extends Roo.LayoutManager
50893 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
50894 * please see: <br><br>
50895 * <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>
50896 * <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>
50899 var layout = new Roo.BorderLayout(document.body, {
50933 preferredTabWidth: 150
50938 var CP = Roo.ContentPanel;
50940 layout.beginUpdate();
50941 layout.add("north", new CP("north", "North"));
50942 layout.add("south", new CP("south", {title: "South", closable: true}));
50943 layout.add("west", new CP("west", {title: "West"}));
50944 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
50945 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
50946 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
50947 layout.getRegion("center").showPanel("center1");
50948 layout.endUpdate();
50951 <b>The container the layout is rendered into can be either the body element or any other element.
50952 If it is not the body element, the container needs to either be an absolute positioned element,
50953 or you will need to add "position:relative" to the css of the container. You will also need to specify
50954 the container size if it is not the body element.</b>
50957 * Create a new BorderLayout
50958 * @param {String/HTMLElement/Element} container The container this layout is bound to
50959 * @param {Object} config Configuration options
50961 Roo.BorderLayout = function(container, config){
50962 config = config || {};
50963 Roo.BorderLayout.superclass.constructor.call(this, container, config);
50964 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
50965 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
50966 var target = this.factory.validRegions[i];
50967 if(config[target]){
50968 this.addRegion(target, config[target]);
50973 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
50975 * Creates and adds a new region if it doesn't already exist.
50976 * @param {String} target The target region key (north, south, east, west or center).
50977 * @param {Object} config The regions config object
50978 * @return {BorderLayoutRegion} The new region
50980 addRegion : function(target, config){
50981 if(!this.regions[target]){
50982 var r = this.factory.create(target, this, config);
50983 this.bindRegion(target, r);
50985 return this.regions[target];
50989 bindRegion : function(name, r){
50990 this.regions[name] = r;
50991 r.on("visibilitychange", this.layout, this);
50992 r.on("paneladded", this.layout, this);
50993 r.on("panelremoved", this.layout, this);
50994 r.on("invalidated", this.layout, this);
50995 r.on("resized", this.onRegionResized, this);
50996 r.on("collapsed", this.onRegionCollapsed, this);
50997 r.on("expanded", this.onRegionExpanded, this);
51001 * Performs a layout update.
51003 layout : function(){
51004 if(this.updating) {
51007 var size = this.getViewSize();
51008 var w = size.width;
51009 var h = size.height;
51014 //var x = 0, y = 0;
51016 var rs = this.regions;
51017 var north = rs["north"];
51018 var south = rs["south"];
51019 var west = rs["west"];
51020 var east = rs["east"];
51021 var center = rs["center"];
51022 //if(this.hideOnLayout){ // not supported anymore
51023 //c.el.setStyle("display", "none");
51025 if(north && north.isVisible()){
51026 var b = north.getBox();
51027 var m = north.getMargins();
51028 b.width = w - (m.left+m.right);
51031 centerY = b.height + b.y + m.bottom;
51032 centerH -= centerY;
51033 north.updateBox(this.safeBox(b));
51035 if(south && south.isVisible()){
51036 var b = south.getBox();
51037 var m = south.getMargins();
51038 b.width = w - (m.left+m.right);
51040 var totalHeight = (b.height + m.top + m.bottom);
51041 b.y = h - totalHeight + m.top;
51042 centerH -= totalHeight;
51043 south.updateBox(this.safeBox(b));
51045 if(west && west.isVisible()){
51046 var b = west.getBox();
51047 var m = west.getMargins();
51048 b.height = centerH - (m.top+m.bottom);
51050 b.y = centerY + m.top;
51051 var totalWidth = (b.width + m.left + m.right);
51052 centerX += totalWidth;
51053 centerW -= totalWidth;
51054 west.updateBox(this.safeBox(b));
51056 if(east && east.isVisible()){
51057 var b = east.getBox();
51058 var m = east.getMargins();
51059 b.height = centerH - (m.top+m.bottom);
51060 var totalWidth = (b.width + m.left + m.right);
51061 b.x = w - totalWidth + m.left;
51062 b.y = centerY + m.top;
51063 centerW -= totalWidth;
51064 east.updateBox(this.safeBox(b));
51067 var m = center.getMargins();
51069 x: centerX + m.left,
51070 y: centerY + m.top,
51071 width: centerW - (m.left+m.right),
51072 height: centerH - (m.top+m.bottom)
51074 //if(this.hideOnLayout){
51075 //center.el.setStyle("display", "block");
51077 center.updateBox(this.safeBox(centerBox));
51080 this.fireEvent("layout", this);
51084 safeBox : function(box){
51085 box.width = Math.max(0, box.width);
51086 box.height = Math.max(0, box.height);
51091 * Adds a ContentPanel (or subclass) to this layout.
51092 * @param {String} target The target region key (north, south, east, west or center).
51093 * @param {Roo.ContentPanel} panel The panel to add
51094 * @return {Roo.ContentPanel} The added panel
51096 add : function(target, panel){
51098 target = target.toLowerCase();
51099 return this.regions[target].add(panel);
51103 * Remove a ContentPanel (or subclass) to this layout.
51104 * @param {String} target The target region key (north, south, east, west or center).
51105 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51106 * @return {Roo.ContentPanel} The removed panel
51108 remove : function(target, panel){
51109 target = target.toLowerCase();
51110 return this.regions[target].remove(panel);
51114 * Searches all regions for a panel with the specified id
51115 * @param {String} panelId
51116 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51118 findPanel : function(panelId){
51119 var rs = this.regions;
51120 for(var target in rs){
51121 if(typeof rs[target] != "function"){
51122 var p = rs[target].getPanel(panelId);
51132 * Searches all regions for a panel with the specified id and activates (shows) it.
51133 * @param {String/ContentPanel} panelId The panels id or the panel itself
51134 * @return {Roo.ContentPanel} The shown panel or null
51136 showPanel : function(panelId) {
51137 var rs = this.regions;
51138 for(var target in rs){
51139 var r = rs[target];
51140 if(typeof r != "function"){
51141 if(r.hasPanel(panelId)){
51142 return r.showPanel(panelId);
51150 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51151 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51153 restoreState : function(provider){
51155 provider = Roo.state.Manager;
51157 var sm = new Roo.LayoutStateManager();
51158 sm.init(this, provider);
51162 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51163 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51164 * a valid ContentPanel config object. Example:
51166 // Create the main layout
51167 var layout = new Roo.BorderLayout('main-ct', {
51178 // Create and add multiple ContentPanels at once via configs
51181 id: 'source-files',
51183 title:'Ext Source Files',
51196 * @param {Object} regions An object containing ContentPanel configs by region name
51198 batchAdd : function(regions){
51199 this.beginUpdate();
51200 for(var rname in regions){
51201 var lr = this.regions[rname];
51203 this.addTypedPanels(lr, regions[rname]);
51210 addTypedPanels : function(lr, ps){
51211 if(typeof ps == 'string'){
51212 lr.add(new Roo.ContentPanel(ps));
51214 else if(ps instanceof Array){
51215 for(var i =0, len = ps.length; i < len; i++){
51216 this.addTypedPanels(lr, ps[i]);
51219 else if(!ps.events){ // raw config?
51221 delete ps.el; // prevent conflict
51222 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51224 else { // panel object assumed!
51229 * Adds a xtype elements to the layout.
51233 xtype : 'ContentPanel',
51240 xtype : 'NestedLayoutPanel',
51246 items : [ ... list of content panels or nested layout panels.. ]
51250 * @param {Object} cfg Xtype definition of item to add.
51252 addxtype : function(cfg)
51254 // basically accepts a pannel...
51255 // can accept a layout region..!?!?
51256 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51258 if (!cfg.xtype.match(/Panel$/)) {
51263 if (typeof(cfg.region) == 'undefined') {
51264 Roo.log("Failed to add Panel, region was not set");
51268 var region = cfg.region;
51274 xitems = cfg.items;
51281 case 'ContentPanel': // ContentPanel (el, cfg)
51282 case 'ScrollPanel': // ContentPanel (el, cfg)
51284 if(cfg.autoCreate) {
51285 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51287 var el = this.el.createChild();
51288 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51291 this.add(region, ret);
51295 case 'TreePanel': // our new panel!
51296 cfg.el = this.el.createChild();
51297 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51298 this.add(region, ret);
51301 case 'NestedLayoutPanel':
51302 // create a new Layout (which is a Border Layout...
51303 var el = this.el.createChild();
51304 var clayout = cfg.layout;
51306 clayout.items = clayout.items || [];
51307 // replace this exitems with the clayout ones..
51308 xitems = clayout.items;
51311 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51312 cfg.background = false;
51314 var layout = new Roo.BorderLayout(el, clayout);
51316 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51317 //console.log('adding nested layout panel ' + cfg.toSource());
51318 this.add(region, ret);
51319 nb = {}; /// find first...
51324 // needs grid and region
51326 //var el = this.getRegion(region).el.createChild();
51327 var el = this.el.createChild();
51328 // create the grid first...
51330 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51332 if (region == 'center' && this.active ) {
51333 cfg.background = false;
51335 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51337 this.add(region, ret);
51338 if (cfg.background) {
51339 ret.on('activate', function(gp) {
51340 if (!gp.grid.rendered) {
51355 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51357 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51358 this.add(region, ret);
51361 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51365 // GridPanel (grid, cfg)
51368 this.beginUpdate();
51372 Roo.each(xitems, function(i) {
51373 region = nb && i.region ? i.region : false;
51375 var add = ret.addxtype(i);
51378 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51379 if (!i.background) {
51380 abn[region] = nb[region] ;
51387 // make the last non-background panel active..
51388 //if (nb) { Roo.log(abn); }
51391 for(var r in abn) {
51392 region = this.getRegion(r);
51394 // tried using nb[r], but it does not work..
51396 region.showPanel(abn[r]);
51407 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51408 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51409 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51410 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51413 var CP = Roo.ContentPanel;
51415 var layout = Roo.BorderLayout.create({
51419 panels: [new CP("north", "North")]
51428 panels: [new CP("west", {title: "West"})]
51437 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51446 panels: [new CP("south", {title: "South", closable: true})]
51453 preferredTabWidth: 150,
51455 new CP("center1", {title: "Close Me", closable: true}),
51456 new CP("center2", {title: "Center Panel", closable: false})
51461 layout.getRegion("center").showPanel("center1");
51466 Roo.BorderLayout.create = function(config, targetEl){
51467 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51468 layout.beginUpdate();
51469 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51470 for(var j = 0, jlen = regions.length; j < jlen; j++){
51471 var lr = regions[j];
51472 if(layout.regions[lr] && config[lr].panels){
51473 var r = layout.regions[lr];
51474 var ps = config[lr].panels;
51475 layout.addTypedPanels(r, ps);
51478 layout.endUpdate();
51483 Roo.BorderLayout.RegionFactory = {
51485 validRegions : ["north","south","east","west","center"],
51488 create : function(target, mgr, config){
51489 target = target.toLowerCase();
51490 if(config.lightweight || config.basic){
51491 return new Roo.BasicLayoutRegion(mgr, config, target);
51495 return new Roo.NorthLayoutRegion(mgr, config);
51497 return new Roo.SouthLayoutRegion(mgr, config);
51499 return new Roo.EastLayoutRegion(mgr, config);
51501 return new Roo.WestLayoutRegion(mgr, config);
51503 return new Roo.CenterLayoutRegion(mgr, config);
51505 throw 'Layout region "'+target+'" not supported.';
51509 * Ext JS Library 1.1.1
51510 * Copyright(c) 2006-2007, Ext JS, LLC.
51512 * Originally Released Under LGPL - original licence link has changed is not relivant.
51515 * <script type="text/javascript">
51519 * @class Roo.BasicLayoutRegion
51520 * @extends Roo.util.Observable
51521 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51522 * and does not have a titlebar, tabs or any other features. All it does is size and position
51523 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51525 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51527 this.position = pos;
51530 * @scope Roo.BasicLayoutRegion
51534 * @event beforeremove
51535 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51536 * @param {Roo.LayoutRegion} this
51537 * @param {Roo.ContentPanel} panel The panel
51538 * @param {Object} e The cancel event object
51540 "beforeremove" : true,
51542 * @event invalidated
51543 * Fires when the layout for this region is changed.
51544 * @param {Roo.LayoutRegion} this
51546 "invalidated" : true,
51548 * @event visibilitychange
51549 * Fires when this region is shown or hidden
51550 * @param {Roo.LayoutRegion} this
51551 * @param {Boolean} visibility true or false
51553 "visibilitychange" : true,
51555 * @event paneladded
51556 * Fires when a panel is added.
51557 * @param {Roo.LayoutRegion} this
51558 * @param {Roo.ContentPanel} panel The panel
51560 "paneladded" : true,
51562 * @event panelremoved
51563 * Fires when a panel is removed.
51564 * @param {Roo.LayoutRegion} this
51565 * @param {Roo.ContentPanel} panel The panel
51567 "panelremoved" : true,
51569 * @event beforecollapse
51570 * Fires when this region before collapse.
51571 * @param {Roo.LayoutRegion} this
51573 "beforecollapse" : true,
51576 * Fires when this region is collapsed.
51577 * @param {Roo.LayoutRegion} this
51579 "collapsed" : true,
51582 * Fires when this region is expanded.
51583 * @param {Roo.LayoutRegion} this
51588 * Fires when this region is slid into view.
51589 * @param {Roo.LayoutRegion} this
51591 "slideshow" : true,
51594 * Fires when this region slides out of view.
51595 * @param {Roo.LayoutRegion} this
51597 "slidehide" : true,
51599 * @event panelactivated
51600 * Fires when a panel is activated.
51601 * @param {Roo.LayoutRegion} this
51602 * @param {Roo.ContentPanel} panel The activated panel
51604 "panelactivated" : true,
51607 * Fires when the user resizes this region.
51608 * @param {Roo.LayoutRegion} this
51609 * @param {Number} newSize The new size (width for east/west, height for north/south)
51613 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51614 this.panels = new Roo.util.MixedCollection();
51615 this.panels.getKey = this.getPanelId.createDelegate(this);
51617 this.activePanel = null;
51618 // ensure listeners are added...
51620 if (config.listeners || config.events) {
51621 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51622 listeners : config.listeners || {},
51623 events : config.events || {}
51627 if(skipConfig !== true){
51628 this.applyConfig(config);
51632 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51633 getPanelId : function(p){
51637 applyConfig : function(config){
51638 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51639 this.config = config;
51644 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51645 * the width, for horizontal (north, south) the height.
51646 * @param {Number} newSize The new width or height
51648 resizeTo : function(newSize){
51649 var el = this.el ? this.el :
51650 (this.activePanel ? this.activePanel.getEl() : null);
51652 switch(this.position){
51655 el.setWidth(newSize);
51656 this.fireEvent("resized", this, newSize);
51660 el.setHeight(newSize);
51661 this.fireEvent("resized", this, newSize);
51667 getBox : function(){
51668 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51671 getMargins : function(){
51672 return this.margins;
51675 updateBox : function(box){
51677 var el = this.activePanel.getEl();
51678 el.dom.style.left = box.x + "px";
51679 el.dom.style.top = box.y + "px";
51680 this.activePanel.setSize(box.width, box.height);
51684 * Returns the container element for this region.
51685 * @return {Roo.Element}
51687 getEl : function(){
51688 return this.activePanel;
51692 * Returns true if this region is currently visible.
51693 * @return {Boolean}
51695 isVisible : function(){
51696 return this.activePanel ? true : false;
51699 setActivePanel : function(panel){
51700 panel = this.getPanel(panel);
51701 if(this.activePanel && this.activePanel != panel){
51702 this.activePanel.setActiveState(false);
51703 this.activePanel.getEl().setLeftTop(-10000,-10000);
51705 this.activePanel = panel;
51706 panel.setActiveState(true);
51708 panel.setSize(this.box.width, this.box.height);
51710 this.fireEvent("panelactivated", this, panel);
51711 this.fireEvent("invalidated");
51715 * Show the specified panel.
51716 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51717 * @return {Roo.ContentPanel} The shown panel or null
51719 showPanel : function(panel){
51720 if(panel = this.getPanel(panel)){
51721 this.setActivePanel(panel);
51727 * Get the active panel for this region.
51728 * @return {Roo.ContentPanel} The active panel or null
51730 getActivePanel : function(){
51731 return this.activePanel;
51735 * Add the passed ContentPanel(s)
51736 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51737 * @return {Roo.ContentPanel} The panel added (if only one was added)
51739 add : function(panel){
51740 if(arguments.length > 1){
51741 for(var i = 0, len = arguments.length; i < len; i++) {
51742 this.add(arguments[i]);
51746 if(this.hasPanel(panel)){
51747 this.showPanel(panel);
51750 var el = panel.getEl();
51751 if(el.dom.parentNode != this.mgr.el.dom){
51752 this.mgr.el.dom.appendChild(el.dom);
51754 if(panel.setRegion){
51755 panel.setRegion(this);
51757 this.panels.add(panel);
51758 el.setStyle("position", "absolute");
51759 if(!panel.background){
51760 this.setActivePanel(panel);
51761 if(this.config.initialSize && this.panels.getCount()==1){
51762 this.resizeTo(this.config.initialSize);
51765 this.fireEvent("paneladded", this, panel);
51770 * Returns true if the panel is in this region.
51771 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51772 * @return {Boolean}
51774 hasPanel : function(panel){
51775 if(typeof panel == "object"){ // must be panel obj
51776 panel = panel.getId();
51778 return this.getPanel(panel) ? true : false;
51782 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51783 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51784 * @param {Boolean} preservePanel Overrides the config preservePanel option
51785 * @return {Roo.ContentPanel} The panel that was removed
51787 remove : function(panel, preservePanel){
51788 panel = this.getPanel(panel);
51793 this.fireEvent("beforeremove", this, panel, e);
51794 if(e.cancel === true){
51797 var panelId = panel.getId();
51798 this.panels.removeKey(panelId);
51803 * Returns the panel specified or null if it's not in this region.
51804 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51805 * @return {Roo.ContentPanel}
51807 getPanel : function(id){
51808 if(typeof id == "object"){ // must be panel obj
51811 return this.panels.get(id);
51815 * Returns this regions position (north/south/east/west/center).
51818 getPosition: function(){
51819 return this.position;
51823 * Ext JS Library 1.1.1
51824 * Copyright(c) 2006-2007, Ext JS, LLC.
51826 * Originally Released Under LGPL - original licence link has changed is not relivant.
51829 * <script type="text/javascript">
51833 * @class Roo.LayoutRegion
51834 * @extends Roo.BasicLayoutRegion
51835 * This class represents a region in a layout manager.
51836 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51837 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51838 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51839 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51840 * @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})
51841 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51842 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51843 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51844 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51845 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51846 * @cfg {String} title The title for the region (overrides panel titles)
51847 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51848 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51849 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51850 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51851 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51852 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51853 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51854 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51855 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51856 * @cfg {Boolean} showPin True to show a pin button
51857 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51858 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51859 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51860 * @cfg {Number} width For East/West panels
51861 * @cfg {Number} height For North/South panels
51862 * @cfg {Boolean} split To show the splitter
51863 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51865 Roo.LayoutRegion = function(mgr, config, pos){
51866 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51867 var dh = Roo.DomHelper;
51868 /** This region's container element
51869 * @type Roo.Element */
51870 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51871 /** This region's title element
51872 * @type Roo.Element */
51874 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51875 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51876 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51878 this.titleEl.enableDisplayMode();
51879 /** This region's title text element
51880 * @type HTMLElement */
51881 this.titleTextEl = this.titleEl.dom.firstChild;
51882 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
51883 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
51884 this.closeBtn.enableDisplayMode();
51885 this.closeBtn.on("click", this.closeClicked, this);
51886 this.closeBtn.hide();
51888 this.createBody(config);
51889 this.visible = true;
51890 this.collapsed = false;
51892 if(config.hideWhenEmpty){
51894 this.on("paneladded", this.validateVisibility, this);
51895 this.on("panelremoved", this.validateVisibility, this);
51897 this.applyConfig(config);
51900 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
51902 createBody : function(){
51903 /** This region's body element
51904 * @type Roo.Element */
51905 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
51908 applyConfig : function(c){
51909 if(c.collapsible && this.position != "center" && !this.collapsedEl){
51910 var dh = Roo.DomHelper;
51911 if(c.titlebar !== false){
51912 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
51913 this.collapseBtn.on("click", this.collapse, this);
51914 this.collapseBtn.enableDisplayMode();
51916 if(c.showPin === true || this.showPin){
51917 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
51918 this.stickBtn.enableDisplayMode();
51919 this.stickBtn.on("click", this.expand, this);
51920 this.stickBtn.hide();
51923 /** This region's collapsed element
51924 * @type Roo.Element */
51925 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
51926 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
51928 if(c.floatable !== false){
51929 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
51930 this.collapsedEl.on("click", this.collapseClick, this);
51933 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
51934 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
51935 id: "message", unselectable: "on", style:{"float":"left"}});
51936 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
51938 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
51939 this.expandBtn.on("click", this.expand, this);
51941 if(this.collapseBtn){
51942 this.collapseBtn.setVisible(c.collapsible == true);
51944 this.cmargins = c.cmargins || this.cmargins ||
51945 (this.position == "west" || this.position == "east" ?
51946 {top: 0, left: 2, right:2, bottom: 0} :
51947 {top: 2, left: 0, right:0, bottom: 2});
51948 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51949 this.bottomTabs = c.tabPosition != "top";
51950 this.autoScroll = c.autoScroll || false;
51951 if(this.autoScroll){
51952 this.bodyEl.setStyle("overflow", "auto");
51954 this.bodyEl.setStyle("overflow", "hidden");
51956 //if(c.titlebar !== false){
51957 if((!c.titlebar && !c.title) || c.titlebar === false){
51958 this.titleEl.hide();
51960 this.titleEl.show();
51962 this.titleTextEl.innerHTML = c.title;
51966 this.duration = c.duration || .30;
51967 this.slideDuration = c.slideDuration || .45;
51970 this.collapse(true);
51977 * Returns true if this region is currently visible.
51978 * @return {Boolean}
51980 isVisible : function(){
51981 return this.visible;
51985 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
51986 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
51988 setCollapsedTitle : function(title){
51989 title = title || " ";
51990 if(this.collapsedTitleTextEl){
51991 this.collapsedTitleTextEl.innerHTML = title;
51995 getBox : function(){
51997 if(!this.collapsed){
51998 b = this.el.getBox(false, true);
52000 b = this.collapsedEl.getBox(false, true);
52005 getMargins : function(){
52006 return this.collapsed ? this.cmargins : this.margins;
52009 highlight : function(){
52010 this.el.addClass("x-layout-panel-dragover");
52013 unhighlight : function(){
52014 this.el.removeClass("x-layout-panel-dragover");
52017 updateBox : function(box){
52019 if(!this.collapsed){
52020 this.el.dom.style.left = box.x + "px";
52021 this.el.dom.style.top = box.y + "px";
52022 this.updateBody(box.width, box.height);
52024 this.collapsedEl.dom.style.left = box.x + "px";
52025 this.collapsedEl.dom.style.top = box.y + "px";
52026 this.collapsedEl.setSize(box.width, box.height);
52029 this.tabs.autoSizeTabs();
52033 updateBody : function(w, h){
52035 this.el.setWidth(w);
52036 w -= this.el.getBorderWidth("rl");
52037 if(this.config.adjustments){
52038 w += this.config.adjustments[0];
52042 this.el.setHeight(h);
52043 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52044 h -= this.el.getBorderWidth("tb");
52045 if(this.config.adjustments){
52046 h += this.config.adjustments[1];
52048 this.bodyEl.setHeight(h);
52050 h = this.tabs.syncHeight(h);
52053 if(this.panelSize){
52054 w = w !== null ? w : this.panelSize.width;
52055 h = h !== null ? h : this.panelSize.height;
52057 if(this.activePanel){
52058 var el = this.activePanel.getEl();
52059 w = w !== null ? w : el.getWidth();
52060 h = h !== null ? h : el.getHeight();
52061 this.panelSize = {width: w, height: h};
52062 this.activePanel.setSize(w, h);
52064 if(Roo.isIE && this.tabs){
52065 this.tabs.el.repaint();
52070 * Returns the container element for this region.
52071 * @return {Roo.Element}
52073 getEl : function(){
52078 * Hides this region.
52081 if(!this.collapsed){
52082 this.el.dom.style.left = "-2000px";
52085 this.collapsedEl.dom.style.left = "-2000px";
52086 this.collapsedEl.hide();
52088 this.visible = false;
52089 this.fireEvent("visibilitychange", this, false);
52093 * Shows this region if it was previously hidden.
52096 if(!this.collapsed){
52099 this.collapsedEl.show();
52101 this.visible = true;
52102 this.fireEvent("visibilitychange", this, true);
52105 closeClicked : function(){
52106 if(this.activePanel){
52107 this.remove(this.activePanel);
52111 collapseClick : function(e){
52113 e.stopPropagation();
52116 e.stopPropagation();
52122 * Collapses this region.
52123 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52125 collapse : function(skipAnim, skipCheck = false){
52126 if(this.collapsed) {
52130 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52132 this.collapsed = true;
52134 this.split.el.hide();
52136 if(this.config.animate && skipAnim !== true){
52137 this.fireEvent("invalidated", this);
52138 this.animateCollapse();
52140 this.el.setLocation(-20000,-20000);
52142 this.collapsedEl.show();
52143 this.fireEvent("collapsed", this);
52144 this.fireEvent("invalidated", this);
52150 animateCollapse : function(){
52155 * Expands this region if it was previously collapsed.
52156 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52157 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52159 expand : function(e, skipAnim){
52161 e.stopPropagation();
52163 if(!this.collapsed || this.el.hasActiveFx()) {
52167 this.afterSlideIn();
52170 this.collapsed = false;
52171 if(this.config.animate && skipAnim !== true){
52172 this.animateExpand();
52176 this.split.el.show();
52178 this.collapsedEl.setLocation(-2000,-2000);
52179 this.collapsedEl.hide();
52180 this.fireEvent("invalidated", this);
52181 this.fireEvent("expanded", this);
52185 animateExpand : function(){
52189 initTabs : function()
52191 this.bodyEl.setStyle("overflow", "hidden");
52192 var ts = new Roo.TabPanel(
52195 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52196 disableTooltips: this.config.disableTabTips,
52197 toolbar : this.config.toolbar
52200 if(this.config.hideTabs){
52201 ts.stripWrap.setDisplayed(false);
52204 ts.resizeTabs = this.config.resizeTabs === true;
52205 ts.minTabWidth = this.config.minTabWidth || 40;
52206 ts.maxTabWidth = this.config.maxTabWidth || 250;
52207 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52208 ts.monitorResize = false;
52209 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52210 ts.bodyEl.addClass('x-layout-tabs-body');
52211 this.panels.each(this.initPanelAsTab, this);
52214 initPanelAsTab : function(panel){
52215 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52216 this.config.closeOnTab && panel.isClosable());
52217 if(panel.tabTip !== undefined){
52218 ti.setTooltip(panel.tabTip);
52220 ti.on("activate", function(){
52221 this.setActivePanel(panel);
52223 if(this.config.closeOnTab){
52224 ti.on("beforeclose", function(t, e){
52226 this.remove(panel);
52232 updatePanelTitle : function(panel, title){
52233 if(this.activePanel == panel){
52234 this.updateTitle(title);
52237 var ti = this.tabs.getTab(panel.getEl().id);
52239 if(panel.tabTip !== undefined){
52240 ti.setTooltip(panel.tabTip);
52245 updateTitle : function(title){
52246 if(this.titleTextEl && !this.config.title){
52247 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52251 setActivePanel : function(panel){
52252 panel = this.getPanel(panel);
52253 if(this.activePanel && this.activePanel != panel){
52254 this.activePanel.setActiveState(false);
52256 this.activePanel = panel;
52257 panel.setActiveState(true);
52258 if(this.panelSize){
52259 panel.setSize(this.panelSize.width, this.panelSize.height);
52262 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52264 this.updateTitle(panel.getTitle());
52266 this.fireEvent("invalidated", this);
52268 this.fireEvent("panelactivated", this, panel);
52272 * Shows the specified panel.
52273 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52274 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52276 showPanel : function(panel)
52278 panel = this.getPanel(panel);
52281 var tab = this.tabs.getTab(panel.getEl().id);
52282 if(tab.isHidden()){
52283 this.tabs.unhideTab(tab.id);
52287 this.setActivePanel(panel);
52294 * Get the active panel for this region.
52295 * @return {Roo.ContentPanel} The active panel or null
52297 getActivePanel : function(){
52298 return this.activePanel;
52301 validateVisibility : function(){
52302 if(this.panels.getCount() < 1){
52303 this.updateTitle(" ");
52304 this.closeBtn.hide();
52307 if(!this.isVisible()){
52314 * Adds the passed ContentPanel(s) to this region.
52315 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52316 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52318 add : function(panel){
52319 if(arguments.length > 1){
52320 for(var i = 0, len = arguments.length; i < len; i++) {
52321 this.add(arguments[i]);
52325 if(this.hasPanel(panel)){
52326 this.showPanel(panel);
52329 panel.setRegion(this);
52330 this.panels.add(panel);
52331 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52332 this.bodyEl.dom.appendChild(panel.getEl().dom);
52333 if(panel.background !== true){
52334 this.setActivePanel(panel);
52336 this.fireEvent("paneladded", this, panel);
52342 this.initPanelAsTab(panel);
52344 if(panel.background !== true){
52345 this.tabs.activate(panel.getEl().id);
52347 this.fireEvent("paneladded", this, panel);
52352 * Hides the tab for the specified panel.
52353 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52355 hidePanel : function(panel){
52356 if(this.tabs && (panel = this.getPanel(panel))){
52357 this.tabs.hideTab(panel.getEl().id);
52362 * Unhides the tab for a previously hidden panel.
52363 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52365 unhidePanel : function(panel){
52366 if(this.tabs && (panel = this.getPanel(panel))){
52367 this.tabs.unhideTab(panel.getEl().id);
52371 clearPanels : function(){
52372 while(this.panels.getCount() > 0){
52373 this.remove(this.panels.first());
52378 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52379 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52380 * @param {Boolean} preservePanel Overrides the config preservePanel option
52381 * @return {Roo.ContentPanel} The panel that was removed
52383 remove : function(panel, preservePanel){
52384 panel = this.getPanel(panel);
52389 this.fireEvent("beforeremove", this, panel, e);
52390 if(e.cancel === true){
52393 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52394 var panelId = panel.getId();
52395 this.panels.removeKey(panelId);
52397 document.body.appendChild(panel.getEl().dom);
52400 this.tabs.removeTab(panel.getEl().id);
52401 }else if (!preservePanel){
52402 this.bodyEl.dom.removeChild(panel.getEl().dom);
52404 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52405 var p = this.panels.first();
52406 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52407 tempEl.appendChild(p.getEl().dom);
52408 this.bodyEl.update("");
52409 this.bodyEl.dom.appendChild(p.getEl().dom);
52411 this.updateTitle(p.getTitle());
52413 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52414 this.setActivePanel(p);
52416 panel.setRegion(null);
52417 if(this.activePanel == panel){
52418 this.activePanel = null;
52420 if(this.config.autoDestroy !== false && preservePanel !== true){
52421 try{panel.destroy();}catch(e){}
52423 this.fireEvent("panelremoved", this, panel);
52428 * Returns the TabPanel component used by this region
52429 * @return {Roo.TabPanel}
52431 getTabs : function(){
52435 createTool : function(parentEl, className){
52436 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52437 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52438 btn.addClassOnOver("x-layout-tools-button-over");
52443 * Ext JS Library 1.1.1
52444 * Copyright(c) 2006-2007, Ext JS, LLC.
52446 * Originally Released Under LGPL - original licence link has changed is not relivant.
52449 * <script type="text/javascript">
52455 * @class Roo.SplitLayoutRegion
52456 * @extends Roo.LayoutRegion
52457 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52459 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52460 this.cursor = cursor;
52461 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52464 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52465 splitTip : "Drag to resize.",
52466 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52467 useSplitTips : false,
52469 applyConfig : function(config){
52470 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52473 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52474 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52475 /** The SplitBar for this region
52476 * @type Roo.SplitBar */
52477 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52478 this.split.on("moved", this.onSplitMove, this);
52479 this.split.useShim = config.useShim === true;
52480 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52481 if(this.useSplitTips){
52482 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52484 if(config.collapsible){
52485 this.split.el.on("dblclick", this.collapse, this);
52488 if(typeof config.minSize != "undefined"){
52489 this.split.minSize = config.minSize;
52491 if(typeof config.maxSize != "undefined"){
52492 this.split.maxSize = config.maxSize;
52494 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52495 this.hideSplitter();
52500 getHMaxSize : function(){
52501 var cmax = this.config.maxSize || 10000;
52502 var center = this.mgr.getRegion("center");
52503 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52506 getVMaxSize : function(){
52507 var cmax = this.config.maxSize || 10000;
52508 var center = this.mgr.getRegion("center");
52509 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52512 onSplitMove : function(split, newSize){
52513 this.fireEvent("resized", this, newSize);
52517 * Returns the {@link Roo.SplitBar} for this region.
52518 * @return {Roo.SplitBar}
52520 getSplitBar : function(){
52525 this.hideSplitter();
52526 Roo.SplitLayoutRegion.superclass.hide.call(this);
52529 hideSplitter : function(){
52531 this.split.el.setLocation(-2000,-2000);
52532 this.split.el.hide();
52538 this.split.el.show();
52540 Roo.SplitLayoutRegion.superclass.show.call(this);
52543 beforeSlide: function(){
52544 if(Roo.isGecko){// firefox overflow auto bug workaround
52545 this.bodyEl.clip();
52547 this.tabs.bodyEl.clip();
52549 if(this.activePanel){
52550 this.activePanel.getEl().clip();
52552 if(this.activePanel.beforeSlide){
52553 this.activePanel.beforeSlide();
52559 afterSlide : function(){
52560 if(Roo.isGecko){// firefox overflow auto bug workaround
52561 this.bodyEl.unclip();
52563 this.tabs.bodyEl.unclip();
52565 if(this.activePanel){
52566 this.activePanel.getEl().unclip();
52567 if(this.activePanel.afterSlide){
52568 this.activePanel.afterSlide();
52574 initAutoHide : function(){
52575 if(this.autoHide !== false){
52576 if(!this.autoHideHd){
52577 var st = new Roo.util.DelayedTask(this.slideIn, this);
52578 this.autoHideHd = {
52579 "mouseout": function(e){
52580 if(!e.within(this.el, true)){
52584 "mouseover" : function(e){
52590 this.el.on(this.autoHideHd);
52594 clearAutoHide : function(){
52595 if(this.autoHide !== false){
52596 this.el.un("mouseout", this.autoHideHd.mouseout);
52597 this.el.un("mouseover", this.autoHideHd.mouseover);
52601 clearMonitor : function(){
52602 Roo.get(document).un("click", this.slideInIf, this);
52605 // these names are backwards but not changed for compat
52606 slideOut : function(){
52607 if(this.isSlid || this.el.hasActiveFx()){
52610 this.isSlid = true;
52611 if(this.collapseBtn){
52612 this.collapseBtn.hide();
52614 this.closeBtnState = this.closeBtn.getStyle('display');
52615 this.closeBtn.hide();
52617 this.stickBtn.show();
52620 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52621 this.beforeSlide();
52622 this.el.setStyle("z-index", 10001);
52623 this.el.slideIn(this.getSlideAnchor(), {
52624 callback: function(){
52626 this.initAutoHide();
52627 Roo.get(document).on("click", this.slideInIf, this);
52628 this.fireEvent("slideshow", this);
52635 afterSlideIn : function(){
52636 this.clearAutoHide();
52637 this.isSlid = false;
52638 this.clearMonitor();
52639 this.el.setStyle("z-index", "");
52640 if(this.collapseBtn){
52641 this.collapseBtn.show();
52643 this.closeBtn.setStyle('display', this.closeBtnState);
52645 this.stickBtn.hide();
52647 this.fireEvent("slidehide", this);
52650 slideIn : function(cb){
52651 if(!this.isSlid || this.el.hasActiveFx()){
52655 this.isSlid = false;
52656 this.beforeSlide();
52657 this.el.slideOut(this.getSlideAnchor(), {
52658 callback: function(){
52659 this.el.setLeftTop(-10000, -10000);
52661 this.afterSlideIn();
52669 slideInIf : function(e){
52670 if(!e.within(this.el)){
52675 animateCollapse : function(){
52676 this.beforeSlide();
52677 this.el.setStyle("z-index", 20000);
52678 var anchor = this.getSlideAnchor();
52679 this.el.slideOut(anchor, {
52680 callback : function(){
52681 this.el.setStyle("z-index", "");
52682 this.collapsedEl.slideIn(anchor, {duration:.3});
52684 this.el.setLocation(-10000,-10000);
52686 this.fireEvent("collapsed", this);
52693 animateExpand : function(){
52694 this.beforeSlide();
52695 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52696 this.el.setStyle("z-index", 20000);
52697 this.collapsedEl.hide({
52700 this.el.slideIn(this.getSlideAnchor(), {
52701 callback : function(){
52702 this.el.setStyle("z-index", "");
52705 this.split.el.show();
52707 this.fireEvent("invalidated", this);
52708 this.fireEvent("expanded", this);
52736 getAnchor : function(){
52737 return this.anchors[this.position];
52740 getCollapseAnchor : function(){
52741 return this.canchors[this.position];
52744 getSlideAnchor : function(){
52745 return this.sanchors[this.position];
52748 getAlignAdj : function(){
52749 var cm = this.cmargins;
52750 switch(this.position){
52766 getExpandAdj : function(){
52767 var c = this.collapsedEl, cm = this.cmargins;
52768 switch(this.position){
52770 return [-(cm.right+c.getWidth()+cm.left), 0];
52773 return [cm.right+c.getWidth()+cm.left, 0];
52776 return [0, -(cm.top+cm.bottom+c.getHeight())];
52779 return [0, cm.top+cm.bottom+c.getHeight()];
52785 * Ext JS Library 1.1.1
52786 * Copyright(c) 2006-2007, Ext JS, LLC.
52788 * Originally Released Under LGPL - original licence link has changed is not relivant.
52791 * <script type="text/javascript">
52794 * These classes are private internal classes
52796 Roo.CenterLayoutRegion = function(mgr, config){
52797 Roo.LayoutRegion.call(this, mgr, config, "center");
52798 this.visible = true;
52799 this.minWidth = config.minWidth || 20;
52800 this.minHeight = config.minHeight || 20;
52803 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52805 // center panel can't be hidden
52809 // center panel can't be hidden
52812 getMinWidth: function(){
52813 return this.minWidth;
52816 getMinHeight: function(){
52817 return this.minHeight;
52822 Roo.NorthLayoutRegion = function(mgr, config){
52823 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52825 this.split.placement = Roo.SplitBar.TOP;
52826 this.split.orientation = Roo.SplitBar.VERTICAL;
52827 this.split.el.addClass("x-layout-split-v");
52829 var size = config.initialSize || config.height;
52830 if(typeof size != "undefined"){
52831 this.el.setHeight(size);
52834 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52835 orientation: Roo.SplitBar.VERTICAL,
52836 getBox : function(){
52837 if(this.collapsed){
52838 return this.collapsedEl.getBox();
52840 var box = this.el.getBox();
52842 box.height += this.split.el.getHeight();
52847 updateBox : function(box){
52848 if(this.split && !this.collapsed){
52849 box.height -= this.split.el.getHeight();
52850 this.split.el.setLeft(box.x);
52851 this.split.el.setTop(box.y+box.height);
52852 this.split.el.setWidth(box.width);
52854 if(this.collapsed){
52855 this.updateBody(box.width, null);
52857 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52861 Roo.SouthLayoutRegion = function(mgr, config){
52862 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52864 this.split.placement = Roo.SplitBar.BOTTOM;
52865 this.split.orientation = Roo.SplitBar.VERTICAL;
52866 this.split.el.addClass("x-layout-split-v");
52868 var size = config.initialSize || config.height;
52869 if(typeof size != "undefined"){
52870 this.el.setHeight(size);
52873 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52874 orientation: Roo.SplitBar.VERTICAL,
52875 getBox : function(){
52876 if(this.collapsed){
52877 return this.collapsedEl.getBox();
52879 var box = this.el.getBox();
52881 var sh = this.split.el.getHeight();
52888 updateBox : function(box){
52889 if(this.split && !this.collapsed){
52890 var sh = this.split.el.getHeight();
52893 this.split.el.setLeft(box.x);
52894 this.split.el.setTop(box.y-sh);
52895 this.split.el.setWidth(box.width);
52897 if(this.collapsed){
52898 this.updateBody(box.width, null);
52900 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52904 Roo.EastLayoutRegion = function(mgr, config){
52905 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
52907 this.split.placement = Roo.SplitBar.RIGHT;
52908 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52909 this.split.el.addClass("x-layout-split-h");
52911 var size = config.initialSize || config.width;
52912 if(typeof size != "undefined"){
52913 this.el.setWidth(size);
52916 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
52917 orientation: Roo.SplitBar.HORIZONTAL,
52918 getBox : function(){
52919 if(this.collapsed){
52920 return this.collapsedEl.getBox();
52922 var box = this.el.getBox();
52924 var sw = this.split.el.getWidth();
52931 updateBox : function(box){
52932 if(this.split && !this.collapsed){
52933 var sw = this.split.el.getWidth();
52935 this.split.el.setLeft(box.x);
52936 this.split.el.setTop(box.y);
52937 this.split.el.setHeight(box.height);
52940 if(this.collapsed){
52941 this.updateBody(null, box.height);
52943 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52947 Roo.WestLayoutRegion = function(mgr, config){
52948 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
52950 this.split.placement = Roo.SplitBar.LEFT;
52951 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52952 this.split.el.addClass("x-layout-split-h");
52954 var size = config.initialSize || config.width;
52955 if(typeof size != "undefined"){
52956 this.el.setWidth(size);
52959 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
52960 orientation: Roo.SplitBar.HORIZONTAL,
52961 getBox : function(){
52962 if(this.collapsed){
52963 return this.collapsedEl.getBox();
52965 var box = this.el.getBox();
52967 box.width += this.split.el.getWidth();
52972 updateBox : function(box){
52973 if(this.split && !this.collapsed){
52974 var sw = this.split.el.getWidth();
52976 this.split.el.setLeft(box.x+box.width);
52977 this.split.el.setTop(box.y);
52978 this.split.el.setHeight(box.height);
52980 if(this.collapsed){
52981 this.updateBody(null, box.height);
52983 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52988 * Ext JS Library 1.1.1
52989 * Copyright(c) 2006-2007, Ext JS, LLC.
52991 * Originally Released Under LGPL - original licence link has changed is not relivant.
52994 * <script type="text/javascript">
52999 * Private internal class for reading and applying state
53001 Roo.LayoutStateManager = function(layout){
53002 // default empty state
53011 Roo.LayoutStateManager.prototype = {
53012 init : function(layout, provider){
53013 this.provider = provider;
53014 var state = provider.get(layout.id+"-layout-state");
53016 var wasUpdating = layout.isUpdating();
53018 layout.beginUpdate();
53020 for(var key in state){
53021 if(typeof state[key] != "function"){
53022 var rstate = state[key];
53023 var r = layout.getRegion(key);
53026 r.resizeTo(rstate.size);
53028 if(rstate.collapsed == true){
53031 r.expand(null, true);
53037 layout.endUpdate();
53039 this.state = state;
53041 this.layout = layout;
53042 layout.on("regionresized", this.onRegionResized, this);
53043 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53044 layout.on("regionexpanded", this.onRegionExpanded, this);
53047 storeState : function(){
53048 this.provider.set(this.layout.id+"-layout-state", this.state);
53051 onRegionResized : function(region, newSize){
53052 this.state[region.getPosition()].size = newSize;
53056 onRegionCollapsed : function(region){
53057 this.state[region.getPosition()].collapsed = true;
53061 onRegionExpanded : function(region){
53062 this.state[region.getPosition()].collapsed = false;
53067 * Ext JS Library 1.1.1
53068 * Copyright(c) 2006-2007, Ext JS, LLC.
53070 * Originally Released Under LGPL - original licence link has changed is not relivant.
53073 * <script type="text/javascript">
53076 * @class Roo.ContentPanel
53077 * @extends Roo.util.Observable
53078 * A basic ContentPanel element.
53079 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53080 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53081 * @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
53082 * @cfg {Boolean} closable True if the panel can be closed/removed
53083 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53084 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53085 * @cfg {Toolbar} toolbar A toolbar for this panel
53086 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53087 * @cfg {String} title The title for this panel
53088 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53089 * @cfg {String} url Calls {@link #setUrl} with this value
53090 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53091 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53092 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53093 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53096 * Create a new ContentPanel.
53097 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53098 * @param {String/Object} config A string to set only the title or a config object
53099 * @param {String} content (optional) Set the HTML content for this panel
53100 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53102 Roo.ContentPanel = function(el, config, content){
53106 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53110 if (config && config.parentLayout) {
53111 el = config.parentLayout.el.createChild();
53114 if(el.autoCreate){ // xtype is available if this is called from factory
53118 this.el = Roo.get(el);
53119 if(!this.el && config && config.autoCreate){
53120 if(typeof config.autoCreate == "object"){
53121 if(!config.autoCreate.id){
53122 config.autoCreate.id = config.id||el;
53124 this.el = Roo.DomHelper.append(document.body,
53125 config.autoCreate, true);
53127 this.el = Roo.DomHelper.append(document.body,
53128 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53131 this.closable = false;
53132 this.loaded = false;
53133 this.active = false;
53134 if(typeof config == "string"){
53135 this.title = config;
53137 Roo.apply(this, config);
53140 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53141 this.wrapEl = this.el.wrap();
53142 this.toolbar.container = this.el.insertSibling(false, 'before');
53143 this.toolbar = new Roo.Toolbar(this.toolbar);
53146 // xtype created footer. - not sure if will work as we normally have to render first..
53147 if (this.footer && !this.footer.el && this.footer.xtype) {
53148 if (!this.wrapEl) {
53149 this.wrapEl = this.el.wrap();
53152 this.footer.container = this.wrapEl.createChild();
53154 this.footer = Roo.factory(this.footer, Roo);
53159 this.resizeEl = Roo.get(this.resizeEl, true);
53161 this.resizeEl = this.el;
53163 // handle view.xtype
53171 * Fires when this panel is activated.
53172 * @param {Roo.ContentPanel} this
53176 * @event deactivate
53177 * Fires when this panel is activated.
53178 * @param {Roo.ContentPanel} this
53180 "deactivate" : true,
53184 * Fires when this panel is resized if fitToFrame is true.
53185 * @param {Roo.ContentPanel} this
53186 * @param {Number} width The width after any component adjustments
53187 * @param {Number} height The height after any component adjustments
53193 * Fires when this tab is created
53194 * @param {Roo.ContentPanel} this
53205 if(this.autoScroll){
53206 this.resizeEl.setStyle("overflow", "auto");
53208 // fix randome scrolling
53209 this.el.on('scroll', function() {
53210 Roo.log('fix random scolling');
53211 this.scrollTo('top',0);
53214 content = content || this.content;
53216 this.setContent(content);
53218 if(config && config.url){
53219 this.setUrl(this.url, this.params, this.loadOnce);
53224 Roo.ContentPanel.superclass.constructor.call(this);
53226 if (this.view && typeof(this.view.xtype) != 'undefined') {
53227 this.view.el = this.el.appendChild(document.createElement("div"));
53228 this.view = Roo.factory(this.view);
53229 this.view.render && this.view.render(false, '');
53233 this.fireEvent('render', this);
53236 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53238 setRegion : function(region){
53239 this.region = region;
53241 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53243 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53248 * Returns the toolbar for this Panel if one was configured.
53249 * @return {Roo.Toolbar}
53251 getToolbar : function(){
53252 return this.toolbar;
53255 setActiveState : function(active){
53256 this.active = active;
53258 this.fireEvent("deactivate", this);
53260 this.fireEvent("activate", this);
53264 * Updates this panel's element
53265 * @param {String} content The new content
53266 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53268 setContent : function(content, loadScripts){
53269 this.el.update(content, loadScripts);
53272 ignoreResize : function(w, h){
53273 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53276 this.lastSize = {width: w, height: h};
53281 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53282 * @return {Roo.UpdateManager} The UpdateManager
53284 getUpdateManager : function(){
53285 return this.el.getUpdateManager();
53288 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53289 * @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:
53292 url: "your-url.php",
53293 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53294 callback: yourFunction,
53295 scope: yourObject, //(optional scope)
53298 text: "Loading...",
53303 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53304 * 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.
53305 * @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}
53306 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53307 * @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.
53308 * @return {Roo.ContentPanel} this
53311 var um = this.el.getUpdateManager();
53312 um.update.apply(um, arguments);
53318 * 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.
53319 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53320 * @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)
53321 * @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)
53322 * @return {Roo.UpdateManager} The UpdateManager
53324 setUrl : function(url, params, loadOnce){
53325 if(this.refreshDelegate){
53326 this.removeListener("activate", this.refreshDelegate);
53328 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53329 this.on("activate", this.refreshDelegate);
53330 return this.el.getUpdateManager();
53333 _handleRefresh : function(url, params, loadOnce){
53334 if(!loadOnce || !this.loaded){
53335 var updater = this.el.getUpdateManager();
53336 updater.update(url, params, this._setLoaded.createDelegate(this));
53340 _setLoaded : function(){
53341 this.loaded = true;
53345 * Returns this panel's id
53348 getId : function(){
53353 * Returns this panel's element - used by regiosn to add.
53354 * @return {Roo.Element}
53356 getEl : function(){
53357 return this.wrapEl || this.el;
53360 adjustForComponents : function(width, height)
53362 //Roo.log('adjustForComponents ');
53363 if(this.resizeEl != this.el){
53364 width -= this.el.getFrameWidth('lr');
53365 height -= this.el.getFrameWidth('tb');
53368 var te = this.toolbar.getEl();
53369 height -= te.getHeight();
53370 te.setWidth(width);
53373 var te = this.footer.getEl();
53374 Roo.log("footer:" + te.getHeight());
53376 height -= te.getHeight();
53377 te.setWidth(width);
53381 if(this.adjustments){
53382 width += this.adjustments[0];
53383 height += this.adjustments[1];
53385 return {"width": width, "height": height};
53388 setSize : function(width, height){
53389 if(this.fitToFrame && !this.ignoreResize(width, height)){
53390 if(this.fitContainer && this.resizeEl != this.el){
53391 this.el.setSize(width, height);
53393 var size = this.adjustForComponents(width, height);
53394 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53395 this.fireEvent('resize', this, size.width, size.height);
53400 * Returns this panel's title
53403 getTitle : function(){
53408 * Set this panel's title
53409 * @param {String} title
53411 setTitle : function(title){
53412 this.title = title;
53414 this.region.updatePanelTitle(this, title);
53419 * Returns true is this panel was configured to be closable
53420 * @return {Boolean}
53422 isClosable : function(){
53423 return this.closable;
53426 beforeSlide : function(){
53428 this.resizeEl.clip();
53431 afterSlide : function(){
53433 this.resizeEl.unclip();
53437 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53438 * Will fail silently if the {@link #setUrl} method has not been called.
53439 * This does not activate the panel, just updates its content.
53441 refresh : function(){
53442 if(this.refreshDelegate){
53443 this.loaded = false;
53444 this.refreshDelegate();
53449 * Destroys this panel
53451 destroy : function(){
53452 this.el.removeAllListeners();
53453 var tempEl = document.createElement("span");
53454 tempEl.appendChild(this.el.dom);
53455 tempEl.innerHTML = "";
53461 * form - if the content panel contains a form - this is a reference to it.
53462 * @type {Roo.form.Form}
53466 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53467 * This contains a reference to it.
53473 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53483 * @param {Object} cfg Xtype definition of item to add.
53486 addxtype : function(cfg) {
53488 if (cfg.xtype.match(/^Form$/)) {
53491 //if (this.footer) {
53492 // el = this.footer.container.insertSibling(false, 'before');
53494 el = this.el.createChild();
53497 this.form = new Roo.form.Form(cfg);
53500 if ( this.form.allItems.length) {
53501 this.form.render(el.dom);
53505 // should only have one of theses..
53506 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53507 // views.. should not be just added - used named prop 'view''
53509 cfg.el = this.el.appendChild(document.createElement("div"));
53512 var ret = new Roo.factory(cfg);
53514 ret.render && ret.render(false, ''); // render blank..
53523 * @class Roo.GridPanel
53524 * @extends Roo.ContentPanel
53526 * Create a new GridPanel.
53527 * @param {Roo.grid.Grid} grid The grid for this panel
53528 * @param {String/Object} config A string to set only the panel's title, or a config object
53530 Roo.GridPanel = function(grid, config){
53533 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53534 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53536 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53538 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53541 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53543 // xtype created footer. - not sure if will work as we normally have to render first..
53544 if (this.footer && !this.footer.el && this.footer.xtype) {
53546 this.footer.container = this.grid.getView().getFooterPanel(true);
53547 this.footer.dataSource = this.grid.dataSource;
53548 this.footer = Roo.factory(this.footer, Roo);
53552 grid.monitorWindowResize = false; // turn off autosizing
53553 grid.autoHeight = false;
53554 grid.autoWidth = false;
53556 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53559 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53560 getId : function(){
53561 return this.grid.id;
53565 * Returns the grid for this panel
53566 * @return {Roo.grid.Grid}
53568 getGrid : function(){
53572 setSize : function(width, height){
53573 if(!this.ignoreResize(width, height)){
53574 var grid = this.grid;
53575 var size = this.adjustForComponents(width, height);
53576 grid.getGridEl().setSize(size.width, size.height);
53581 beforeSlide : function(){
53582 this.grid.getView().scroller.clip();
53585 afterSlide : function(){
53586 this.grid.getView().scroller.unclip();
53589 destroy : function(){
53590 this.grid.destroy();
53592 Roo.GridPanel.superclass.destroy.call(this);
53598 * @class Roo.NestedLayoutPanel
53599 * @extends Roo.ContentPanel
53601 * Create a new NestedLayoutPanel.
53604 * @param {Roo.BorderLayout} layout The layout for this panel
53605 * @param {String/Object} config A string to set only the title or a config object
53607 Roo.NestedLayoutPanel = function(layout, config)
53609 // construct with only one argument..
53610 /* FIXME - implement nicer consturctors
53611 if (layout.layout) {
53613 layout = config.layout;
53614 delete config.layout;
53616 if (layout.xtype && !layout.getEl) {
53617 // then layout needs constructing..
53618 layout = Roo.factory(layout, Roo);
53623 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53625 layout.monitorWindowResize = false; // turn off autosizing
53626 this.layout = layout;
53627 this.layout.getEl().addClass("x-layout-nested-layout");
53634 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53636 setSize : function(width, height){
53637 if(!this.ignoreResize(width, height)){
53638 var size = this.adjustForComponents(width, height);
53639 var el = this.layout.getEl();
53640 el.setSize(size.width, size.height);
53641 var touch = el.dom.offsetWidth;
53642 this.layout.layout();
53643 // ie requires a double layout on the first pass
53644 if(Roo.isIE && !this.initialized){
53645 this.initialized = true;
53646 this.layout.layout();
53651 // activate all subpanels if not currently active..
53653 setActiveState : function(active){
53654 this.active = active;
53656 this.fireEvent("deactivate", this);
53660 this.fireEvent("activate", this);
53661 // not sure if this should happen before or after..
53662 if (!this.layout) {
53663 return; // should not happen..
53666 for (var r in this.layout.regions) {
53667 reg = this.layout.getRegion(r);
53668 if (reg.getActivePanel()) {
53669 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53670 reg.setActivePanel(reg.getActivePanel());
53673 if (!reg.panels.length) {
53676 reg.showPanel(reg.getPanel(0));
53685 * Returns the nested BorderLayout for this panel
53686 * @return {Roo.BorderLayout}
53688 getLayout : function(){
53689 return this.layout;
53693 * Adds a xtype elements to the layout of the nested panel
53697 xtype : 'ContentPanel',
53704 xtype : 'NestedLayoutPanel',
53710 items : [ ... list of content panels or nested layout panels.. ]
53714 * @param {Object} cfg Xtype definition of item to add.
53716 addxtype : function(cfg) {
53717 return this.layout.addxtype(cfg);
53722 Roo.ScrollPanel = function(el, config, content){
53723 config = config || {};
53724 config.fitToFrame = true;
53725 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53727 this.el.dom.style.overflow = "hidden";
53728 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53729 this.el.removeClass("x-layout-inactive-content");
53730 this.el.on("mousewheel", this.onWheel, this);
53732 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53733 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53734 up.unselectable(); down.unselectable();
53735 up.on("click", this.scrollUp, this);
53736 down.on("click", this.scrollDown, this);
53737 up.addClassOnOver("x-scroller-btn-over");
53738 down.addClassOnOver("x-scroller-btn-over");
53739 up.addClassOnClick("x-scroller-btn-click");
53740 down.addClassOnClick("x-scroller-btn-click");
53741 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53743 this.resizeEl = this.el;
53744 this.el = wrap; this.up = up; this.down = down;
53747 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53749 wheelIncrement : 5,
53750 scrollUp : function(){
53751 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53754 scrollDown : function(){
53755 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53758 afterScroll : function(){
53759 var el = this.resizeEl;
53760 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53761 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53762 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53765 setSize : function(){
53766 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53767 this.afterScroll();
53770 onWheel : function(e){
53771 var d = e.getWheelDelta();
53772 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53773 this.afterScroll();
53777 setContent : function(content, loadScripts){
53778 this.resizeEl.update(content, loadScripts);
53792 * @class Roo.TreePanel
53793 * @extends Roo.ContentPanel
53795 * Create a new TreePanel. - defaults to fit/scoll contents.
53796 * @param {String/Object} config A string to set only the panel's title, or a config object
53797 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53799 Roo.TreePanel = function(config){
53800 var el = config.el;
53801 var tree = config.tree;
53802 delete config.tree;
53803 delete config.el; // hopefull!
53805 // wrapper for IE7 strict & safari scroll issue
53807 var treeEl = el.createChild();
53808 config.resizeEl = treeEl;
53812 Roo.TreePanel.superclass.constructor.call(this, el, config);
53815 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53816 //console.log(tree);
53817 this.on('activate', function()
53819 if (this.tree.rendered) {
53822 //console.log('render tree');
53823 this.tree.render();
53825 // this should not be needed.. - it's actually the 'el' that resizes?
53826 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53828 //this.on('resize', function (cp, w, h) {
53829 // this.tree.innerCt.setWidth(w);
53830 // this.tree.innerCt.setHeight(h);
53831 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53838 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53855 * Ext JS Library 1.1.1
53856 * Copyright(c) 2006-2007, Ext JS, LLC.
53858 * Originally Released Under LGPL - original licence link has changed is not relivant.
53861 * <script type="text/javascript">
53866 * @class Roo.ReaderLayout
53867 * @extends Roo.BorderLayout
53868 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53869 * center region containing two nested regions (a top one for a list view and one for item preview below),
53870 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53871 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53872 * expedites the setup of the overall layout and regions for this common application style.
53875 var reader = new Roo.ReaderLayout();
53876 var CP = Roo.ContentPanel; // shortcut for adding
53878 reader.beginUpdate();
53879 reader.add("north", new CP("north", "North"));
53880 reader.add("west", new CP("west", {title: "West"}));
53881 reader.add("east", new CP("east", {title: "East"}));
53883 reader.regions.listView.add(new CP("listView", "List"));
53884 reader.regions.preview.add(new CP("preview", "Preview"));
53885 reader.endUpdate();
53888 * Create a new ReaderLayout
53889 * @param {Object} config Configuration options
53890 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
53891 * document.body if omitted)
53893 Roo.ReaderLayout = function(config, renderTo){
53894 var c = config || {size:{}};
53895 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
53896 north: c.north !== false ? Roo.apply({
53900 }, c.north) : false,
53901 west: c.west !== false ? Roo.apply({
53909 margins:{left:5,right:0,bottom:5,top:5},
53910 cmargins:{left:5,right:5,bottom:5,top:5}
53911 }, c.west) : false,
53912 east: c.east !== false ? Roo.apply({
53920 margins:{left:0,right:5,bottom:5,top:5},
53921 cmargins:{left:5,right:5,bottom:5,top:5}
53922 }, c.east) : false,
53923 center: Roo.apply({
53924 tabPosition: 'top',
53928 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
53932 this.el.addClass('x-reader');
53934 this.beginUpdate();
53936 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
53937 south: c.preview !== false ? Roo.apply({
53944 cmargins:{top:5,left:0, right:0, bottom:0}
53945 }, c.preview) : false,
53946 center: Roo.apply({
53952 this.add('center', new Roo.NestedLayoutPanel(inner,
53953 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
53957 this.regions.preview = inner.getRegion('south');
53958 this.regions.listView = inner.getRegion('center');
53961 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
53963 * Ext JS Library 1.1.1
53964 * Copyright(c) 2006-2007, Ext JS, LLC.
53966 * Originally Released Under LGPL - original licence link has changed is not relivant.
53969 * <script type="text/javascript">
53973 * @class Roo.grid.Grid
53974 * @extends Roo.util.Observable
53975 * This class represents the primary interface of a component based grid control.
53976 * <br><br>Usage:<pre><code>
53977 var grid = new Roo.grid.Grid("my-container-id", {
53980 selModel: mySelectionModel,
53981 autoSizeColumns: true,
53982 monitorWindowResize: false,
53983 trackMouseOver: true
53988 * <b>Common Problems:</b><br/>
53989 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
53990 * element will correct this<br/>
53991 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
53992 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
53993 * are unpredictable.<br/>
53994 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
53995 * grid to calculate dimensions/offsets.<br/>
53997 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53998 * The container MUST have some type of size defined for the grid to fill. The container will be
53999 * automatically set to position relative if it isn't already.
54000 * @param {Object} config A config object that sets properties on this grid.
54002 Roo.grid.Grid = function(container, config){
54003 // initialize the container
54004 this.container = Roo.get(container);
54005 this.container.update("");
54006 this.container.setStyle("overflow", "hidden");
54007 this.container.addClass('x-grid-container');
54009 this.id = this.container.id;
54011 Roo.apply(this, config);
54012 // check and correct shorthanded configs
54014 this.dataSource = this.ds;
54018 this.colModel = this.cm;
54022 this.selModel = this.sm;
54026 if (this.selModel) {
54027 this.selModel = Roo.factory(this.selModel, Roo.grid);
54028 this.sm = this.selModel;
54029 this.sm.xmodule = this.xmodule || false;
54031 if (typeof(this.colModel.config) == 'undefined') {
54032 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54033 this.cm = this.colModel;
54034 this.cm.xmodule = this.xmodule || false;
54036 if (this.dataSource) {
54037 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54038 this.ds = this.dataSource;
54039 this.ds.xmodule = this.xmodule || false;
54046 this.container.setWidth(this.width);
54050 this.container.setHeight(this.height);
54057 * The raw click event for the entire grid.
54058 * @param {Roo.EventObject} e
54063 * The raw dblclick event for the entire grid.
54064 * @param {Roo.EventObject} e
54068 * @event contextmenu
54069 * The raw contextmenu event for the entire grid.
54070 * @param {Roo.EventObject} e
54072 "contextmenu" : true,
54075 * The raw mousedown event for the entire grid.
54076 * @param {Roo.EventObject} e
54078 "mousedown" : true,
54081 * The raw mouseup event for the entire grid.
54082 * @param {Roo.EventObject} e
54087 * The raw mouseover event for the entire grid.
54088 * @param {Roo.EventObject} e
54090 "mouseover" : true,
54093 * The raw mouseout event for the entire grid.
54094 * @param {Roo.EventObject} e
54099 * The raw keypress event for the entire grid.
54100 * @param {Roo.EventObject} e
54105 * The raw keydown event for the entire grid.
54106 * @param {Roo.EventObject} e
54114 * Fires when a cell is clicked
54115 * @param {Grid} this
54116 * @param {Number} rowIndex
54117 * @param {Number} columnIndex
54118 * @param {Roo.EventObject} e
54120 "cellclick" : true,
54122 * @event celldblclick
54123 * Fires when a cell is double clicked
54124 * @param {Grid} this
54125 * @param {Number} rowIndex
54126 * @param {Number} columnIndex
54127 * @param {Roo.EventObject} e
54129 "celldblclick" : true,
54132 * Fires when a row is clicked
54133 * @param {Grid} this
54134 * @param {Number} rowIndex
54135 * @param {Roo.EventObject} e
54139 * @event rowdblclick
54140 * Fires when a row is double clicked
54141 * @param {Grid} this
54142 * @param {Number} rowIndex
54143 * @param {Roo.EventObject} e
54145 "rowdblclick" : true,
54147 * @event headerclick
54148 * Fires when a header is clicked
54149 * @param {Grid} this
54150 * @param {Number} columnIndex
54151 * @param {Roo.EventObject} e
54153 "headerclick" : true,
54155 * @event headerdblclick
54156 * Fires when a header cell is double clicked
54157 * @param {Grid} this
54158 * @param {Number} columnIndex
54159 * @param {Roo.EventObject} e
54161 "headerdblclick" : true,
54163 * @event rowcontextmenu
54164 * Fires when a row is right clicked
54165 * @param {Grid} this
54166 * @param {Number} rowIndex
54167 * @param {Roo.EventObject} e
54169 "rowcontextmenu" : true,
54171 * @event cellcontextmenu
54172 * Fires when a cell is right clicked
54173 * @param {Grid} this
54174 * @param {Number} rowIndex
54175 * @param {Number} cellIndex
54176 * @param {Roo.EventObject} e
54178 "cellcontextmenu" : true,
54180 * @event headercontextmenu
54181 * Fires when a header is right clicked
54182 * @param {Grid} this
54183 * @param {Number} columnIndex
54184 * @param {Roo.EventObject} e
54186 "headercontextmenu" : true,
54188 * @event bodyscroll
54189 * Fires when the body element is scrolled
54190 * @param {Number} scrollLeft
54191 * @param {Number} scrollTop
54193 "bodyscroll" : true,
54195 * @event columnresize
54196 * Fires when the user resizes a column
54197 * @param {Number} columnIndex
54198 * @param {Number} newSize
54200 "columnresize" : true,
54202 * @event columnmove
54203 * Fires when the user moves a column
54204 * @param {Number} oldIndex
54205 * @param {Number} newIndex
54207 "columnmove" : true,
54210 * Fires when row(s) start being dragged
54211 * @param {Grid} this
54212 * @param {Roo.GridDD} dd The drag drop object
54213 * @param {event} e The raw browser event
54215 "startdrag" : true,
54218 * Fires when a drag operation is complete
54219 * @param {Grid} this
54220 * @param {Roo.GridDD} dd The drag drop object
54221 * @param {event} e The raw browser event
54226 * Fires when dragged row(s) are dropped on a valid DD target
54227 * @param {Grid} this
54228 * @param {Roo.GridDD} dd The drag drop object
54229 * @param {String} targetId The target drag drop object
54230 * @param {event} e The raw browser event
54235 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54236 * @param {Grid} this
54237 * @param {Roo.GridDD} dd The drag drop object
54238 * @param {String} targetId The target drag drop object
54239 * @param {event} e The raw browser event
54244 * Fires when the dragged row(s) first cross another DD target while being dragged
54245 * @param {Grid} this
54246 * @param {Roo.GridDD} dd The drag drop object
54247 * @param {String} targetId The target drag drop object
54248 * @param {event} e The raw browser event
54250 "dragenter" : true,
54253 * Fires when the dragged row(s) leave another DD target while being dragged
54254 * @param {Grid} this
54255 * @param {Roo.GridDD} dd The drag drop object
54256 * @param {String} targetId The target drag drop object
54257 * @param {event} e The raw browser event
54262 * Fires when a row is rendered, so you can change add a style to it.
54263 * @param {GridView} gridview The grid view
54264 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54270 * Fires when the grid is rendered
54271 * @param {Grid} grid
54276 Roo.grid.Grid.superclass.constructor.call(this);
54278 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54281 * @cfg {String} ddGroup - drag drop group.
54285 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54287 minColumnWidth : 25,
54290 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54291 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54292 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54294 autoSizeColumns : false,
54297 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54299 autoSizeHeaders : true,
54302 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54304 monitorWindowResize : true,
54307 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54308 * rows measured to get a columns size. Default is 0 (all rows).
54310 maxRowsToMeasure : 0,
54313 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54315 trackMouseOver : true,
54318 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54322 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54324 enableDragDrop : false,
54327 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54329 enableColumnMove : true,
54332 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54334 enableColumnHide : true,
54337 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54339 enableRowHeightSync : false,
54342 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54347 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54349 autoHeight : false,
54352 * @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.
54354 autoExpandColumn : false,
54357 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54360 autoExpandMin : 50,
54363 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54365 autoExpandMax : 1000,
54368 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54373 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54377 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54387 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54388 * of a fixed width. Default is false.
54391 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54394 * Called once after all setup has been completed and the grid is ready to be rendered.
54395 * @return {Roo.grid.Grid} this
54397 render : function()
54399 var c = this.container;
54400 // try to detect autoHeight/width mode
54401 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54402 this.autoHeight = true;
54404 var view = this.getView();
54407 c.on("click", this.onClick, this);
54408 c.on("dblclick", this.onDblClick, this);
54409 c.on("contextmenu", this.onContextMenu, this);
54410 c.on("keydown", this.onKeyDown, this);
54412 c.on("touchstart", this.onTouchStart, this);
54415 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54417 this.getSelectionModel().init(this);
54422 this.loadMask = new Roo.LoadMask(this.container,
54423 Roo.apply({store:this.dataSource}, this.loadMask));
54427 if (this.toolbar && this.toolbar.xtype) {
54428 this.toolbar.container = this.getView().getHeaderPanel(true);
54429 this.toolbar = new Roo.Toolbar(this.toolbar);
54431 if (this.footer && this.footer.xtype) {
54432 this.footer.dataSource = this.getDataSource();
54433 this.footer.container = this.getView().getFooterPanel(true);
54434 this.footer = Roo.factory(this.footer, Roo);
54436 if (this.dropTarget && this.dropTarget.xtype) {
54437 delete this.dropTarget.xtype;
54438 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54442 this.rendered = true;
54443 this.fireEvent('render', this);
54448 * Reconfigures the grid to use a different Store and Column Model.
54449 * The View will be bound to the new objects and refreshed.
54450 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54451 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54453 reconfigure : function(dataSource, colModel){
54455 this.loadMask.destroy();
54456 this.loadMask = new Roo.LoadMask(this.container,
54457 Roo.apply({store:dataSource}, this.loadMask));
54459 this.view.bind(dataSource, colModel);
54460 this.dataSource = dataSource;
54461 this.colModel = colModel;
54462 this.view.refresh(true);
54466 onKeyDown : function(e){
54467 this.fireEvent("keydown", e);
54471 * Destroy this grid.
54472 * @param {Boolean} removeEl True to remove the element
54474 destroy : function(removeEl, keepListeners){
54476 this.loadMask.destroy();
54478 var c = this.container;
54479 c.removeAllListeners();
54480 this.view.destroy();
54481 this.colModel.purgeListeners();
54482 if(!keepListeners){
54483 this.purgeListeners();
54486 if(removeEl === true){
54492 processEvent : function(name, e){
54493 // does this fire select???
54494 //Roo.log('grid:processEvent ' + name);
54496 if (name != 'touchstart' ) {
54497 this.fireEvent(name, e);
54500 var t = e.getTarget();
54502 var header = v.findHeaderIndex(t);
54503 if(header !== false){
54504 var ename = name == 'touchstart' ? 'click' : name;
54506 this.fireEvent("header" + ename, this, header, e);
54508 var row = v.findRowIndex(t);
54509 var cell = v.findCellIndex(t);
54510 if (name == 'touchstart') {
54511 // first touch is always a click.
54512 // hopefull this happens after selection is updated.?
54515 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54516 var cs = this.selModel.getSelectedCell();
54517 if (row == cs[0] && cell == cs[1]){
54521 if (typeof(this.selModel.getSelections) != 'undefined') {
54522 var cs = this.selModel.getSelections();
54523 var ds = this.dataSource;
54524 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54535 this.fireEvent("row" + name, this, row, e);
54536 if(cell !== false){
54537 this.fireEvent("cell" + name, this, row, cell, e);
54544 onClick : function(e){
54545 this.processEvent("click", e);
54548 onTouchStart : function(e){
54549 this.processEvent("touchstart", e);
54553 onContextMenu : function(e, t){
54554 this.processEvent("contextmenu", e);
54558 onDblClick : function(e){
54559 this.processEvent("dblclick", e);
54563 walkCells : function(row, col, step, fn, scope){
54564 var cm = this.colModel, clen = cm.getColumnCount();
54565 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54577 if(fn.call(scope || this, row, col, cm) === true){
54595 if(fn.call(scope || this, row, col, cm) === true){
54607 getSelections : function(){
54608 return this.selModel.getSelections();
54612 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54613 * but if manual update is required this method will initiate it.
54615 autoSize : function(){
54617 this.view.layout();
54618 if(this.view.adjustForScroll){
54619 this.view.adjustForScroll();
54625 * Returns the grid's underlying element.
54626 * @return {Element} The element
54628 getGridEl : function(){
54629 return this.container;
54632 // private for compatibility, overridden by editor grid
54633 stopEditing : function(){},
54636 * Returns the grid's SelectionModel.
54637 * @return {SelectionModel}
54639 getSelectionModel : function(){
54640 if(!this.selModel){
54641 this.selModel = new Roo.grid.RowSelectionModel();
54643 return this.selModel;
54647 * Returns the grid's DataSource.
54648 * @return {DataSource}
54650 getDataSource : function(){
54651 return this.dataSource;
54655 * Returns the grid's ColumnModel.
54656 * @return {ColumnModel}
54658 getColumnModel : function(){
54659 return this.colModel;
54663 * Returns the grid's GridView object.
54664 * @return {GridView}
54666 getView : function(){
54668 this.view = new Roo.grid.GridView(this.viewConfig);
54673 * Called to get grid's drag proxy text, by default returns this.ddText.
54676 getDragDropText : function(){
54677 var count = this.selModel.getCount();
54678 return String.format(this.ddText, count, count == 1 ? '' : 's');
54682 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54683 * %0 is replaced with the number of selected rows.
54686 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54688 * Ext JS Library 1.1.1
54689 * Copyright(c) 2006-2007, Ext JS, LLC.
54691 * Originally Released Under LGPL - original licence link has changed is not relivant.
54694 * <script type="text/javascript">
54697 Roo.grid.AbstractGridView = function(){
54701 "beforerowremoved" : true,
54702 "beforerowsinserted" : true,
54703 "beforerefresh" : true,
54704 "rowremoved" : true,
54705 "rowsinserted" : true,
54706 "rowupdated" : true,
54709 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54712 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54713 rowClass : "x-grid-row",
54714 cellClass : "x-grid-cell",
54715 tdClass : "x-grid-td",
54716 hdClass : "x-grid-hd",
54717 splitClass : "x-grid-hd-split",
54719 init: function(grid){
54721 var cid = this.grid.getGridEl().id;
54722 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54723 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54724 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54725 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54728 getColumnRenderers : function(){
54729 var renderers = [];
54730 var cm = this.grid.colModel;
54731 var colCount = cm.getColumnCount();
54732 for(var i = 0; i < colCount; i++){
54733 renderers[i] = cm.getRenderer(i);
54738 getColumnIds : function(){
54740 var cm = this.grid.colModel;
54741 var colCount = cm.getColumnCount();
54742 for(var i = 0; i < colCount; i++){
54743 ids[i] = cm.getColumnId(i);
54748 getDataIndexes : function(){
54749 if(!this.indexMap){
54750 this.indexMap = this.buildIndexMap();
54752 return this.indexMap.colToData;
54755 getColumnIndexByDataIndex : function(dataIndex){
54756 if(!this.indexMap){
54757 this.indexMap = this.buildIndexMap();
54759 return this.indexMap.dataToCol[dataIndex];
54763 * Set a css style for a column dynamically.
54764 * @param {Number} colIndex The index of the column
54765 * @param {String} name The css property name
54766 * @param {String} value The css value
54768 setCSSStyle : function(colIndex, name, value){
54769 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54770 Roo.util.CSS.updateRule(selector, name, value);
54773 generateRules : function(cm){
54774 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54775 Roo.util.CSS.removeStyleSheet(rulesId);
54776 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54777 var cid = cm.getColumnId(i);
54778 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54779 this.tdSelector, cid, " {\n}\n",
54780 this.hdSelector, cid, " {\n}\n",
54781 this.splitSelector, cid, " {\n}\n");
54783 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54787 * Ext JS Library 1.1.1
54788 * Copyright(c) 2006-2007, Ext JS, LLC.
54790 * Originally Released Under LGPL - original licence link has changed is not relivant.
54793 * <script type="text/javascript">
54797 // This is a support class used internally by the Grid components
54798 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54800 this.view = grid.getView();
54801 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54802 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54804 this.setHandleElId(Roo.id(hd));
54805 this.setOuterHandleElId(Roo.id(hd2));
54807 this.scroll = false;
54809 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54811 getDragData : function(e){
54812 var t = Roo.lib.Event.getTarget(e);
54813 var h = this.view.findHeaderCell(t);
54815 return {ddel: h.firstChild, header:h};
54820 onInitDrag : function(e){
54821 this.view.headersDisabled = true;
54822 var clone = this.dragData.ddel.cloneNode(true);
54823 clone.id = Roo.id();
54824 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54825 this.proxy.update(clone);
54829 afterValidDrop : function(){
54831 setTimeout(function(){
54832 v.headersDisabled = false;
54836 afterInvalidDrop : function(){
54838 setTimeout(function(){
54839 v.headersDisabled = false;
54845 * Ext JS Library 1.1.1
54846 * Copyright(c) 2006-2007, Ext JS, LLC.
54848 * Originally Released Under LGPL - original licence link has changed is not relivant.
54851 * <script type="text/javascript">
54854 // This is a support class used internally by the Grid components
54855 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54857 this.view = grid.getView();
54858 // split the proxies so they don't interfere with mouse events
54859 this.proxyTop = Roo.DomHelper.append(document.body, {
54860 cls:"col-move-top", html:" "
54862 this.proxyBottom = Roo.DomHelper.append(document.body, {
54863 cls:"col-move-bottom", html:" "
54865 this.proxyTop.hide = this.proxyBottom.hide = function(){
54866 this.setLeftTop(-100,-100);
54867 this.setStyle("visibility", "hidden");
54869 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54870 // temporarily disabled
54871 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54872 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54874 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54875 proxyOffsets : [-4, -9],
54876 fly: Roo.Element.fly,
54878 getTargetFromEvent : function(e){
54879 var t = Roo.lib.Event.getTarget(e);
54880 var cindex = this.view.findCellIndex(t);
54881 if(cindex !== false){
54882 return this.view.getHeaderCell(cindex);
54887 nextVisible : function(h){
54888 var v = this.view, cm = this.grid.colModel;
54891 if(!cm.isHidden(v.getCellIndex(h))){
54899 prevVisible : function(h){
54900 var v = this.view, cm = this.grid.colModel;
54903 if(!cm.isHidden(v.getCellIndex(h))){
54911 positionIndicator : function(h, n, e){
54912 var x = Roo.lib.Event.getPageX(e);
54913 var r = Roo.lib.Dom.getRegion(n.firstChild);
54914 var px, pt, py = r.top + this.proxyOffsets[1];
54915 if((r.right - x) <= (r.right-r.left)/2){
54916 px = r.right+this.view.borderWidth;
54922 var oldIndex = this.view.getCellIndex(h);
54923 var newIndex = this.view.getCellIndex(n);
54925 if(this.grid.colModel.isFixed(newIndex)){
54929 var locked = this.grid.colModel.isLocked(newIndex);
54934 if(oldIndex < newIndex){
54937 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
54940 px += this.proxyOffsets[0];
54941 this.proxyTop.setLeftTop(px, py);
54942 this.proxyTop.show();
54943 if(!this.bottomOffset){
54944 this.bottomOffset = this.view.mainHd.getHeight();
54946 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
54947 this.proxyBottom.show();
54951 onNodeEnter : function(n, dd, e, data){
54952 if(data.header != n){
54953 this.positionIndicator(data.header, n, e);
54957 onNodeOver : function(n, dd, e, data){
54958 var result = false;
54959 if(data.header != n){
54960 result = this.positionIndicator(data.header, n, e);
54963 this.proxyTop.hide();
54964 this.proxyBottom.hide();
54966 return result ? this.dropAllowed : this.dropNotAllowed;
54969 onNodeOut : function(n, dd, e, data){
54970 this.proxyTop.hide();
54971 this.proxyBottom.hide();
54974 onNodeDrop : function(n, dd, e, data){
54975 var h = data.header;
54977 var cm = this.grid.colModel;
54978 var x = Roo.lib.Event.getPageX(e);
54979 var r = Roo.lib.Dom.getRegion(n.firstChild);
54980 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
54981 var oldIndex = this.view.getCellIndex(h);
54982 var newIndex = this.view.getCellIndex(n);
54983 var locked = cm.isLocked(newIndex);
54987 if(oldIndex < newIndex){
54990 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
54993 cm.setLocked(oldIndex, locked, true);
54994 cm.moveColumn(oldIndex, newIndex);
54995 this.grid.fireEvent("columnmove", oldIndex, newIndex);
55003 * Ext JS Library 1.1.1
55004 * Copyright(c) 2006-2007, Ext JS, LLC.
55006 * Originally Released Under LGPL - original licence link has changed is not relivant.
55009 * <script type="text/javascript">
55013 * @class Roo.grid.GridView
55014 * @extends Roo.util.Observable
55017 * @param {Object} config
55019 Roo.grid.GridView = function(config){
55020 Roo.grid.GridView.superclass.constructor.call(this);
55023 Roo.apply(this, config);
55026 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
55028 unselectable : 'unselectable="on"',
55029 unselectableCls : 'x-unselectable',
55032 rowClass : "x-grid-row",
55034 cellClass : "x-grid-col",
55036 tdClass : "x-grid-td",
55038 hdClass : "x-grid-hd",
55040 splitClass : "x-grid-split",
55042 sortClasses : ["sort-asc", "sort-desc"],
55044 enableMoveAnim : false,
55048 dh : Roo.DomHelper,
55050 fly : Roo.Element.fly,
55052 css : Roo.util.CSS,
55058 scrollIncrement : 22,
55060 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55062 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55064 bind : function(ds, cm){
55066 this.ds.un("load", this.onLoad, this);
55067 this.ds.un("datachanged", this.onDataChange, this);
55068 this.ds.un("add", this.onAdd, this);
55069 this.ds.un("remove", this.onRemove, this);
55070 this.ds.un("update", this.onUpdate, this);
55071 this.ds.un("clear", this.onClear, this);
55074 ds.on("load", this.onLoad, this);
55075 ds.on("datachanged", this.onDataChange, this);
55076 ds.on("add", this.onAdd, this);
55077 ds.on("remove", this.onRemove, this);
55078 ds.on("update", this.onUpdate, this);
55079 ds.on("clear", this.onClear, this);
55084 this.cm.un("widthchange", this.onColWidthChange, this);
55085 this.cm.un("headerchange", this.onHeaderChange, this);
55086 this.cm.un("hiddenchange", this.onHiddenChange, this);
55087 this.cm.un("columnmoved", this.onColumnMove, this);
55088 this.cm.un("columnlockchange", this.onColumnLock, this);
55091 this.generateRules(cm);
55092 cm.on("widthchange", this.onColWidthChange, this);
55093 cm.on("headerchange", this.onHeaderChange, this);
55094 cm.on("hiddenchange", this.onHiddenChange, this);
55095 cm.on("columnmoved", this.onColumnMove, this);
55096 cm.on("columnlockchange", this.onColumnLock, this);
55101 init: function(grid){
55102 Roo.grid.GridView.superclass.init.call(this, grid);
55104 this.bind(grid.dataSource, grid.colModel);
55106 grid.on("headerclick", this.handleHeaderClick, this);
55108 if(grid.trackMouseOver){
55109 grid.on("mouseover", this.onRowOver, this);
55110 grid.on("mouseout", this.onRowOut, this);
55112 grid.cancelTextSelection = function(){};
55113 this.gridId = grid.id;
55115 var tpls = this.templates || {};
55118 tpls.master = new Roo.Template(
55119 '<div class="x-grid" hidefocus="true">',
55120 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55121 '<div class="x-grid-topbar"></div>',
55122 '<div class="x-grid-scroller"><div></div></div>',
55123 '<div class="x-grid-locked">',
55124 '<div class="x-grid-header">{lockedHeader}</div>',
55125 '<div class="x-grid-body">{lockedBody}</div>',
55127 '<div class="x-grid-viewport">',
55128 '<div class="x-grid-header">{header}</div>',
55129 '<div class="x-grid-body">{body}</div>',
55131 '<div class="x-grid-bottombar"></div>',
55133 '<div class="x-grid-resize-proxy"> </div>',
55136 tpls.master.disableformats = true;
55140 tpls.header = new Roo.Template(
55141 '<table border="0" cellspacing="0" cellpadding="0">',
55142 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55145 tpls.header.disableformats = true;
55147 tpls.header.compile();
55150 tpls.hcell = new Roo.Template(
55151 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55152 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55155 tpls.hcell.disableFormats = true;
55157 tpls.hcell.compile();
55160 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55161 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55162 tpls.hsplit.disableFormats = true;
55164 tpls.hsplit.compile();
55167 tpls.body = new Roo.Template(
55168 '<table border="0" cellspacing="0" cellpadding="0">',
55169 "<tbody>{rows}</tbody>",
55172 tpls.body.disableFormats = true;
55174 tpls.body.compile();
55177 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55178 tpls.row.disableFormats = true;
55180 tpls.row.compile();
55183 tpls.cell = new Roo.Template(
55184 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55185 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55186 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55189 tpls.cell.disableFormats = true;
55191 tpls.cell.compile();
55193 this.templates = tpls;
55196 // remap these for backwards compat
55197 onColWidthChange : function(){
55198 this.updateColumns.apply(this, arguments);
55200 onHeaderChange : function(){
55201 this.updateHeaders.apply(this, arguments);
55203 onHiddenChange : function(){
55204 this.handleHiddenChange.apply(this, arguments);
55206 onColumnMove : function(){
55207 this.handleColumnMove.apply(this, arguments);
55209 onColumnLock : function(){
55210 this.handleLockChange.apply(this, arguments);
55213 onDataChange : function(){
55215 this.updateHeaderSortState();
55218 onClear : function(){
55222 onUpdate : function(ds, record){
55223 this.refreshRow(record);
55226 refreshRow : function(record){
55227 var ds = this.ds, index;
55228 if(typeof record == 'number'){
55230 record = ds.getAt(index);
55232 index = ds.indexOf(record);
55234 this.insertRows(ds, index, index, true);
55235 this.onRemove(ds, record, index+1, true);
55236 this.syncRowHeights(index, index);
55238 this.fireEvent("rowupdated", this, index, record);
55241 onAdd : function(ds, records, index){
55242 this.insertRows(ds, index, index + (records.length-1));
55245 onRemove : function(ds, record, index, isUpdate){
55246 if(isUpdate !== true){
55247 this.fireEvent("beforerowremoved", this, index, record);
55249 var bt = this.getBodyTable(), lt = this.getLockedTable();
55250 if(bt.rows[index]){
55251 bt.firstChild.removeChild(bt.rows[index]);
55253 if(lt.rows[index]){
55254 lt.firstChild.removeChild(lt.rows[index]);
55256 if(isUpdate !== true){
55257 this.stripeRows(index);
55258 this.syncRowHeights(index, index);
55260 this.fireEvent("rowremoved", this, index, record);
55264 onLoad : function(){
55265 this.scrollToTop();
55269 * Scrolls the grid to the top
55271 scrollToTop : function(){
55273 this.scroller.dom.scrollTop = 0;
55279 * Gets a panel in the header of the grid that can be used for toolbars etc.
55280 * After modifying the contents of this panel a call to grid.autoSize() may be
55281 * required to register any changes in size.
55282 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55283 * @return Roo.Element
55285 getHeaderPanel : function(doShow){
55287 this.headerPanel.show();
55289 return this.headerPanel;
55293 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55294 * After modifying the contents of this panel a call to grid.autoSize() may be
55295 * required to register any changes in size.
55296 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55297 * @return Roo.Element
55299 getFooterPanel : function(doShow){
55301 this.footerPanel.show();
55303 return this.footerPanel;
55306 initElements : function(){
55307 var E = Roo.Element;
55308 var el = this.grid.getGridEl().dom.firstChild;
55309 var cs = el.childNodes;
55311 this.el = new E(el);
55313 this.focusEl = new E(el.firstChild);
55314 this.focusEl.swallowEvent("click", true);
55316 this.headerPanel = new E(cs[1]);
55317 this.headerPanel.enableDisplayMode("block");
55319 this.scroller = new E(cs[2]);
55320 this.scrollSizer = new E(this.scroller.dom.firstChild);
55322 this.lockedWrap = new E(cs[3]);
55323 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55324 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55326 this.mainWrap = new E(cs[4]);
55327 this.mainHd = new E(this.mainWrap.dom.firstChild);
55328 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55330 this.footerPanel = new E(cs[5]);
55331 this.footerPanel.enableDisplayMode("block");
55333 this.resizeProxy = new E(cs[6]);
55335 this.headerSelector = String.format(
55336 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55337 this.lockedHd.id, this.mainHd.id
55340 this.splitterSelector = String.format(
55341 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55342 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55345 idToCssName : function(s)
55347 return s.replace(/[^a-z0-9]+/ig, '-');
55350 getHeaderCell : function(index){
55351 return Roo.DomQuery.select(this.headerSelector)[index];
55354 getHeaderCellMeasure : function(index){
55355 return this.getHeaderCell(index).firstChild;
55358 getHeaderCellText : function(index){
55359 return this.getHeaderCell(index).firstChild.firstChild;
55362 getLockedTable : function(){
55363 return this.lockedBody.dom.firstChild;
55366 getBodyTable : function(){
55367 return this.mainBody.dom.firstChild;
55370 getLockedRow : function(index){
55371 return this.getLockedTable().rows[index];
55374 getRow : function(index){
55375 return this.getBodyTable().rows[index];
55378 getRowComposite : function(index){
55380 this.rowEl = new Roo.CompositeElementLite();
55382 var els = [], lrow, mrow;
55383 if(lrow = this.getLockedRow(index)){
55386 if(mrow = this.getRow(index)){
55389 this.rowEl.elements = els;
55393 * Gets the 'td' of the cell
55395 * @param {Integer} rowIndex row to select
55396 * @param {Integer} colIndex column to select
55400 getCell : function(rowIndex, colIndex){
55401 var locked = this.cm.getLockedCount();
55403 if(colIndex < locked){
55404 source = this.lockedBody.dom.firstChild;
55406 source = this.mainBody.dom.firstChild;
55407 colIndex -= locked;
55409 return source.rows[rowIndex].childNodes[colIndex];
55412 getCellText : function(rowIndex, colIndex){
55413 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55416 getCellBox : function(cell){
55417 var b = this.fly(cell).getBox();
55418 if(Roo.isOpera){ // opera fails to report the Y
55419 b.y = cell.offsetTop + this.mainBody.getY();
55424 getCellIndex : function(cell){
55425 var id = String(cell.className).match(this.cellRE);
55427 return parseInt(id[1], 10);
55432 findHeaderIndex : function(n){
55433 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55434 return r ? this.getCellIndex(r) : false;
55437 findHeaderCell : function(n){
55438 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55439 return r ? r : false;
55442 findRowIndex : function(n){
55446 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55447 return r ? r.rowIndex : false;
55450 findCellIndex : function(node){
55451 var stop = this.el.dom;
55452 while(node && node != stop){
55453 if(this.findRE.test(node.className)){
55454 return this.getCellIndex(node);
55456 node = node.parentNode;
55461 getColumnId : function(index){
55462 return this.cm.getColumnId(index);
55465 getSplitters : function()
55467 if(this.splitterSelector){
55468 return Roo.DomQuery.select(this.splitterSelector);
55474 getSplitter : function(index){
55475 return this.getSplitters()[index];
55478 onRowOver : function(e, t){
55480 if((row = this.findRowIndex(t)) !== false){
55481 this.getRowComposite(row).addClass("x-grid-row-over");
55485 onRowOut : function(e, t){
55487 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55488 this.getRowComposite(row).removeClass("x-grid-row-over");
55492 renderHeaders : function(){
55494 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55495 var cb = [], lb = [], sb = [], lsb = [], p = {};
55496 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55497 p.cellId = "x-grid-hd-0-" + i;
55498 p.splitId = "x-grid-csplit-0-" + i;
55499 p.id = cm.getColumnId(i);
55500 p.value = cm.getColumnHeader(i) || "";
55501 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55502 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55503 if(!cm.isLocked(i)){
55504 cb[cb.length] = ct.apply(p);
55505 sb[sb.length] = st.apply(p);
55507 lb[lb.length] = ct.apply(p);
55508 lsb[lsb.length] = st.apply(p);
55511 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55512 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55515 updateHeaders : function(){
55516 var html = this.renderHeaders();
55517 this.lockedHd.update(html[0]);
55518 this.mainHd.update(html[1]);
55522 * Focuses the specified row.
55523 * @param {Number} row The row index
55525 focusRow : function(row)
55527 //Roo.log('GridView.focusRow');
55528 var x = this.scroller.dom.scrollLeft;
55529 this.focusCell(row, 0, false);
55530 this.scroller.dom.scrollLeft = x;
55534 * Focuses the specified cell.
55535 * @param {Number} row The row index
55536 * @param {Number} col The column index
55537 * @param {Boolean} hscroll false to disable horizontal scrolling
55539 focusCell : function(row, col, hscroll)
55541 //Roo.log('GridView.focusCell');
55542 var el = this.ensureVisible(row, col, hscroll);
55543 this.focusEl.alignTo(el, "tl-tl");
55545 this.focusEl.focus();
55547 this.focusEl.focus.defer(1, this.focusEl);
55552 * Scrolls the specified cell into view
55553 * @param {Number} row The row index
55554 * @param {Number} col The column index
55555 * @param {Boolean} hscroll false to disable horizontal scrolling
55557 ensureVisible : function(row, col, hscroll)
55559 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55560 //return null; //disable for testing.
55561 if(typeof row != "number"){
55562 row = row.rowIndex;
55564 if(row < 0 && row >= this.ds.getCount()){
55567 col = (col !== undefined ? col : 0);
55568 var cm = this.grid.colModel;
55569 while(cm.isHidden(col)){
55573 var el = this.getCell(row, col);
55577 var c = this.scroller.dom;
55579 var ctop = parseInt(el.offsetTop, 10);
55580 var cleft = parseInt(el.offsetLeft, 10);
55581 var cbot = ctop + el.offsetHeight;
55582 var cright = cleft + el.offsetWidth;
55584 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55585 var stop = parseInt(c.scrollTop, 10);
55586 var sleft = parseInt(c.scrollLeft, 10);
55587 var sbot = stop + ch;
55588 var sright = sleft + c.clientWidth;
55590 Roo.log('GridView.ensureVisible:' +
55592 ' c.clientHeight:' + c.clientHeight +
55593 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55601 c.scrollTop = ctop;
55602 //Roo.log("set scrolltop to ctop DISABLE?");
55603 }else if(cbot > sbot){
55604 //Roo.log("set scrolltop to cbot-ch");
55605 c.scrollTop = cbot-ch;
55608 if(hscroll !== false){
55610 c.scrollLeft = cleft;
55611 }else if(cright > sright){
55612 c.scrollLeft = cright-c.clientWidth;
55619 updateColumns : function(){
55620 this.grid.stopEditing();
55621 var cm = this.grid.colModel, colIds = this.getColumnIds();
55622 //var totalWidth = cm.getTotalWidth();
55624 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55625 //if(cm.isHidden(i)) continue;
55626 var w = cm.getColumnWidth(i);
55627 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55628 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55630 this.updateSplitters();
55633 generateRules : function(cm){
55634 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55635 Roo.util.CSS.removeStyleSheet(rulesId);
55636 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55637 var cid = cm.getColumnId(i);
55639 if(cm.config[i].align){
55640 align = 'text-align:'+cm.config[i].align+';';
55643 if(cm.isHidden(i)){
55644 hidden = 'display:none;';
55646 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55648 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55649 this.hdSelector, cid, " {\n", align, width, "}\n",
55650 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55651 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55653 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55656 updateSplitters : function(){
55657 var cm = this.cm, s = this.getSplitters();
55658 if(s){ // splitters not created yet
55659 var pos = 0, locked = true;
55660 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55661 if(cm.isHidden(i)) {
55664 var w = cm.getColumnWidth(i); // make sure it's a number
55665 if(!cm.isLocked(i) && locked){
55670 s[i].style.left = (pos-this.splitOffset) + "px";
55675 handleHiddenChange : function(colModel, colIndex, hidden){
55677 this.hideColumn(colIndex);
55679 this.unhideColumn(colIndex);
55683 hideColumn : function(colIndex){
55684 var cid = this.getColumnId(colIndex);
55685 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55686 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55688 this.updateHeaders();
55690 this.updateSplitters();
55694 unhideColumn : function(colIndex){
55695 var cid = this.getColumnId(colIndex);
55696 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55697 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55700 this.updateHeaders();
55702 this.updateSplitters();
55706 insertRows : function(dm, firstRow, lastRow, isUpdate){
55707 if(firstRow == 0 && lastRow == dm.getCount()-1){
55711 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55713 var s = this.getScrollState();
55714 var markup = this.renderRows(firstRow, lastRow);
55715 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55716 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55717 this.restoreScroll(s);
55719 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55720 this.syncRowHeights(firstRow, lastRow);
55721 this.stripeRows(firstRow);
55727 bufferRows : function(markup, target, index){
55728 var before = null, trows = target.rows, tbody = target.tBodies[0];
55729 if(index < trows.length){
55730 before = trows[index];
55732 var b = document.createElement("div");
55733 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55734 var rows = b.firstChild.rows;
55735 for(var i = 0, len = rows.length; i < len; i++){
55737 tbody.insertBefore(rows[0], before);
55739 tbody.appendChild(rows[0]);
55746 deleteRows : function(dm, firstRow, lastRow){
55747 if(dm.getRowCount()<1){
55748 this.fireEvent("beforerefresh", this);
55749 this.mainBody.update("");
55750 this.lockedBody.update("");
55751 this.fireEvent("refresh", this);
55753 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55754 var bt = this.getBodyTable();
55755 var tbody = bt.firstChild;
55756 var rows = bt.rows;
55757 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55758 tbody.removeChild(rows[firstRow]);
55760 this.stripeRows(firstRow);
55761 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55765 updateRows : function(dataSource, firstRow, lastRow){
55766 var s = this.getScrollState();
55768 this.restoreScroll(s);
55771 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55775 this.updateHeaderSortState();
55778 getScrollState : function(){
55780 var sb = this.scroller.dom;
55781 return {left: sb.scrollLeft, top: sb.scrollTop};
55784 stripeRows : function(startRow){
55785 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55788 startRow = startRow || 0;
55789 var rows = this.getBodyTable().rows;
55790 var lrows = this.getLockedTable().rows;
55791 var cls = ' x-grid-row-alt ';
55792 for(var i = startRow, len = rows.length; i < len; i++){
55793 var row = rows[i], lrow = lrows[i];
55794 var isAlt = ((i+1) % 2 == 0);
55795 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55796 if(isAlt == hasAlt){
55800 row.className += " x-grid-row-alt";
55802 row.className = row.className.replace("x-grid-row-alt", "");
55805 lrow.className = row.className;
55810 restoreScroll : function(state){
55811 //Roo.log('GridView.restoreScroll');
55812 var sb = this.scroller.dom;
55813 sb.scrollLeft = state.left;
55814 sb.scrollTop = state.top;
55818 syncScroll : function(){
55819 //Roo.log('GridView.syncScroll');
55820 var sb = this.scroller.dom;
55821 var sh = this.mainHd.dom;
55822 var bs = this.mainBody.dom;
55823 var lv = this.lockedBody.dom;
55824 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55825 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55828 handleScroll : function(e){
55830 var sb = this.scroller.dom;
55831 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55835 handleWheel : function(e){
55836 var d = e.getWheelDelta();
55837 this.scroller.dom.scrollTop -= d*22;
55838 // set this here to prevent jumpy scrolling on large tables
55839 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55843 renderRows : function(startRow, endRow){
55844 // pull in all the crap needed to render rows
55845 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55846 var colCount = cm.getColumnCount();
55848 if(ds.getCount() < 1){
55852 // build a map for all the columns
55854 for(var i = 0; i < colCount; i++){
55855 var name = cm.getDataIndex(i);
55857 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55858 renderer : cm.getRenderer(i),
55859 id : cm.getColumnId(i),
55860 locked : cm.isLocked(i),
55861 has_editor : cm.isCellEditable(i)
55865 startRow = startRow || 0;
55866 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55868 // records to render
55869 var rs = ds.getRange(startRow, endRow);
55871 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55874 // As much as I hate to duplicate code, this was branched because FireFox really hates
55875 // [].join("") on strings. The performance difference was substantial enough to
55876 // branch this function
55877 doRender : Roo.isGecko ?
55878 function(cs, rs, ds, startRow, colCount, stripe){
55879 var ts = this.templates, ct = ts.cell, rt = ts.row;
55881 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55883 var hasListener = this.grid.hasListener('rowclass');
55885 for(var j = 0, len = rs.length; j < len; j++){
55886 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
55887 for(var i = 0; i < colCount; i++){
55889 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55891 p.css = p.attr = "";
55892 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55893 if(p.value == undefined || p.value === "") {
55894 p.value = " ";
55897 p.css += ' x-grid-editable-cell';
55899 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
55900 p.css += ' x-grid-dirty-cell';
55902 var markup = ct.apply(p);
55910 if(stripe && ((rowIndex+1) % 2 == 0)){
55911 alt.push("x-grid-row-alt")
55914 alt.push( " x-grid-dirty-row");
55917 if(this.getRowClass){
55918 alt.push(this.getRowClass(r, rowIndex));
55924 rowIndex : rowIndex,
55927 this.grid.fireEvent('rowclass', this, rowcfg);
55928 alt.push(rowcfg.rowClass);
55930 rp.alt = alt.join(" ");
55931 lbuf+= rt.apply(rp);
55933 buf+= rt.apply(rp);
55935 return [lbuf, buf];
55937 function(cs, rs, ds, startRow, colCount, stripe){
55938 var ts = this.templates, ct = ts.cell, rt = ts.row;
55940 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55941 var hasListener = this.grid.hasListener('rowclass');
55944 for(var j = 0, len = rs.length; j < len; j++){
55945 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
55946 for(var i = 0; i < colCount; i++){
55948 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55950 p.css = p.attr = "";
55951 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55952 if(p.value == undefined || p.value === "") {
55953 p.value = " ";
55957 p.css += ' x-grid-editable-cell';
55959 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
55960 p.css += ' x-grid-dirty-cell'
55963 var markup = ct.apply(p);
55965 cb[cb.length] = markup;
55967 lcb[lcb.length] = markup;
55971 if(stripe && ((rowIndex+1) % 2 == 0)){
55972 alt.push( "x-grid-row-alt");
55975 alt.push(" x-grid-dirty-row");
55978 if(this.getRowClass){
55979 alt.push( this.getRowClass(r, rowIndex));
55985 rowIndex : rowIndex,
55988 this.grid.fireEvent('rowclass', this, rowcfg);
55989 alt.push(rowcfg.rowClass);
55992 rp.alt = alt.join(" ");
55993 rp.cells = lcb.join("");
55994 lbuf[lbuf.length] = rt.apply(rp);
55995 rp.cells = cb.join("");
55996 buf[buf.length] = rt.apply(rp);
55998 return [lbuf.join(""), buf.join("")];
56001 renderBody : function(){
56002 var markup = this.renderRows();
56003 var bt = this.templates.body;
56004 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
56008 * Refreshes the grid
56009 * @param {Boolean} headersToo
56011 refresh : function(headersToo){
56012 this.fireEvent("beforerefresh", this);
56013 this.grid.stopEditing();
56014 var result = this.renderBody();
56015 this.lockedBody.update(result[0]);
56016 this.mainBody.update(result[1]);
56017 if(headersToo === true){
56018 this.updateHeaders();
56019 this.updateColumns();
56020 this.updateSplitters();
56021 this.updateHeaderSortState();
56023 this.syncRowHeights();
56025 this.fireEvent("refresh", this);
56028 handleColumnMove : function(cm, oldIndex, newIndex){
56029 this.indexMap = null;
56030 var s = this.getScrollState();
56031 this.refresh(true);
56032 this.restoreScroll(s);
56033 this.afterMove(newIndex);
56036 afterMove : function(colIndex){
56037 if(this.enableMoveAnim && Roo.enableFx){
56038 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56040 // if multisort - fix sortOrder, and reload..
56041 if (this.grid.dataSource.multiSort) {
56042 // the we can call sort again..
56043 var dm = this.grid.dataSource;
56044 var cm = this.grid.colModel;
56046 for(var i = 0; i < cm.config.length; i++ ) {
56048 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56049 continue; // dont' bother, it's not in sort list or being set.
56052 so.push(cm.config[i].dataIndex);
56055 dm.load(dm.lastOptions);
56062 updateCell : function(dm, rowIndex, dataIndex){
56063 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56064 if(typeof colIndex == "undefined"){ // not present in grid
56067 var cm = this.grid.colModel;
56068 var cell = this.getCell(rowIndex, colIndex);
56069 var cellText = this.getCellText(rowIndex, colIndex);
56072 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56073 id : cm.getColumnId(colIndex),
56074 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56076 var renderer = cm.getRenderer(colIndex);
56077 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56078 if(typeof val == "undefined" || val === "") {
56081 cellText.innerHTML = val;
56082 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56083 this.syncRowHeights(rowIndex, rowIndex);
56086 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56088 if(this.grid.autoSizeHeaders){
56089 var h = this.getHeaderCellMeasure(colIndex);
56090 maxWidth = Math.max(maxWidth, h.scrollWidth);
56093 if(this.cm.isLocked(colIndex)){
56094 tb = this.getLockedTable();
56097 tb = this.getBodyTable();
56098 index = colIndex - this.cm.getLockedCount();
56101 var rows = tb.rows;
56102 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56103 for(var i = 0; i < stopIndex; i++){
56104 var cell = rows[i].childNodes[index].firstChild;
56105 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56108 return maxWidth + /*margin for error in IE*/ 5;
56111 * Autofit a column to its content.
56112 * @param {Number} colIndex
56113 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56115 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56116 if(this.cm.isHidden(colIndex)){
56117 return; // can't calc a hidden column
56120 var cid = this.cm.getColumnId(colIndex);
56121 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56122 if(this.grid.autoSizeHeaders){
56123 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56126 var newWidth = this.calcColumnWidth(colIndex);
56127 this.cm.setColumnWidth(colIndex,
56128 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56129 if(!suppressEvent){
56130 this.grid.fireEvent("columnresize", colIndex, newWidth);
56135 * Autofits all columns to their content and then expands to fit any extra space in the grid
56137 autoSizeColumns : function(){
56138 var cm = this.grid.colModel;
56139 var colCount = cm.getColumnCount();
56140 for(var i = 0; i < colCount; i++){
56141 this.autoSizeColumn(i, true, true);
56143 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56146 this.updateColumns();
56152 * Autofits all columns to the grid's width proportionate with their current size
56153 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56155 fitColumns : function(reserveScrollSpace){
56156 var cm = this.grid.colModel;
56157 var colCount = cm.getColumnCount();
56161 for (i = 0; i < colCount; i++){
56162 if(!cm.isHidden(i) && !cm.isFixed(i)){
56163 w = cm.getColumnWidth(i);
56169 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56170 if(reserveScrollSpace){
56173 var frac = (avail - cm.getTotalWidth())/width;
56174 while (cols.length){
56177 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56179 this.updateColumns();
56183 onRowSelect : function(rowIndex){
56184 var row = this.getRowComposite(rowIndex);
56185 row.addClass("x-grid-row-selected");
56188 onRowDeselect : function(rowIndex){
56189 var row = this.getRowComposite(rowIndex);
56190 row.removeClass("x-grid-row-selected");
56193 onCellSelect : function(row, col){
56194 var cell = this.getCell(row, col);
56196 Roo.fly(cell).addClass("x-grid-cell-selected");
56200 onCellDeselect : function(row, col){
56201 var cell = this.getCell(row, col);
56203 Roo.fly(cell).removeClass("x-grid-cell-selected");
56207 updateHeaderSortState : function(){
56209 // sort state can be single { field: xxx, direction : yyy}
56210 // or { xxx=>ASC , yyy : DESC ..... }
56213 if (!this.ds.multiSort) {
56214 var state = this.ds.getSortState();
56218 mstate[state.field] = state.direction;
56219 // FIXME... - this is not used here.. but might be elsewhere..
56220 this.sortState = state;
56223 mstate = this.ds.sortToggle;
56225 //remove existing sort classes..
56227 var sc = this.sortClasses;
56228 var hds = this.el.select(this.headerSelector).removeClass(sc);
56230 for(var f in mstate) {
56232 var sortColumn = this.cm.findColumnIndex(f);
56234 if(sortColumn != -1){
56235 var sortDir = mstate[f];
56236 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56245 handleHeaderClick : function(g, index,e){
56247 Roo.log("header click");
56250 // touch events on header are handled by context
56251 this.handleHdCtx(g,index,e);
56256 if(this.headersDisabled){
56259 var dm = g.dataSource, cm = g.colModel;
56260 if(!cm.isSortable(index)){
56265 if (dm.multiSort) {
56266 // update the sortOrder
56268 for(var i = 0; i < cm.config.length; i++ ) {
56270 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56271 continue; // dont' bother, it's not in sort list or being set.
56274 so.push(cm.config[i].dataIndex);
56280 dm.sort(cm.getDataIndex(index));
56284 destroy : function(){
56286 this.colMenu.removeAll();
56287 Roo.menu.MenuMgr.unregister(this.colMenu);
56288 this.colMenu.getEl().remove();
56289 delete this.colMenu;
56292 this.hmenu.removeAll();
56293 Roo.menu.MenuMgr.unregister(this.hmenu);
56294 this.hmenu.getEl().remove();
56297 if(this.grid.enableColumnMove){
56298 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56300 for(var dd in dds){
56301 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56302 var elid = dds[dd].dragElId;
56304 Roo.get(elid).remove();
56305 } else if(dds[dd].config.isTarget){
56306 dds[dd].proxyTop.remove();
56307 dds[dd].proxyBottom.remove();
56310 if(Roo.dd.DDM.locationCache[dd]){
56311 delete Roo.dd.DDM.locationCache[dd];
56314 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56317 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56318 this.bind(null, null);
56319 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56322 handleLockChange : function(){
56323 this.refresh(true);
56326 onDenyColumnLock : function(){
56330 onDenyColumnHide : function(){
56334 handleHdMenuClick : function(item){
56335 var index = this.hdCtxIndex;
56336 var cm = this.cm, ds = this.ds;
56339 ds.sort(cm.getDataIndex(index), "ASC");
56342 ds.sort(cm.getDataIndex(index), "DESC");
56345 var lc = cm.getLockedCount();
56346 if(cm.getColumnCount(true) <= lc+1){
56347 this.onDenyColumnLock();
56351 cm.setLocked(index, true, true);
56352 cm.moveColumn(index, lc);
56353 this.grid.fireEvent("columnmove", index, lc);
56355 cm.setLocked(index, true);
56359 var lc = cm.getLockedCount();
56360 if((lc-1) != index){
56361 cm.setLocked(index, false, true);
56362 cm.moveColumn(index, lc-1);
56363 this.grid.fireEvent("columnmove", index, lc-1);
56365 cm.setLocked(index, false);
56368 case 'wider': // used to expand cols on touch..
56370 var cw = cm.getColumnWidth(index);
56371 cw += (item.id == 'wider' ? 1 : -1) * 50;
56372 cw = Math.max(0, cw);
56373 cw = Math.min(cw,4000);
56374 cm.setColumnWidth(index, cw);
56378 index = cm.getIndexById(item.id.substr(4));
56380 if(item.checked && cm.getColumnCount(true) <= 1){
56381 this.onDenyColumnHide();
56384 cm.setHidden(index, item.checked);
56390 beforeColMenuShow : function(){
56391 var cm = this.cm, colCount = cm.getColumnCount();
56392 this.colMenu.removeAll();
56393 for(var i = 0; i < colCount; i++){
56394 this.colMenu.add(new Roo.menu.CheckItem({
56395 id: "col-"+cm.getColumnId(i),
56396 text: cm.getColumnHeader(i),
56397 checked: !cm.isHidden(i),
56403 handleHdCtx : function(g, index, e){
56405 var hd = this.getHeaderCell(index);
56406 this.hdCtxIndex = index;
56407 var ms = this.hmenu.items, cm = this.cm;
56408 ms.get("asc").setDisabled(!cm.isSortable(index));
56409 ms.get("desc").setDisabled(!cm.isSortable(index));
56410 if(this.grid.enableColLock !== false){
56411 ms.get("lock").setDisabled(cm.isLocked(index));
56412 ms.get("unlock").setDisabled(!cm.isLocked(index));
56414 this.hmenu.show(hd, "tl-bl");
56417 handleHdOver : function(e){
56418 var hd = this.findHeaderCell(e.getTarget());
56419 if(hd && !this.headersDisabled){
56420 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56421 this.fly(hd).addClass("x-grid-hd-over");
56426 handleHdOut : function(e){
56427 var hd = this.findHeaderCell(e.getTarget());
56429 this.fly(hd).removeClass("x-grid-hd-over");
56433 handleSplitDblClick : function(e, t){
56434 var i = this.getCellIndex(t);
56435 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56436 this.autoSizeColumn(i, true);
56441 render : function(){
56444 var colCount = cm.getColumnCount();
56446 if(this.grid.monitorWindowResize === true){
56447 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56449 var header = this.renderHeaders();
56450 var body = this.templates.body.apply({rows:""});
56451 var html = this.templates.master.apply({
56454 lockedHeader: header[0],
56458 //this.updateColumns();
56460 this.grid.getGridEl().dom.innerHTML = html;
56462 this.initElements();
56464 // a kludge to fix the random scolling effect in webkit
56465 this.el.on("scroll", function() {
56466 this.el.dom.scrollTop=0; // hopefully not recursive..
56469 this.scroller.on("scroll", this.handleScroll, this);
56470 this.lockedBody.on("mousewheel", this.handleWheel, this);
56471 this.mainBody.on("mousewheel", this.handleWheel, this);
56473 this.mainHd.on("mouseover", this.handleHdOver, this);
56474 this.mainHd.on("mouseout", this.handleHdOut, this);
56475 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56476 {delegate: "."+this.splitClass});
56478 this.lockedHd.on("mouseover", this.handleHdOver, this);
56479 this.lockedHd.on("mouseout", this.handleHdOut, this);
56480 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56481 {delegate: "."+this.splitClass});
56483 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56484 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56487 this.updateSplitters();
56489 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56490 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56491 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56494 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56495 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56497 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56498 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56500 if(this.grid.enableColLock !== false){
56501 this.hmenu.add('-',
56502 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56503 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56507 this.hmenu.add('-',
56508 {id:"wider", text: this.columnsWiderText},
56509 {id:"narrow", text: this.columnsNarrowText }
56515 if(this.grid.enableColumnHide !== false){
56517 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56518 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56519 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56521 this.hmenu.add('-',
56522 {id:"columns", text: this.columnsText, menu: this.colMenu}
56525 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56527 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56530 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56531 this.dd = new Roo.grid.GridDragZone(this.grid, {
56532 ddGroup : this.grid.ddGroup || 'GridDD'
56538 for(var i = 0; i < colCount; i++){
56539 if(cm.isHidden(i)){
56540 this.hideColumn(i);
56542 if(cm.config[i].align){
56543 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56544 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56548 this.updateHeaderSortState();
56550 this.beforeInitialResize();
56553 // two part rendering gives faster view to the user
56554 this.renderPhase2.defer(1, this);
56557 renderPhase2 : function(){
56558 // render the rows now
56560 if(this.grid.autoSizeColumns){
56561 this.autoSizeColumns();
56565 beforeInitialResize : function(){
56569 onColumnSplitterMoved : function(i, w){
56570 this.userResized = true;
56571 var cm = this.grid.colModel;
56572 cm.setColumnWidth(i, w, true);
56573 var cid = cm.getColumnId(i);
56574 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56575 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56576 this.updateSplitters();
56578 this.grid.fireEvent("columnresize", i, w);
56581 syncRowHeights : function(startIndex, endIndex){
56582 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56583 startIndex = startIndex || 0;
56584 var mrows = this.getBodyTable().rows;
56585 var lrows = this.getLockedTable().rows;
56586 var len = mrows.length-1;
56587 endIndex = Math.min(endIndex || len, len);
56588 for(var i = startIndex; i <= endIndex; i++){
56589 var m = mrows[i], l = lrows[i];
56590 var h = Math.max(m.offsetHeight, l.offsetHeight);
56591 m.style.height = l.style.height = h + "px";
56596 layout : function(initialRender, is2ndPass){
56598 var auto = g.autoHeight;
56599 var scrollOffset = 16;
56600 var c = g.getGridEl(), cm = this.cm,
56601 expandCol = g.autoExpandColumn,
56603 //c.beginMeasure();
56605 if(!c.dom.offsetWidth){ // display:none?
56607 this.lockedWrap.show();
56608 this.mainWrap.show();
56613 var hasLock = this.cm.isLocked(0);
56615 var tbh = this.headerPanel.getHeight();
56616 var bbh = this.footerPanel.getHeight();
56619 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56620 var newHeight = ch + c.getBorderWidth("tb");
56622 newHeight = Math.min(g.maxHeight, newHeight);
56624 c.setHeight(newHeight);
56628 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56631 var s = this.scroller;
56633 var csize = c.getSize(true);
56635 this.el.setSize(csize.width, csize.height);
56637 this.headerPanel.setWidth(csize.width);
56638 this.footerPanel.setWidth(csize.width);
56640 var hdHeight = this.mainHd.getHeight();
56641 var vw = csize.width;
56642 var vh = csize.height - (tbh + bbh);
56646 var bt = this.getBodyTable();
56648 if(cm.getLockedCount() == cm.config.length){
56649 bt = this.getLockedTable();
56652 var ltWidth = hasLock ?
56653 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56655 var scrollHeight = bt.offsetHeight;
56656 var scrollWidth = ltWidth + bt.offsetWidth;
56657 var vscroll = false, hscroll = false;
56659 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56661 var lw = this.lockedWrap, mw = this.mainWrap;
56662 var lb = this.lockedBody, mb = this.mainBody;
56664 setTimeout(function(){
56665 var t = s.dom.offsetTop;
56666 var w = s.dom.clientWidth,
56667 h = s.dom.clientHeight;
56670 lw.setSize(ltWidth, h);
56672 mw.setLeftTop(ltWidth, t);
56673 mw.setSize(w-ltWidth, h);
56675 lb.setHeight(h-hdHeight);
56676 mb.setHeight(h-hdHeight);
56678 if(is2ndPass !== true && !gv.userResized && expandCol){
56679 // high speed resize without full column calculation
56681 var ci = cm.getIndexById(expandCol);
56683 ci = cm.findColumnIndex(expandCol);
56685 ci = Math.max(0, ci); // make sure it's got at least the first col.
56686 var expandId = cm.getColumnId(ci);
56687 var tw = cm.getTotalWidth(false);
56688 var currentWidth = cm.getColumnWidth(ci);
56689 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56690 if(currentWidth != cw){
56691 cm.setColumnWidth(ci, cw, true);
56692 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56693 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56694 gv.updateSplitters();
56695 gv.layout(false, true);
56707 onWindowResize : function(){
56708 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56714 appendFooter : function(parentEl){
56718 sortAscText : "Sort Ascending",
56719 sortDescText : "Sort Descending",
56720 lockText : "Lock Column",
56721 unlockText : "Unlock Column",
56722 columnsText : "Columns",
56724 columnsWiderText : "Wider",
56725 columnsNarrowText : "Thinner"
56729 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56730 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56731 this.proxy.el.addClass('x-grid3-col-dd');
56734 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56735 handleMouseDown : function(e){
56739 callHandleMouseDown : function(e){
56740 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56745 * Ext JS Library 1.1.1
56746 * Copyright(c) 2006-2007, Ext JS, LLC.
56748 * Originally Released Under LGPL - original licence link has changed is not relivant.
56751 * <script type="text/javascript">
56755 // This is a support class used internally by the Grid components
56756 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56758 this.view = grid.getView();
56759 this.proxy = this.view.resizeProxy;
56760 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56761 "gridSplitters" + this.grid.getGridEl().id, {
56762 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56764 this.setHandleElId(Roo.id(hd));
56765 this.setOuterHandleElId(Roo.id(hd2));
56766 this.scroll = false;
56768 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56769 fly: Roo.Element.fly,
56771 b4StartDrag : function(x, y){
56772 this.view.headersDisabled = true;
56773 this.proxy.setHeight(this.view.mainWrap.getHeight());
56774 var w = this.cm.getColumnWidth(this.cellIndex);
56775 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56776 this.resetConstraints();
56777 this.setXConstraint(minw, 1000);
56778 this.setYConstraint(0, 0);
56779 this.minX = x - minw;
56780 this.maxX = x + 1000;
56782 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56786 handleMouseDown : function(e){
56787 ev = Roo.EventObject.setEvent(e);
56788 var t = this.fly(ev.getTarget());
56789 if(t.hasClass("x-grid-split")){
56790 this.cellIndex = this.view.getCellIndex(t.dom);
56791 this.split = t.dom;
56792 this.cm = this.grid.colModel;
56793 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56794 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56799 endDrag : function(e){
56800 this.view.headersDisabled = false;
56801 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56802 var diff = endX - this.startPos;
56803 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56806 autoOffset : function(){
56807 this.setDelta(0,0);
56811 * Ext JS Library 1.1.1
56812 * Copyright(c) 2006-2007, Ext JS, LLC.
56814 * Originally Released Under LGPL - original licence link has changed is not relivant.
56817 * <script type="text/javascript">
56821 // This is a support class used internally by the Grid components
56822 Roo.grid.GridDragZone = function(grid, config){
56823 this.view = grid.getView();
56824 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56825 if(this.view.lockedBody){
56826 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56827 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56829 this.scroll = false;
56831 this.ddel = document.createElement('div');
56832 this.ddel.className = 'x-grid-dd-wrap';
56835 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56836 ddGroup : "GridDD",
56838 getDragData : function(e){
56839 var t = Roo.lib.Event.getTarget(e);
56840 var rowIndex = this.view.findRowIndex(t);
56841 var sm = this.grid.selModel;
56843 //Roo.log(rowIndex);
56845 if (sm.getSelectedCell) {
56846 // cell selection..
56847 if (!sm.getSelectedCell()) {
56850 if (rowIndex != sm.getSelectedCell()[0]) {
56856 if(rowIndex !== false){
56861 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56863 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56866 if (e.hasModifier()){
56867 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56870 Roo.log("getDragData");
56875 rowIndex: rowIndex,
56876 selections:sm.getSelections ? sm.getSelections() : (
56877 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
56884 onInitDrag : function(e){
56885 var data = this.dragData;
56886 this.ddel.innerHTML = this.grid.getDragDropText();
56887 this.proxy.update(this.ddel);
56888 // fire start drag?
56891 afterRepair : function(){
56892 this.dragging = false;
56895 getRepairXY : function(e, data){
56899 onEndDrag : function(data, e){
56903 onValidDrop : function(dd, e, id){
56908 beforeInvalidDrop : function(e, id){
56913 * Ext JS Library 1.1.1
56914 * Copyright(c) 2006-2007, Ext JS, LLC.
56916 * Originally Released Under LGPL - original licence link has changed is not relivant.
56919 * <script type="text/javascript">
56924 * @class Roo.grid.ColumnModel
56925 * @extends Roo.util.Observable
56926 * This is the default implementation of a ColumnModel used by the Grid. It defines
56927 * the columns in the grid.
56930 var colModel = new Roo.grid.ColumnModel([
56931 {header: "Ticker", width: 60, sortable: true, locked: true},
56932 {header: "Company Name", width: 150, sortable: true},
56933 {header: "Market Cap.", width: 100, sortable: true},
56934 {header: "$ Sales", width: 100, sortable: true, renderer: money},
56935 {header: "Employees", width: 100, sortable: true, resizable: false}
56940 * The config options listed for this class are options which may appear in each
56941 * individual column definition.
56942 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
56944 * @param {Object} config An Array of column config objects. See this class's
56945 * config objects for details.
56947 Roo.grid.ColumnModel = function(config){
56949 * The config passed into the constructor
56951 this.config = config;
56954 // if no id, create one
56955 // if the column does not have a dataIndex mapping,
56956 // map it to the order it is in the config
56957 for(var i = 0, len = config.length; i < len; i++){
56959 if(typeof c.dataIndex == "undefined"){
56962 if(typeof c.renderer == "string"){
56963 c.renderer = Roo.util.Format[c.renderer];
56965 if(typeof c.id == "undefined"){
56968 if(c.editor && c.editor.xtype){
56969 c.editor = Roo.factory(c.editor, Roo.grid);
56971 if(c.editor && c.editor.isFormField){
56972 c.editor = new Roo.grid.GridEditor(c.editor);
56974 this.lookup[c.id] = c;
56978 * The width of columns which have no width specified (defaults to 100)
56981 this.defaultWidth = 100;
56984 * Default sortable of columns which have no sortable specified (defaults to false)
56987 this.defaultSortable = false;
56991 * @event widthchange
56992 * Fires when the width of a column changes.
56993 * @param {ColumnModel} this
56994 * @param {Number} columnIndex The column index
56995 * @param {Number} newWidth The new width
56997 "widthchange": true,
56999 * @event headerchange
57000 * Fires when the text of a header changes.
57001 * @param {ColumnModel} this
57002 * @param {Number} columnIndex The column index
57003 * @param {Number} newText The new header text
57005 "headerchange": true,
57007 * @event hiddenchange
57008 * Fires when a column is hidden or "unhidden".
57009 * @param {ColumnModel} this
57010 * @param {Number} columnIndex The column index
57011 * @param {Boolean} hidden true if hidden, false otherwise
57013 "hiddenchange": true,
57015 * @event columnmoved
57016 * Fires when a column is moved.
57017 * @param {ColumnModel} this
57018 * @param {Number} oldIndex
57019 * @param {Number} newIndex
57021 "columnmoved" : true,
57023 * @event columlockchange
57024 * Fires when a column's locked state is changed
57025 * @param {ColumnModel} this
57026 * @param {Number} colIndex
57027 * @param {Boolean} locked true if locked
57029 "columnlockchange" : true
57031 Roo.grid.ColumnModel.superclass.constructor.call(this);
57033 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57035 * @cfg {String} header The header text to display in the Grid view.
57038 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57039 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57040 * specified, the column's index is used as an index into the Record's data Array.
57043 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57044 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57047 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57048 * Defaults to the value of the {@link #defaultSortable} property.
57049 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57052 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57055 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57058 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57061 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57064 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57065 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57066 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57067 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57070 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57073 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57076 * @cfg {String} cursor (Optional)
57079 * @cfg {String} tooltip (Optional)
57082 * @cfg {Number} xs (Optional)
57085 * @cfg {Number} sm (Optional)
57088 * @cfg {Number} md (Optional)
57091 * @cfg {Number} lg (Optional)
57094 * Returns the id of the column at the specified index.
57095 * @param {Number} index The column index
57096 * @return {String} the id
57098 getColumnId : function(index){
57099 return this.config[index].id;
57103 * Returns the column for a specified id.
57104 * @param {String} id The column id
57105 * @return {Object} the column
57107 getColumnById : function(id){
57108 return this.lookup[id];
57113 * Returns the column for a specified dataIndex.
57114 * @param {String} dataIndex The column dataIndex
57115 * @return {Object|Boolean} the column or false if not found
57117 getColumnByDataIndex: function(dataIndex){
57118 var index = this.findColumnIndex(dataIndex);
57119 return index > -1 ? this.config[index] : false;
57123 * Returns the index for a specified column id.
57124 * @param {String} id The column id
57125 * @return {Number} the index, or -1 if not found
57127 getIndexById : function(id){
57128 for(var i = 0, len = this.config.length; i < len; i++){
57129 if(this.config[i].id == id){
57137 * Returns the index for a specified column dataIndex.
57138 * @param {String} dataIndex The column dataIndex
57139 * @return {Number} the index, or -1 if not found
57142 findColumnIndex : function(dataIndex){
57143 for(var i = 0, len = this.config.length; i < len; i++){
57144 if(this.config[i].dataIndex == dataIndex){
57152 moveColumn : function(oldIndex, newIndex){
57153 var c = this.config[oldIndex];
57154 this.config.splice(oldIndex, 1);
57155 this.config.splice(newIndex, 0, c);
57156 this.dataMap = null;
57157 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57160 isLocked : function(colIndex){
57161 return this.config[colIndex].locked === true;
57164 setLocked : function(colIndex, value, suppressEvent){
57165 if(this.isLocked(colIndex) == value){
57168 this.config[colIndex].locked = value;
57169 if(!suppressEvent){
57170 this.fireEvent("columnlockchange", this, colIndex, value);
57174 getTotalLockedWidth : function(){
57175 var totalWidth = 0;
57176 for(var i = 0; i < this.config.length; i++){
57177 if(this.isLocked(i) && !this.isHidden(i)){
57178 this.totalWidth += this.getColumnWidth(i);
57184 getLockedCount : function(){
57185 for(var i = 0, len = this.config.length; i < len; i++){
57186 if(!this.isLocked(i)){
57191 return this.config.length;
57195 * Returns the number of columns.
57198 getColumnCount : function(visibleOnly){
57199 if(visibleOnly === true){
57201 for(var i = 0, len = this.config.length; i < len; i++){
57202 if(!this.isHidden(i)){
57208 return this.config.length;
57212 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57213 * @param {Function} fn
57214 * @param {Object} scope (optional)
57215 * @return {Array} result
57217 getColumnsBy : function(fn, scope){
57219 for(var i = 0, len = this.config.length; i < len; i++){
57220 var c = this.config[i];
57221 if(fn.call(scope||this, c, i) === true){
57229 * Returns true if the specified column is sortable.
57230 * @param {Number} col The column index
57231 * @return {Boolean}
57233 isSortable : function(col){
57234 if(typeof this.config[col].sortable == "undefined"){
57235 return this.defaultSortable;
57237 return this.config[col].sortable;
57241 * Returns the rendering (formatting) function defined for the column.
57242 * @param {Number} col The column index.
57243 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57245 getRenderer : function(col){
57246 if(!this.config[col].renderer){
57247 return Roo.grid.ColumnModel.defaultRenderer;
57249 return this.config[col].renderer;
57253 * Sets the rendering (formatting) function for a column.
57254 * @param {Number} col The column index
57255 * @param {Function} fn The function to use to process the cell's raw data
57256 * to return HTML markup for the grid view. The render function is called with
57257 * the following parameters:<ul>
57258 * <li>Data value.</li>
57259 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57260 * <li>css A CSS style string to apply to the table cell.</li>
57261 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57262 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57263 * <li>Row index</li>
57264 * <li>Column index</li>
57265 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57267 setRenderer : function(col, fn){
57268 this.config[col].renderer = fn;
57272 * Returns the width for the specified column.
57273 * @param {Number} col The column index
57276 getColumnWidth : function(col){
57277 return this.config[col].width * 1 || this.defaultWidth;
57281 * Sets the width for a column.
57282 * @param {Number} col The column index
57283 * @param {Number} width The new width
57285 setColumnWidth : function(col, width, suppressEvent){
57286 this.config[col].width = width;
57287 this.totalWidth = null;
57288 if(!suppressEvent){
57289 this.fireEvent("widthchange", this, col, width);
57294 * Returns the total width of all columns.
57295 * @param {Boolean} includeHidden True to include hidden column widths
57298 getTotalWidth : function(includeHidden){
57299 if(!this.totalWidth){
57300 this.totalWidth = 0;
57301 for(var i = 0, len = this.config.length; i < len; i++){
57302 if(includeHidden || !this.isHidden(i)){
57303 this.totalWidth += this.getColumnWidth(i);
57307 return this.totalWidth;
57311 * Returns the header for the specified column.
57312 * @param {Number} col The column index
57315 getColumnHeader : function(col){
57316 return this.config[col].header;
57320 * Sets the header for a column.
57321 * @param {Number} col The column index
57322 * @param {String} header The new header
57324 setColumnHeader : function(col, header){
57325 this.config[col].header = header;
57326 this.fireEvent("headerchange", this, col, header);
57330 * Returns the tooltip for the specified column.
57331 * @param {Number} col The column index
57334 getColumnTooltip : function(col){
57335 return this.config[col].tooltip;
57338 * Sets the tooltip for a column.
57339 * @param {Number} col The column index
57340 * @param {String} tooltip The new tooltip
57342 setColumnTooltip : function(col, tooltip){
57343 this.config[col].tooltip = tooltip;
57347 * Returns the dataIndex for the specified column.
57348 * @param {Number} col The column index
57351 getDataIndex : function(col){
57352 return this.config[col].dataIndex;
57356 * Sets the dataIndex for a column.
57357 * @param {Number} col The column index
57358 * @param {Number} dataIndex The new dataIndex
57360 setDataIndex : function(col, dataIndex){
57361 this.config[col].dataIndex = dataIndex;
57367 * Returns true if the cell is editable.
57368 * @param {Number} colIndex The column index
57369 * @param {Number} rowIndex The row index - this is nto actually used..?
57370 * @return {Boolean}
57372 isCellEditable : function(colIndex, rowIndex){
57373 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57377 * Returns the editor defined for the cell/column.
57378 * return false or null to disable editing.
57379 * @param {Number} colIndex The column index
57380 * @param {Number} rowIndex The row index
57383 getCellEditor : function(colIndex, rowIndex){
57384 return this.config[colIndex].editor;
57388 * Sets if a column is editable.
57389 * @param {Number} col The column index
57390 * @param {Boolean} editable True if the column is editable
57392 setEditable : function(col, editable){
57393 this.config[col].editable = editable;
57398 * Returns true if the column is hidden.
57399 * @param {Number} colIndex The column index
57400 * @return {Boolean}
57402 isHidden : function(colIndex){
57403 return this.config[colIndex].hidden;
57408 * Returns true if the column width cannot be changed
57410 isFixed : function(colIndex){
57411 return this.config[colIndex].fixed;
57415 * Returns true if the column can be resized
57416 * @return {Boolean}
57418 isResizable : function(colIndex){
57419 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57422 * Sets if a column is hidden.
57423 * @param {Number} colIndex The column index
57424 * @param {Boolean} hidden True if the column is hidden
57426 setHidden : function(colIndex, hidden){
57427 this.config[colIndex].hidden = hidden;
57428 this.totalWidth = null;
57429 this.fireEvent("hiddenchange", this, colIndex, hidden);
57433 * Sets the editor for a column.
57434 * @param {Number} col The column index
57435 * @param {Object} editor The editor object
57437 setEditor : function(col, editor){
57438 this.config[col].editor = editor;
57442 Roo.grid.ColumnModel.defaultRenderer = function(value)
57444 if(typeof value == "object") {
57447 if(typeof value == "string" && value.length < 1){
57451 return String.format("{0}", value);
57454 // Alias for backwards compatibility
57455 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57458 * Ext JS Library 1.1.1
57459 * Copyright(c) 2006-2007, Ext JS, LLC.
57461 * Originally Released Under LGPL - original licence link has changed is not relivant.
57464 * <script type="text/javascript">
57468 * @class Roo.grid.AbstractSelectionModel
57469 * @extends Roo.util.Observable
57470 * Abstract base class for grid SelectionModels. It provides the interface that should be
57471 * implemented by descendant classes. This class should not be directly instantiated.
57474 Roo.grid.AbstractSelectionModel = function(){
57475 this.locked = false;
57476 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57479 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57480 /** @ignore Called by the grid automatically. Do not call directly. */
57481 init : function(grid){
57487 * Locks the selections.
57490 this.locked = true;
57494 * Unlocks the selections.
57496 unlock : function(){
57497 this.locked = false;
57501 * Returns true if the selections are locked.
57502 * @return {Boolean}
57504 isLocked : function(){
57505 return this.locked;
57509 * Ext JS Library 1.1.1
57510 * Copyright(c) 2006-2007, Ext JS, LLC.
57512 * Originally Released Under LGPL - original licence link has changed is not relivant.
57515 * <script type="text/javascript">
57518 * @extends Roo.grid.AbstractSelectionModel
57519 * @class Roo.grid.RowSelectionModel
57520 * The default SelectionModel used by {@link Roo.grid.Grid}.
57521 * It supports multiple selections and keyboard selection/navigation.
57523 * @param {Object} config
57525 Roo.grid.RowSelectionModel = function(config){
57526 Roo.apply(this, config);
57527 this.selections = new Roo.util.MixedCollection(false, function(o){
57532 this.lastActive = false;
57536 * @event selectionchange
57537 * Fires when the selection changes
57538 * @param {SelectionModel} this
57540 "selectionchange" : true,
57542 * @event afterselectionchange
57543 * Fires after the selection changes (eg. by key press or clicking)
57544 * @param {SelectionModel} this
57546 "afterselectionchange" : true,
57548 * @event beforerowselect
57549 * Fires when a row is selected being selected, return false to cancel.
57550 * @param {SelectionModel} this
57551 * @param {Number} rowIndex The selected index
57552 * @param {Boolean} keepExisting False if other selections will be cleared
57554 "beforerowselect" : true,
57557 * Fires when a row is selected.
57558 * @param {SelectionModel} this
57559 * @param {Number} rowIndex The selected index
57560 * @param {Roo.data.Record} r The record
57562 "rowselect" : true,
57564 * @event rowdeselect
57565 * Fires when a row is deselected.
57566 * @param {SelectionModel} this
57567 * @param {Number} rowIndex The selected index
57569 "rowdeselect" : true
57571 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57572 this.locked = false;
57575 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57577 * @cfg {Boolean} singleSelect
57578 * True to allow selection of only one row at a time (defaults to false)
57580 singleSelect : false,
57583 initEvents : function(){
57585 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57586 this.grid.on("mousedown", this.handleMouseDown, this);
57587 }else{ // allow click to work like normal
57588 this.grid.on("rowclick", this.handleDragableRowClick, this);
57591 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57592 "up" : function(e){
57594 this.selectPrevious(e.shiftKey);
57595 }else if(this.last !== false && this.lastActive !== false){
57596 var last = this.last;
57597 this.selectRange(this.last, this.lastActive-1);
57598 this.grid.getView().focusRow(this.lastActive);
57599 if(last !== false){
57603 this.selectFirstRow();
57605 this.fireEvent("afterselectionchange", this);
57607 "down" : function(e){
57609 this.selectNext(e.shiftKey);
57610 }else if(this.last !== false && this.lastActive !== false){
57611 var last = this.last;
57612 this.selectRange(this.last, this.lastActive+1);
57613 this.grid.getView().focusRow(this.lastActive);
57614 if(last !== false){
57618 this.selectFirstRow();
57620 this.fireEvent("afterselectionchange", this);
57625 var view = this.grid.view;
57626 view.on("refresh", this.onRefresh, this);
57627 view.on("rowupdated", this.onRowUpdated, this);
57628 view.on("rowremoved", this.onRemove, this);
57632 onRefresh : function(){
57633 var ds = this.grid.dataSource, i, v = this.grid.view;
57634 var s = this.selections;
57635 s.each(function(r){
57636 if((i = ds.indexOfId(r.id)) != -1){
57638 s.add(ds.getAt(i)); // updating the selection relate data
57646 onRemove : function(v, index, r){
57647 this.selections.remove(r);
57651 onRowUpdated : function(v, index, r){
57652 if(this.isSelected(r)){
57653 v.onRowSelect(index);
57659 * @param {Array} records The records to select
57660 * @param {Boolean} keepExisting (optional) True to keep existing selections
57662 selectRecords : function(records, keepExisting){
57664 this.clearSelections();
57666 var ds = this.grid.dataSource;
57667 for(var i = 0, len = records.length; i < len; i++){
57668 this.selectRow(ds.indexOf(records[i]), true);
57673 * Gets the number of selected rows.
57676 getCount : function(){
57677 return this.selections.length;
57681 * Selects the first row in the grid.
57683 selectFirstRow : function(){
57688 * Select the last row.
57689 * @param {Boolean} keepExisting (optional) True to keep existing selections
57691 selectLastRow : function(keepExisting){
57692 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57696 * Selects the row immediately following the last selected row.
57697 * @param {Boolean} keepExisting (optional) True to keep existing selections
57699 selectNext : function(keepExisting){
57700 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57701 this.selectRow(this.last+1, keepExisting);
57702 this.grid.getView().focusRow(this.last);
57707 * Selects the row that precedes the last selected row.
57708 * @param {Boolean} keepExisting (optional) True to keep existing selections
57710 selectPrevious : function(keepExisting){
57712 this.selectRow(this.last-1, keepExisting);
57713 this.grid.getView().focusRow(this.last);
57718 * Returns the selected records
57719 * @return {Array} Array of selected records
57721 getSelections : function(){
57722 return [].concat(this.selections.items);
57726 * Returns the first selected record.
57729 getSelected : function(){
57730 return this.selections.itemAt(0);
57735 * Clears all selections.
57737 clearSelections : function(fast){
57742 var ds = this.grid.dataSource;
57743 var s = this.selections;
57744 s.each(function(r){
57745 this.deselectRow(ds.indexOfId(r.id));
57749 this.selections.clear();
57756 * Selects all rows.
57758 selectAll : function(){
57762 this.selections.clear();
57763 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57764 this.selectRow(i, true);
57769 * Returns True if there is a selection.
57770 * @return {Boolean}
57772 hasSelection : function(){
57773 return this.selections.length > 0;
57777 * Returns True if the specified row is selected.
57778 * @param {Number/Record} record The record or index of the record to check
57779 * @return {Boolean}
57781 isSelected : function(index){
57782 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57783 return (r && this.selections.key(r.id) ? true : false);
57787 * Returns True if the specified record id is selected.
57788 * @param {String} id The id of record to check
57789 * @return {Boolean}
57791 isIdSelected : function(id){
57792 return (this.selections.key(id) ? true : false);
57796 handleMouseDown : function(e, t){
57797 var view = this.grid.getView(), rowIndex;
57798 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57801 if(e.shiftKey && this.last !== false){
57802 var last = this.last;
57803 this.selectRange(last, rowIndex, e.ctrlKey);
57804 this.last = last; // reset the last
57805 view.focusRow(rowIndex);
57807 var isSelected = this.isSelected(rowIndex);
57808 if(e.button !== 0 && isSelected){
57809 view.focusRow(rowIndex);
57810 }else if(e.ctrlKey && isSelected){
57811 this.deselectRow(rowIndex);
57812 }else if(!isSelected){
57813 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57814 view.focusRow(rowIndex);
57817 this.fireEvent("afterselectionchange", this);
57820 handleDragableRowClick : function(grid, rowIndex, e)
57822 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57823 this.selectRow(rowIndex, false);
57824 grid.view.focusRow(rowIndex);
57825 this.fireEvent("afterselectionchange", this);
57830 * Selects multiple rows.
57831 * @param {Array} rows Array of the indexes of the row to select
57832 * @param {Boolean} keepExisting (optional) True to keep existing selections
57834 selectRows : function(rows, keepExisting){
57836 this.clearSelections();
57838 for(var i = 0, len = rows.length; i < len; i++){
57839 this.selectRow(rows[i], true);
57844 * Selects a range of rows. All rows in between startRow and endRow are also selected.
57845 * @param {Number} startRow The index of the first row in the range
57846 * @param {Number} endRow The index of the last row in the range
57847 * @param {Boolean} keepExisting (optional) True to retain existing selections
57849 selectRange : function(startRow, endRow, keepExisting){
57854 this.clearSelections();
57856 if(startRow <= endRow){
57857 for(var i = startRow; i <= endRow; i++){
57858 this.selectRow(i, true);
57861 for(var i = startRow; i >= endRow; i--){
57862 this.selectRow(i, true);
57868 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57869 * @param {Number} startRow The index of the first row in the range
57870 * @param {Number} endRow The index of the last row in the range
57872 deselectRange : function(startRow, endRow, preventViewNotify){
57876 for(var i = startRow; i <= endRow; i++){
57877 this.deselectRow(i, preventViewNotify);
57883 * @param {Number} row The index of the row to select
57884 * @param {Boolean} keepExisting (optional) True to keep existing selections
57886 selectRow : function(index, keepExisting, preventViewNotify){
57887 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
57890 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
57891 if(!keepExisting || this.singleSelect){
57892 this.clearSelections();
57894 var r = this.grid.dataSource.getAt(index);
57895 this.selections.add(r);
57896 this.last = this.lastActive = index;
57897 if(!preventViewNotify){
57898 this.grid.getView().onRowSelect(index);
57900 this.fireEvent("rowselect", this, index, r);
57901 this.fireEvent("selectionchange", this);
57907 * @param {Number} row The index of the row to deselect
57909 deselectRow : function(index, preventViewNotify){
57913 if(this.last == index){
57916 if(this.lastActive == index){
57917 this.lastActive = false;
57919 var r = this.grid.dataSource.getAt(index);
57920 this.selections.remove(r);
57921 if(!preventViewNotify){
57922 this.grid.getView().onRowDeselect(index);
57924 this.fireEvent("rowdeselect", this, index);
57925 this.fireEvent("selectionchange", this);
57929 restoreLast : function(){
57931 this.last = this._last;
57936 acceptsNav : function(row, col, cm){
57937 return !cm.isHidden(col) && cm.isCellEditable(col, row);
57941 onEditorKey : function(field, e){
57942 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
57947 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
57949 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
57951 }else if(k == e.ENTER && !e.ctrlKey){
57955 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
57957 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
57959 }else if(k == e.ESC){
57963 g.startEditing(newCell[0], newCell[1]);
57968 * Ext JS Library 1.1.1
57969 * Copyright(c) 2006-2007, Ext JS, LLC.
57971 * Originally Released Under LGPL - original licence link has changed is not relivant.
57974 * <script type="text/javascript">
57977 * @class Roo.grid.CellSelectionModel
57978 * @extends Roo.grid.AbstractSelectionModel
57979 * This class provides the basic implementation for cell selection in a grid.
57981 * @param {Object} config The object containing the configuration of this model.
57982 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
57984 Roo.grid.CellSelectionModel = function(config){
57985 Roo.apply(this, config);
57987 this.selection = null;
57991 * @event beforerowselect
57992 * Fires before a cell is selected.
57993 * @param {SelectionModel} this
57994 * @param {Number} rowIndex The selected row index
57995 * @param {Number} colIndex The selected cell index
57997 "beforecellselect" : true,
57999 * @event cellselect
58000 * Fires when a cell is selected.
58001 * @param {SelectionModel} this
58002 * @param {Number} rowIndex The selected row index
58003 * @param {Number} colIndex The selected cell index
58005 "cellselect" : true,
58007 * @event selectionchange
58008 * Fires when the active selection changes.
58009 * @param {SelectionModel} this
58010 * @param {Object} selection null for no selection or an object (o) with two properties
58012 <li>o.record: the record object for the row the selection is in</li>
58013 <li>o.cell: An array of [rowIndex, columnIndex]</li>
58016 "selectionchange" : true,
58019 * Fires when the tab (or enter) was pressed on the last editable cell
58020 * You can use this to trigger add new row.
58021 * @param {SelectionModel} this
58025 * @event beforeeditnext
58026 * Fires before the next editable sell is made active
58027 * You can use this to skip to another cell or fire the tabend
58028 * if you set cell to false
58029 * @param {Object} eventdata object : { cell : [ row, col ] }
58031 "beforeeditnext" : true
58033 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58036 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58038 enter_is_tab: false,
58041 initEvents : function(){
58042 this.grid.on("mousedown", this.handleMouseDown, this);
58043 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58044 var view = this.grid.view;
58045 view.on("refresh", this.onViewChange, this);
58046 view.on("rowupdated", this.onRowUpdated, this);
58047 view.on("beforerowremoved", this.clearSelections, this);
58048 view.on("beforerowsinserted", this.clearSelections, this);
58049 if(this.grid.isEditor){
58050 this.grid.on("beforeedit", this.beforeEdit, this);
58055 beforeEdit : function(e){
58056 this.select(e.row, e.column, false, true, e.record);
58060 onRowUpdated : function(v, index, r){
58061 if(this.selection && this.selection.record == r){
58062 v.onCellSelect(index, this.selection.cell[1]);
58067 onViewChange : function(){
58068 this.clearSelections(true);
58072 * Returns the currently selected cell,.
58073 * @return {Array} The selected cell (row, column) or null if none selected.
58075 getSelectedCell : function(){
58076 return this.selection ? this.selection.cell : null;
58080 * Clears all selections.
58081 * @param {Boolean} true to prevent the gridview from being notified about the change.
58083 clearSelections : function(preventNotify){
58084 var s = this.selection;
58086 if(preventNotify !== true){
58087 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58089 this.selection = null;
58090 this.fireEvent("selectionchange", this, null);
58095 * Returns true if there is a selection.
58096 * @return {Boolean}
58098 hasSelection : function(){
58099 return this.selection ? true : false;
58103 handleMouseDown : function(e, t){
58104 var v = this.grid.getView();
58105 if(this.isLocked()){
58108 var row = v.findRowIndex(t);
58109 var cell = v.findCellIndex(t);
58110 if(row !== false && cell !== false){
58111 this.select(row, cell);
58117 * @param {Number} rowIndex
58118 * @param {Number} collIndex
58120 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58121 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58122 this.clearSelections();
58123 r = r || this.grid.dataSource.getAt(rowIndex);
58126 cell : [rowIndex, colIndex]
58128 if(!preventViewNotify){
58129 var v = this.grid.getView();
58130 v.onCellSelect(rowIndex, colIndex);
58131 if(preventFocus !== true){
58132 v.focusCell(rowIndex, colIndex);
58135 this.fireEvent("cellselect", this, rowIndex, colIndex);
58136 this.fireEvent("selectionchange", this, this.selection);
58141 isSelectable : function(rowIndex, colIndex, cm){
58142 return !cm.isHidden(colIndex);
58146 handleKeyDown : function(e){
58147 //Roo.log('Cell Sel Model handleKeyDown');
58148 if(!e.isNavKeyPress()){
58151 var g = this.grid, s = this.selection;
58154 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58156 this.select(cell[0], cell[1]);
58161 var walk = function(row, col, step){
58162 return g.walkCells(row, col, step, sm.isSelectable, sm);
58164 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58171 // handled by onEditorKey
58172 if (g.isEditor && g.editing) {
58176 newCell = walk(r, c-1, -1);
58178 newCell = walk(r, c+1, 1);
58183 newCell = walk(r+1, c, 1);
58187 newCell = walk(r-1, c, -1);
58191 newCell = walk(r, c+1, 1);
58195 newCell = walk(r, c-1, -1);
58200 if(g.isEditor && !g.editing){
58201 g.startEditing(r, c);
58210 this.select(newCell[0], newCell[1]);
58216 acceptsNav : function(row, col, cm){
58217 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58221 * @param {Number} field (not used) - as it's normally used as a listener
58222 * @param {Number} e - event - fake it by using
58224 * var e = Roo.EventObjectImpl.prototype;
58225 * e.keyCode = e.TAB
58229 onEditorKey : function(field, e){
58231 var k = e.getKey(),
58234 ed = g.activeEditor,
58236 ///Roo.log('onEditorKey' + k);
58239 if (this.enter_is_tab && k == e.ENTER) {
58245 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58247 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58253 } else if(k == e.ENTER && !e.ctrlKey){
58256 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58258 } else if(k == e.ESC){
58263 var ecall = { cell : newCell, forward : forward };
58264 this.fireEvent('beforeeditnext', ecall );
58265 newCell = ecall.cell;
58266 forward = ecall.forward;
58270 //Roo.log('next cell after edit');
58271 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58272 } else if (forward) {
58273 // tabbed past last
58274 this.fireEvent.defer(100, this, ['tabend',this]);
58279 * Ext JS Library 1.1.1
58280 * Copyright(c) 2006-2007, Ext JS, LLC.
58282 * Originally Released Under LGPL - original licence link has changed is not relivant.
58285 * <script type="text/javascript">
58289 * @class Roo.grid.EditorGrid
58290 * @extends Roo.grid.Grid
58291 * Class for creating and editable grid.
58292 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58293 * The container MUST have some type of size defined for the grid to fill. The container will be
58294 * automatically set to position relative if it isn't already.
58295 * @param {Object} dataSource The data model to bind to
58296 * @param {Object} colModel The column model with info about this grid's columns
58298 Roo.grid.EditorGrid = function(container, config){
58299 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58300 this.getGridEl().addClass("xedit-grid");
58302 if(!this.selModel){
58303 this.selModel = new Roo.grid.CellSelectionModel();
58306 this.activeEditor = null;
58310 * @event beforeedit
58311 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58312 * <ul style="padding:5px;padding-left:16px;">
58313 * <li>grid - This grid</li>
58314 * <li>record - The record being edited</li>
58315 * <li>field - The field name being edited</li>
58316 * <li>value - The value for the field being edited.</li>
58317 * <li>row - The grid row index</li>
58318 * <li>column - The grid column index</li>
58319 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58321 * @param {Object} e An edit event (see above for description)
58323 "beforeedit" : true,
58326 * Fires after a cell is edited. <br />
58327 * <ul style="padding:5px;padding-left:16px;">
58328 * <li>grid - This grid</li>
58329 * <li>record - The record being edited</li>
58330 * <li>field - The field name being edited</li>
58331 * <li>value - The value being set</li>
58332 * <li>originalValue - The original value for the field, before the edit.</li>
58333 * <li>row - The grid row index</li>
58334 * <li>column - The grid column index</li>
58336 * @param {Object} e An edit event (see above for description)
58338 "afteredit" : true,
58340 * @event validateedit
58341 * Fires after a cell is edited, but before the value is set in the record.
58342 * You can use this to modify the value being set in the field, Return false
58343 * to cancel the change. The edit event object has the following properties <br />
58344 * <ul style="padding:5px;padding-left:16px;">
58345 * <li>editor - This editor</li>
58346 * <li>grid - This grid</li>
58347 * <li>record - The record being edited</li>
58348 * <li>field - The field name being edited</li>
58349 * <li>value - The value being set</li>
58350 * <li>originalValue - The original value for the field, before the edit.</li>
58351 * <li>row - The grid row index</li>
58352 * <li>column - The grid column index</li>
58353 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58355 * @param {Object} e An edit event (see above for description)
58357 "validateedit" : true
58359 this.on("bodyscroll", this.stopEditing, this);
58360 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58363 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58365 * @cfg {Number} clicksToEdit
58366 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58373 trackMouseOver: false, // causes very odd FF errors
58375 onCellDblClick : function(g, row, col){
58376 this.startEditing(row, col);
58379 onEditComplete : function(ed, value, startValue){
58380 this.editing = false;
58381 this.activeEditor = null;
58382 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58384 var field = this.colModel.getDataIndex(ed.col);
58389 originalValue: startValue,
58396 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58399 if(String(value) !== String(startValue)){
58401 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58402 r.set(field, e.value);
58403 // if we are dealing with a combo box..
58404 // then we also set the 'name' colum to be the displayField
58405 if (ed.field.displayField && ed.field.name) {
58406 r.set(ed.field.name, ed.field.el.dom.value);
58409 delete e.cancel; //?? why!!!
58410 this.fireEvent("afteredit", e);
58413 this.fireEvent("afteredit", e); // always fire it!
58415 this.view.focusCell(ed.row, ed.col);
58419 * Starts editing the specified for the specified row/column
58420 * @param {Number} rowIndex
58421 * @param {Number} colIndex
58423 startEditing : function(row, col){
58424 this.stopEditing();
58425 if(this.colModel.isCellEditable(col, row)){
58426 this.view.ensureVisible(row, col, true);
58428 var r = this.dataSource.getAt(row);
58429 var field = this.colModel.getDataIndex(col);
58430 var cell = Roo.get(this.view.getCell(row,col));
58435 value: r.data[field],
58440 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58441 this.editing = true;
58442 var ed = this.colModel.getCellEditor(col, row);
58448 ed.render(ed.parentEl || document.body);
58454 (function(){ // complex but required for focus issues in safari, ie and opera
58458 ed.on("complete", this.onEditComplete, this, {single: true});
58459 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58460 this.activeEditor = ed;
58461 var v = r.data[field];
58462 ed.startEdit(this.view.getCell(row, col), v);
58463 // combo's with 'displayField and name set
58464 if (ed.field.displayField && ed.field.name) {
58465 ed.field.el.dom.value = r.data[ed.field.name];
58469 }).defer(50, this);
58475 * Stops any active editing
58477 stopEditing : function(){
58478 if(this.activeEditor){
58479 this.activeEditor.completeEdit();
58481 this.activeEditor = null;
58485 * Called to get grid's drag proxy text, by default returns this.ddText.
58488 getDragDropText : function(){
58489 var count = this.selModel.getSelectedCell() ? 1 : 0;
58490 return String.format(this.ddText, count, count == 1 ? '' : 's');
58495 * Ext JS Library 1.1.1
58496 * Copyright(c) 2006-2007, Ext JS, LLC.
58498 * Originally Released Under LGPL - original licence link has changed is not relivant.
58501 * <script type="text/javascript">
58504 // private - not really -- you end up using it !
58505 // This is a support class used internally by the Grid components
58508 * @class Roo.grid.GridEditor
58509 * @extends Roo.Editor
58510 * Class for creating and editable grid elements.
58511 * @param {Object} config any settings (must include field)
58513 Roo.grid.GridEditor = function(field, config){
58514 if (!config && field.field) {
58516 field = Roo.factory(config.field, Roo.form);
58518 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58519 field.monitorTab = false;
58522 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58525 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58528 alignment: "tl-tl",
58531 cls: "x-small-editor x-grid-editor",
58536 * Ext JS Library 1.1.1
58537 * Copyright(c) 2006-2007, Ext JS, LLC.
58539 * Originally Released Under LGPL - original licence link has changed is not relivant.
58542 * <script type="text/javascript">
58547 Roo.grid.PropertyRecord = Roo.data.Record.create([
58548 {name:'name',type:'string'}, 'value'
58552 Roo.grid.PropertyStore = function(grid, source){
58554 this.store = new Roo.data.Store({
58555 recordType : Roo.grid.PropertyRecord
58557 this.store.on('update', this.onUpdate, this);
58559 this.setSource(source);
58561 Roo.grid.PropertyStore.superclass.constructor.call(this);
58566 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58567 setSource : function(o){
58569 this.store.removeAll();
58572 if(this.isEditableValue(o[k])){
58573 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58576 this.store.loadRecords({records: data}, {}, true);
58579 onUpdate : function(ds, record, type){
58580 if(type == Roo.data.Record.EDIT){
58581 var v = record.data['value'];
58582 var oldValue = record.modified['value'];
58583 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58584 this.source[record.id] = v;
58586 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58593 getProperty : function(row){
58594 return this.store.getAt(row);
58597 isEditableValue: function(val){
58598 if(val && val instanceof Date){
58600 }else if(typeof val == 'object' || typeof val == 'function'){
58606 setValue : function(prop, value){
58607 this.source[prop] = value;
58608 this.store.getById(prop).set('value', value);
58611 getSource : function(){
58612 return this.source;
58616 Roo.grid.PropertyColumnModel = function(grid, store){
58619 g.PropertyColumnModel.superclass.constructor.call(this, [
58620 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58621 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58623 this.store = store;
58624 this.bselect = Roo.DomHelper.append(document.body, {
58625 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58626 {tag: 'option', value: 'true', html: 'true'},
58627 {tag: 'option', value: 'false', html: 'false'}
58630 Roo.id(this.bselect);
58633 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58634 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58635 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58636 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58637 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58639 this.renderCellDelegate = this.renderCell.createDelegate(this);
58640 this.renderPropDelegate = this.renderProp.createDelegate(this);
58643 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58647 valueText : 'Value',
58649 dateFormat : 'm/j/Y',
58652 renderDate : function(dateVal){
58653 return dateVal.dateFormat(this.dateFormat);
58656 renderBool : function(bVal){
58657 return bVal ? 'true' : 'false';
58660 isCellEditable : function(colIndex, rowIndex){
58661 return colIndex == 1;
58664 getRenderer : function(col){
58666 this.renderCellDelegate : this.renderPropDelegate;
58669 renderProp : function(v){
58670 return this.getPropertyName(v);
58673 renderCell : function(val){
58675 if(val instanceof Date){
58676 rv = this.renderDate(val);
58677 }else if(typeof val == 'boolean'){
58678 rv = this.renderBool(val);
58680 return Roo.util.Format.htmlEncode(rv);
58683 getPropertyName : function(name){
58684 var pn = this.grid.propertyNames;
58685 return pn && pn[name] ? pn[name] : name;
58688 getCellEditor : function(colIndex, rowIndex){
58689 var p = this.store.getProperty(rowIndex);
58690 var n = p.data['name'], val = p.data['value'];
58692 if(typeof(this.grid.customEditors[n]) == 'string'){
58693 return this.editors[this.grid.customEditors[n]];
58695 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58696 return this.grid.customEditors[n];
58698 if(val instanceof Date){
58699 return this.editors['date'];
58700 }else if(typeof val == 'number'){
58701 return this.editors['number'];
58702 }else if(typeof val == 'boolean'){
58703 return this.editors['boolean'];
58705 return this.editors['string'];
58711 * @class Roo.grid.PropertyGrid
58712 * @extends Roo.grid.EditorGrid
58713 * This class represents the interface of a component based property grid control.
58714 * <br><br>Usage:<pre><code>
58715 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58723 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58724 * The container MUST have some type of size defined for the grid to fill. The container will be
58725 * automatically set to position relative if it isn't already.
58726 * @param {Object} config A config object that sets properties on this grid.
58728 Roo.grid.PropertyGrid = function(container, config){
58729 config = config || {};
58730 var store = new Roo.grid.PropertyStore(this);
58731 this.store = store;
58732 var cm = new Roo.grid.PropertyColumnModel(this, store);
58733 store.store.sort('name', 'ASC');
58734 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58737 enableColLock:false,
58738 enableColumnMove:false,
58740 trackMouseOver: false,
58743 this.getGridEl().addClass('x-props-grid');
58744 this.lastEditRow = null;
58745 this.on('columnresize', this.onColumnResize, this);
58748 * @event beforepropertychange
58749 * Fires before a property changes (return false to stop?)
58750 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58751 * @param {String} id Record Id
58752 * @param {String} newval New Value
58753 * @param {String} oldval Old Value
58755 "beforepropertychange": true,
58757 * @event propertychange
58758 * Fires after a property changes
58759 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58760 * @param {String} id Record Id
58761 * @param {String} newval New Value
58762 * @param {String} oldval Old Value
58764 "propertychange": true
58766 this.customEditors = this.customEditors || {};
58768 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58771 * @cfg {Object} customEditors map of colnames=> custom editors.
58772 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58773 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58774 * false disables editing of the field.
58778 * @cfg {Object} propertyNames map of property Names to their displayed value
58781 render : function(){
58782 Roo.grid.PropertyGrid.superclass.render.call(this);
58783 this.autoSize.defer(100, this);
58786 autoSize : function(){
58787 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58789 this.view.fitColumns();
58793 onColumnResize : function(){
58794 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58798 * Sets the data for the Grid
58799 * accepts a Key => Value object of all the elements avaiable.
58800 * @param {Object} data to appear in grid.
58802 setSource : function(source){
58803 this.store.setSource(source);
58807 * Gets all the data from the grid.
58808 * @return {Object} data data stored in grid
58810 getSource : function(){
58811 return this.store.getSource();
58820 * @class Roo.grid.Calendar
58821 * @extends Roo.util.Grid
58822 * This class extends the Grid to provide a calendar widget
58823 * <br><br>Usage:<pre><code>
58824 var grid = new Roo.grid.Calendar("my-container-id", {
58827 selModel: mySelectionModel,
58828 autoSizeColumns: true,
58829 monitorWindowResize: false,
58830 trackMouseOver: true
58831 eventstore : real data store..
58837 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58838 * The container MUST have some type of size defined for the grid to fill. The container will be
58839 * automatically set to position relative if it isn't already.
58840 * @param {Object} config A config object that sets properties on this grid.
58842 Roo.grid.Calendar = function(container, config){
58843 // initialize the container
58844 this.container = Roo.get(container);
58845 this.container.update("");
58846 this.container.setStyle("overflow", "hidden");
58847 this.container.addClass('x-grid-container');
58849 this.id = this.container.id;
58851 Roo.apply(this, config);
58852 // check and correct shorthanded configs
58856 for (var r = 0;r < 6;r++) {
58859 for (var c =0;c < 7;c++) {
58863 if (this.eventStore) {
58864 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58865 this.eventStore.on('load',this.onLoad, this);
58866 this.eventStore.on('beforeload',this.clearEvents, this);
58870 this.dataSource = new Roo.data.Store({
58871 proxy: new Roo.data.MemoryProxy(rows),
58872 reader: new Roo.data.ArrayReader({}, [
58873 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58876 this.dataSource.load();
58877 this.ds = this.dataSource;
58878 this.ds.xmodule = this.xmodule || false;
58881 var cellRender = function(v,x,r)
58883 return String.format(
58884 '<div class="fc-day fc-widget-content"><div>' +
58885 '<div class="fc-event-container"></div>' +
58886 '<div class="fc-day-number">{0}</div>'+
58888 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
58889 '</div></div>', v);
58894 this.colModel = new Roo.grid.ColumnModel( [
58896 xtype: 'ColumnModel',
58898 dataIndex : 'weekday0',
58900 renderer : cellRender
58903 xtype: 'ColumnModel',
58905 dataIndex : 'weekday1',
58907 renderer : cellRender
58910 xtype: 'ColumnModel',
58912 dataIndex : 'weekday2',
58913 header : 'Tuesday',
58914 renderer : cellRender
58917 xtype: 'ColumnModel',
58919 dataIndex : 'weekday3',
58920 header : 'Wednesday',
58921 renderer : cellRender
58924 xtype: 'ColumnModel',
58926 dataIndex : 'weekday4',
58927 header : 'Thursday',
58928 renderer : cellRender
58931 xtype: 'ColumnModel',
58933 dataIndex : 'weekday5',
58935 renderer : cellRender
58938 xtype: 'ColumnModel',
58940 dataIndex : 'weekday6',
58941 header : 'Saturday',
58942 renderer : cellRender
58945 this.cm = this.colModel;
58946 this.cm.xmodule = this.xmodule || false;
58950 //this.selModel = new Roo.grid.CellSelectionModel();
58951 //this.sm = this.selModel;
58952 //this.selModel.init(this);
58956 this.container.setWidth(this.width);
58960 this.container.setHeight(this.height);
58967 * The raw click event for the entire grid.
58968 * @param {Roo.EventObject} e
58973 * The raw dblclick event for the entire grid.
58974 * @param {Roo.EventObject} e
58978 * @event contextmenu
58979 * The raw contextmenu event for the entire grid.
58980 * @param {Roo.EventObject} e
58982 "contextmenu" : true,
58985 * The raw mousedown event for the entire grid.
58986 * @param {Roo.EventObject} e
58988 "mousedown" : true,
58991 * The raw mouseup event for the entire grid.
58992 * @param {Roo.EventObject} e
58997 * The raw mouseover event for the entire grid.
58998 * @param {Roo.EventObject} e
59000 "mouseover" : true,
59003 * The raw mouseout event for the entire grid.
59004 * @param {Roo.EventObject} e
59009 * The raw keypress event for the entire grid.
59010 * @param {Roo.EventObject} e
59015 * The raw keydown event for the entire grid.
59016 * @param {Roo.EventObject} e
59024 * Fires when a cell is clicked
59025 * @param {Grid} this
59026 * @param {Number} rowIndex
59027 * @param {Number} columnIndex
59028 * @param {Roo.EventObject} e
59030 "cellclick" : true,
59032 * @event celldblclick
59033 * Fires when a cell is double clicked
59034 * @param {Grid} this
59035 * @param {Number} rowIndex
59036 * @param {Number} columnIndex
59037 * @param {Roo.EventObject} e
59039 "celldblclick" : true,
59042 * Fires when a row is clicked
59043 * @param {Grid} this
59044 * @param {Number} rowIndex
59045 * @param {Roo.EventObject} e
59049 * @event rowdblclick
59050 * Fires when a row is double clicked
59051 * @param {Grid} this
59052 * @param {Number} rowIndex
59053 * @param {Roo.EventObject} e
59055 "rowdblclick" : true,
59057 * @event headerclick
59058 * Fires when a header is clicked
59059 * @param {Grid} this
59060 * @param {Number} columnIndex
59061 * @param {Roo.EventObject} e
59063 "headerclick" : true,
59065 * @event headerdblclick
59066 * Fires when a header cell is double clicked
59067 * @param {Grid} this
59068 * @param {Number} columnIndex
59069 * @param {Roo.EventObject} e
59071 "headerdblclick" : true,
59073 * @event rowcontextmenu
59074 * Fires when a row is right clicked
59075 * @param {Grid} this
59076 * @param {Number} rowIndex
59077 * @param {Roo.EventObject} e
59079 "rowcontextmenu" : true,
59081 * @event cellcontextmenu
59082 * Fires when a cell is right clicked
59083 * @param {Grid} this
59084 * @param {Number} rowIndex
59085 * @param {Number} cellIndex
59086 * @param {Roo.EventObject} e
59088 "cellcontextmenu" : true,
59090 * @event headercontextmenu
59091 * Fires when a header is right clicked
59092 * @param {Grid} this
59093 * @param {Number} columnIndex
59094 * @param {Roo.EventObject} e
59096 "headercontextmenu" : true,
59098 * @event bodyscroll
59099 * Fires when the body element is scrolled
59100 * @param {Number} scrollLeft
59101 * @param {Number} scrollTop
59103 "bodyscroll" : true,
59105 * @event columnresize
59106 * Fires when the user resizes a column
59107 * @param {Number} columnIndex
59108 * @param {Number} newSize
59110 "columnresize" : true,
59112 * @event columnmove
59113 * Fires when the user moves a column
59114 * @param {Number} oldIndex
59115 * @param {Number} newIndex
59117 "columnmove" : true,
59120 * Fires when row(s) start being dragged
59121 * @param {Grid} this
59122 * @param {Roo.GridDD} dd The drag drop object
59123 * @param {event} e The raw browser event
59125 "startdrag" : true,
59128 * Fires when a drag operation is complete
59129 * @param {Grid} this
59130 * @param {Roo.GridDD} dd The drag drop object
59131 * @param {event} e The raw browser event
59136 * Fires when dragged row(s) are dropped on a valid DD target
59137 * @param {Grid} this
59138 * @param {Roo.GridDD} dd The drag drop object
59139 * @param {String} targetId The target drag drop object
59140 * @param {event} e The raw browser event
59145 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59146 * @param {Grid} this
59147 * @param {Roo.GridDD} dd The drag drop object
59148 * @param {String} targetId The target drag drop object
59149 * @param {event} e The raw browser event
59154 * Fires when the dragged row(s) first cross another DD target while being dragged
59155 * @param {Grid} this
59156 * @param {Roo.GridDD} dd The drag drop object
59157 * @param {String} targetId The target drag drop object
59158 * @param {event} e The raw browser event
59160 "dragenter" : true,
59163 * Fires when the dragged row(s) leave another DD target while being dragged
59164 * @param {Grid} this
59165 * @param {Roo.GridDD} dd The drag drop object
59166 * @param {String} targetId The target drag drop object
59167 * @param {event} e The raw browser event
59172 * Fires when a row is rendered, so you can change add a style to it.
59173 * @param {GridView} gridview The grid view
59174 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59180 * Fires when the grid is rendered
59181 * @param {Grid} grid
59186 * Fires when a date is selected
59187 * @param {DatePicker} this
59188 * @param {Date} date The selected date
59192 * @event monthchange
59193 * Fires when the displayed month changes
59194 * @param {DatePicker} this
59195 * @param {Date} date The selected month
59197 'monthchange': true,
59199 * @event evententer
59200 * Fires when mouse over an event
59201 * @param {Calendar} this
59202 * @param {event} Event
59204 'evententer': true,
59206 * @event eventleave
59207 * Fires when the mouse leaves an
59208 * @param {Calendar} this
59211 'eventleave': true,
59213 * @event eventclick
59214 * Fires when the mouse click an
59215 * @param {Calendar} this
59218 'eventclick': true,
59220 * @event eventrender
59221 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59222 * @param {Calendar} this
59223 * @param {data} data to be modified
59225 'eventrender': true
59229 Roo.grid.Grid.superclass.constructor.call(this);
59230 this.on('render', function() {
59231 this.view.el.addClass('x-grid-cal');
59233 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59237 if (!Roo.grid.Calendar.style) {
59238 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59241 '.x-grid-cal .x-grid-col' : {
59242 height: 'auto !important',
59243 'vertical-align': 'top'
59245 '.x-grid-cal .fc-event-hori' : {
59256 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59258 * @cfg {Store} eventStore The store that loads events.
59263 activeDate : false,
59266 monitorWindowResize : false,
59269 resizeColumns : function() {
59270 var col = (this.view.el.getWidth() / 7) - 3;
59271 // loop through cols, and setWidth
59272 for(var i =0 ; i < 7 ; i++){
59273 this.cm.setColumnWidth(i, col);
59276 setDate :function(date) {
59278 Roo.log('setDate?');
59280 this.resizeColumns();
59281 var vd = this.activeDate;
59282 this.activeDate = date;
59283 // if(vd && this.el){
59284 // var t = date.getTime();
59285 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59286 // Roo.log('using add remove');
59288 // this.fireEvent('monthchange', this, date);
59290 // this.cells.removeClass("fc-state-highlight");
59291 // this.cells.each(function(c){
59292 // if(c.dateValue == t){
59293 // c.addClass("fc-state-highlight");
59294 // setTimeout(function(){
59295 // try{c.dom.firstChild.focus();}catch(e){}
59305 var days = date.getDaysInMonth();
59307 var firstOfMonth = date.getFirstDateOfMonth();
59308 var startingPos = firstOfMonth.getDay()-this.startDay;
59310 if(startingPos < this.startDay){
59314 var pm = date.add(Date.MONTH, -1);
59315 var prevStart = pm.getDaysInMonth()-startingPos;
59319 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59321 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59322 //this.cells.addClassOnOver('fc-state-hover');
59324 var cells = this.cells.elements;
59325 var textEls = this.textNodes;
59327 //Roo.each(cells, function(cell){
59328 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59331 days += startingPos;
59333 // convert everything to numbers so it's fast
59334 var day = 86400000;
59335 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59338 //Roo.log(prevStart);
59340 var today = new Date().clearTime().getTime();
59341 var sel = date.clearTime().getTime();
59342 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59343 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59344 var ddMatch = this.disabledDatesRE;
59345 var ddText = this.disabledDatesText;
59346 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59347 var ddaysText = this.disabledDaysText;
59348 var format = this.format;
59350 var setCellClass = function(cal, cell){
59352 //Roo.log('set Cell Class');
59354 var t = d.getTime();
59359 cell.dateValue = t;
59361 cell.className += " fc-today";
59362 cell.className += " fc-state-highlight";
59363 cell.title = cal.todayText;
59366 // disable highlight in other month..
59367 cell.className += " fc-state-highlight";
59372 //cell.className = " fc-state-disabled";
59373 cell.title = cal.minText;
59377 //cell.className = " fc-state-disabled";
59378 cell.title = cal.maxText;
59382 if(ddays.indexOf(d.getDay()) != -1){
59383 // cell.title = ddaysText;
59384 // cell.className = " fc-state-disabled";
59387 if(ddMatch && format){
59388 var fvalue = d.dateFormat(format);
59389 if(ddMatch.test(fvalue)){
59390 cell.title = ddText.replace("%0", fvalue);
59391 cell.className = " fc-state-disabled";
59395 if (!cell.initialClassName) {
59396 cell.initialClassName = cell.dom.className;
59399 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59404 for(; i < startingPos; i++) {
59405 cells[i].dayName = (++prevStart);
59406 Roo.log(textEls[i]);
59407 d.setDate(d.getDate()+1);
59409 //cells[i].className = "fc-past fc-other-month";
59410 setCellClass(this, cells[i]);
59415 for(; i < days; i++){
59416 intDay = i - startingPos + 1;
59417 cells[i].dayName = (intDay);
59418 d.setDate(d.getDate()+1);
59420 cells[i].className = ''; // "x-date-active";
59421 setCellClass(this, cells[i]);
59425 for(; i < 42; i++) {
59426 //textEls[i].innerHTML = (++extraDays);
59428 d.setDate(d.getDate()+1);
59429 cells[i].dayName = (++extraDays);
59430 cells[i].className = "fc-future fc-other-month";
59431 setCellClass(this, cells[i]);
59434 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59436 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59438 // this will cause all the cells to mis
59441 for (var r = 0;r < 6;r++) {
59442 for (var c =0;c < 7;c++) {
59443 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59447 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59448 for(i=0;i<cells.length;i++) {
59450 this.cells.elements[i].dayName = cells[i].dayName ;
59451 this.cells.elements[i].className = cells[i].className;
59452 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59453 this.cells.elements[i].title = cells[i].title ;
59454 this.cells.elements[i].dateValue = cells[i].dateValue ;
59460 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59461 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59463 ////if(totalRows != 6){
59464 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59465 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59468 this.fireEvent('monthchange', this, date);
59473 * Returns the grid's SelectionModel.
59474 * @return {SelectionModel}
59476 getSelectionModel : function(){
59477 if(!this.selModel){
59478 this.selModel = new Roo.grid.CellSelectionModel();
59480 return this.selModel;
59484 this.eventStore.load()
59490 findCell : function(dt) {
59491 dt = dt.clearTime().getTime();
59493 this.cells.each(function(c){
59494 //Roo.log("check " +c.dateValue + '?=' + dt);
59495 if(c.dateValue == dt){
59505 findCells : function(rec) {
59506 var s = rec.data.start_dt.clone().clearTime().getTime();
59508 var e= rec.data.end_dt.clone().clearTime().getTime();
59511 this.cells.each(function(c){
59512 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59514 if(c.dateValue > e){
59517 if(c.dateValue < s){
59526 findBestRow: function(cells)
59530 for (var i =0 ; i < cells.length;i++) {
59531 ret = Math.max(cells[i].rows || 0,ret);
59538 addItem : function(rec)
59540 // look for vertical location slot in
59541 var cells = this.findCells(rec);
59543 rec.row = this.findBestRow(cells);
59545 // work out the location.
59549 for(var i =0; i < cells.length; i++) {
59557 if (crow.start.getY() == cells[i].getY()) {
59559 crow.end = cells[i];
59575 for (var i = 0; i < cells.length;i++) {
59576 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59583 clearEvents: function() {
59585 if (!this.eventStore.getCount()) {
59588 // reset number of rows in cells.
59589 Roo.each(this.cells.elements, function(c){
59593 this.eventStore.each(function(e) {
59594 this.clearEvent(e);
59599 clearEvent : function(ev)
59602 Roo.each(ev.els, function(el) {
59603 el.un('mouseenter' ,this.onEventEnter, this);
59604 el.un('mouseleave' ,this.onEventLeave, this);
59612 renderEvent : function(ev,ctr) {
59614 ctr = this.view.el.select('.fc-event-container',true).first();
59618 this.clearEvent(ev);
59624 var cells = ev.cells;
59625 var rows = ev.rows;
59626 this.fireEvent('eventrender', this, ev);
59628 for(var i =0; i < rows.length; i++) {
59632 cls += ' fc-event-start';
59634 if ((i+1) == rows.length) {
59635 cls += ' fc-event-end';
59638 //Roo.log(ev.data);
59639 // how many rows should it span..
59640 var cg = this.eventTmpl.append(ctr,Roo.apply({
59643 }, ev.data) , true);
59646 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59647 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59648 cg.on('click', this.onEventClick, this, ev);
59652 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59653 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59656 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59657 cg.setWidth(ebox.right - sbox.x -2);
59661 renderEvents: function()
59663 // first make sure there is enough space..
59665 if (!this.eventTmpl) {
59666 this.eventTmpl = new Roo.Template(
59667 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59668 '<div class="fc-event-inner">' +
59669 '<span class="fc-event-time">{time}</span>' +
59670 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59672 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59680 this.cells.each(function(c) {
59681 //Roo.log(c.select('.fc-day-content div',true).first());
59682 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59685 var ctr = this.view.el.select('.fc-event-container',true).first();
59688 this.eventStore.each(function(ev){
59690 this.renderEvent(ev);
59694 this.view.layout();
59698 onEventEnter: function (e, el,event,d) {
59699 this.fireEvent('evententer', this, el, event);
59702 onEventLeave: function (e, el,event,d) {
59703 this.fireEvent('eventleave', this, el, event);
59706 onEventClick: function (e, el,event,d) {
59707 this.fireEvent('eventclick', this, el, event);
59710 onMonthChange: function () {
59714 onLoad: function () {
59716 //Roo.log('calendar onload');
59718 if(this.eventStore.getCount() > 0){
59722 this.eventStore.each(function(d){
59727 if (typeof(add.end_dt) == 'undefined') {
59728 Roo.log("Missing End time in calendar data: ");
59732 if (typeof(add.start_dt) == 'undefined') {
59733 Roo.log("Missing Start time in calendar data: ");
59737 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59738 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59739 add.id = add.id || d.id;
59740 add.title = add.title || '??';
59748 this.renderEvents();
59758 render : function ()
59762 if (!this.view.el.hasClass('course-timesheet')) {
59763 this.view.el.addClass('course-timesheet');
59765 if (this.tsStyle) {
59770 Roo.log(_this.grid.view.el.getWidth());
59773 this.tsStyle = Roo.util.CSS.createStyleSheet({
59774 '.course-timesheet .x-grid-row' : {
59777 '.x-grid-row td' : {
59778 'vertical-align' : 0
59780 '.course-edit-link' : {
59782 'text-overflow' : 'ellipsis',
59783 'overflow' : 'hidden',
59784 'white-space' : 'nowrap',
59785 'cursor' : 'pointer'
59790 '.de-act-sup-link' : {
59791 'color' : 'purple',
59792 'text-decoration' : 'line-through'
59796 'text-decoration' : 'line-through'
59798 '.course-timesheet .course-highlight' : {
59799 'border-top-style': 'dashed !important',
59800 'border-bottom-bottom': 'dashed !important'
59802 '.course-timesheet .course-item' : {
59803 'font-family' : 'tahoma, arial, helvetica',
59804 'font-size' : '11px',
59805 'overflow' : 'hidden',
59806 'padding-left' : '10px',
59807 'padding-right' : '10px',
59808 'padding-top' : '10px'
59816 monitorWindowResize : false,
59817 cellrenderer : function(v,x,r)
59822 xtype: 'CellSelectionModel',
59829 beforeload : function (_self, options)
59831 options.params = options.params || {};
59832 options.params._month = _this.monthField.getValue();
59833 options.params.limit = 9999;
59834 options.params['sort'] = 'when_dt';
59835 options.params['dir'] = 'ASC';
59836 this.proxy.loadResponse = this.loadResponse;
59838 //this.addColumns();
59840 load : function (_self, records, options)
59842 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59843 // if you click on the translation.. you can edit it...
59844 var el = Roo.get(this);
59845 var id = el.dom.getAttribute('data-id');
59846 var d = el.dom.getAttribute('data-date');
59847 var t = el.dom.getAttribute('data-time');
59848 //var id = this.child('span').dom.textContent;
59851 Pman.Dialog.CourseCalendar.show({
59855 productitem_active : id ? 1 : 0
59857 _this.grid.ds.load({});
59862 _this.panel.fireEvent('resize', [ '', '' ]);
59865 loadResponse : function(o, success, response){
59866 // this is overridden on before load..
59868 Roo.log("our code?");
59869 //Roo.log(success);
59870 //Roo.log(response)
59871 delete this.activeRequest;
59873 this.fireEvent("loadexception", this, o, response);
59874 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59879 result = o.reader.read(response);
59881 Roo.log("load exception?");
59882 this.fireEvent("loadexception", this, o, response, e);
59883 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59886 Roo.log("ready...");
59887 // loop through result.records;
59888 // and set this.tdate[date] = [] << array of records..
59890 Roo.each(result.records, function(r){
59892 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
59893 _this.tdata[r.data.when_dt.format('j')] = [];
59895 _this.tdata[r.data.when_dt.format('j')].push(r.data);
59898 //Roo.log(_this.tdata);
59900 result.records = [];
59901 result.totalRecords = 6;
59903 // let's generate some duumy records for the rows.
59904 //var st = _this.dateField.getValue();
59906 // work out monday..
59907 //st = st.add(Date.DAY, -1 * st.format('w'));
59909 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59911 var firstOfMonth = date.getFirstDayOfMonth();
59912 var days = date.getDaysInMonth();
59914 var firstAdded = false;
59915 for (var i = 0; i < result.totalRecords ; i++) {
59916 //var d= st.add(Date.DAY, i);
59919 for(var w = 0 ; w < 7 ; w++){
59920 if(!firstAdded && firstOfMonth != w){
59927 var dd = (d > 0 && d < 10) ? "0"+d : d;
59928 row['weekday'+w] = String.format(
59929 '<span style="font-size: 16px;"><b>{0}</b></span>'+
59930 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
59932 date.format('Y-m-')+dd
59935 if(typeof(_this.tdata[d]) != 'undefined'){
59936 Roo.each(_this.tdata[d], function(r){
59940 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
59941 if(r.parent_id*1>0){
59942 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
59945 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
59946 deactive = 'de-act-link';
59949 row['weekday'+w] += String.format(
59950 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
59952 r.product_id_name, //1
59953 r.when_dt.format('h:ia'), //2
59963 // only do this if something added..
59965 result.records.push(_this.grid.dataSource.reader.newRow(row));
59969 // push it twice. (second one with an hour..
59973 this.fireEvent("load", this, o, o.request.arg);
59974 o.request.callback.call(o.request.scope, result, o.request.arg, true);
59976 sortInfo : {field: 'when_dt', direction : 'ASC' },
59978 xtype: 'HttpProxy',
59981 url : baseURL + '/Roo/Shop_course.php'
59984 xtype: 'JsonReader',
60001 'name': 'parent_id',
60005 'name': 'product_id',
60009 'name': 'productitem_id',
60027 click : function (_self, e)
60029 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60030 sd.setMonth(sd.getMonth()-1);
60031 _this.monthField.setValue(sd.format('Y-m-d'));
60032 _this.grid.ds.load({});
60038 xtype: 'Separator',
60042 xtype: 'MonthField',
60045 render : function (_self)
60047 _this.monthField = _self;
60048 // _this.monthField.set today
60050 select : function (combo, date)
60052 _this.grid.ds.load({});
60055 value : (function() { return new Date(); })()
60058 xtype: 'Separator',
60064 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60074 click : function (_self, e)
60076 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60077 sd.setMonth(sd.getMonth()+1);
60078 _this.monthField.setValue(sd.format('Y-m-d'));
60079 _this.grid.ds.load({});
60092 * Ext JS Library 1.1.1
60093 * Copyright(c) 2006-2007, Ext JS, LLC.
60095 * Originally Released Under LGPL - original licence link has changed is not relivant.
60098 * <script type="text/javascript">
60102 * @class Roo.LoadMask
60103 * A simple utility class for generically masking elements while loading data. If the element being masked has
60104 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60105 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60106 * element's UpdateManager load indicator and will be destroyed after the initial load.
60108 * Create a new LoadMask
60109 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60110 * @param {Object} config The config object
60112 Roo.LoadMask = function(el, config){
60113 this.el = Roo.get(el);
60114 Roo.apply(this, config);
60116 this.store.on('beforeload', this.onBeforeLoad, this);
60117 this.store.on('load', this.onLoad, this);
60118 this.store.on('loadexception', this.onLoadException, this);
60119 this.removeMask = false;
60121 var um = this.el.getUpdateManager();
60122 um.showLoadIndicator = false; // disable the default indicator
60123 um.on('beforeupdate', this.onBeforeLoad, this);
60124 um.on('update', this.onLoad, this);
60125 um.on('failure', this.onLoad, this);
60126 this.removeMask = true;
60130 Roo.LoadMask.prototype = {
60132 * @cfg {Boolean} removeMask
60133 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60134 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60137 * @cfg {String} msg
60138 * The text to display in a centered loading message box (defaults to 'Loading...')
60140 msg : 'Loading...',
60142 * @cfg {String} msgCls
60143 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60145 msgCls : 'x-mask-loading',
60148 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60154 * Disables the mask to prevent it from being displayed
60156 disable : function(){
60157 this.disabled = true;
60161 * Enables the mask so that it can be displayed
60163 enable : function(){
60164 this.disabled = false;
60167 onLoadException : function()
60169 Roo.log(arguments);
60171 if (typeof(arguments[3]) != 'undefined') {
60172 Roo.MessageBox.alert("Error loading",arguments[3]);
60176 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60177 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60186 this.el.unmask(this.removeMask);
60189 onLoad : function()
60191 this.el.unmask(this.removeMask);
60195 onBeforeLoad : function(){
60196 if(!this.disabled){
60197 this.el.mask(this.msg, this.msgCls);
60202 destroy : function(){
60204 this.store.un('beforeload', this.onBeforeLoad, this);
60205 this.store.un('load', this.onLoad, this);
60206 this.store.un('loadexception', this.onLoadException, this);
60208 var um = this.el.getUpdateManager();
60209 um.un('beforeupdate', this.onBeforeLoad, this);
60210 um.un('update', this.onLoad, this);
60211 um.un('failure', this.onLoad, this);
60216 * Ext JS Library 1.1.1
60217 * Copyright(c) 2006-2007, Ext JS, LLC.
60219 * Originally Released Under LGPL - original licence link has changed is not relivant.
60222 * <script type="text/javascript">
60227 * @class Roo.XTemplate
60228 * @extends Roo.Template
60229 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60231 var t = new Roo.XTemplate(
60232 '<select name="{name}">',
60233 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60237 // then append, applying the master template values
60240 * Supported features:
60245 {a_variable} - output encoded.
60246 {a_variable.format:("Y-m-d")} - call a method on the variable
60247 {a_variable:raw} - unencoded output
60248 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60249 {a_variable:this.method_on_template(...)} - call a method on the template object.
60254 <tpl for="a_variable or condition.."></tpl>
60255 <tpl if="a_variable or condition"></tpl>
60256 <tpl exec="some javascript"></tpl>
60257 <tpl name="named_template"></tpl> (experimental)
60259 <tpl for="."></tpl> - just iterate the property..
60260 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60264 Roo.XTemplate = function()
60266 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60273 Roo.extend(Roo.XTemplate, Roo.Template, {
60276 * The various sub templates
60281 * basic tag replacing syntax
60284 * // you can fake an object call by doing this
60288 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60291 * compile the template
60293 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60296 compile: function()
60300 s = ['<tpl>', s, '</tpl>'].join('');
60302 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60303 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60304 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60305 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60306 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60311 while(true == !!(m = s.match(re))){
60312 var forMatch = m[0].match(nameRe),
60313 ifMatch = m[0].match(ifRe),
60314 execMatch = m[0].match(execRe),
60315 namedMatch = m[0].match(namedRe),
60320 name = forMatch && forMatch[1] ? forMatch[1] : '';
60323 // if - puts fn into test..
60324 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60326 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60331 // exec - calls a function... returns empty if true is returned.
60332 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60334 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60342 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60343 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60344 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60347 var uid = namedMatch ? namedMatch[1] : id;
60351 id: namedMatch ? namedMatch[1] : id,
60358 s = s.replace(m[0], '');
60360 s = s.replace(m[0], '{xtpl'+ id + '}');
60365 for(var i = tpls.length-1; i >= 0; --i){
60366 this.compileTpl(tpls[i]);
60367 this.tpls[tpls[i].id] = tpls[i];
60369 this.master = tpls[tpls.length-1];
60373 * same as applyTemplate, except it's done to one of the subTemplates
60374 * when using named templates, you can do:
60376 * var str = pl.applySubTemplate('your-name', values);
60379 * @param {Number} id of the template
60380 * @param {Object} values to apply to template
60381 * @param {Object} parent (normaly the instance of this object)
60383 applySubTemplate : function(id, values, parent)
60387 var t = this.tpls[id];
60391 if(t.test && !t.test.call(this, values, parent)){
60395 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60396 Roo.log(e.toString());
60402 if(t.exec && t.exec.call(this, values, parent)){
60406 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60407 Roo.log(e.toString());
60412 var vs = t.target ? t.target.call(this, values, parent) : values;
60413 parent = t.target ? values : parent;
60414 if(t.target && vs instanceof Array){
60416 for(var i = 0, len = vs.length; i < len; i++){
60417 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60419 return buf.join('');
60421 return t.compiled.call(this, vs, parent);
60423 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60424 Roo.log(e.toString());
60425 Roo.log(t.compiled);
60430 compileTpl : function(tpl)
60432 var fm = Roo.util.Format;
60433 var useF = this.disableFormats !== true;
60434 var sep = Roo.isGecko ? "+" : ",";
60435 var undef = function(str) {
60436 Roo.log("Property not found :" + str);
60440 var fn = function(m, name, format, args)
60442 //Roo.log(arguments);
60443 args = args ? args.replace(/\\'/g,"'") : args;
60444 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60445 if (typeof(format) == 'undefined') {
60446 format= 'htmlEncode';
60448 if (format == 'raw' ) {
60452 if(name.substr(0, 4) == 'xtpl'){
60453 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60456 // build an array of options to determine if value is undefined..
60458 // basically get 'xxxx.yyyy' then do
60459 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60460 // (function () { Roo.log("Property not found"); return ''; })() :
60465 Roo.each(name.split('.'), function(st) {
60466 lookfor += (lookfor.length ? '.': '') + st;
60467 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60470 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60473 if(format && useF){
60475 args = args ? ',' + args : "";
60477 if(format.substr(0, 5) != "this."){
60478 format = "fm." + format + '(';
60480 format = 'this.call("'+ format.substr(5) + '", ';
60484 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60488 // called with xxyx.yuu:(test,test)
60490 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60492 // raw.. - :raw modifier..
60493 return "'"+ sep + udef_st + name + ")"+sep+"'";
60497 // branched to use + in gecko and [].join() in others
60499 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60500 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60503 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60504 body.push(tpl.body.replace(/(\r\n|\n)/g,
60505 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60506 body.push("'].join('');};};");
60507 body = body.join('');
60510 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60512 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60518 applyTemplate : function(values){
60519 return this.master.compiled.call(this, values, {});
60520 //var s = this.subs;
60523 apply : function(){
60524 return this.applyTemplate.apply(this, arguments);
60529 Roo.XTemplate.from = function(el){
60530 el = Roo.getDom(el);
60531 return new Roo.XTemplate(el.value || el.innerHTML);