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 * Ext JS Library 1.1.1
6060 * Copyright(c) 2006-2007, Ext JS, LLC.
6062 * Originally Released Under LGPL - original licence link has changed is not relivant.
6065 * <script type="text/javascript">
6069 * @class Roo.EventManager
6070 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6071 * several useful events directly.
6072 * See {@link Roo.EventObject} for more details on normalized event objects.
6075 Roo.EventManager = function(){
6076 var docReadyEvent, docReadyProcId, docReadyState = false;
6077 var resizeEvent, resizeTask, textEvent, textSize;
6078 var E = Roo.lib.Event;
6079 var D = Roo.lib.Dom;
6084 var fireDocReady = function(){
6086 docReadyState = true;
6089 clearInterval(docReadyProcId);
6091 if(Roo.isGecko || Roo.isOpera) {
6092 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6095 var defer = document.getElementById("ie-deferred-loader");
6097 defer.onreadystatechange = null;
6098 defer.parentNode.removeChild(defer);
6102 docReadyEvent.fire();
6103 docReadyEvent.clearListeners();
6108 var initDocReady = function(){
6109 docReadyEvent = new Roo.util.Event();
6110 if(Roo.isGecko || Roo.isOpera) {
6111 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6113 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6114 var defer = document.getElementById("ie-deferred-loader");
6115 defer.onreadystatechange = function(){
6116 if(this.readyState == "complete"){
6120 }else if(Roo.isSafari){
6121 docReadyProcId = setInterval(function(){
6122 var rs = document.readyState;
6123 if(rs == "complete") {
6128 // no matter what, make sure it fires on load
6129 E.on(window, "load", fireDocReady);
6132 var createBuffered = function(h, o){
6133 var task = new Roo.util.DelayedTask(h);
6135 // create new event object impl so new events don't wipe out properties
6136 e = new Roo.EventObjectImpl(e);
6137 task.delay(o.buffer, h, null, [e]);
6141 var createSingle = function(h, el, ename, fn){
6143 Roo.EventManager.removeListener(el, ename, fn);
6148 var createDelayed = function(h, o){
6150 // create new event object impl so new events don't wipe out properties
6151 e = new Roo.EventObjectImpl(e);
6152 setTimeout(function(){
6157 var transitionEndVal = false;
6159 var transitionEnd = function()
6161 if (transitionEndVal) {
6162 return transitionEndVal;
6164 var el = document.createElement('div');
6166 var transEndEventNames = {
6167 WebkitTransition : 'webkitTransitionEnd',
6168 MozTransition : 'transitionend',
6169 OTransition : 'oTransitionEnd otransitionend',
6170 transition : 'transitionend'
6173 for (var name in transEndEventNames) {
6174 if (el.style[name] !== undefined) {
6175 transitionEndVal = transEndEventNames[name];
6176 return transitionEndVal ;
6182 var listen = function(element, ename, opt, fn, scope){
6183 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6184 fn = fn || o.fn; scope = scope || o.scope;
6185 var el = Roo.getDom(element);
6189 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6192 if (ename == 'transitionend') {
6193 ename = transitionEnd();
6195 var h = function(e){
6196 e = Roo.EventObject.setEvent(e);
6199 t = e.getTarget(o.delegate, el);
6206 if(o.stopEvent === true){
6209 if(o.preventDefault === true){
6212 if(o.stopPropagation === true){
6213 e.stopPropagation();
6216 if(o.normalized === false){
6220 fn.call(scope || el, e, t, o);
6223 h = createDelayed(h, o);
6226 h = createSingle(h, el, ename, fn);
6229 h = createBuffered(h, o);
6231 fn._handlers = fn._handlers || [];
6234 fn._handlers.push([Roo.id(el), ename, h]);
6239 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6240 el.addEventListener("DOMMouseScroll", h, false);
6241 E.on(window, 'unload', function(){
6242 el.removeEventListener("DOMMouseScroll", h, false);
6245 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6246 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6251 var stopListening = function(el, ename, fn){
6252 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6254 for(var i = 0, len = hds.length; i < len; i++){
6256 if(h[0] == id && h[1] == ename){
6263 E.un(el, ename, hd);
6264 el = Roo.getDom(el);
6265 if(ename == "mousewheel" && el.addEventListener){
6266 el.removeEventListener("DOMMouseScroll", hd, false);
6268 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6269 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6273 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6280 * @scope Roo.EventManager
6285 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6286 * object with a Roo.EventObject
6287 * @param {Function} fn The method the event invokes
6288 * @param {Object} scope An object that becomes the scope of the handler
6289 * @param {boolean} override If true, the obj passed in becomes
6290 * the execution scope of the listener
6291 * @return {Function} The wrapped function
6294 wrap : function(fn, scope, override){
6296 Roo.EventObject.setEvent(e);
6297 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6302 * Appends an event handler to an element (shorthand for addListener)
6303 * @param {String/HTMLElement} element The html element or id to assign the
6304 * @param {String} eventName The type of event to listen for
6305 * @param {Function} handler The method the event invokes
6306 * @param {Object} scope (optional) The scope in which to execute the handler
6307 * function. The handler function's "this" context.
6308 * @param {Object} options (optional) An object containing handler configuration
6309 * properties. This may contain any of the following properties:<ul>
6310 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6311 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6312 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6313 * <li>preventDefault {Boolean} True to prevent the default action</li>
6314 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6315 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6316 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6317 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6318 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6319 * by the specified number of milliseconds. If the event fires again within that time, the original
6320 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6323 * <b>Combining Options</b><br>
6324 * Using the options argument, it is possible to combine different types of listeners:<br>
6326 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6328 el.on('click', this.onClick, this, {
6335 * <b>Attaching multiple handlers in 1 call</b><br>
6336 * The method also allows for a single argument to be passed which is a config object containing properties
6337 * which specify multiple handlers.
6347 fn: this.onMouseOver
6356 * Or a shorthand syntax:<br>
6359 'click' : this.onClick,
6360 'mouseover' : this.onMouseOver,
6361 'mouseout' : this.onMouseOut
6365 addListener : function(element, eventName, fn, scope, options){
6366 if(typeof eventName == "object"){
6372 if(typeof o[e] == "function"){
6374 listen(element, e, o, o[e], o.scope);
6376 // individual options
6377 listen(element, e, o[e]);
6382 return listen(element, eventName, options, fn, scope);
6386 * Removes an event handler
6388 * @param {String/HTMLElement} element The id or html element to remove the
6390 * @param {String} eventName The type of event
6391 * @param {Function} fn
6392 * @return {Boolean} True if a listener was actually removed
6394 removeListener : function(element, eventName, fn){
6395 return stopListening(element, eventName, fn);
6399 * Fires when the document is ready (before onload and before images are loaded). Can be
6400 * accessed shorthanded Roo.onReady().
6401 * @param {Function} fn The method the event invokes
6402 * @param {Object} scope An object that becomes the scope of the handler
6403 * @param {boolean} options
6405 onDocumentReady : function(fn, scope, options){
6406 if(docReadyState){ // if it already fired
6407 docReadyEvent.addListener(fn, scope, options);
6408 docReadyEvent.fire();
6409 docReadyEvent.clearListeners();
6415 docReadyEvent.addListener(fn, scope, options);
6419 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6420 * @param {Function} fn The method the event invokes
6421 * @param {Object} scope An object that becomes the scope of the handler
6422 * @param {boolean} options
6424 onWindowResize : function(fn, scope, options){
6426 resizeEvent = new Roo.util.Event();
6427 resizeTask = new Roo.util.DelayedTask(function(){
6428 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6430 E.on(window, "resize", function(){
6432 resizeTask.delay(50);
6434 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6438 resizeEvent.addListener(fn, scope, options);
6442 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6443 * @param {Function} fn The method the event invokes
6444 * @param {Object} scope An object that becomes the scope of the handler
6445 * @param {boolean} options
6447 onTextResize : function(fn, scope, options){
6449 textEvent = new Roo.util.Event();
6450 var textEl = new Roo.Element(document.createElement('div'));
6451 textEl.dom.className = 'x-text-resize';
6452 textEl.dom.innerHTML = 'X';
6453 textEl.appendTo(document.body);
6454 textSize = textEl.dom.offsetHeight;
6455 setInterval(function(){
6456 if(textEl.dom.offsetHeight != textSize){
6457 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6459 }, this.textResizeInterval);
6461 textEvent.addListener(fn, scope, options);
6465 * Removes the passed window resize listener.
6466 * @param {Function} fn The method the event invokes
6467 * @param {Object} scope The scope of handler
6469 removeResizeListener : function(fn, scope){
6471 resizeEvent.removeListener(fn, scope);
6476 fireResize : function(){
6478 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6482 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6486 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6488 textResizeInterval : 50
6493 * @scopeAlias pub=Roo.EventManager
6497 * Appends an event handler to an element (shorthand for addListener)
6498 * @param {String/HTMLElement} element The html element or id to assign the
6499 * @param {String} eventName The type of event to listen for
6500 * @param {Function} handler The method the event invokes
6501 * @param {Object} scope (optional) The scope in which to execute the handler
6502 * function. The handler function's "this" context.
6503 * @param {Object} options (optional) An object containing handler configuration
6504 * properties. This may contain any of the following properties:<ul>
6505 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6506 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6507 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6508 * <li>preventDefault {Boolean} True to prevent the default action</li>
6509 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6510 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6511 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6512 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6513 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6514 * by the specified number of milliseconds. If the event fires again within that time, the original
6515 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6518 * <b>Combining Options</b><br>
6519 * Using the options argument, it is possible to combine different types of listeners:<br>
6521 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6523 el.on('click', this.onClick, this, {
6530 * <b>Attaching multiple handlers in 1 call</b><br>
6531 * The method also allows for a single argument to be passed which is a config object containing properties
6532 * which specify multiple handlers.
6542 fn: this.onMouseOver
6551 * Or a shorthand syntax:<br>
6554 'click' : this.onClick,
6555 'mouseover' : this.onMouseOver,
6556 'mouseout' : this.onMouseOut
6560 pub.on = pub.addListener;
6561 pub.un = pub.removeListener;
6563 pub.stoppedMouseDownEvent = new Roo.util.Event();
6567 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6568 * @param {Function} fn The method the event invokes
6569 * @param {Object} scope An object that becomes the scope of the handler
6570 * @param {boolean} override If true, the obj passed in becomes
6571 * the execution scope of the listener
6575 Roo.onReady = Roo.EventManager.onDocumentReady;
6577 Roo.onReady(function(){
6578 var bd = Roo.get(document.body);
6583 : Roo.isGecko ? "roo-gecko"
6584 : Roo.isOpera ? "roo-opera"
6585 : Roo.isSafari ? "roo-safari" : ""];
6588 cls.push("roo-mac");
6591 cls.push("roo-linux");
6594 cls.push("roo-ios");
6597 cls.push("roo-touch");
6599 if(Roo.isBorderBox){
6600 cls.push('roo-border-box');
6602 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6603 var p = bd.dom.parentNode;
6605 p.className += ' roo-strict';
6608 bd.addClass(cls.join(' '));
6612 * @class Roo.EventObject
6613 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6614 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6617 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6619 var target = e.getTarget();
6622 var myDiv = Roo.get("myDiv");
6623 myDiv.on("click", handleClick);
6625 Roo.EventManager.on("myDiv", 'click', handleClick);
6626 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6630 Roo.EventObject = function(){
6632 var E = Roo.lib.Event;
6634 // safari keypress events for special keys return bad keycodes
6637 63235 : 39, // right
6640 63276 : 33, // page up
6641 63277 : 34, // page down
6642 63272 : 46, // delete
6647 // normalize button clicks
6648 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6649 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6651 Roo.EventObjectImpl = function(e){
6653 this.setEvent(e.browserEvent || e);
6656 Roo.EventObjectImpl.prototype = {
6658 * Used to fix doc tools.
6659 * @scope Roo.EventObject.prototype
6665 /** The normal browser event */
6666 browserEvent : null,
6667 /** The button pressed in a mouse event */
6669 /** True if the shift key was down during the event */
6671 /** True if the control key was down during the event */
6673 /** True if the alt key was down during the event */
6732 setEvent : function(e){
6733 if(e == this || (e && e.browserEvent)){ // already wrapped
6736 this.browserEvent = e;
6738 // normalize buttons
6739 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6740 if(e.type == 'click' && this.button == -1){
6744 this.shiftKey = e.shiftKey;
6745 // mac metaKey behaves like ctrlKey
6746 this.ctrlKey = e.ctrlKey || e.metaKey;
6747 this.altKey = e.altKey;
6748 // in getKey these will be normalized for the mac
6749 this.keyCode = e.keyCode;
6750 // keyup warnings on firefox.
6751 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6752 // cache the target for the delayed and or buffered events
6753 this.target = E.getTarget(e);
6755 this.xy = E.getXY(e);
6758 this.shiftKey = false;
6759 this.ctrlKey = false;
6760 this.altKey = false;
6770 * Stop the event (preventDefault and stopPropagation)
6772 stopEvent : function(){
6773 if(this.browserEvent){
6774 if(this.browserEvent.type == 'mousedown'){
6775 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6777 E.stopEvent(this.browserEvent);
6782 * Prevents the browsers default handling of the event.
6784 preventDefault : function(){
6785 if(this.browserEvent){
6786 E.preventDefault(this.browserEvent);
6791 isNavKeyPress : function(){
6792 var k = this.keyCode;
6793 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6794 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6797 isSpecialKey : function(){
6798 var k = this.keyCode;
6799 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6800 (k == 16) || (k == 17) ||
6801 (k >= 18 && k <= 20) ||
6802 (k >= 33 && k <= 35) ||
6803 (k >= 36 && k <= 39) ||
6804 (k >= 44 && k <= 45);
6807 * Cancels bubbling of the event.
6809 stopPropagation : function(){
6810 if(this.browserEvent){
6811 if(this.type == 'mousedown'){
6812 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6814 E.stopPropagation(this.browserEvent);
6819 * Gets the key code for the event.
6822 getCharCode : function(){
6823 return this.charCode || this.keyCode;
6827 * Returns a normalized keyCode for the event.
6828 * @return {Number} The key code
6830 getKey : function(){
6831 var k = this.keyCode || this.charCode;
6832 return Roo.isSafari ? (safariKeys[k] || k) : k;
6836 * Gets the x coordinate of the event.
6839 getPageX : function(){
6844 * Gets the y coordinate of the event.
6847 getPageY : function(){
6852 * Gets the time of the event.
6855 getTime : function(){
6856 if(this.browserEvent){
6857 return E.getTime(this.browserEvent);
6863 * Gets the page coordinates of the event.
6864 * @return {Array} The xy values like [x, y]
6871 * Gets the target for the event.
6872 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6873 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6874 search as a number or element (defaults to 10 || document.body)
6875 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6876 * @return {HTMLelement}
6878 getTarget : function(selector, maxDepth, returnEl){
6879 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6882 * Gets the related target.
6883 * @return {HTMLElement}
6885 getRelatedTarget : function(){
6886 if(this.browserEvent){
6887 return E.getRelatedTarget(this.browserEvent);
6893 * Normalizes mouse wheel delta across browsers
6894 * @return {Number} The delta
6896 getWheelDelta : function(){
6897 var e = this.browserEvent;
6899 if(e.wheelDelta){ /* IE/Opera. */
6900 delta = e.wheelDelta/120;
6901 }else if(e.detail){ /* Mozilla case. */
6902 delta = -e.detail/3;
6908 * Returns true if the control, meta, shift or alt key was pressed during this event.
6911 hasModifier : function(){
6912 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6916 * Returns true if the target of this event equals el or is a child of el
6917 * @param {String/HTMLElement/Element} el
6918 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6921 within : function(el, related){
6922 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6923 return t && Roo.fly(el).contains(t);
6926 getPoint : function(){
6927 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6931 return new Roo.EventObjectImpl();
6936 * Ext JS Library 1.1.1
6937 * Copyright(c) 2006-2007, Ext JS, LLC.
6939 * Originally Released Under LGPL - original licence link has changed is not relivant.
6942 * <script type="text/javascript">
6946 // was in Composite Element!??!?!
6949 var D = Roo.lib.Dom;
6950 var E = Roo.lib.Event;
6951 var A = Roo.lib.Anim;
6953 // local style camelizing for speed
6955 var camelRe = /(-[a-z])/gi;
6956 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6957 var view = document.defaultView;
6960 * @class Roo.Element
6961 * Represents an Element in the DOM.<br><br>
6964 var el = Roo.get("my-div");
6967 var el = getEl("my-div");
6969 // or with a DOM element
6970 var el = Roo.get(myDivElement);
6972 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6973 * each call instead of constructing a new one.<br><br>
6974 * <b>Animations</b><br />
6975 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6976 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6978 Option Default Description
6979 --------- -------- ---------------------------------------------
6980 duration .35 The duration of the animation in seconds
6981 easing easeOut The YUI easing method
6982 callback none A function to execute when the anim completes
6983 scope this The scope (this) of the callback function
6985 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6986 * manipulate the animation. Here's an example:
6988 var el = Roo.get("my-div");
6993 // default animation
6994 el.setWidth(100, true);
6996 // animation with some options set
7003 // using the "anim" property to get the Anim object
7009 el.setWidth(100, opt);
7011 if(opt.anim.isAnimated()){
7015 * <b> Composite (Collections of) Elements</b><br />
7016 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7017 * @constructor Create a new Element directly.
7018 * @param {String/HTMLElement} element
7019 * @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).
7021 Roo.Element = function(element, forceNew){
7022 var dom = typeof element == "string" ?
7023 document.getElementById(element) : element;
7024 if(!dom){ // invalid id/element
7028 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7029 return Roo.Element.cache[id];
7039 * The DOM element ID
7042 this.id = id || Roo.id(dom);
7045 var El = Roo.Element;
7049 * The element's default display mode (defaults to "")
7052 originalDisplay : "",
7056 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7062 * Sets the element's visibility mode. When setVisible() is called it
7063 * will use this to determine whether to set the visibility or the display property.
7064 * @param visMode Element.VISIBILITY or Element.DISPLAY
7065 * @return {Roo.Element} this
7067 setVisibilityMode : function(visMode){
7068 this.visibilityMode = visMode;
7072 * Convenience method for setVisibilityMode(Element.DISPLAY)
7073 * @param {String} display (optional) What to set display to when visible
7074 * @return {Roo.Element} this
7076 enableDisplayMode : function(display){
7077 this.setVisibilityMode(El.DISPLAY);
7078 if(typeof display != "undefined") { this.originalDisplay = display; }
7083 * 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)
7084 * @param {String} selector The simple selector to test
7085 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7086 search as a number or element (defaults to 10 || document.body)
7087 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7088 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7090 findParent : function(simpleSelector, maxDepth, returnEl){
7091 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7092 maxDepth = maxDepth || 50;
7093 if(typeof maxDepth != "number"){
7094 stopEl = Roo.getDom(maxDepth);
7097 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7098 if(dq.is(p, simpleSelector)){
7099 return returnEl ? Roo.get(p) : p;
7109 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7110 * @param {String} selector The simple selector to test
7111 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7112 search as a number or element (defaults to 10 || document.body)
7113 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7114 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7116 findParentNode : function(simpleSelector, maxDepth, returnEl){
7117 var p = Roo.fly(this.dom.parentNode, '_internal');
7118 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7122 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7123 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7124 * @param {String} selector The simple selector to test
7125 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7126 search as a number or element (defaults to 10 || document.body)
7127 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7129 up : function(simpleSelector, maxDepth){
7130 return this.findParentNode(simpleSelector, maxDepth, true);
7136 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7137 * @param {String} selector The simple selector to test
7138 * @return {Boolean} True if this element matches the selector, else false
7140 is : function(simpleSelector){
7141 return Roo.DomQuery.is(this.dom, simpleSelector);
7145 * Perform animation on this element.
7146 * @param {Object} args The YUI animation control args
7147 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7148 * @param {Function} onComplete (optional) Function to call when animation completes
7149 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7150 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7151 * @return {Roo.Element} this
7153 animate : function(args, duration, onComplete, easing, animType){
7154 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7159 * @private Internal animation call
7161 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7162 animType = animType || 'run';
7164 var anim = Roo.lib.Anim[animType](
7166 (opt.duration || defaultDur) || .35,
7167 (opt.easing || defaultEase) || 'easeOut',
7169 Roo.callback(cb, this);
7170 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7178 // private legacy anim prep
7179 preanim : function(a, i){
7180 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7184 * Removes worthless text nodes
7185 * @param {Boolean} forceReclean (optional) By default the element
7186 * keeps track if it has been cleaned already so
7187 * you can call this over and over. However, if you update the element and
7188 * need to force a reclean, you can pass true.
7190 clean : function(forceReclean){
7191 if(this.isCleaned && forceReclean !== true){
7195 var d = this.dom, n = d.firstChild, ni = -1;
7197 var nx = n.nextSibling;
7198 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7205 this.isCleaned = true;
7210 calcOffsetsTo : function(el){
7213 var restorePos = false;
7214 if(el.getStyle('position') == 'static'){
7215 el.position('relative');
7220 while(op && op != d && op.tagName != 'HTML'){
7223 op = op.offsetParent;
7226 el.position('static');
7232 * Scrolls this element into view within the passed container.
7233 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7234 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7235 * @return {Roo.Element} this
7237 scrollIntoView : function(container, hscroll){
7238 var c = Roo.getDom(container) || document.body;
7241 var o = this.calcOffsetsTo(c),
7244 b = t+el.offsetHeight,
7245 r = l+el.offsetWidth;
7247 var ch = c.clientHeight;
7248 var ct = parseInt(c.scrollTop, 10);
7249 var cl = parseInt(c.scrollLeft, 10);
7251 var cr = cl + c.clientWidth;
7259 if(hscroll !== false){
7263 c.scrollLeft = r-c.clientWidth;
7270 scrollChildIntoView : function(child, hscroll){
7271 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7275 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7276 * the new height may not be available immediately.
7277 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7278 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7279 * @param {Function} onComplete (optional) Function to call when animation completes
7280 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7281 * @return {Roo.Element} this
7283 autoHeight : function(animate, duration, onComplete, easing){
7284 var oldHeight = this.getHeight();
7286 this.setHeight(1); // force clipping
7287 setTimeout(function(){
7288 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7290 this.setHeight(height);
7292 if(typeof onComplete == "function"){
7296 this.setHeight(oldHeight); // restore original height
7297 this.setHeight(height, animate, duration, function(){
7299 if(typeof onComplete == "function") { onComplete(); }
7300 }.createDelegate(this), easing);
7302 }.createDelegate(this), 0);
7307 * Returns true if this element is an ancestor of the passed element
7308 * @param {HTMLElement/String} el The element to check
7309 * @return {Boolean} True if this element is an ancestor of el, else false
7311 contains : function(el){
7312 if(!el){return false;}
7313 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7317 * Checks whether the element is currently visible using both visibility and display properties.
7318 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7319 * @return {Boolean} True if the element is currently visible, else false
7321 isVisible : function(deep) {
7322 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7323 if(deep !== true || !vis){
7326 var p = this.dom.parentNode;
7327 while(p && p.tagName.toLowerCase() != "body"){
7328 if(!Roo.fly(p, '_isVisible').isVisible()){
7337 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7338 * @param {String} selector The CSS selector
7339 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7340 * @return {CompositeElement/CompositeElementLite} The composite element
7342 select : function(selector, unique){
7343 return El.select(selector, unique, this.dom);
7347 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7348 * @param {String} selector The CSS selector
7349 * @return {Array} An array of the matched nodes
7351 query : function(selector, unique){
7352 return Roo.DomQuery.select(selector, this.dom);
7356 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7357 * @param {String} selector The CSS selector
7358 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7359 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7361 child : function(selector, returnDom){
7362 var n = Roo.DomQuery.selectNode(selector, this.dom);
7363 return returnDom ? n : Roo.get(n);
7367 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7368 * @param {String} selector The CSS selector
7369 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7370 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7372 down : function(selector, returnDom){
7373 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7374 return returnDom ? n : Roo.get(n);
7378 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7379 * @param {String} group The group the DD object is member of
7380 * @param {Object} config The DD config object
7381 * @param {Object} overrides An object containing methods to override/implement on the DD object
7382 * @return {Roo.dd.DD} The DD object
7384 initDD : function(group, config, overrides){
7385 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7386 return Roo.apply(dd, overrides);
7390 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7391 * @param {String} group The group the DDProxy object is member of
7392 * @param {Object} config The DDProxy config object
7393 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7394 * @return {Roo.dd.DDProxy} The DDProxy object
7396 initDDProxy : function(group, config, overrides){
7397 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7398 return Roo.apply(dd, overrides);
7402 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7403 * @param {String} group The group the DDTarget object is member of
7404 * @param {Object} config The DDTarget config object
7405 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7406 * @return {Roo.dd.DDTarget} The DDTarget object
7408 initDDTarget : function(group, config, overrides){
7409 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7410 return Roo.apply(dd, overrides);
7414 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7415 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7416 * @param {Boolean} visible Whether the element is visible
7417 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7418 * @return {Roo.Element} this
7420 setVisible : function(visible, animate){
7422 if(this.visibilityMode == El.DISPLAY){
7423 this.setDisplayed(visible);
7426 this.dom.style.visibility = visible ? "visible" : "hidden";
7429 // closure for composites
7431 var visMode = this.visibilityMode;
7433 this.setOpacity(.01);
7434 this.setVisible(true);
7436 this.anim({opacity: { to: (visible?1:0) }},
7437 this.preanim(arguments, 1),
7438 null, .35, 'easeIn', function(){
7440 if(visMode == El.DISPLAY){
7441 dom.style.display = "none";
7443 dom.style.visibility = "hidden";
7445 Roo.get(dom).setOpacity(1);
7453 * Returns true if display is not "none"
7456 isDisplayed : function() {
7457 return this.getStyle("display") != "none";
7461 * Toggles the element's visibility or display, depending on visibility mode.
7462 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7463 * @return {Roo.Element} this
7465 toggle : function(animate){
7466 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7471 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7472 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7473 * @return {Roo.Element} this
7475 setDisplayed : function(value) {
7476 if(typeof value == "boolean"){
7477 value = value ? this.originalDisplay : "none";
7479 this.setStyle("display", value);
7484 * Tries to focus the element. Any exceptions are caught and ignored.
7485 * @return {Roo.Element} this
7487 focus : function() {
7495 * Tries to blur the element. Any exceptions are caught and ignored.
7496 * @return {Roo.Element} this
7506 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7507 * @param {String/Array} className The CSS class to add, or an array of classes
7508 * @return {Roo.Element} this
7510 addClass : function(className){
7511 if(className instanceof Array){
7512 for(var i = 0, len = className.length; i < len; i++) {
7513 this.addClass(className[i]);
7516 if(className && !this.hasClass(className)){
7517 this.dom.className = this.dom.className + " " + className;
7524 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7525 * @param {String/Array} className The CSS class to add, or an array of classes
7526 * @return {Roo.Element} this
7528 radioClass : function(className){
7529 var siblings = this.dom.parentNode.childNodes;
7530 for(var i = 0; i < siblings.length; i++) {
7531 var s = siblings[i];
7532 if(s.nodeType == 1){
7533 Roo.get(s).removeClass(className);
7536 this.addClass(className);
7541 * Removes one or more CSS classes from the element.
7542 * @param {String/Array} className The CSS class to remove, or an array of classes
7543 * @return {Roo.Element} this
7545 removeClass : function(className){
7546 if(!className || !this.dom.className){
7549 if(className instanceof Array){
7550 for(var i = 0, len = className.length; i < len; i++) {
7551 this.removeClass(className[i]);
7554 if(this.hasClass(className)){
7555 var re = this.classReCache[className];
7557 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7558 this.classReCache[className] = re;
7560 this.dom.className =
7561 this.dom.className.replace(re, " ");
7571 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7572 * @param {String} className The CSS class to toggle
7573 * @return {Roo.Element} this
7575 toggleClass : function(className){
7576 if(this.hasClass(className)){
7577 this.removeClass(className);
7579 this.addClass(className);
7585 * Checks if the specified CSS class exists on this element's DOM node.
7586 * @param {String} className The CSS class to check for
7587 * @return {Boolean} True if the class exists, else false
7589 hasClass : function(className){
7590 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7594 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7595 * @param {String} oldClassName The CSS class to replace
7596 * @param {String} newClassName The replacement CSS class
7597 * @return {Roo.Element} this
7599 replaceClass : function(oldClassName, newClassName){
7600 this.removeClass(oldClassName);
7601 this.addClass(newClassName);
7606 * Returns an object with properties matching the styles requested.
7607 * For example, el.getStyles('color', 'font-size', 'width') might return
7608 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7609 * @param {String} style1 A style name
7610 * @param {String} style2 A style name
7611 * @param {String} etc.
7612 * @return {Object} The style object
7614 getStyles : function(){
7615 var a = arguments, len = a.length, r = {};
7616 for(var i = 0; i < len; i++){
7617 r[a[i]] = this.getStyle(a[i]);
7623 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7624 * @param {String} property The style property whose value is returned.
7625 * @return {String} The current value of the style property for this element.
7627 getStyle : function(){
7628 return view && view.getComputedStyle ?
7630 var el = this.dom, v, cs, camel;
7631 if(prop == 'float'){
7634 if(el.style && (v = el.style[prop])){
7637 if(cs = view.getComputedStyle(el, "")){
7638 if(!(camel = propCache[prop])){
7639 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7646 var el = this.dom, v, cs, camel;
7647 if(prop == 'opacity'){
7648 if(typeof el.style.filter == 'string'){
7649 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7651 var fv = parseFloat(m[1]);
7653 return fv ? fv / 100 : 0;
7658 }else if(prop == 'float'){
7659 prop = "styleFloat";
7661 if(!(camel = propCache[prop])){
7662 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7664 if(v = el.style[camel]){
7667 if(cs = el.currentStyle){
7675 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7676 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7677 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7678 * @return {Roo.Element} this
7680 setStyle : function(prop, value){
7681 if(typeof prop == "string"){
7683 if (prop == 'float') {
7684 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7689 if(!(camel = propCache[prop])){
7690 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7693 if(camel == 'opacity') {
7694 this.setOpacity(value);
7696 this.dom.style[camel] = value;
7699 for(var style in prop){
7700 if(typeof prop[style] != "function"){
7701 this.setStyle(style, prop[style]);
7709 * More flexible version of {@link #setStyle} for setting style properties.
7710 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7711 * a function which returns such a specification.
7712 * @return {Roo.Element} this
7714 applyStyles : function(style){
7715 Roo.DomHelper.applyStyles(this.dom, style);
7720 * 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).
7721 * @return {Number} The X position of the element
7724 return D.getX(this.dom);
7728 * 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).
7729 * @return {Number} The Y position of the element
7732 return D.getY(this.dom);
7736 * 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).
7737 * @return {Array} The XY position of the element
7740 return D.getXY(this.dom);
7744 * 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).
7745 * @param {Number} The X position of the element
7746 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7747 * @return {Roo.Element} this
7749 setX : function(x, animate){
7751 D.setX(this.dom, x);
7753 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7759 * 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).
7760 * @param {Number} The Y position of the element
7761 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7762 * @return {Roo.Element} this
7764 setY : function(y, animate){
7766 D.setY(this.dom, y);
7768 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7774 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7775 * @param {String} left The left CSS property value
7776 * @return {Roo.Element} this
7778 setLeft : function(left){
7779 this.setStyle("left", this.addUnits(left));
7784 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7785 * @param {String} top The top CSS property value
7786 * @return {Roo.Element} this
7788 setTop : function(top){
7789 this.setStyle("top", this.addUnits(top));
7794 * Sets the element's CSS right style.
7795 * @param {String} right The right CSS property value
7796 * @return {Roo.Element} this
7798 setRight : function(right){
7799 this.setStyle("right", this.addUnits(right));
7804 * Sets the element's CSS bottom style.
7805 * @param {String} bottom The bottom CSS property value
7806 * @return {Roo.Element} this
7808 setBottom : function(bottom){
7809 this.setStyle("bottom", this.addUnits(bottom));
7814 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7815 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7816 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7817 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7818 * @return {Roo.Element} this
7820 setXY : function(pos, animate){
7822 D.setXY(this.dom, pos);
7824 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7830 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7831 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7832 * @param {Number} x X value for new position (coordinates are page-based)
7833 * @param {Number} y Y value for new position (coordinates are page-based)
7834 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7835 * @return {Roo.Element} this
7837 setLocation : function(x, y, animate){
7838 this.setXY([x, y], this.preanim(arguments, 2));
7843 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7844 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7845 * @param {Number} x X value for new position (coordinates are page-based)
7846 * @param {Number} y Y value for new position (coordinates are page-based)
7847 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7848 * @return {Roo.Element} this
7850 moveTo : function(x, y, animate){
7851 this.setXY([x, y], this.preanim(arguments, 2));
7856 * Returns the region of the given element.
7857 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7858 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7860 getRegion : function(){
7861 return D.getRegion(this.dom);
7865 * Returns the offset height of the element
7866 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7867 * @return {Number} The element's height
7869 getHeight : function(contentHeight){
7870 var h = this.dom.offsetHeight || 0;
7871 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7875 * Returns the offset width of the element
7876 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7877 * @return {Number} The element's width
7879 getWidth : function(contentWidth){
7880 var w = this.dom.offsetWidth || 0;
7881 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7885 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7886 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7887 * if a height has not been set using CSS.
7890 getComputedHeight : function(){
7891 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7893 h = parseInt(this.getStyle('height'), 10) || 0;
7894 if(!this.isBorderBox()){
7895 h += this.getFrameWidth('tb');
7902 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7903 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7904 * if a width has not been set using CSS.
7907 getComputedWidth : function(){
7908 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7910 w = parseInt(this.getStyle('width'), 10) || 0;
7911 if(!this.isBorderBox()){
7912 w += this.getFrameWidth('lr');
7919 * Returns the size of the element.
7920 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7921 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7923 getSize : function(contentSize){
7924 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7928 * Returns the width and height of the viewport.
7929 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7931 getViewSize : function(){
7932 var d = this.dom, doc = document, aw = 0, ah = 0;
7933 if(d == doc || d == doc.body){
7934 return {width : D.getViewWidth(), height: D.getViewHeight()};
7937 width : d.clientWidth,
7938 height: d.clientHeight
7944 * Returns the value of the "value" attribute
7945 * @param {Boolean} asNumber true to parse the value as a number
7946 * @return {String/Number}
7948 getValue : function(asNumber){
7949 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7953 adjustWidth : function(width){
7954 if(typeof width == "number"){
7955 if(this.autoBoxAdjust && !this.isBorderBox()){
7956 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7966 adjustHeight : function(height){
7967 if(typeof height == "number"){
7968 if(this.autoBoxAdjust && !this.isBorderBox()){
7969 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7979 * Set the width of the element
7980 * @param {Number} width The new width
7981 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7982 * @return {Roo.Element} this
7984 setWidth : function(width, animate){
7985 width = this.adjustWidth(width);
7987 this.dom.style.width = this.addUnits(width);
7989 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7995 * Set the height of the element
7996 * @param {Number} height The new height
7997 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7998 * @return {Roo.Element} this
8000 setHeight : function(height, animate){
8001 height = this.adjustHeight(height);
8003 this.dom.style.height = this.addUnits(height);
8005 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8011 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8012 * @param {Number} width The new width
8013 * @param {Number} height The new height
8014 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8015 * @return {Roo.Element} this
8017 setSize : function(width, height, animate){
8018 if(typeof width == "object"){ // in case of object from getSize()
8019 height = width.height; width = width.width;
8021 width = this.adjustWidth(width); height = this.adjustHeight(height);
8023 this.dom.style.width = this.addUnits(width);
8024 this.dom.style.height = this.addUnits(height);
8026 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8032 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8033 * @param {Number} x X value for new position (coordinates are page-based)
8034 * @param {Number} y Y value for new position (coordinates are page-based)
8035 * @param {Number} width The new width
8036 * @param {Number} height The new height
8037 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8038 * @return {Roo.Element} this
8040 setBounds : function(x, y, width, height, animate){
8042 this.setSize(width, height);
8043 this.setLocation(x, y);
8045 width = this.adjustWidth(width); height = this.adjustHeight(height);
8046 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8047 this.preanim(arguments, 4), 'motion');
8053 * 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.
8054 * @param {Roo.lib.Region} region The region to fill
8055 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8056 * @return {Roo.Element} this
8058 setRegion : function(region, animate){
8059 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8064 * Appends an event handler
8066 * @param {String} eventName The type of event to append
8067 * @param {Function} fn The method the event invokes
8068 * @param {Object} scope (optional) The scope (this object) of the fn
8069 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8071 addListener : function(eventName, fn, scope, options){
8073 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8078 * Removes an event handler from this element
8079 * @param {String} eventName the type of event to remove
8080 * @param {Function} fn the method the event invokes
8081 * @return {Roo.Element} this
8083 removeListener : function(eventName, fn){
8084 Roo.EventManager.removeListener(this.dom, eventName, fn);
8089 * Removes all previous added listeners from this element
8090 * @return {Roo.Element} this
8092 removeAllListeners : function(){
8093 E.purgeElement(this.dom);
8097 relayEvent : function(eventName, observable){
8098 this.on(eventName, function(e){
8099 observable.fireEvent(eventName, e);
8104 * Set the opacity of the element
8105 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8106 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8107 * @return {Roo.Element} this
8109 setOpacity : function(opacity, animate){
8111 var s = this.dom.style;
8114 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8115 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8117 s.opacity = opacity;
8120 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8126 * Gets the left X coordinate
8127 * @param {Boolean} local True to get the local css position instead of page coordinate
8130 getLeft : function(local){
8134 return parseInt(this.getStyle("left"), 10) || 0;
8139 * Gets the right X coordinate of the element (element X position + element width)
8140 * @param {Boolean} local True to get the local css position instead of page coordinate
8143 getRight : function(local){
8145 return this.getX() + this.getWidth();
8147 return (this.getLeft(true) + this.getWidth()) || 0;
8152 * Gets the top Y coordinate
8153 * @param {Boolean} local True to get the local css position instead of page coordinate
8156 getTop : function(local) {
8160 return parseInt(this.getStyle("top"), 10) || 0;
8165 * Gets the bottom Y coordinate of the element (element Y position + element height)
8166 * @param {Boolean} local True to get the local css position instead of page coordinate
8169 getBottom : function(local){
8171 return this.getY() + this.getHeight();
8173 return (this.getTop(true) + this.getHeight()) || 0;
8178 * Initializes positioning on this element. If a desired position is not passed, it will make the
8179 * the element positioned relative IF it is not already positioned.
8180 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8181 * @param {Number} zIndex (optional) The zIndex to apply
8182 * @param {Number} x (optional) Set the page X position
8183 * @param {Number} y (optional) Set the page Y position
8185 position : function(pos, zIndex, x, y){
8187 if(this.getStyle('position') == 'static'){
8188 this.setStyle('position', 'relative');
8191 this.setStyle("position", pos);
8194 this.setStyle("z-index", zIndex);
8196 if(x !== undefined && y !== undefined){
8198 }else if(x !== undefined){
8200 }else if(y !== undefined){
8206 * Clear positioning back to the default when the document was loaded
8207 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8208 * @return {Roo.Element} this
8210 clearPositioning : function(value){
8218 "position" : "static"
8224 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8225 * snapshot before performing an update and then restoring the element.
8228 getPositioning : function(){
8229 var l = this.getStyle("left");
8230 var t = this.getStyle("top");
8232 "position" : this.getStyle("position"),
8234 "right" : l ? "" : this.getStyle("right"),
8236 "bottom" : t ? "" : this.getStyle("bottom"),
8237 "z-index" : this.getStyle("z-index")
8242 * Gets the width of the border(s) for the specified side(s)
8243 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8244 * passing lr would get the border (l)eft width + the border (r)ight width.
8245 * @return {Number} The width of the sides passed added together
8247 getBorderWidth : function(side){
8248 return this.addStyles(side, El.borders);
8252 * Gets the width of the padding(s) for the specified side(s)
8253 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8254 * passing lr would get the padding (l)eft + the padding (r)ight.
8255 * @return {Number} The padding of the sides passed added together
8257 getPadding : function(side){
8258 return this.addStyles(side, El.paddings);
8262 * Set positioning with an object returned by getPositioning().
8263 * @param {Object} posCfg
8264 * @return {Roo.Element} this
8266 setPositioning : function(pc){
8267 this.applyStyles(pc);
8268 if(pc.right == "auto"){
8269 this.dom.style.right = "";
8271 if(pc.bottom == "auto"){
8272 this.dom.style.bottom = "";
8278 fixDisplay : function(){
8279 if(this.getStyle("display") == "none"){
8280 this.setStyle("visibility", "hidden");
8281 this.setStyle("display", this.originalDisplay); // first try reverting to default
8282 if(this.getStyle("display") == "none"){ // if that fails, default to block
8283 this.setStyle("display", "block");
8289 * Quick set left and top adding default units
8290 * @param {String} left The left CSS property value
8291 * @param {String} top The top CSS property value
8292 * @return {Roo.Element} this
8294 setLeftTop : function(left, top){
8295 this.dom.style.left = this.addUnits(left);
8296 this.dom.style.top = this.addUnits(top);
8301 * Move this element relative to its current position.
8302 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8303 * @param {Number} distance How far to move the element in pixels
8304 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8305 * @return {Roo.Element} this
8307 move : function(direction, distance, animate){
8308 var xy = this.getXY();
8309 direction = direction.toLowerCase();
8313 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8317 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8322 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8327 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8334 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8335 * @return {Roo.Element} this
8338 if(!this.isClipped){
8339 this.isClipped = true;
8340 this.originalClip = {
8341 "o": this.getStyle("overflow"),
8342 "x": this.getStyle("overflow-x"),
8343 "y": this.getStyle("overflow-y")
8345 this.setStyle("overflow", "hidden");
8346 this.setStyle("overflow-x", "hidden");
8347 this.setStyle("overflow-y", "hidden");
8353 * Return clipping (overflow) to original clipping before clip() was called
8354 * @return {Roo.Element} this
8356 unclip : function(){
8358 this.isClipped = false;
8359 var o = this.originalClip;
8360 if(o.o){this.setStyle("overflow", o.o);}
8361 if(o.x){this.setStyle("overflow-x", o.x);}
8362 if(o.y){this.setStyle("overflow-y", o.y);}
8369 * Gets the x,y coordinates specified by the anchor position on the element.
8370 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8371 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8372 * {width: (target width), height: (target height)} (defaults to the element's current size)
8373 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8374 * @return {Array} [x, y] An array containing the element's x and y coordinates
8376 getAnchorXY : function(anchor, local, s){
8377 //Passing a different size is useful for pre-calculating anchors,
8378 //especially for anchored animations that change the el size.
8380 var w, h, vp = false;
8383 if(d == document.body || d == document){
8385 w = D.getViewWidth(); h = D.getViewHeight();
8387 w = this.getWidth(); h = this.getHeight();
8390 w = s.width; h = s.height;
8392 var x = 0, y = 0, r = Math.round;
8393 switch((anchor || "tl").toLowerCase()){
8435 var sc = this.getScroll();
8436 return [x + sc.left, y + sc.top];
8438 //Add the element's offset xy
8439 var o = this.getXY();
8440 return [x+o[0], y+o[1]];
8444 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8445 * supported position values.
8446 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8447 * @param {String} position The position to align to.
8448 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8449 * @return {Array} [x, y]
8451 getAlignToXY : function(el, p, o){
8455 throw "Element.alignTo with an element that doesn't exist";
8457 var c = false; //constrain to viewport
8458 var p1 = "", p2 = "";
8465 }else if(p.indexOf("-") == -1){
8468 p = p.toLowerCase();
8469 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8471 throw "Element.alignTo with an invalid alignment " + p;
8473 p1 = m[1]; p2 = m[2]; c = !!m[3];
8475 //Subtract the aligned el's internal xy from the target's offset xy
8476 //plus custom offset to get the aligned el's new offset xy
8477 var a1 = this.getAnchorXY(p1, true);
8478 var a2 = el.getAnchorXY(p2, false);
8479 var x = a2[0] - a1[0] + o[0];
8480 var y = a2[1] - a1[1] + o[1];
8482 //constrain the aligned el to viewport if necessary
8483 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8484 // 5px of margin for ie
8485 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8487 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8488 //perpendicular to the vp border, allow the aligned el to slide on that border,
8489 //otherwise swap the aligned el to the opposite border of the target.
8490 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8491 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8492 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8493 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8496 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8497 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8499 if((x+w) > dw + scrollX){
8500 x = swapX ? r.left-w : dw+scrollX-w;
8503 x = swapX ? r.right : scrollX;
8505 if((y+h) > dh + scrollY){
8506 y = swapY ? r.top-h : dh+scrollY-h;
8509 y = swapY ? r.bottom : scrollY;
8516 getConstrainToXY : function(){
8517 var os = {top:0, left:0, bottom:0, right: 0};
8519 return function(el, local, offsets, proposedXY){
8521 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8523 var vw, vh, vx = 0, vy = 0;
8524 if(el.dom == document.body || el.dom == document){
8525 vw = Roo.lib.Dom.getViewWidth();
8526 vh = Roo.lib.Dom.getViewHeight();
8528 vw = el.dom.clientWidth;
8529 vh = el.dom.clientHeight;
8531 var vxy = el.getXY();
8537 var s = el.getScroll();
8539 vx += offsets.left + s.left;
8540 vy += offsets.top + s.top;
8542 vw -= offsets.right;
8543 vh -= offsets.bottom;
8548 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8549 var x = xy[0], y = xy[1];
8550 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8552 // only move it if it needs it
8555 // first validate right/bottom
8564 // then make sure top/left isn't negative
8573 return moved ? [x, y] : false;
8578 adjustForConstraints : function(xy, parent, offsets){
8579 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8583 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8584 * document it aligns it to the viewport.
8585 * The position parameter is optional, and can be specified in any one of the following formats:
8587 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8588 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8589 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8590 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8591 * <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
8592 * element's anchor point, and the second value is used as the target's anchor point.</li>
8594 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8595 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8596 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8597 * that specified in order to enforce the viewport constraints.
8598 * Following are all of the supported anchor positions:
8601 ----- -----------------------------
8602 tl The top left corner (default)
8603 t The center of the top edge
8604 tr The top right corner
8605 l The center of the left edge
8606 c In the center of the element
8607 r The center of the right edge
8608 bl The bottom left corner
8609 b The center of the bottom edge
8610 br The bottom right corner
8614 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8615 el.alignTo("other-el");
8617 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8618 el.alignTo("other-el", "tr?");
8620 // align the bottom right corner of el with the center left edge of other-el
8621 el.alignTo("other-el", "br-l?");
8623 // align the center of el with the bottom left corner of other-el and
8624 // adjust the x position by -6 pixels (and the y position by 0)
8625 el.alignTo("other-el", "c-bl", [-6, 0]);
8627 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8628 * @param {String} position The position to align to.
8629 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8630 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8631 * @return {Roo.Element} this
8633 alignTo : function(element, position, offsets, animate){
8634 var xy = this.getAlignToXY(element, position, offsets);
8635 this.setXY(xy, this.preanim(arguments, 3));
8640 * Anchors an element to another element and realigns it when the window is resized.
8641 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8642 * @param {String} position The position to align to.
8643 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8644 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8645 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8646 * is a number, it is used as the buffer delay (defaults to 50ms).
8647 * @param {Function} callback The function to call after the animation finishes
8648 * @return {Roo.Element} this
8650 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8651 var action = function(){
8652 this.alignTo(el, alignment, offsets, animate);
8653 Roo.callback(callback, this);
8655 Roo.EventManager.onWindowResize(action, this);
8656 var tm = typeof monitorScroll;
8657 if(tm != 'undefined'){
8658 Roo.EventManager.on(window, 'scroll', action, this,
8659 {buffer: tm == 'number' ? monitorScroll : 50});
8661 action.call(this); // align immediately
8665 * Clears any opacity settings from this element. Required in some cases for IE.
8666 * @return {Roo.Element} this
8668 clearOpacity : function(){
8669 if (window.ActiveXObject) {
8670 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8671 this.dom.style.filter = "";
8674 this.dom.style.opacity = "";
8675 this.dom.style["-moz-opacity"] = "";
8676 this.dom.style["-khtml-opacity"] = "";
8682 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8683 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8684 * @return {Roo.Element} this
8686 hide : function(animate){
8687 this.setVisible(false, this.preanim(arguments, 0));
8692 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8693 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8694 * @return {Roo.Element} this
8696 show : function(animate){
8697 this.setVisible(true, this.preanim(arguments, 0));
8702 * @private Test if size has a unit, otherwise appends the default
8704 addUnits : function(size){
8705 return Roo.Element.addUnits(size, this.defaultUnit);
8709 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8710 * @return {Roo.Element} this
8712 beginMeasure : function(){
8714 if(el.offsetWidth || el.offsetHeight){
8715 return this; // offsets work already
8718 var p = this.dom, b = document.body; // start with this element
8719 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8720 var pe = Roo.get(p);
8721 if(pe.getStyle('display') == 'none'){
8722 changed.push({el: p, visibility: pe.getStyle("visibility")});
8723 p.style.visibility = "hidden";
8724 p.style.display = "block";
8728 this._measureChanged = changed;
8734 * Restores displays to before beginMeasure was called
8735 * @return {Roo.Element} this
8737 endMeasure : function(){
8738 var changed = this._measureChanged;
8740 for(var i = 0, len = changed.length; i < len; i++) {
8742 r.el.style.visibility = r.visibility;
8743 r.el.style.display = "none";
8745 this._measureChanged = null;
8751 * Update the innerHTML of this element, optionally searching for and processing scripts
8752 * @param {String} html The new HTML
8753 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8754 * @param {Function} callback For async script loading you can be noticed when the update completes
8755 * @return {Roo.Element} this
8757 update : function(html, loadScripts, callback){
8758 if(typeof html == "undefined"){
8761 if(loadScripts !== true){
8762 this.dom.innerHTML = html;
8763 if(typeof callback == "function"){
8771 html += '<span id="' + id + '"></span>';
8773 E.onAvailable(id, function(){
8774 var hd = document.getElementsByTagName("head")[0];
8775 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8776 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8777 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8780 while(match = re.exec(html)){
8781 var attrs = match[1];
8782 var srcMatch = attrs ? attrs.match(srcRe) : false;
8783 if(srcMatch && srcMatch[2]){
8784 var s = document.createElement("script");
8785 s.src = srcMatch[2];
8786 var typeMatch = attrs.match(typeRe);
8787 if(typeMatch && typeMatch[2]){
8788 s.type = typeMatch[2];
8791 }else if(match[2] && match[2].length > 0){
8792 if(window.execScript) {
8793 window.execScript(match[2]);
8801 window.eval(match[2]);
8805 var el = document.getElementById(id);
8806 if(el){el.parentNode.removeChild(el);}
8807 if(typeof callback == "function"){
8811 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8816 * Direct access to the UpdateManager update() method (takes the same parameters).
8817 * @param {String/Function} url The url for this request or a function to call to get the url
8818 * @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}
8819 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8820 * @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.
8821 * @return {Roo.Element} this
8824 var um = this.getUpdateManager();
8825 um.update.apply(um, arguments);
8830 * Gets this element's UpdateManager
8831 * @return {Roo.UpdateManager} The UpdateManager
8833 getUpdateManager : function(){
8834 if(!this.updateManager){
8835 this.updateManager = new Roo.UpdateManager(this);
8837 return this.updateManager;
8841 * Disables text selection for this element (normalized across browsers)
8842 * @return {Roo.Element} this
8844 unselectable : function(){
8845 this.dom.unselectable = "on";
8846 this.swallowEvent("selectstart", true);
8847 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8848 this.addClass("x-unselectable");
8853 * Calculates the x, y to center this element on the screen
8854 * @return {Array} The x, y values [x, y]
8856 getCenterXY : function(){
8857 return this.getAlignToXY(document, 'c-c');
8861 * Centers the Element in either the viewport, or another Element.
8862 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8864 center : function(centerIn){
8865 this.alignTo(centerIn || document, 'c-c');
8870 * Tests various css rules/browsers to determine if this element uses a border box
8873 isBorderBox : function(){
8874 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8878 * Return a box {x, y, width, height} that can be used to set another elements
8879 * size/location to match this element.
8880 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8881 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8882 * @return {Object} box An object in the format {x, y, width, height}
8884 getBox : function(contentBox, local){
8889 var left = parseInt(this.getStyle("left"), 10) || 0;
8890 var top = parseInt(this.getStyle("top"), 10) || 0;
8893 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8895 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8897 var l = this.getBorderWidth("l")+this.getPadding("l");
8898 var r = this.getBorderWidth("r")+this.getPadding("r");
8899 var t = this.getBorderWidth("t")+this.getPadding("t");
8900 var b = this.getBorderWidth("b")+this.getPadding("b");
8901 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)};
8903 bx.right = bx.x + bx.width;
8904 bx.bottom = bx.y + bx.height;
8909 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8910 for more information about the sides.
8911 * @param {String} sides
8914 getFrameWidth : function(sides, onlyContentBox){
8915 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8919 * 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.
8920 * @param {Object} box The box to fill {x, y, width, height}
8921 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8922 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8923 * @return {Roo.Element} this
8925 setBox : function(box, adjust, animate){
8926 var w = box.width, h = box.height;
8927 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8928 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8929 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8931 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8936 * Forces the browser to repaint this element
8937 * @return {Roo.Element} this
8939 repaint : function(){
8941 this.addClass("x-repaint");
8942 setTimeout(function(){
8943 Roo.get(dom).removeClass("x-repaint");
8949 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8950 * then it returns the calculated width of the sides (see getPadding)
8951 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8952 * @return {Object/Number}
8954 getMargins : function(side){
8957 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8958 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8959 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8960 right: parseInt(this.getStyle("margin-right"), 10) || 0
8963 return this.addStyles(side, El.margins);
8968 addStyles : function(sides, styles){
8970 for(var i = 0, len = sides.length; i < len; i++){
8971 v = this.getStyle(styles[sides.charAt(i)]);
8973 w = parseInt(v, 10);
8981 * Creates a proxy element of this element
8982 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8983 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8984 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8985 * @return {Roo.Element} The new proxy element
8987 createProxy : function(config, renderTo, matchBox){
8989 renderTo = Roo.getDom(renderTo);
8991 renderTo = document.body;
8993 config = typeof config == "object" ?
8994 config : {tag : "div", cls: config};
8995 var proxy = Roo.DomHelper.append(renderTo, config, true);
8997 proxy.setBox(this.getBox());
9003 * Puts a mask over this element to disable user interaction. Requires core.css.
9004 * This method can only be applied to elements which accept child nodes.
9005 * @param {String} msg (optional) A message to display in the mask
9006 * @param {String} msgCls (optional) A css class to apply to the msg element
9007 * @return {Element} The mask element
9009 mask : function(msg, msgCls)
9011 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9012 this.setStyle("position", "relative");
9015 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9017 this.addClass("x-masked");
9018 this._mask.setDisplayed(true);
9023 while (dom && dom.style) {
9024 if (!isNaN(parseInt(dom.style.zIndex))) {
9025 z = Math.max(z, parseInt(dom.style.zIndex));
9027 dom = dom.parentNode;
9029 // if we are masking the body - then it hides everything..
9030 if (this.dom == document.body) {
9032 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9033 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9036 if(typeof msg == 'string'){
9038 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9040 var mm = this._maskMsg;
9041 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9042 if (mm.dom.firstChild) { // weird IE issue?
9043 mm.dom.firstChild.innerHTML = msg;
9045 mm.setDisplayed(true);
9047 mm.setStyle('z-index', z + 102);
9049 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9050 this._mask.setHeight(this.getHeight());
9052 this._mask.setStyle('z-index', z + 100);
9058 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9059 * it is cached for reuse.
9061 unmask : function(removeEl){
9063 if(removeEl === true){
9064 this._mask.remove();
9067 this._maskMsg.remove();
9068 delete this._maskMsg;
9071 this._mask.setDisplayed(false);
9073 this._maskMsg.setDisplayed(false);
9077 this.removeClass("x-masked");
9081 * Returns true if this element is masked
9084 isMasked : function(){
9085 return this._mask && this._mask.isVisible();
9089 * Creates an iframe shim for this element to keep selects and other windowed objects from
9091 * @return {Roo.Element} The new shim element
9093 createShim : function(){
9094 var el = document.createElement('iframe');
9095 el.frameBorder = 'no';
9096 el.className = 'roo-shim';
9097 if(Roo.isIE && Roo.isSecure){
9098 el.src = Roo.SSL_SECURE_URL;
9100 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9101 shim.autoBoxAdjust = false;
9106 * Removes this element from the DOM and deletes it from the cache
9108 remove : function(){
9109 if(this.dom.parentNode){
9110 this.dom.parentNode.removeChild(this.dom);
9112 delete El.cache[this.dom.id];
9116 * Sets up event handlers to add and remove a css class when the mouse is over this element
9117 * @param {String} className
9118 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9119 * mouseout events for children elements
9120 * @return {Roo.Element} this
9122 addClassOnOver : function(className, preventFlicker){
9123 this.on("mouseover", function(){
9124 Roo.fly(this, '_internal').addClass(className);
9126 var removeFn = function(e){
9127 if(preventFlicker !== true || !e.within(this, true)){
9128 Roo.fly(this, '_internal').removeClass(className);
9131 this.on("mouseout", removeFn, this.dom);
9136 * Sets up event handlers to add and remove a css class when this element has the focus
9137 * @param {String} className
9138 * @return {Roo.Element} this
9140 addClassOnFocus : function(className){
9141 this.on("focus", function(){
9142 Roo.fly(this, '_internal').addClass(className);
9144 this.on("blur", function(){
9145 Roo.fly(this, '_internal').removeClass(className);
9150 * 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)
9151 * @param {String} className
9152 * @return {Roo.Element} this
9154 addClassOnClick : function(className){
9156 this.on("mousedown", function(){
9157 Roo.fly(dom, '_internal').addClass(className);
9158 var d = Roo.get(document);
9159 var fn = function(){
9160 Roo.fly(dom, '_internal').removeClass(className);
9161 d.removeListener("mouseup", fn);
9163 d.on("mouseup", fn);
9169 * Stops the specified event from bubbling and optionally prevents the default action
9170 * @param {String} eventName
9171 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9172 * @return {Roo.Element} this
9174 swallowEvent : function(eventName, preventDefault){
9175 var fn = function(e){
9176 e.stopPropagation();
9181 if(eventName instanceof Array){
9182 for(var i = 0, len = eventName.length; i < len; i++){
9183 this.on(eventName[i], fn);
9187 this.on(eventName, fn);
9194 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9197 * Sizes this element to its parent element's dimensions performing
9198 * neccessary box adjustments.
9199 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9200 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9201 * @return {Roo.Element} this
9203 fitToParent : function(monitorResize, targetParent) {
9204 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9205 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9206 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9209 var p = Roo.get(targetParent || this.dom.parentNode);
9210 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9211 if (monitorResize === true) {
9212 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9213 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9219 * Gets the next sibling, skipping text nodes
9220 * @return {HTMLElement} The next sibling or null
9222 getNextSibling : function(){
9223 var n = this.dom.nextSibling;
9224 while(n && n.nodeType != 1){
9231 * Gets the previous sibling, skipping text nodes
9232 * @return {HTMLElement} The previous sibling or null
9234 getPrevSibling : function(){
9235 var n = this.dom.previousSibling;
9236 while(n && n.nodeType != 1){
9237 n = n.previousSibling;
9244 * Appends the passed element(s) to this element
9245 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9246 * @return {Roo.Element} this
9248 appendChild: function(el){
9255 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9256 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9257 * automatically generated with the specified attributes.
9258 * @param {HTMLElement} insertBefore (optional) a child element of this element
9259 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9260 * @return {Roo.Element} The new child element
9262 createChild: function(config, insertBefore, returnDom){
9263 config = config || {tag:'div'};
9265 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9267 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9271 * Appends this element to the passed element
9272 * @param {String/HTMLElement/Element} el The new parent element
9273 * @return {Roo.Element} this
9275 appendTo: function(el){
9276 el = Roo.getDom(el);
9277 el.appendChild(this.dom);
9282 * Inserts this element before the passed element in the DOM
9283 * @param {String/HTMLElement/Element} el The element to insert before
9284 * @return {Roo.Element} this
9286 insertBefore: function(el){
9287 el = Roo.getDom(el);
9288 el.parentNode.insertBefore(this.dom, el);
9293 * Inserts this element after the passed element in the DOM
9294 * @param {String/HTMLElement/Element} el The element to insert after
9295 * @return {Roo.Element} this
9297 insertAfter: function(el){
9298 el = Roo.getDom(el);
9299 el.parentNode.insertBefore(this.dom, el.nextSibling);
9304 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9305 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9306 * @return {Roo.Element} The new child
9308 insertFirst: function(el, returnDom){
9310 if(typeof el == 'object' && !el.nodeType){ // dh config
9311 return this.createChild(el, this.dom.firstChild, returnDom);
9313 el = Roo.getDom(el);
9314 this.dom.insertBefore(el, this.dom.firstChild);
9315 return !returnDom ? Roo.get(el) : el;
9320 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9321 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9322 * @param {String} where (optional) 'before' or 'after' defaults to before
9323 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9324 * @return {Roo.Element} the inserted Element
9326 insertSibling: function(el, where, returnDom){
9327 where = where ? where.toLowerCase() : 'before';
9329 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9331 if(typeof el == 'object' && !el.nodeType){ // dh config
9332 if(where == 'after' && !this.dom.nextSibling){
9333 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9335 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9339 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9340 where == 'before' ? this.dom : this.dom.nextSibling);
9349 * Creates and wraps this element with another element
9350 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9351 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9352 * @return {HTMLElement/Element} The newly created wrapper element
9354 wrap: function(config, returnDom){
9356 config = {tag: "div"};
9358 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9359 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9364 * Replaces the passed element with this element
9365 * @param {String/HTMLElement/Element} el The element to replace
9366 * @return {Roo.Element} this
9368 replace: function(el){
9370 this.insertBefore(el);
9376 * Inserts an html fragment into this element
9377 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9378 * @param {String} html The HTML fragment
9379 * @param {Boolean} returnEl True to return an Roo.Element
9380 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9382 insertHtml : function(where, html, returnEl){
9383 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9384 return returnEl ? Roo.get(el) : el;
9388 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9389 * @param {Object} o The object with the attributes
9390 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9391 * @return {Roo.Element} this
9393 set : function(o, useSet){
9395 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9397 if(attr == "style" || typeof o[attr] == "function") { continue; }
9399 el.className = o["cls"];
9402 el.setAttribute(attr, o[attr]);
9409 Roo.DomHelper.applyStyles(el, o.style);
9415 * Convenience method for constructing a KeyMap
9416 * @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:
9417 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9418 * @param {Function} fn The function to call
9419 * @param {Object} scope (optional) The scope of the function
9420 * @return {Roo.KeyMap} The KeyMap created
9422 addKeyListener : function(key, fn, scope){
9424 if(typeof key != "object" || key instanceof Array){
9440 return new Roo.KeyMap(this, config);
9444 * Creates a KeyMap for this element
9445 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9446 * @return {Roo.KeyMap} The KeyMap created
9448 addKeyMap : function(config){
9449 return new Roo.KeyMap(this, config);
9453 * Returns true if this element is scrollable.
9456 isScrollable : function(){
9458 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9462 * 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().
9463 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9464 * @param {Number} value The new scroll value
9465 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9466 * @return {Element} this
9469 scrollTo : function(side, value, animate){
9470 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9472 this.dom[prop] = value;
9474 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9475 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9481 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9482 * within this element's scrollable range.
9483 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9484 * @param {Number} distance How far to scroll the element in pixels
9485 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9486 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9487 * was scrolled as far as it could go.
9489 scroll : function(direction, distance, animate){
9490 if(!this.isScrollable()){
9494 var l = el.scrollLeft, t = el.scrollTop;
9495 var w = el.scrollWidth, h = el.scrollHeight;
9496 var cw = el.clientWidth, ch = el.clientHeight;
9497 direction = direction.toLowerCase();
9498 var scrolled = false;
9499 var a = this.preanim(arguments, 2);
9504 var v = Math.min(l + distance, w-cw);
9505 this.scrollTo("left", v, a);
9512 var v = Math.max(l - distance, 0);
9513 this.scrollTo("left", v, a);
9521 var v = Math.max(t - distance, 0);
9522 this.scrollTo("top", v, a);
9530 var v = Math.min(t + distance, h-ch);
9531 this.scrollTo("top", v, a);
9540 * Translates the passed page coordinates into left/top css values for this element
9541 * @param {Number/Array} x The page x or an array containing [x, y]
9542 * @param {Number} y The page y
9543 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9545 translatePoints : function(x, y){
9546 if(typeof x == 'object' || x instanceof Array){
9549 var p = this.getStyle('position');
9550 var o = this.getXY();
9552 var l = parseInt(this.getStyle('left'), 10);
9553 var t = parseInt(this.getStyle('top'), 10);
9556 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9559 t = (p == "relative") ? 0 : this.dom.offsetTop;
9562 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9566 * Returns the current scroll position of the element.
9567 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9569 getScroll : function(){
9570 var d = this.dom, doc = document;
9571 if(d == doc || d == doc.body){
9572 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9573 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9574 return {left: l, top: t};
9576 return {left: d.scrollLeft, top: d.scrollTop};
9581 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9582 * are convert to standard 6 digit hex color.
9583 * @param {String} attr The css attribute
9584 * @param {String} defaultValue The default value to use when a valid color isn't found
9585 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9588 getColor : function(attr, defaultValue, prefix){
9589 var v = this.getStyle(attr);
9590 if(!v || v == "transparent" || v == "inherit") {
9591 return defaultValue;
9593 var color = typeof prefix == "undefined" ? "#" : prefix;
9594 if(v.substr(0, 4) == "rgb("){
9595 var rvs = v.slice(4, v.length -1).split(",");
9596 for(var i = 0; i < 3; i++){
9597 var h = parseInt(rvs[i]).toString(16);
9604 if(v.substr(0, 1) == "#"){
9606 for(var i = 1; i < 4; i++){
9607 var c = v.charAt(i);
9610 }else if(v.length == 7){
9611 color += v.substr(1);
9615 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9619 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9620 * gradient background, rounded corners and a 4-way shadow.
9621 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9622 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9623 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9624 * @return {Roo.Element} this
9626 boxWrap : function(cls){
9627 cls = cls || 'x-box';
9628 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9629 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9634 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9635 * @param {String} namespace The namespace in which to look for the attribute
9636 * @param {String} name The attribute name
9637 * @return {String} The attribute value
9639 getAttributeNS : Roo.isIE ? function(ns, name){
9641 var type = typeof d[ns+":"+name];
9642 if(type != 'undefined' && type != 'unknown'){
9643 return d[ns+":"+name];
9646 } : function(ns, name){
9648 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9653 * Sets or Returns the value the dom attribute value
9654 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9655 * @param {String} value (optional) The value to set the attribute to
9656 * @return {String} The attribute value
9658 attr : function(name){
9659 if (arguments.length > 1) {
9660 this.dom.setAttribute(name, arguments[1]);
9661 return arguments[1];
9663 if (typeof(name) == 'object') {
9664 for(var i in name) {
9665 this.attr(i, name[i]);
9671 if (!this.dom.hasAttribute(name)) {
9674 return this.dom.getAttribute(name);
9681 var ep = El.prototype;
9684 * Appends an event handler (Shorthand for addListener)
9685 * @param {String} eventName The type of event to append
9686 * @param {Function} fn The method the event invokes
9687 * @param {Object} scope (optional) The scope (this object) of the fn
9688 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9691 ep.on = ep.addListener;
9693 ep.mon = ep.addListener;
9696 * Removes an event handler from this element (shorthand for removeListener)
9697 * @param {String} eventName the type of event to remove
9698 * @param {Function} fn the method the event invokes
9699 * @return {Roo.Element} this
9702 ep.un = ep.removeListener;
9705 * true to automatically adjust width and height settings for box-model issues (default to true)
9707 ep.autoBoxAdjust = true;
9710 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9713 El.addUnits = function(v, defaultUnit){
9714 if(v === "" || v == "auto"){
9717 if(v === undefined){
9720 if(typeof v == "number" || !El.unitPattern.test(v)){
9721 return v + (defaultUnit || 'px');
9726 // special markup used throughout Roo when box wrapping elements
9727 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>';
9729 * Visibility mode constant - Use visibility to hide element
9735 * Visibility mode constant - Use display to hide element
9741 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9742 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9743 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9755 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9756 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9757 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9758 * @return {Element} The Element object
9761 El.get = function(el){
9763 if(!el){ return null; }
9764 if(typeof el == "string"){ // element id
9765 if(!(elm = document.getElementById(el))){
9768 if(ex = El.cache[el]){
9771 ex = El.cache[el] = new El(elm);
9774 }else if(el.tagName){ // dom element
9778 if(ex = El.cache[id]){
9781 ex = El.cache[id] = new El(el);
9784 }else if(el instanceof El){
9786 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9787 // catch case where it hasn't been appended
9788 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9791 }else if(el.isComposite){
9793 }else if(el instanceof Array){
9794 return El.select(el);
9795 }else if(el == document){
9796 // create a bogus element object representing the document object
9798 var f = function(){};
9799 f.prototype = El.prototype;
9801 docEl.dom = document;
9809 El.uncache = function(el){
9810 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9812 delete El.cache[a[i].id || a[i]];
9818 // Garbage collection - uncache elements/purge listeners on orphaned elements
9819 // so we don't hold a reference and cause the browser to retain them
9820 El.garbageCollect = function(){
9821 if(!Roo.enableGarbageCollector){
9822 clearInterval(El.collectorThread);
9825 for(var eid in El.cache){
9826 var el = El.cache[eid], d = el.dom;
9827 // -------------------------------------------------------
9828 // Determining what is garbage:
9829 // -------------------------------------------------------
9831 // dom node is null, definitely garbage
9832 // -------------------------------------------------------
9834 // no parentNode == direct orphan, definitely garbage
9835 // -------------------------------------------------------
9836 // !d.offsetParent && !document.getElementById(eid)
9837 // display none elements have no offsetParent so we will
9838 // also try to look it up by it's id. However, check
9839 // offsetParent first so we don't do unneeded lookups.
9840 // This enables collection of elements that are not orphans
9841 // directly, but somewhere up the line they have an orphan
9843 // -------------------------------------------------------
9844 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9845 delete El.cache[eid];
9846 if(d && Roo.enableListenerCollection){
9852 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9856 El.Flyweight = function(dom){
9859 El.Flyweight.prototype = El.prototype;
9861 El._flyweights = {};
9863 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9864 * the dom node can be overwritten by other code.
9865 * @param {String/HTMLElement} el The dom node or id
9866 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9867 * prevent conflicts (e.g. internally Roo uses "_internal")
9869 * @return {Element} The shared Element object
9871 El.fly = function(el, named){
9872 named = named || '_global';
9873 el = Roo.getDom(el);
9877 if(!El._flyweights[named]){
9878 El._flyweights[named] = new El.Flyweight();
9880 El._flyweights[named].dom = el;
9881 return El._flyweights[named];
9885 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9886 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9887 * Shorthand of {@link Roo.Element#get}
9888 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9889 * @return {Element} The Element object
9895 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9896 * the dom node can be overwritten by other code.
9897 * Shorthand of {@link Roo.Element#fly}
9898 * @param {String/HTMLElement} el The dom node or id
9899 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9900 * prevent conflicts (e.g. internally Roo uses "_internal")
9902 * @return {Element} The shared Element object
9908 // speedy lookup for elements never to box adjust
9909 var noBoxAdjust = Roo.isStrict ? {
9912 input:1, select:1, textarea:1
9914 if(Roo.isIE || Roo.isGecko){
9915 noBoxAdjust['button'] = 1;
9919 Roo.EventManager.on(window, 'unload', function(){
9921 delete El._flyweights;
9929 Roo.Element.selectorFunction = Roo.DomQuery.select;
9932 Roo.Element.select = function(selector, unique, root){
9934 if(typeof selector == "string"){
9935 els = Roo.Element.selectorFunction(selector, root);
9936 }else if(selector.length !== undefined){
9939 throw "Invalid selector";
9941 if(unique === true){
9942 return new Roo.CompositeElement(els);
9944 return new Roo.CompositeElementLite(els);
9948 * Selects elements based on the passed CSS selector to enable working on them as 1.
9949 * @param {String/Array} selector The CSS selector or an array of elements
9950 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9951 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9952 * @return {CompositeElementLite/CompositeElement}
9956 Roo.select = Roo.Element.select;
9973 * Ext JS Library 1.1.1
9974 * Copyright(c) 2006-2007, Ext JS, LLC.
9976 * Originally Released Under LGPL - original licence link has changed is not relivant.
9979 * <script type="text/javascript">
9984 //Notifies Element that fx methods are available
9985 Roo.enableFx = true;
9989 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9990 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9991 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9992 * Element effects to work.</p><br/>
9994 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9995 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9996 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9997 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9998 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9999 * expected results and should be done with care.</p><br/>
10001 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10002 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10005 ----- -----------------------------
10006 tl The top left corner
10007 t The center of the top edge
10008 tr The top right corner
10009 l The center of the left edge
10010 r The center of the right edge
10011 bl The bottom left corner
10012 b The center of the bottom edge
10013 br The bottom right corner
10015 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10016 * below are common options that can be passed to any Fx method.</b>
10017 * @cfg {Function} callback A function called when the effect is finished
10018 * @cfg {Object} scope The scope of the effect function
10019 * @cfg {String} easing A valid Easing value for the effect
10020 * @cfg {String} afterCls A css class to apply after the effect
10021 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10022 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10023 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10024 * effects that end with the element being visually hidden, ignored otherwise)
10025 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10026 * a function which returns such a specification that will be applied to the Element after the effect finishes
10027 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10028 * @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
10029 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10033 * Slides the element into view. An anchor point can be optionally passed to set the point of
10034 * origin for the slide effect. This function automatically handles wrapping the element with
10035 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10038 // default: slide the element in from the top
10041 // custom: slide the element in from the right with a 2-second duration
10042 el.slideIn('r', { duration: 2 });
10044 // common config options shown with default values
10050 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10051 * @param {Object} options (optional) Object literal with any of the Fx config options
10052 * @return {Roo.Element} The Element
10054 slideIn : function(anchor, o){
10055 var el = this.getFxEl();
10058 el.queueFx(o, function(){
10060 anchor = anchor || "t";
10062 // fix display to visibility
10065 // restore values after effect
10066 var r = this.getFxRestore();
10067 var b = this.getBox();
10068 // fixed size for slide
10072 var wrap = this.fxWrap(r.pos, o, "hidden");
10074 var st = this.dom.style;
10075 st.visibility = "visible";
10076 st.position = "absolute";
10078 // clear out temp styles after slide and unwrap
10079 var after = function(){
10080 el.fxUnwrap(wrap, r.pos, o);
10081 st.width = r.width;
10082 st.height = r.height;
10085 // time to calc the positions
10086 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10088 switch(anchor.toLowerCase()){
10090 wrap.setSize(b.width, 0);
10091 st.left = st.bottom = "0";
10095 wrap.setSize(0, b.height);
10096 st.right = st.top = "0";
10100 wrap.setSize(0, b.height);
10101 wrap.setX(b.right);
10102 st.left = st.top = "0";
10103 a = {width: bw, points: pt};
10106 wrap.setSize(b.width, 0);
10107 wrap.setY(b.bottom);
10108 st.left = st.top = "0";
10109 a = {height: bh, points: pt};
10112 wrap.setSize(0, 0);
10113 st.right = st.bottom = "0";
10114 a = {width: bw, height: bh};
10117 wrap.setSize(0, 0);
10118 wrap.setY(b.y+b.height);
10119 st.right = st.top = "0";
10120 a = {width: bw, height: bh, points: pt};
10123 wrap.setSize(0, 0);
10124 wrap.setXY([b.right, b.bottom]);
10125 st.left = st.top = "0";
10126 a = {width: bw, height: bh, points: pt};
10129 wrap.setSize(0, 0);
10130 wrap.setX(b.x+b.width);
10131 st.left = st.bottom = "0";
10132 a = {width: bw, height: bh, points: pt};
10135 this.dom.style.visibility = "visible";
10138 arguments.callee.anim = wrap.fxanim(a,
10148 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10149 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10150 * 'hidden') but block elements will still take up space in the document. The element must be removed
10151 * from the DOM using the 'remove' config option if desired. This function automatically handles
10152 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10155 // default: slide the element out to the top
10158 // custom: slide the element out to the right with a 2-second duration
10159 el.slideOut('r', { duration: 2 });
10161 // common config options shown with default values
10169 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10170 * @param {Object} options (optional) Object literal with any of the Fx config options
10171 * @return {Roo.Element} The Element
10173 slideOut : function(anchor, o){
10174 var el = this.getFxEl();
10177 el.queueFx(o, function(){
10179 anchor = anchor || "t";
10181 // restore values after effect
10182 var r = this.getFxRestore();
10184 var b = this.getBox();
10185 // fixed size for slide
10189 var wrap = this.fxWrap(r.pos, o, "visible");
10191 var st = this.dom.style;
10192 st.visibility = "visible";
10193 st.position = "absolute";
10197 var after = function(){
10199 el.setDisplayed(false);
10204 el.fxUnwrap(wrap, r.pos, o);
10206 st.width = r.width;
10207 st.height = r.height;
10212 var a, zero = {to: 0};
10213 switch(anchor.toLowerCase()){
10215 st.left = st.bottom = "0";
10216 a = {height: zero};
10219 st.right = st.top = "0";
10223 st.left = st.top = "0";
10224 a = {width: zero, points: {to:[b.right, b.y]}};
10227 st.left = st.top = "0";
10228 a = {height: zero, points: {to:[b.x, b.bottom]}};
10231 st.right = st.bottom = "0";
10232 a = {width: zero, height: zero};
10235 st.right = st.top = "0";
10236 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10239 st.left = st.top = "0";
10240 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10243 st.left = st.bottom = "0";
10244 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10248 arguments.callee.anim = wrap.fxanim(a,
10258 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10259 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10260 * The element must be removed from the DOM using the 'remove' config option if desired.
10266 // common config options shown with default values
10274 * @param {Object} options (optional) Object literal with any of the Fx config options
10275 * @return {Roo.Element} The Element
10277 puff : function(o){
10278 var el = this.getFxEl();
10281 el.queueFx(o, function(){
10282 this.clearOpacity();
10285 // restore values after effect
10286 var r = this.getFxRestore();
10287 var st = this.dom.style;
10289 var after = function(){
10291 el.setDisplayed(false);
10298 el.setPositioning(r.pos);
10299 st.width = r.width;
10300 st.height = r.height;
10305 var width = this.getWidth();
10306 var height = this.getHeight();
10308 arguments.callee.anim = this.fxanim({
10309 width : {to: this.adjustWidth(width * 2)},
10310 height : {to: this.adjustHeight(height * 2)},
10311 points : {by: [-(width * .5), -(height * .5)]},
10313 fontSize: {to:200, unit: "%"}
10324 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10325 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10326 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10332 // all config options shown with default values
10340 * @param {Object} options (optional) Object literal with any of the Fx config options
10341 * @return {Roo.Element} The Element
10343 switchOff : function(o){
10344 var el = this.getFxEl();
10347 el.queueFx(o, function(){
10348 this.clearOpacity();
10351 // restore values after effect
10352 var r = this.getFxRestore();
10353 var st = this.dom.style;
10355 var after = function(){
10357 el.setDisplayed(false);
10363 el.setPositioning(r.pos);
10364 st.width = r.width;
10365 st.height = r.height;
10370 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10371 this.clearOpacity();
10375 points:{by:[0, this.getHeight() * .5]}
10376 }, o, 'motion', 0.3, 'easeIn', after);
10377 }).defer(100, this);
10384 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10385 * changed using the "attr" config option) and then fading back to the original color. If no original
10386 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10389 // default: highlight background to yellow
10392 // custom: highlight foreground text to blue for 2 seconds
10393 el.highlight("0000ff", { attr: 'color', duration: 2 });
10395 // common config options shown with default values
10396 el.highlight("ffff9c", {
10397 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10398 endColor: (current color) or "ffffff",
10403 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10404 * @param {Object} options (optional) Object literal with any of the Fx config options
10405 * @return {Roo.Element} The Element
10407 highlight : function(color, o){
10408 var el = this.getFxEl();
10411 el.queueFx(o, function(){
10412 color = color || "ffff9c";
10413 attr = o.attr || "backgroundColor";
10415 this.clearOpacity();
10418 var origColor = this.getColor(attr);
10419 var restoreColor = this.dom.style[attr];
10420 endColor = (o.endColor || origColor) || "ffffff";
10422 var after = function(){
10423 el.dom.style[attr] = restoreColor;
10428 a[attr] = {from: color, to: endColor};
10429 arguments.callee.anim = this.fxanim(a,
10439 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10442 // default: a single light blue ripple
10445 // custom: 3 red ripples lasting 3 seconds total
10446 el.frame("ff0000", 3, { duration: 3 });
10448 // common config options shown with default values
10449 el.frame("C3DAF9", 1, {
10450 duration: 1 //duration of entire animation (not each individual ripple)
10451 // Note: Easing is not configurable and will be ignored if included
10454 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10455 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10456 * @param {Object} options (optional) Object literal with any of the Fx config options
10457 * @return {Roo.Element} The Element
10459 frame : function(color, count, o){
10460 var el = this.getFxEl();
10463 el.queueFx(o, function(){
10464 color = color || "#C3DAF9";
10465 if(color.length == 6){
10466 color = "#" + color;
10468 count = count || 1;
10469 duration = o.duration || 1;
10472 var b = this.getBox();
10473 var animFn = function(){
10474 var proxy = this.createProxy({
10477 visbility:"hidden",
10478 position:"absolute",
10479 "z-index":"35000", // yee haw
10480 border:"0px solid " + color
10483 var scale = Roo.isBorderBox ? 2 : 1;
10485 top:{from:b.y, to:b.y - 20},
10486 left:{from:b.x, to:b.x - 20},
10487 borderWidth:{from:0, to:10},
10488 opacity:{from:1, to:0},
10489 height:{from:b.height, to:(b.height + (20*scale))},
10490 width:{from:b.width, to:(b.width + (20*scale))}
10491 }, duration, function(){
10495 animFn.defer((duration/2)*1000, this);
10506 * Creates a pause before any subsequent queued effects begin. If there are
10507 * no effects queued after the pause it will have no effect.
10512 * @param {Number} seconds The length of time to pause (in seconds)
10513 * @return {Roo.Element} The Element
10515 pause : function(seconds){
10516 var el = this.getFxEl();
10519 el.queueFx(o, function(){
10520 setTimeout(function(){
10522 }, seconds * 1000);
10528 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10529 * using the "endOpacity" config option.
10532 // default: fade in from opacity 0 to 100%
10535 // custom: fade in from opacity 0 to 75% over 2 seconds
10536 el.fadeIn({ endOpacity: .75, duration: 2});
10538 // common config options shown with default values
10540 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10545 * @param {Object} options (optional) Object literal with any of the Fx config options
10546 * @return {Roo.Element} The Element
10548 fadeIn : function(o){
10549 var el = this.getFxEl();
10551 el.queueFx(o, function(){
10552 this.setOpacity(0);
10554 this.dom.style.visibility = 'visible';
10555 var to = o.endOpacity || 1;
10556 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10557 o, null, .5, "easeOut", function(){
10559 this.clearOpacity();
10568 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10569 * using the "endOpacity" config option.
10572 // default: fade out from the element's current opacity to 0
10575 // custom: fade out from the element's current opacity to 25% over 2 seconds
10576 el.fadeOut({ endOpacity: .25, duration: 2});
10578 // common config options shown with default values
10580 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10587 * @param {Object} options (optional) Object literal with any of the Fx config options
10588 * @return {Roo.Element} The Element
10590 fadeOut : function(o){
10591 var el = this.getFxEl();
10593 el.queueFx(o, function(){
10594 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10595 o, null, .5, "easeOut", function(){
10596 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10597 this.dom.style.display = "none";
10599 this.dom.style.visibility = "hidden";
10601 this.clearOpacity();
10609 * Animates the transition of an element's dimensions from a starting height/width
10610 * to an ending height/width.
10613 // change height and width to 100x100 pixels
10614 el.scale(100, 100);
10616 // common config options shown with default values. The height and width will default to
10617 // the element's existing values if passed as null.
10620 [element's height], {
10625 * @param {Number} width The new width (pass undefined to keep the original width)
10626 * @param {Number} height The new height (pass undefined to keep the original height)
10627 * @param {Object} options (optional) Object literal with any of the Fx config options
10628 * @return {Roo.Element} The Element
10630 scale : function(w, h, o){
10631 this.shift(Roo.apply({}, o, {
10639 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10640 * Any of these properties not specified in the config object will not be changed. This effect
10641 * requires that at least one new dimension, position or opacity setting must be passed in on
10642 * the config object in order for the function to have any effect.
10645 // slide the element horizontally to x position 200 while changing the height and opacity
10646 el.shift({ x: 200, height: 50, opacity: .8 });
10648 // common config options shown with default values.
10650 width: [element's width],
10651 height: [element's height],
10652 x: [element's x position],
10653 y: [element's y position],
10654 opacity: [element's opacity],
10659 * @param {Object} options Object literal with any of the Fx config options
10660 * @return {Roo.Element} The Element
10662 shift : function(o){
10663 var el = this.getFxEl();
10665 el.queueFx(o, function(){
10666 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10667 if(w !== undefined){
10668 a.width = {to: this.adjustWidth(w)};
10670 if(h !== undefined){
10671 a.height = {to: this.adjustHeight(h)};
10673 if(x !== undefined || y !== undefined){
10675 x !== undefined ? x : this.getX(),
10676 y !== undefined ? y : this.getY()
10679 if(op !== undefined){
10680 a.opacity = {to: op};
10682 if(o.xy !== undefined){
10683 a.points = {to: o.xy};
10685 arguments.callee.anim = this.fxanim(a,
10686 o, 'motion', .35, "easeOut", function(){
10694 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10695 * ending point of the effect.
10698 // default: slide the element downward while fading out
10701 // custom: slide the element out to the right with a 2-second duration
10702 el.ghost('r', { duration: 2 });
10704 // common config options shown with default values
10712 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10713 * @param {Object} options (optional) Object literal with any of the Fx config options
10714 * @return {Roo.Element} The Element
10716 ghost : function(anchor, o){
10717 var el = this.getFxEl();
10720 el.queueFx(o, function(){
10721 anchor = anchor || "b";
10723 // restore values after effect
10724 var r = this.getFxRestore();
10725 var w = this.getWidth(),
10726 h = this.getHeight();
10728 var st = this.dom.style;
10730 var after = function(){
10732 el.setDisplayed(false);
10738 el.setPositioning(r.pos);
10739 st.width = r.width;
10740 st.height = r.height;
10745 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10746 switch(anchor.toLowerCase()){
10773 arguments.callee.anim = this.fxanim(a,
10783 * Ensures that all effects queued after syncFx is called on the element are
10784 * run concurrently. This is the opposite of {@link #sequenceFx}.
10785 * @return {Roo.Element} The Element
10787 syncFx : function(){
10788 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10797 * Ensures that all effects queued after sequenceFx is called on the element are
10798 * run in sequence. This is the opposite of {@link #syncFx}.
10799 * @return {Roo.Element} The Element
10801 sequenceFx : function(){
10802 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10804 concurrent : false,
10811 nextFx : function(){
10812 var ef = this.fxQueue[0];
10819 * Returns true if the element has any effects actively running or queued, else returns false.
10820 * @return {Boolean} True if element has active effects, else false
10822 hasActiveFx : function(){
10823 return this.fxQueue && this.fxQueue[0];
10827 * Stops any running effects and clears the element's internal effects queue if it contains
10828 * any additional effects that haven't started yet.
10829 * @return {Roo.Element} The Element
10831 stopFx : function(){
10832 if(this.hasActiveFx()){
10833 var cur = this.fxQueue[0];
10834 if(cur && cur.anim && cur.anim.isAnimated()){
10835 this.fxQueue = [cur]; // clear out others
10836 cur.anim.stop(true);
10843 beforeFx : function(o){
10844 if(this.hasActiveFx() && !o.concurrent){
10855 * Returns true if the element is currently blocking so that no other effect can be queued
10856 * until this effect is finished, else returns false if blocking is not set. This is commonly
10857 * used to ensure that an effect initiated by a user action runs to completion prior to the
10858 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10859 * @return {Boolean} True if blocking, else false
10861 hasFxBlock : function(){
10862 var q = this.fxQueue;
10863 return q && q[0] && q[0].block;
10867 queueFx : function(o, fn){
10871 if(!this.hasFxBlock()){
10872 Roo.applyIf(o, this.fxDefaults);
10874 var run = this.beforeFx(o);
10875 fn.block = o.block;
10876 this.fxQueue.push(fn);
10888 fxWrap : function(pos, o, vis){
10890 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10893 wrapXY = this.getXY();
10895 var div = document.createElement("div");
10896 div.style.visibility = vis;
10897 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10898 wrap.setPositioning(pos);
10899 if(wrap.getStyle("position") == "static"){
10900 wrap.position("relative");
10902 this.clearPositioning('auto');
10904 wrap.dom.appendChild(this.dom);
10906 wrap.setXY(wrapXY);
10913 fxUnwrap : function(wrap, pos, o){
10914 this.clearPositioning();
10915 this.setPositioning(pos);
10917 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10923 getFxRestore : function(){
10924 var st = this.dom.style;
10925 return {pos: this.getPositioning(), width: st.width, height : st.height};
10929 afterFx : function(o){
10931 this.applyStyles(o.afterStyle);
10934 this.addClass(o.afterCls);
10936 if(o.remove === true){
10939 Roo.callback(o.callback, o.scope, [this]);
10941 this.fxQueue.shift();
10947 getFxEl : function(){ // support for composite element fx
10948 return Roo.get(this.dom);
10952 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10953 animType = animType || 'run';
10955 var anim = Roo.lib.Anim[animType](
10957 (opt.duration || defaultDur) || .35,
10958 (opt.easing || defaultEase) || 'easeOut',
10960 Roo.callback(cb, this);
10969 // backwords compat
10970 Roo.Fx.resize = Roo.Fx.scale;
10972 //When included, Roo.Fx is automatically applied to Element so that all basic
10973 //effects are available directly via the Element API
10974 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10976 * Ext JS Library 1.1.1
10977 * Copyright(c) 2006-2007, Ext JS, LLC.
10979 * Originally Released Under LGPL - original licence link has changed is not relivant.
10982 * <script type="text/javascript">
10987 * @class Roo.CompositeElement
10988 * Standard composite class. Creates a Roo.Element for every element in the collection.
10990 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10991 * actions will be performed on all the elements in this collection.</b>
10993 * All methods return <i>this</i> and can be chained.
10995 var els = Roo.select("#some-el div.some-class", true);
10996 // or select directly from an existing element
10997 var el = Roo.get('some-el');
10998 el.select('div.some-class', true);
11000 els.setWidth(100); // all elements become 100 width
11001 els.hide(true); // all elements fade out and hide
11003 els.setWidth(100).hide(true);
11006 Roo.CompositeElement = function(els){
11007 this.elements = [];
11008 this.addElements(els);
11010 Roo.CompositeElement.prototype = {
11012 addElements : function(els){
11016 if(typeof els == "string"){
11017 els = Roo.Element.selectorFunction(els);
11019 var yels = this.elements;
11020 var index = yels.length-1;
11021 for(var i = 0, len = els.length; i < len; i++) {
11022 yels[++index] = Roo.get(els[i]);
11028 * Clears this composite and adds the elements returned by the passed selector.
11029 * @param {String/Array} els A string CSS selector, an array of elements or an element
11030 * @return {CompositeElement} this
11032 fill : function(els){
11033 this.elements = [];
11039 * Filters this composite to only elements that match the passed selector.
11040 * @param {String} selector A string CSS selector
11041 * @param {Boolean} inverse return inverse filter (not matches)
11042 * @return {CompositeElement} this
11044 filter : function(selector, inverse){
11046 inverse = inverse || false;
11047 this.each(function(el){
11048 var match = inverse ? !el.is(selector) : el.is(selector);
11050 els[els.length] = el.dom;
11057 invoke : function(fn, args){
11058 var els = this.elements;
11059 for(var i = 0, len = els.length; i < len; i++) {
11060 Roo.Element.prototype[fn].apply(els[i], args);
11065 * Adds elements to this composite.
11066 * @param {String/Array} els A string CSS selector, an array of elements or an element
11067 * @return {CompositeElement} this
11069 add : function(els){
11070 if(typeof els == "string"){
11071 this.addElements(Roo.Element.selectorFunction(els));
11072 }else if(els.length !== undefined){
11073 this.addElements(els);
11075 this.addElements([els]);
11080 * Calls the passed function passing (el, this, index) for each element in this composite.
11081 * @param {Function} fn The function to call
11082 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11083 * @return {CompositeElement} this
11085 each : function(fn, scope){
11086 var els = this.elements;
11087 for(var i = 0, len = els.length; i < len; i++){
11088 if(fn.call(scope || els[i], els[i], this, i) === false) {
11096 * Returns the Element object at the specified index
11097 * @param {Number} index
11098 * @return {Roo.Element}
11100 item : function(index){
11101 return this.elements[index] || null;
11105 * Returns the first Element
11106 * @return {Roo.Element}
11108 first : function(){
11109 return this.item(0);
11113 * Returns the last Element
11114 * @return {Roo.Element}
11117 return this.item(this.elements.length-1);
11121 * Returns the number of elements in this composite
11124 getCount : function(){
11125 return this.elements.length;
11129 * Returns true if this composite contains the passed element
11132 contains : function(el){
11133 return this.indexOf(el) !== -1;
11137 * Returns true if this composite contains the passed element
11140 indexOf : function(el){
11141 return this.elements.indexOf(Roo.get(el));
11146 * Removes the specified element(s).
11147 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11148 * or an array of any of those.
11149 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11150 * @return {CompositeElement} this
11152 removeElement : function(el, removeDom){
11153 if(el instanceof Array){
11154 for(var i = 0, len = el.length; i < len; i++){
11155 this.removeElement(el[i]);
11159 var index = typeof el == 'number' ? el : this.indexOf(el);
11162 var d = this.elements[index];
11166 d.parentNode.removeChild(d);
11169 this.elements.splice(index, 1);
11175 * Replaces the specified element with the passed element.
11176 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11178 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11179 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11180 * @return {CompositeElement} this
11182 replaceElement : function(el, replacement, domReplace){
11183 var index = typeof el == 'number' ? el : this.indexOf(el);
11186 this.elements[index].replaceWith(replacement);
11188 this.elements.splice(index, 1, Roo.get(replacement))
11195 * Removes all elements.
11197 clear : function(){
11198 this.elements = [];
11202 Roo.CompositeElement.createCall = function(proto, fnName){
11203 if(!proto[fnName]){
11204 proto[fnName] = function(){
11205 return this.invoke(fnName, arguments);
11209 for(var fnName in Roo.Element.prototype){
11210 if(typeof Roo.Element.prototype[fnName] == "function"){
11211 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11217 * Ext JS Library 1.1.1
11218 * Copyright(c) 2006-2007, Ext JS, LLC.
11220 * Originally Released Under LGPL - original licence link has changed is not relivant.
11223 * <script type="text/javascript">
11227 * @class Roo.CompositeElementLite
11228 * @extends Roo.CompositeElement
11229 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11231 var els = Roo.select("#some-el div.some-class");
11232 // or select directly from an existing element
11233 var el = Roo.get('some-el');
11234 el.select('div.some-class');
11236 els.setWidth(100); // all elements become 100 width
11237 els.hide(true); // all elements fade out and hide
11239 els.setWidth(100).hide(true);
11240 </code></pre><br><br>
11241 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11242 * actions will be performed on all the elements in this collection.</b>
11244 Roo.CompositeElementLite = function(els){
11245 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11246 this.el = new Roo.Element.Flyweight();
11248 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11249 addElements : function(els){
11251 if(els instanceof Array){
11252 this.elements = this.elements.concat(els);
11254 var yels = this.elements;
11255 var index = yels.length-1;
11256 for(var i = 0, len = els.length; i < len; i++) {
11257 yels[++index] = els[i];
11263 invoke : function(fn, args){
11264 var els = this.elements;
11266 for(var i = 0, len = els.length; i < len; i++) {
11268 Roo.Element.prototype[fn].apply(el, args);
11273 * Returns a flyweight Element of the dom element object at the specified index
11274 * @param {Number} index
11275 * @return {Roo.Element}
11277 item : function(index){
11278 if(!this.elements[index]){
11281 this.el.dom = this.elements[index];
11285 // fixes scope with flyweight
11286 addListener : function(eventName, handler, scope, opt){
11287 var els = this.elements;
11288 for(var i = 0, len = els.length; i < len; i++) {
11289 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11295 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11296 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11297 * a reference to the dom node, use el.dom.</b>
11298 * @param {Function} fn The function to call
11299 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11300 * @return {CompositeElement} this
11302 each : function(fn, scope){
11303 var els = this.elements;
11305 for(var i = 0, len = els.length; i < len; i++){
11307 if(fn.call(scope || el, el, this, i) === false){
11314 indexOf : function(el){
11315 return this.elements.indexOf(Roo.getDom(el));
11318 replaceElement : function(el, replacement, domReplace){
11319 var index = typeof el == 'number' ? el : this.indexOf(el);
11321 replacement = Roo.getDom(replacement);
11323 var d = this.elements[index];
11324 d.parentNode.insertBefore(replacement, d);
11325 d.parentNode.removeChild(d);
11327 this.elements.splice(index, 1, replacement);
11332 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11336 * Ext JS Library 1.1.1
11337 * Copyright(c) 2006-2007, Ext JS, LLC.
11339 * Originally Released Under LGPL - original licence link has changed is not relivant.
11342 * <script type="text/javascript">
11348 * @class Roo.data.Connection
11349 * @extends Roo.util.Observable
11350 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11351 * either to a configured URL, or to a URL specified at request time.<br><br>
11353 * Requests made by this class are asynchronous, and will return immediately. No data from
11354 * the server will be available to the statement immediately following the {@link #request} call.
11355 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11357 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11358 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11359 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11360 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11361 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11362 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11363 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11364 * standard DOM methods.
11366 * @param {Object} config a configuration object.
11368 Roo.data.Connection = function(config){
11369 Roo.apply(this, config);
11372 * @event beforerequest
11373 * Fires before a network request is made to retrieve a data object.
11374 * @param {Connection} conn This Connection object.
11375 * @param {Object} options The options config object passed to the {@link #request} method.
11377 "beforerequest" : true,
11379 * @event requestcomplete
11380 * Fires if the request was successfully completed.
11381 * @param {Connection} conn This Connection object.
11382 * @param {Object} response The XHR object containing the response data.
11383 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11384 * @param {Object} options The options config object passed to the {@link #request} method.
11386 "requestcomplete" : true,
11388 * @event requestexception
11389 * Fires if an error HTTP status was returned from the server.
11390 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11391 * @param {Connection} conn This Connection object.
11392 * @param {Object} response The XHR object containing the response data.
11393 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11394 * @param {Object} options The options config object passed to the {@link #request} method.
11396 "requestexception" : true
11398 Roo.data.Connection.superclass.constructor.call(this);
11401 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11403 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11406 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11407 * extra parameters to each request made by this object. (defaults to undefined)
11410 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11411 * to each request made by this object. (defaults to undefined)
11414 * @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)
11417 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11421 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11427 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11430 disableCaching: true,
11433 * Sends an HTTP request to a remote server.
11434 * @param {Object} options An object which may contain the following properties:<ul>
11435 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11436 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11437 * request, a url encoded string or a function to call to get either.</li>
11438 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11439 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11440 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11441 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11442 * <li>options {Object} The parameter to the request call.</li>
11443 * <li>success {Boolean} True if the request succeeded.</li>
11444 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11446 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11447 * The callback is passed the following parameters:<ul>
11448 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11449 * <li>options {Object} The parameter to the request call.</li>
11451 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11452 * The callback is passed the following parameters:<ul>
11453 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11454 * <li>options {Object} The parameter to the request call.</li>
11456 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11457 * for the callback function. Defaults to the browser window.</li>
11458 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11459 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11460 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11461 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11462 * params for the post data. Any params will be appended to the URL.</li>
11463 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11465 * @return {Number} transactionId
11467 request : function(o){
11468 if(this.fireEvent("beforerequest", this, o) !== false){
11471 if(typeof p == "function"){
11472 p = p.call(o.scope||window, o);
11474 if(typeof p == "object"){
11475 p = Roo.urlEncode(o.params);
11477 if(this.extraParams){
11478 var extras = Roo.urlEncode(this.extraParams);
11479 p = p ? (p + '&' + extras) : extras;
11482 var url = o.url || this.url;
11483 if(typeof url == 'function'){
11484 url = url.call(o.scope||window, o);
11488 var form = Roo.getDom(o.form);
11489 url = url || form.action;
11491 var enctype = form.getAttribute("enctype");
11492 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11493 return this.doFormUpload(o, p, url);
11495 var f = Roo.lib.Ajax.serializeForm(form);
11496 p = p ? (p + '&' + f) : f;
11499 var hs = o.headers;
11500 if(this.defaultHeaders){
11501 hs = Roo.apply(hs || {}, this.defaultHeaders);
11508 success: this.handleResponse,
11509 failure: this.handleFailure,
11511 argument: {options: o},
11512 timeout : o.timeout || this.timeout
11515 var method = o.method||this.method||(p ? "POST" : "GET");
11517 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11518 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11521 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11525 }else if(this.autoAbort !== false){
11529 if((method == 'GET' && p) || o.xmlData){
11530 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11533 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11534 return this.transId;
11536 Roo.callback(o.callback, o.scope, [o, null, null]);
11542 * Determine whether this object has a request outstanding.
11543 * @param {Number} transactionId (Optional) defaults to the last transaction
11544 * @return {Boolean} True if there is an outstanding request.
11546 isLoading : function(transId){
11548 return Roo.lib.Ajax.isCallInProgress(transId);
11550 return this.transId ? true : false;
11555 * Aborts any outstanding request.
11556 * @param {Number} transactionId (Optional) defaults to the last transaction
11558 abort : function(transId){
11559 if(transId || this.isLoading()){
11560 Roo.lib.Ajax.abort(transId || this.transId);
11565 handleResponse : function(response){
11566 this.transId = false;
11567 var options = response.argument.options;
11568 response.argument = options ? options.argument : null;
11569 this.fireEvent("requestcomplete", this, response, options);
11570 Roo.callback(options.success, options.scope, [response, options]);
11571 Roo.callback(options.callback, options.scope, [options, true, response]);
11575 handleFailure : function(response, e){
11576 this.transId = false;
11577 var options = response.argument.options;
11578 response.argument = options ? options.argument : null;
11579 this.fireEvent("requestexception", this, response, options, e);
11580 Roo.callback(options.failure, options.scope, [response, options]);
11581 Roo.callback(options.callback, options.scope, [options, false, response]);
11585 doFormUpload : function(o, ps, url){
11587 var frame = document.createElement('iframe');
11590 frame.className = 'x-hidden';
11592 frame.src = Roo.SSL_SECURE_URL;
11594 document.body.appendChild(frame);
11597 document.frames[id].name = id;
11600 var form = Roo.getDom(o.form);
11602 form.method = 'POST';
11603 form.enctype = form.encoding = 'multipart/form-data';
11609 if(ps){ // add dynamic params
11611 ps = Roo.urlDecode(ps, false);
11613 if(ps.hasOwnProperty(k)){
11614 hd = document.createElement('input');
11615 hd.type = 'hidden';
11618 form.appendChild(hd);
11625 var r = { // bogus response object
11630 r.argument = o ? o.argument : null;
11635 doc = frame.contentWindow.document;
11637 doc = (frame.contentDocument || window.frames[id].document);
11639 if(doc && doc.body){
11640 r.responseText = doc.body.innerHTML;
11642 if(doc && doc.XMLDocument){
11643 r.responseXML = doc.XMLDocument;
11645 r.responseXML = doc;
11652 Roo.EventManager.removeListener(frame, 'load', cb, this);
11654 this.fireEvent("requestcomplete", this, r, o);
11655 Roo.callback(o.success, o.scope, [r, o]);
11656 Roo.callback(o.callback, o.scope, [o, true, r]);
11658 setTimeout(function(){document.body.removeChild(frame);}, 100);
11661 Roo.EventManager.on(frame, 'load', cb, this);
11664 if(hiddens){ // remove dynamic params
11665 for(var i = 0, len = hiddens.length; i < len; i++){
11666 form.removeChild(hiddens[i]);
11673 * Ext JS Library 1.1.1
11674 * Copyright(c) 2006-2007, Ext JS, LLC.
11676 * Originally Released Under LGPL - original licence link has changed is not relivant.
11679 * <script type="text/javascript">
11683 * Global Ajax request class.
11686 * @extends Roo.data.Connection
11689 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11690 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11691 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11692 * @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)
11693 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11694 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11695 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11697 Roo.Ajax = new Roo.data.Connection({
11706 * Serialize the passed form into a url encoded string
11708 * @param {String/HTMLElement} form
11711 serializeForm : function(form){
11712 return Roo.lib.Ajax.serializeForm(form);
11716 * Ext JS Library 1.1.1
11717 * Copyright(c) 2006-2007, Ext JS, LLC.
11719 * Originally Released Under LGPL - original licence link has changed is not relivant.
11722 * <script type="text/javascript">
11727 * @class Roo.UpdateManager
11728 * @extends Roo.util.Observable
11729 * Provides AJAX-style update for Element object.<br><br>
11732 * // Get it from a Roo.Element object
11733 * var el = Roo.get("foo");
11734 * var mgr = el.getUpdateManager();
11735 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11737 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11739 * // or directly (returns the same UpdateManager instance)
11740 * var mgr = new Roo.UpdateManager("myElementId");
11741 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11742 * mgr.on("update", myFcnNeedsToKnow);
11744 // short handed call directly from the element object
11745 Roo.get("foo").load({
11749 text: "Loading Foo..."
11753 * Create new UpdateManager directly.
11754 * @param {String/HTMLElement/Roo.Element} el The element to update
11755 * @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).
11757 Roo.UpdateManager = function(el, forceNew){
11759 if(!forceNew && el.updateManager){
11760 return el.updateManager;
11763 * The Element object
11764 * @type Roo.Element
11768 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11771 this.defaultUrl = null;
11775 * @event beforeupdate
11776 * Fired before an update is made, return false from your handler and the update is cancelled.
11777 * @param {Roo.Element} el
11778 * @param {String/Object/Function} url
11779 * @param {String/Object} params
11781 "beforeupdate": true,
11784 * Fired after successful update is made.
11785 * @param {Roo.Element} el
11786 * @param {Object} oResponseObject The response Object
11791 * Fired on update failure.
11792 * @param {Roo.Element} el
11793 * @param {Object} oResponseObject The response Object
11797 var d = Roo.UpdateManager.defaults;
11799 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11802 this.sslBlankUrl = d.sslBlankUrl;
11804 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11807 this.disableCaching = d.disableCaching;
11809 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11812 this.indicatorText = d.indicatorText;
11814 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11817 this.showLoadIndicator = d.showLoadIndicator;
11819 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11822 this.timeout = d.timeout;
11825 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11828 this.loadScripts = d.loadScripts;
11831 * Transaction object of current executing transaction
11833 this.transaction = null;
11838 this.autoRefreshProcId = null;
11840 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11843 this.refreshDelegate = this.refresh.createDelegate(this);
11845 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11848 this.updateDelegate = this.update.createDelegate(this);
11850 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11853 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11857 this.successDelegate = this.processSuccess.createDelegate(this);
11861 this.failureDelegate = this.processFailure.createDelegate(this);
11863 if(!this.renderer){
11865 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11867 this.renderer = new Roo.UpdateManager.BasicRenderer();
11870 Roo.UpdateManager.superclass.constructor.call(this);
11873 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11875 * Get the Element this UpdateManager is bound to
11876 * @return {Roo.Element} The element
11878 getEl : function(){
11882 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11883 * @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:
11886 url: "your-url.php",<br/>
11887 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11888 callback: yourFunction,<br/>
11889 scope: yourObject, //(optional scope) <br/>
11890 discardUrl: false, <br/>
11891 nocache: false,<br/>
11892 text: "Loading...",<br/>
11894 scripts: false<br/>
11897 * The only required property is url. The optional properties nocache, text and scripts
11898 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11899 * @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}
11900 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11901 * @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.
11903 update : function(url, params, callback, discardUrl){
11904 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11905 var method = this.method,
11907 if(typeof url == "object"){ // must be config object
11910 params = params || cfg.params;
11911 callback = callback || cfg.callback;
11912 discardUrl = discardUrl || cfg.discardUrl;
11913 if(callback && cfg.scope){
11914 callback = callback.createDelegate(cfg.scope);
11916 if(typeof cfg.method != "undefined"){method = cfg.method;};
11917 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11918 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11919 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11920 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11922 this.showLoading();
11924 this.defaultUrl = url;
11926 if(typeof url == "function"){
11927 url = url.call(this);
11930 method = method || (params ? "POST" : "GET");
11931 if(method == "GET"){
11932 url = this.prepareUrl(url);
11935 var o = Roo.apply(cfg ||{}, {
11938 success: this.successDelegate,
11939 failure: this.failureDelegate,
11940 callback: undefined,
11941 timeout: (this.timeout*1000),
11942 argument: {"url": url, "form": null, "callback": callback, "params": params}
11944 Roo.log("updated manager called with timeout of " + o.timeout);
11945 this.transaction = Roo.Ajax.request(o);
11950 * 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.
11951 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11952 * @param {String/HTMLElement} form The form Id or form element
11953 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11954 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11955 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11957 formUpdate : function(form, url, reset, callback){
11958 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11959 if(typeof url == "function"){
11960 url = url.call(this);
11962 form = Roo.getDom(form);
11963 this.transaction = Roo.Ajax.request({
11966 success: this.successDelegate,
11967 failure: this.failureDelegate,
11968 timeout: (this.timeout*1000),
11969 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11971 this.showLoading.defer(1, this);
11976 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11977 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11979 refresh : function(callback){
11980 if(this.defaultUrl == null){
11983 this.update(this.defaultUrl, null, callback, true);
11987 * Set this element to auto refresh.
11988 * @param {Number} interval How often to update (in seconds).
11989 * @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)
11990 * @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}
11991 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11992 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11994 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11996 this.update(url || this.defaultUrl, params, callback, true);
11998 if(this.autoRefreshProcId){
11999 clearInterval(this.autoRefreshProcId);
12001 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12005 * Stop auto refresh on this element.
12007 stopAutoRefresh : function(){
12008 if(this.autoRefreshProcId){
12009 clearInterval(this.autoRefreshProcId);
12010 delete this.autoRefreshProcId;
12014 isAutoRefreshing : function(){
12015 return this.autoRefreshProcId ? true : false;
12018 * Called to update the element to "Loading" state. Override to perform custom action.
12020 showLoading : function(){
12021 if(this.showLoadIndicator){
12022 this.el.update(this.indicatorText);
12027 * Adds unique parameter to query string if disableCaching = true
12030 prepareUrl : function(url){
12031 if(this.disableCaching){
12032 var append = "_dc=" + (new Date().getTime());
12033 if(url.indexOf("?") !== -1){
12034 url += "&" + append;
12036 url += "?" + append;
12045 processSuccess : function(response){
12046 this.transaction = null;
12047 if(response.argument.form && response.argument.reset){
12048 try{ // put in try/catch since some older FF releases had problems with this
12049 response.argument.form.reset();
12052 if(this.loadScripts){
12053 this.renderer.render(this.el, response, this,
12054 this.updateComplete.createDelegate(this, [response]));
12056 this.renderer.render(this.el, response, this);
12057 this.updateComplete(response);
12061 updateComplete : function(response){
12062 this.fireEvent("update", this.el, response);
12063 if(typeof response.argument.callback == "function"){
12064 response.argument.callback(this.el, true, response);
12071 processFailure : function(response){
12072 this.transaction = null;
12073 this.fireEvent("failure", this.el, response);
12074 if(typeof response.argument.callback == "function"){
12075 response.argument.callback(this.el, false, response);
12080 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12081 * @param {Object} renderer The object implementing the render() method
12083 setRenderer : function(renderer){
12084 this.renderer = renderer;
12087 getRenderer : function(){
12088 return this.renderer;
12092 * Set the defaultUrl used for updates
12093 * @param {String/Function} defaultUrl The url or a function to call to get the url
12095 setDefaultUrl : function(defaultUrl){
12096 this.defaultUrl = defaultUrl;
12100 * Aborts the executing transaction
12102 abort : function(){
12103 if(this.transaction){
12104 Roo.Ajax.abort(this.transaction);
12109 * Returns true if an update is in progress
12110 * @return {Boolean}
12112 isUpdating : function(){
12113 if(this.transaction){
12114 return Roo.Ajax.isLoading(this.transaction);
12121 * @class Roo.UpdateManager.defaults
12122 * @static (not really - but it helps the doc tool)
12123 * The defaults collection enables customizing the default properties of UpdateManager
12125 Roo.UpdateManager.defaults = {
12127 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12133 * True to process scripts by default (Defaults to false).
12136 loadScripts : false,
12139 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12142 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12144 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12147 disableCaching : false,
12149 * Whether to show indicatorText when loading (Defaults to true).
12152 showLoadIndicator : true,
12154 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12157 indicatorText : '<div class="loading-indicator">Loading...</div>'
12161 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12163 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12164 * @param {String/HTMLElement/Roo.Element} el The element to update
12165 * @param {String} url The url
12166 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12167 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12170 * @member Roo.UpdateManager
12172 Roo.UpdateManager.updateElement = function(el, url, params, options){
12173 var um = Roo.get(el, true).getUpdateManager();
12174 Roo.apply(um, options);
12175 um.update(url, params, options ? options.callback : null);
12177 // alias for backwards compat
12178 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12180 * @class Roo.UpdateManager.BasicRenderer
12181 * Default Content renderer. Updates the elements innerHTML with the responseText.
12183 Roo.UpdateManager.BasicRenderer = function(){};
12185 Roo.UpdateManager.BasicRenderer.prototype = {
12187 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12188 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12189 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12190 * @param {Roo.Element} el The element being rendered
12191 * @param {Object} response The YUI Connect response object
12192 * @param {UpdateManager} updateManager The calling update manager
12193 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12195 render : function(el, response, updateManager, callback){
12196 el.update(response.responseText, updateManager.loadScripts, callback);
12202 * (c)) Alan Knowles
12208 * @class Roo.DomTemplate
12209 * @extends Roo.Template
12210 * An effort at a dom based template engine..
12212 * Similar to XTemplate, except it uses dom parsing to create the template..
12214 * Supported features:
12219 {a_variable} - output encoded.
12220 {a_variable.format:("Y-m-d")} - call a method on the variable
12221 {a_variable:raw} - unencoded output
12222 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12223 {a_variable:this.method_on_template(...)} - call a method on the template object.
12228 <div roo-for="a_variable or condition.."></div>
12229 <div roo-if="a_variable or condition"></div>
12230 <div roo-exec="some javascript"></div>
12231 <div roo-name="named_template"></div>
12236 Roo.DomTemplate = function()
12238 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12245 Roo.extend(Roo.DomTemplate, Roo.Template, {
12247 * id counter for sub templates.
12251 * flag to indicate if dom parser is inside a pre,
12252 * it will strip whitespace if not.
12257 * The various sub templates
12265 * basic tag replacing syntax
12268 * // you can fake an object call by doing this
12272 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12273 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12275 iterChild : function (node, method) {
12277 var oldPre = this.inPre;
12278 if (node.tagName == 'PRE') {
12281 for( var i = 0; i < node.childNodes.length; i++) {
12282 method.call(this, node.childNodes[i]);
12284 this.inPre = oldPre;
12290 * compile the template
12292 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12295 compile: function()
12299 // covert the html into DOM...
12303 doc = document.implementation.createHTMLDocument("");
12304 doc.documentElement.innerHTML = this.html ;
12305 div = doc.documentElement;
12307 // old IE... - nasty -- it causes all sorts of issues.. with
12308 // images getting pulled from server..
12309 div = document.createElement('div');
12310 div.innerHTML = this.html;
12312 //doc.documentElement.innerHTML = htmlBody
12318 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12320 var tpls = this.tpls;
12322 // create a top level template from the snippet..
12324 //Roo.log(div.innerHTML);
12331 body : div.innerHTML,
12344 Roo.each(tpls, function(tp){
12345 this.compileTpl(tp);
12346 this.tpls[tp.id] = tp;
12349 this.master = tpls[0];
12355 compileNode : function(node, istop) {
12360 // skip anything not a tag..
12361 if (node.nodeType != 1) {
12362 if (node.nodeType == 3 && !this.inPre) {
12363 // reduce white space..
12364 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12387 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12388 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12389 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12390 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12396 // just itterate children..
12397 this.iterChild(node,this.compileNode);
12400 tpl.uid = this.id++;
12401 tpl.value = node.getAttribute('roo-' + tpl.attr);
12402 node.removeAttribute('roo-'+ tpl.attr);
12403 if (tpl.attr != 'name') {
12404 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12405 node.parentNode.replaceChild(placeholder, node);
12408 var placeholder = document.createElement('span');
12409 placeholder.className = 'roo-tpl-' + tpl.value;
12410 node.parentNode.replaceChild(placeholder, node);
12413 // parent now sees '{domtplXXXX}
12414 this.iterChild(node,this.compileNode);
12416 // we should now have node body...
12417 var div = document.createElement('div');
12418 div.appendChild(node);
12420 // this has the unfortunate side effect of converting tagged attributes
12421 // eg. href="{...}" into %7C...%7D
12422 // this has been fixed by searching for those combo's although it's a bit hacky..
12425 tpl.body = div.innerHTML;
12432 switch (tpl.value) {
12433 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12434 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12435 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12440 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12444 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12448 tpl.id = tpl.value; // replace non characters???
12454 this.tpls.push(tpl);
12464 * Compile a segment of the template into a 'sub-template'
12470 compileTpl : function(tpl)
12472 var fm = Roo.util.Format;
12473 var useF = this.disableFormats !== true;
12475 var sep = Roo.isGecko ? "+\n" : ",\n";
12477 var undef = function(str) {
12478 Roo.debug && Roo.log("Property not found :" + str);
12482 //Roo.log(tpl.body);
12486 var fn = function(m, lbrace, name, format, args)
12489 //Roo.log(arguments);
12490 args = args ? args.replace(/\\'/g,"'") : args;
12491 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12492 if (typeof(format) == 'undefined') {
12493 format = 'htmlEncode';
12495 if (format == 'raw' ) {
12499 if(name.substr(0, 6) == 'domtpl'){
12500 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12503 // build an array of options to determine if value is undefined..
12505 // basically get 'xxxx.yyyy' then do
12506 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12507 // (function () { Roo.log("Property not found"); return ''; })() :
12512 Roo.each(name.split('.'), function(st) {
12513 lookfor += (lookfor.length ? '.': '') + st;
12514 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12517 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12520 if(format && useF){
12522 args = args ? ',' + args : "";
12524 if(format.substr(0, 5) != "this."){
12525 format = "fm." + format + '(';
12527 format = 'this.call("'+ format.substr(5) + '", ';
12531 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12534 if (args && args.length) {
12535 // called with xxyx.yuu:(test,test)
12537 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12539 // raw.. - :raw modifier..
12540 return "'"+ sep + udef_st + name + ")"+sep+"'";
12544 // branched to use + in gecko and [].join() in others
12546 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12547 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12550 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12551 body.push(tpl.body.replace(/(\r\n|\n)/g,
12552 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12553 body.push("'].join('');};};");
12554 body = body.join('');
12557 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12559 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12566 * same as applyTemplate, except it's done to one of the subTemplates
12567 * when using named templates, you can do:
12569 * var str = pl.applySubTemplate('your-name', values);
12572 * @param {Number} id of the template
12573 * @param {Object} values to apply to template
12574 * @param {Object} parent (normaly the instance of this object)
12576 applySubTemplate : function(id, values, parent)
12580 var t = this.tpls[id];
12584 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12585 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12589 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12596 if(t.execCall && t.execCall.call(this, values, parent)){
12600 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12606 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12607 parent = t.target ? values : parent;
12608 if(t.forCall && vs instanceof Array){
12610 for(var i = 0, len = vs.length; i < len; i++){
12612 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12614 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12616 //Roo.log(t.compiled);
12620 return buf.join('');
12623 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12628 return t.compiled.call(this, vs, parent);
12630 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12632 //Roo.log(t.compiled);
12640 applyTemplate : function(values){
12641 return this.master.compiled.call(this, values, {});
12642 //var s = this.subs;
12645 apply : function(){
12646 return this.applyTemplate.apply(this, arguments);
12651 Roo.DomTemplate.from = function(el){
12652 el = Roo.getDom(el);
12653 return new Roo.Domtemplate(el.value || el.innerHTML);
12656 * Ext JS Library 1.1.1
12657 * Copyright(c) 2006-2007, Ext JS, LLC.
12659 * Originally Released Under LGPL - original licence link has changed is not relivant.
12662 * <script type="text/javascript">
12666 * @class Roo.util.DelayedTask
12667 * Provides a convenient method of performing setTimeout where a new
12668 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12669 * You can use this class to buffer
12670 * the keypress events for a certain number of milliseconds, and perform only if they stop
12671 * for that amount of time.
12672 * @constructor The parameters to this constructor serve as defaults and are not required.
12673 * @param {Function} fn (optional) The default function to timeout
12674 * @param {Object} scope (optional) The default scope of that timeout
12675 * @param {Array} args (optional) The default Array of arguments
12677 Roo.util.DelayedTask = function(fn, scope, args){
12678 var id = null, d, t;
12680 var call = function(){
12681 var now = new Date().getTime();
12685 fn.apply(scope, args || []);
12689 * Cancels any pending timeout and queues a new one
12690 * @param {Number} delay The milliseconds to delay
12691 * @param {Function} newFn (optional) Overrides function passed to constructor
12692 * @param {Object} newScope (optional) Overrides scope passed to constructor
12693 * @param {Array} newArgs (optional) Overrides args passed to constructor
12695 this.delay = function(delay, newFn, newScope, newArgs){
12696 if(id && delay != d){
12700 t = new Date().getTime();
12702 scope = newScope || scope;
12703 args = newArgs || args;
12705 id = setInterval(call, d);
12710 * Cancel the last queued timeout
12712 this.cancel = function(){
12720 * Ext JS Library 1.1.1
12721 * Copyright(c) 2006-2007, Ext JS, LLC.
12723 * Originally Released Under LGPL - original licence link has changed is not relivant.
12726 * <script type="text/javascript">
12730 Roo.util.TaskRunner = function(interval){
12731 interval = interval || 10;
12732 var tasks = [], removeQueue = [];
12734 var running = false;
12736 var stopThread = function(){
12742 var startThread = function(){
12745 id = setInterval(runTasks, interval);
12749 var removeTask = function(task){
12750 removeQueue.push(task);
12756 var runTasks = function(){
12757 if(removeQueue.length > 0){
12758 for(var i = 0, len = removeQueue.length; i < len; i++){
12759 tasks.remove(removeQueue[i]);
12762 if(tasks.length < 1){
12767 var now = new Date().getTime();
12768 for(var i = 0, len = tasks.length; i < len; ++i){
12770 var itime = now - t.taskRunTime;
12771 if(t.interval <= itime){
12772 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12773 t.taskRunTime = now;
12774 if(rt === false || t.taskRunCount === t.repeat){
12779 if(t.duration && t.duration <= (now - t.taskStartTime)){
12786 * Queues a new task.
12787 * @param {Object} task
12789 this.start = function(task){
12791 task.taskStartTime = new Date().getTime();
12792 task.taskRunTime = 0;
12793 task.taskRunCount = 0;
12798 this.stop = function(task){
12803 this.stopAll = function(){
12805 for(var i = 0, len = tasks.length; i < len; i++){
12806 if(tasks[i].onStop){
12815 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12817 * Ext JS Library 1.1.1
12818 * Copyright(c) 2006-2007, Ext JS, LLC.
12820 * Originally Released Under LGPL - original licence link has changed is not relivant.
12823 * <script type="text/javascript">
12828 * @class Roo.util.MixedCollection
12829 * @extends Roo.util.Observable
12830 * A Collection class that maintains both numeric indexes and keys and exposes events.
12832 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12833 * collection (defaults to false)
12834 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12835 * and return the key value for that item. This is used when available to look up the key on items that
12836 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12837 * equivalent to providing an implementation for the {@link #getKey} method.
12839 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12847 * Fires when the collection is cleared.
12852 * Fires when an item is added to the collection.
12853 * @param {Number} index The index at which the item was added.
12854 * @param {Object} o The item added.
12855 * @param {String} key The key associated with the added item.
12860 * Fires when an item is replaced in the collection.
12861 * @param {String} key he key associated with the new added.
12862 * @param {Object} old The item being replaced.
12863 * @param {Object} new The new item.
12868 * Fires when an item is removed from the collection.
12869 * @param {Object} o The item being removed.
12870 * @param {String} key (optional) The key associated with the removed item.
12875 this.allowFunctions = allowFunctions === true;
12877 this.getKey = keyFn;
12879 Roo.util.MixedCollection.superclass.constructor.call(this);
12882 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12883 allowFunctions : false,
12886 * Adds an item to the collection.
12887 * @param {String} key The key to associate with the item
12888 * @param {Object} o The item to add.
12889 * @return {Object} The item added.
12891 add : function(key, o){
12892 if(arguments.length == 1){
12894 key = this.getKey(o);
12896 if(typeof key == "undefined" || key === null){
12898 this.items.push(o);
12899 this.keys.push(null);
12901 var old = this.map[key];
12903 return this.replace(key, o);
12906 this.items.push(o);
12908 this.keys.push(key);
12910 this.fireEvent("add", this.length-1, o, key);
12915 * MixedCollection has a generic way to fetch keys if you implement getKey.
12918 var mc = new Roo.util.MixedCollection();
12919 mc.add(someEl.dom.id, someEl);
12920 mc.add(otherEl.dom.id, otherEl);
12924 var mc = new Roo.util.MixedCollection();
12925 mc.getKey = function(el){
12931 // or via the constructor
12932 var mc = new Roo.util.MixedCollection(false, function(el){
12938 * @param o {Object} The item for which to find the key.
12939 * @return {Object} The key for the passed item.
12941 getKey : function(o){
12946 * Replaces an item in the collection.
12947 * @param {String} key The key associated with the item to replace, or the item to replace.
12948 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12949 * @return {Object} The new item.
12951 replace : function(key, o){
12952 if(arguments.length == 1){
12954 key = this.getKey(o);
12956 var old = this.item(key);
12957 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12958 return this.add(key, o);
12960 var index = this.indexOfKey(key);
12961 this.items[index] = o;
12963 this.fireEvent("replace", key, old, o);
12968 * Adds all elements of an Array or an Object to the collection.
12969 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12970 * an Array of values, each of which are added to the collection.
12972 addAll : function(objs){
12973 if(arguments.length > 1 || objs instanceof Array){
12974 var args = arguments.length > 1 ? arguments : objs;
12975 for(var i = 0, len = args.length; i < len; i++){
12979 for(var key in objs){
12980 if(this.allowFunctions || typeof objs[key] != "function"){
12981 this.add(key, objs[key]);
12988 * Executes the specified function once for every item in the collection, passing each
12989 * item as the first and only parameter. returning false from the function will stop the iteration.
12990 * @param {Function} fn The function to execute for each item.
12991 * @param {Object} scope (optional) The scope in which to execute the function.
12993 each : function(fn, scope){
12994 var items = [].concat(this.items); // each safe for removal
12995 for(var i = 0, len = items.length; i < len; i++){
12996 if(fn.call(scope || items[i], items[i], i, len) === false){
13003 * Executes the specified function once for every key in the collection, passing each
13004 * key, and its associated item as the first two parameters.
13005 * @param {Function} fn The function to execute for each item.
13006 * @param {Object} scope (optional) The scope in which to execute the function.
13008 eachKey : function(fn, scope){
13009 for(var i = 0, len = this.keys.length; i < len; i++){
13010 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13015 * Returns the first item in the collection which elicits a true return value from the
13016 * passed selection function.
13017 * @param {Function} fn The selection function to execute for each item.
13018 * @param {Object} scope (optional) The scope in which to execute the function.
13019 * @return {Object} The first item in the collection which returned true from the selection function.
13021 find : function(fn, scope){
13022 for(var i = 0, len = this.items.length; i < len; i++){
13023 if(fn.call(scope || window, this.items[i], this.keys[i])){
13024 return this.items[i];
13031 * Inserts an item at the specified index in the collection.
13032 * @param {Number} index The index to insert the item at.
13033 * @param {String} key The key to associate with the new item, or the item itself.
13034 * @param {Object} o (optional) If the second parameter was a key, the new item.
13035 * @return {Object} The item inserted.
13037 insert : function(index, key, o){
13038 if(arguments.length == 2){
13040 key = this.getKey(o);
13042 if(index >= this.length){
13043 return this.add(key, o);
13046 this.items.splice(index, 0, o);
13047 if(typeof key != "undefined" && key != null){
13050 this.keys.splice(index, 0, key);
13051 this.fireEvent("add", index, o, key);
13056 * Removed an item from the collection.
13057 * @param {Object} o The item to remove.
13058 * @return {Object} The item removed.
13060 remove : function(o){
13061 return this.removeAt(this.indexOf(o));
13065 * Remove an item from a specified index in the collection.
13066 * @param {Number} index The index within the collection of the item to remove.
13068 removeAt : function(index){
13069 if(index < this.length && index >= 0){
13071 var o = this.items[index];
13072 this.items.splice(index, 1);
13073 var key = this.keys[index];
13074 if(typeof key != "undefined"){
13075 delete this.map[key];
13077 this.keys.splice(index, 1);
13078 this.fireEvent("remove", o, key);
13083 * Removed an item associated with the passed key fom the collection.
13084 * @param {String} key The key of the item to remove.
13086 removeKey : function(key){
13087 return this.removeAt(this.indexOfKey(key));
13091 * Returns the number of items in the collection.
13092 * @return {Number} the number of items in the collection.
13094 getCount : function(){
13095 return this.length;
13099 * Returns index within the collection of the passed Object.
13100 * @param {Object} o The item to find the index of.
13101 * @return {Number} index of the item.
13103 indexOf : function(o){
13104 if(!this.items.indexOf){
13105 for(var i = 0, len = this.items.length; i < len; i++){
13106 if(this.items[i] == o) {
13112 return this.items.indexOf(o);
13117 * Returns index within the collection of the passed key.
13118 * @param {String} key The key to find the index of.
13119 * @return {Number} index of the key.
13121 indexOfKey : function(key){
13122 if(!this.keys.indexOf){
13123 for(var i = 0, len = this.keys.length; i < len; i++){
13124 if(this.keys[i] == key) {
13130 return this.keys.indexOf(key);
13135 * Returns the item associated with the passed key OR index. Key has priority over index.
13136 * @param {String/Number} key The key or index of the item.
13137 * @return {Object} The item associated with the passed key.
13139 item : function(key){
13140 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13141 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13145 * Returns the item at the specified index.
13146 * @param {Number} index The index of the item.
13149 itemAt : function(index){
13150 return this.items[index];
13154 * Returns the item associated with the passed key.
13155 * @param {String/Number} key The key of the item.
13156 * @return {Object} The item associated with the passed key.
13158 key : function(key){
13159 return this.map[key];
13163 * Returns true if the collection contains the passed Object as an item.
13164 * @param {Object} o The Object to look for in the collection.
13165 * @return {Boolean} True if the collection contains the Object as an item.
13167 contains : function(o){
13168 return this.indexOf(o) != -1;
13172 * Returns true if the collection contains the passed Object as a key.
13173 * @param {String} key The key to look for in the collection.
13174 * @return {Boolean} True if the collection contains the Object as a key.
13176 containsKey : function(key){
13177 return typeof this.map[key] != "undefined";
13181 * Removes all items from the collection.
13183 clear : function(){
13188 this.fireEvent("clear");
13192 * Returns the first item in the collection.
13193 * @return {Object} the first item in the collection..
13195 first : function(){
13196 return this.items[0];
13200 * Returns the last item in the collection.
13201 * @return {Object} the last item in the collection..
13204 return this.items[this.length-1];
13207 _sort : function(property, dir, fn){
13208 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13209 fn = fn || function(a, b){
13212 var c = [], k = this.keys, items = this.items;
13213 for(var i = 0, len = items.length; i < len; i++){
13214 c[c.length] = {key: k[i], value: items[i], index: i};
13216 c.sort(function(a, b){
13217 var v = fn(a[property], b[property]) * dsc;
13219 v = (a.index < b.index ? -1 : 1);
13223 for(var i = 0, len = c.length; i < len; i++){
13224 items[i] = c[i].value;
13227 this.fireEvent("sort", this);
13231 * Sorts this collection with the passed comparison function
13232 * @param {String} direction (optional) "ASC" or "DESC"
13233 * @param {Function} fn (optional) comparison function
13235 sort : function(dir, fn){
13236 this._sort("value", dir, fn);
13240 * Sorts this collection by keys
13241 * @param {String} direction (optional) "ASC" or "DESC"
13242 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13244 keySort : function(dir, fn){
13245 this._sort("key", dir, fn || function(a, b){
13246 return String(a).toUpperCase()-String(b).toUpperCase();
13251 * Returns a range of items in this collection
13252 * @param {Number} startIndex (optional) defaults to 0
13253 * @param {Number} endIndex (optional) default to the last item
13254 * @return {Array} An array of items
13256 getRange : function(start, end){
13257 var items = this.items;
13258 if(items.length < 1){
13261 start = start || 0;
13262 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13265 for(var i = start; i <= end; i++) {
13266 r[r.length] = items[i];
13269 for(var i = start; i >= end; i--) {
13270 r[r.length] = items[i];
13277 * Filter the <i>objects</i> in this collection by a specific property.
13278 * Returns a new collection that has been filtered.
13279 * @param {String} property A property on your objects
13280 * @param {String/RegExp} value Either string that the property values
13281 * should start with or a RegExp to test against the property
13282 * @return {MixedCollection} The new filtered collection
13284 filter : function(property, value){
13285 if(!value.exec){ // not a regex
13286 value = String(value);
13287 if(value.length == 0){
13288 return this.clone();
13290 value = new RegExp("^" + Roo.escapeRe(value), "i");
13292 return this.filterBy(function(o){
13293 return o && value.test(o[property]);
13298 * Filter by a function. * Returns a new collection that has been filtered.
13299 * The passed function will be called with each
13300 * object in the collection. If the function returns true, the value is included
13301 * otherwise it is filtered.
13302 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13303 * @param {Object} scope (optional) The scope of the function (defaults to this)
13304 * @return {MixedCollection} The new filtered collection
13306 filterBy : function(fn, scope){
13307 var r = new Roo.util.MixedCollection();
13308 r.getKey = this.getKey;
13309 var k = this.keys, it = this.items;
13310 for(var i = 0, len = it.length; i < len; i++){
13311 if(fn.call(scope||this, it[i], k[i])){
13312 r.add(k[i], it[i]);
13319 * Creates a duplicate of this collection
13320 * @return {MixedCollection}
13322 clone : function(){
13323 var r = new Roo.util.MixedCollection();
13324 var k = this.keys, it = this.items;
13325 for(var i = 0, len = it.length; i < len; i++){
13326 r.add(k[i], it[i]);
13328 r.getKey = this.getKey;
13333 * Returns the item associated with the passed key or index.
13335 * @param {String/Number} key The key or index of the item.
13336 * @return {Object} The item associated with the passed key.
13338 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13340 * Ext JS Library 1.1.1
13341 * Copyright(c) 2006-2007, Ext JS, LLC.
13343 * Originally Released Under LGPL - original licence link has changed is not relivant.
13346 * <script type="text/javascript">
13349 * @class Roo.util.JSON
13350 * Modified version of Douglas Crockford"s json.js that doesn"t
13351 * mess with the Object prototype
13352 * http://www.json.org/js.html
13355 Roo.util.JSON = new (function(){
13356 var useHasOwn = {}.hasOwnProperty ? true : false;
13358 // crashes Safari in some instances
13359 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13361 var pad = function(n) {
13362 return n < 10 ? "0" + n : n;
13375 var encodeString = function(s){
13376 if (/["\\\x00-\x1f]/.test(s)) {
13377 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13382 c = b.charCodeAt();
13384 Math.floor(c / 16).toString(16) +
13385 (c % 16).toString(16);
13388 return '"' + s + '"';
13391 var encodeArray = function(o){
13392 var a = ["["], b, i, l = o.length, v;
13393 for (i = 0; i < l; i += 1) {
13395 switch (typeof v) {
13404 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13412 var encodeDate = function(o){
13413 return '"' + o.getFullYear() + "-" +
13414 pad(o.getMonth() + 1) + "-" +
13415 pad(o.getDate()) + "T" +
13416 pad(o.getHours()) + ":" +
13417 pad(o.getMinutes()) + ":" +
13418 pad(o.getSeconds()) + '"';
13422 * Encodes an Object, Array or other value
13423 * @param {Mixed} o The variable to encode
13424 * @return {String} The JSON string
13426 this.encode = function(o)
13428 // should this be extended to fully wrap stringify..
13430 if(typeof o == "undefined" || o === null){
13432 }else if(o instanceof Array){
13433 return encodeArray(o);
13434 }else if(o instanceof Date){
13435 return encodeDate(o);
13436 }else if(typeof o == "string"){
13437 return encodeString(o);
13438 }else if(typeof o == "number"){
13439 return isFinite(o) ? String(o) : "null";
13440 }else if(typeof o == "boolean"){
13443 var a = ["{"], b, i, v;
13445 if(!useHasOwn || o.hasOwnProperty(i)) {
13447 switch (typeof v) {
13456 a.push(this.encode(i), ":",
13457 v === null ? "null" : this.encode(v));
13468 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13469 * @param {String} json The JSON string
13470 * @return {Object} The resulting object
13472 this.decode = function(json){
13474 return /** eval:var:json */ eval("(" + json + ')');
13478 * Shorthand for {@link Roo.util.JSON#encode}
13479 * @member Roo encode
13481 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13483 * Shorthand for {@link Roo.util.JSON#decode}
13484 * @member Roo decode
13486 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13489 * Ext JS Library 1.1.1
13490 * Copyright(c) 2006-2007, Ext JS, LLC.
13492 * Originally Released Under LGPL - original licence link has changed is not relivant.
13495 * <script type="text/javascript">
13499 * @class Roo.util.Format
13500 * Reusable data formatting functions
13503 Roo.util.Format = function(){
13504 var trimRe = /^\s+|\s+$/g;
13507 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13508 * @param {String} value The string to truncate
13509 * @param {Number} length The maximum length to allow before truncating
13510 * @return {String} The converted text
13512 ellipsis : function(value, len){
13513 if(value && value.length > len){
13514 return value.substr(0, len-3)+"...";
13520 * Checks a reference and converts it to empty string if it is undefined
13521 * @param {Mixed} value Reference to check
13522 * @return {Mixed} Empty string if converted, otherwise the original value
13524 undef : function(value){
13525 return typeof value != "undefined" ? value : "";
13529 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13530 * @param {String} value The string to encode
13531 * @return {String} The encoded text
13533 htmlEncode : function(value){
13534 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13538 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13539 * @param {String} value The string to decode
13540 * @return {String} The decoded text
13542 htmlDecode : function(value){
13543 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13547 * Trims any whitespace from either side of a string
13548 * @param {String} value The text to trim
13549 * @return {String} The trimmed text
13551 trim : function(value){
13552 return String(value).replace(trimRe, "");
13556 * Returns a substring from within an original string
13557 * @param {String} value The original text
13558 * @param {Number} start The start index of the substring
13559 * @param {Number} length The length of the substring
13560 * @return {String} The substring
13562 substr : function(value, start, length){
13563 return String(value).substr(start, length);
13567 * Converts a string to all lower case letters
13568 * @param {String} value The text to convert
13569 * @return {String} The converted text
13571 lowercase : function(value){
13572 return String(value).toLowerCase();
13576 * Converts a string to all upper case letters
13577 * @param {String} value The text to convert
13578 * @return {String} The converted text
13580 uppercase : function(value){
13581 return String(value).toUpperCase();
13585 * Converts the first character only of a string to upper case
13586 * @param {String} value The text to convert
13587 * @return {String} The converted text
13589 capitalize : function(value){
13590 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13594 call : function(value, fn){
13595 if(arguments.length > 2){
13596 var args = Array.prototype.slice.call(arguments, 2);
13597 args.unshift(value);
13599 return /** eval:var:value */ eval(fn).apply(window, args);
13601 /** eval:var:value */
13602 return /** eval:var:value */ eval(fn).call(window, value);
13608 * safer version of Math.toFixed..??/
13609 * @param {Number/String} value The numeric value to format
13610 * @param {Number/String} value Decimal places
13611 * @return {String} The formatted currency string
13613 toFixed : function(v, n)
13615 // why not use to fixed - precision is buggered???
13617 return Math.round(v-0);
13619 var fact = Math.pow(10,n+1);
13620 v = (Math.round((v-0)*fact))/fact;
13621 var z = (''+fact).substring(2);
13622 if (v == Math.floor(v)) {
13623 return Math.floor(v) + '.' + z;
13626 // now just padd decimals..
13627 var ps = String(v).split('.');
13628 var fd = (ps[1] + z);
13629 var r = fd.substring(0,n);
13630 var rm = fd.substring(n);
13632 return ps[0] + '.' + r;
13634 r*=1; // turn it into a number;
13636 if (String(r).length != n) {
13639 r = String(r).substring(1); // chop the end off.
13642 return ps[0] + '.' + r;
13647 * Format a number as US currency
13648 * @param {Number/String} value The numeric value to format
13649 * @return {String} The formatted currency string
13651 usMoney : function(v){
13652 return '$' + Roo.util.Format.number(v);
13657 * eventually this should probably emulate php's number_format
13658 * @param {Number/String} value The numeric value to format
13659 * @param {Number} decimals number of decimal places
13660 * @return {String} The formatted currency string
13662 number : function(v,decimals)
13664 // multiply and round.
13665 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13666 var mul = Math.pow(10, decimals);
13667 var zero = String(mul).substring(1);
13668 v = (Math.round((v-0)*mul))/mul;
13670 // if it's '0' number.. then
13672 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13674 var ps = v.split('.');
13678 var r = /(\d+)(\d{3})/;
13680 while (r.test(whole)) {
13681 whole = whole.replace(r, '$1' + ',' + '$2');
13687 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13688 // does not have decimals
13689 (decimals ? ('.' + zero) : '');
13692 return whole + sub ;
13696 * Parse a value into a formatted date using the specified format pattern.
13697 * @param {Mixed} value The value to format
13698 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13699 * @return {String} The formatted date string
13701 date : function(v, format){
13705 if(!(v instanceof Date)){
13706 v = new Date(Date.parse(v));
13708 return v.dateFormat(format || Roo.util.Format.defaults.date);
13712 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13713 * @param {String} format Any valid date format string
13714 * @return {Function} The date formatting function
13716 dateRenderer : function(format){
13717 return function(v){
13718 return Roo.util.Format.date(v, format);
13723 stripTagsRE : /<\/?[^>]+>/gi,
13726 * Strips all HTML tags
13727 * @param {Mixed} value The text from which to strip tags
13728 * @return {String} The stripped text
13730 stripTags : function(v){
13731 return !v ? v : String(v).replace(this.stripTagsRE, "");
13735 Roo.util.Format.defaults = {
13739 * Ext JS Library 1.1.1
13740 * Copyright(c) 2006-2007, Ext JS, LLC.
13742 * Originally Released Under LGPL - original licence link has changed is not relivant.
13745 * <script type="text/javascript">
13752 * @class Roo.MasterTemplate
13753 * @extends Roo.Template
13754 * Provides a template that can have child templates. The syntax is:
13756 var t = new Roo.MasterTemplate(
13757 '<select name="{name}">',
13758 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13761 t.add('options', {value: 'foo', text: 'bar'});
13762 // or you can add multiple child elements in one shot
13763 t.addAll('options', [
13764 {value: 'foo', text: 'bar'},
13765 {value: 'foo2', text: 'bar2'},
13766 {value: 'foo3', text: 'bar3'}
13768 // then append, applying the master template values
13769 t.append('my-form', {name: 'my-select'});
13771 * A name attribute for the child template is not required if you have only one child
13772 * template or you want to refer to them by index.
13774 Roo.MasterTemplate = function(){
13775 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13776 this.originalHtml = this.html;
13778 var m, re = this.subTemplateRe;
13781 while(m = re.exec(this.html)){
13782 var name = m[1], content = m[2];
13787 tpl : new Roo.Template(content)
13790 st[name] = st[subIndex];
13792 st[subIndex].tpl.compile();
13793 st[subIndex].tpl.call = this.call.createDelegate(this);
13796 this.subCount = subIndex;
13799 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13801 * The regular expression used to match sub templates
13805 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13808 * Applies the passed values to a child template.
13809 * @param {String/Number} name (optional) The name or index of the child template
13810 * @param {Array/Object} values The values to be applied to the template
13811 * @return {MasterTemplate} this
13813 add : function(name, values){
13814 if(arguments.length == 1){
13815 values = arguments[0];
13818 var s = this.subs[name];
13819 s.buffer[s.buffer.length] = s.tpl.apply(values);
13824 * Applies all the passed values to a child template.
13825 * @param {String/Number} name (optional) The name or index of the child template
13826 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13827 * @param {Boolean} reset (optional) True to reset the template first
13828 * @return {MasterTemplate} this
13830 fill : function(name, values, reset){
13832 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13840 for(var i = 0, len = values.length; i < len; i++){
13841 this.add(name, values[i]);
13847 * Resets the template for reuse
13848 * @return {MasterTemplate} this
13850 reset : function(){
13852 for(var i = 0; i < this.subCount; i++){
13858 applyTemplate : function(values){
13860 var replaceIndex = -1;
13861 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13862 return s[++replaceIndex].buffer.join("");
13864 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13867 apply : function(){
13868 return this.applyTemplate.apply(this, arguments);
13871 compile : function(){return this;}
13875 * Alias for fill().
13878 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13880 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13881 * var tpl = Roo.MasterTemplate.from('element-id');
13882 * @param {String/HTMLElement} el
13883 * @param {Object} config
13886 Roo.MasterTemplate.from = function(el, config){
13887 el = Roo.getDom(el);
13888 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13891 * Ext JS Library 1.1.1
13892 * Copyright(c) 2006-2007, Ext JS, LLC.
13894 * Originally Released Under LGPL - original licence link has changed is not relivant.
13897 * <script type="text/javascript">
13902 * @class Roo.util.CSS
13903 * Utility class for manipulating CSS rules
13906 Roo.util.CSS = function(){
13908 var doc = document;
13910 var camelRe = /(-[a-z])/gi;
13911 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13915 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13916 * tag and appended to the HEAD of the document.
13917 * @param {String|Object} cssText The text containing the css rules
13918 * @param {String} id An id to add to the stylesheet for later removal
13919 * @return {StyleSheet}
13921 createStyleSheet : function(cssText, id){
13923 var head = doc.getElementsByTagName("head")[0];
13924 var nrules = doc.createElement("style");
13925 nrules.setAttribute("type", "text/css");
13927 nrules.setAttribute("id", id);
13929 if (typeof(cssText) != 'string') {
13930 // support object maps..
13931 // not sure if this a good idea..
13932 // perhaps it should be merged with the general css handling
13933 // and handle js style props.
13934 var cssTextNew = [];
13935 for(var n in cssText) {
13937 for(var k in cssText[n]) {
13938 citems.push( k + ' : ' +cssText[n][k] + ';' );
13940 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13943 cssText = cssTextNew.join("\n");
13949 head.appendChild(nrules);
13950 ss = nrules.styleSheet;
13951 ss.cssText = cssText;
13954 nrules.appendChild(doc.createTextNode(cssText));
13956 nrules.cssText = cssText;
13958 head.appendChild(nrules);
13959 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13961 this.cacheStyleSheet(ss);
13966 * Removes a style or link tag by id
13967 * @param {String} id The id of the tag
13969 removeStyleSheet : function(id){
13970 var existing = doc.getElementById(id);
13972 existing.parentNode.removeChild(existing);
13977 * Dynamically swaps an existing stylesheet reference for a new one
13978 * @param {String} id The id of an existing link tag to remove
13979 * @param {String} url The href of the new stylesheet to include
13981 swapStyleSheet : function(id, url){
13982 this.removeStyleSheet(id);
13983 var ss = doc.createElement("link");
13984 ss.setAttribute("rel", "stylesheet");
13985 ss.setAttribute("type", "text/css");
13986 ss.setAttribute("id", id);
13987 ss.setAttribute("href", url);
13988 doc.getElementsByTagName("head")[0].appendChild(ss);
13992 * Refresh the rule cache if you have dynamically added stylesheets
13993 * @return {Object} An object (hash) of rules indexed by selector
13995 refreshCache : function(){
13996 return this.getRules(true);
14000 cacheStyleSheet : function(stylesheet){
14004 try{// try catch for cross domain access issue
14005 var ssRules = stylesheet.cssRules || stylesheet.rules;
14006 for(var j = ssRules.length-1; j >= 0; --j){
14007 rules[ssRules[j].selectorText] = ssRules[j];
14013 * Gets all css rules for the document
14014 * @param {Boolean} refreshCache true to refresh the internal cache
14015 * @return {Object} An object (hash) of rules indexed by selector
14017 getRules : function(refreshCache){
14018 if(rules == null || refreshCache){
14020 var ds = doc.styleSheets;
14021 for(var i =0, len = ds.length; i < len; i++){
14023 this.cacheStyleSheet(ds[i]);
14031 * Gets an an individual CSS rule by selector(s)
14032 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14033 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14034 * @return {CSSRule} The CSS rule or null if one is not found
14036 getRule : function(selector, refreshCache){
14037 var rs = this.getRules(refreshCache);
14038 if(!(selector instanceof Array)){
14039 return rs[selector];
14041 for(var i = 0; i < selector.length; i++){
14042 if(rs[selector[i]]){
14043 return rs[selector[i]];
14051 * Updates a rule property
14052 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14053 * @param {String} property The css property
14054 * @param {String} value The new value for the property
14055 * @return {Boolean} true If a rule was found and updated
14057 updateRule : function(selector, property, value){
14058 if(!(selector instanceof Array)){
14059 var rule = this.getRule(selector);
14061 rule.style[property.replace(camelRe, camelFn)] = value;
14065 for(var i = 0; i < selector.length; i++){
14066 if(this.updateRule(selector[i], property, value)){
14076 * Ext JS Library 1.1.1
14077 * Copyright(c) 2006-2007, Ext JS, LLC.
14079 * Originally Released Under LGPL - original licence link has changed is not relivant.
14082 * <script type="text/javascript">
14088 * @class Roo.util.ClickRepeater
14089 * @extends Roo.util.Observable
14091 * A wrapper class which can be applied to any element. Fires a "click" event while the
14092 * mouse is pressed. The interval between firings may be specified in the config but
14093 * defaults to 10 milliseconds.
14095 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14097 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14098 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14099 * Similar to an autorepeat key delay.
14100 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14101 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14102 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14103 * "interval" and "delay" are ignored. "immediate" is honored.
14104 * @cfg {Boolean} preventDefault True to prevent the default click event
14105 * @cfg {Boolean} stopDefault True to stop the default click event
14108 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14109 * 2007-02-02 jvs Renamed to ClickRepeater
14110 * 2007-02-03 jvs Modifications for FF Mac and Safari
14113 * @param {String/HTMLElement/Element} el The element to listen on
14114 * @param {Object} config
14116 Roo.util.ClickRepeater = function(el, config)
14118 this.el = Roo.get(el);
14119 this.el.unselectable();
14121 Roo.apply(this, config);
14126 * Fires when the mouse button is depressed.
14127 * @param {Roo.util.ClickRepeater} this
14129 "mousedown" : true,
14132 * Fires on a specified interval during the time the element is pressed.
14133 * @param {Roo.util.ClickRepeater} this
14138 * Fires when the mouse key is released.
14139 * @param {Roo.util.ClickRepeater} this
14144 this.el.on("mousedown", this.handleMouseDown, this);
14145 if(this.preventDefault || this.stopDefault){
14146 this.el.on("click", function(e){
14147 if(this.preventDefault){
14148 e.preventDefault();
14150 if(this.stopDefault){
14156 // allow inline handler
14158 this.on("click", this.handler, this.scope || this);
14161 Roo.util.ClickRepeater.superclass.constructor.call(this);
14164 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14167 preventDefault : true,
14168 stopDefault : false,
14172 handleMouseDown : function(){
14173 clearTimeout(this.timer);
14175 if(this.pressClass){
14176 this.el.addClass(this.pressClass);
14178 this.mousedownTime = new Date();
14180 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14181 this.el.on("mouseout", this.handleMouseOut, this);
14183 this.fireEvent("mousedown", this);
14184 this.fireEvent("click", this);
14186 this.timer = this.click.defer(this.delay || this.interval, this);
14190 click : function(){
14191 this.fireEvent("click", this);
14192 this.timer = this.click.defer(this.getInterval(), this);
14196 getInterval: function(){
14197 if(!this.accelerate){
14198 return this.interval;
14200 var pressTime = this.mousedownTime.getElapsed();
14201 if(pressTime < 500){
14203 }else if(pressTime < 1700){
14205 }else if(pressTime < 2600){
14207 }else if(pressTime < 3500){
14209 }else if(pressTime < 4400){
14211 }else if(pressTime < 5300){
14213 }else if(pressTime < 6200){
14221 handleMouseOut : function(){
14222 clearTimeout(this.timer);
14223 if(this.pressClass){
14224 this.el.removeClass(this.pressClass);
14226 this.el.on("mouseover", this.handleMouseReturn, this);
14230 handleMouseReturn : function(){
14231 this.el.un("mouseover", this.handleMouseReturn);
14232 if(this.pressClass){
14233 this.el.addClass(this.pressClass);
14239 handleMouseUp : function(){
14240 clearTimeout(this.timer);
14241 this.el.un("mouseover", this.handleMouseReturn);
14242 this.el.un("mouseout", this.handleMouseOut);
14243 Roo.get(document).un("mouseup", this.handleMouseUp);
14244 this.el.removeClass(this.pressClass);
14245 this.fireEvent("mouseup", this);
14249 * Ext JS Library 1.1.1
14250 * Copyright(c) 2006-2007, Ext JS, LLC.
14252 * Originally Released Under LGPL - original licence link has changed is not relivant.
14255 * <script type="text/javascript">
14260 * @class Roo.KeyNav
14261 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14262 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14263 * way to implement custom navigation schemes for any UI component.</p>
14264 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14265 * pageUp, pageDown, del, home, end. Usage:</p>
14267 var nav = new Roo.KeyNav("my-element", {
14268 "left" : function(e){
14269 this.moveLeft(e.ctrlKey);
14271 "right" : function(e){
14272 this.moveRight(e.ctrlKey);
14274 "enter" : function(e){
14281 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14282 * @param {Object} config The config
14284 Roo.KeyNav = function(el, config){
14285 this.el = Roo.get(el);
14286 Roo.apply(this, config);
14287 if(!this.disabled){
14288 this.disabled = true;
14293 Roo.KeyNav.prototype = {
14295 * @cfg {Boolean} disabled
14296 * True to disable this KeyNav instance (defaults to false)
14300 * @cfg {String} defaultEventAction
14301 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14302 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14303 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14305 defaultEventAction: "stopEvent",
14307 * @cfg {Boolean} forceKeyDown
14308 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14309 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14310 * handle keydown instead of keypress.
14312 forceKeyDown : false,
14315 prepareEvent : function(e){
14316 var k = e.getKey();
14317 var h = this.keyToHandler[k];
14318 //if(h && this[h]){
14319 // e.stopPropagation();
14321 if(Roo.isSafari && h && k >= 37 && k <= 40){
14327 relay : function(e){
14328 var k = e.getKey();
14329 var h = this.keyToHandler[k];
14331 if(this.doRelay(e, this[h], h) !== true){
14332 e[this.defaultEventAction]();
14338 doRelay : function(e, h, hname){
14339 return h.call(this.scope || this, e);
14342 // possible handlers
14356 // quick lookup hash
14373 * Enable this KeyNav
14375 enable: function(){
14377 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14378 // the EventObject will normalize Safari automatically
14379 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14380 this.el.on("keydown", this.relay, this);
14382 this.el.on("keydown", this.prepareEvent, this);
14383 this.el.on("keypress", this.relay, this);
14385 this.disabled = false;
14390 * Disable this KeyNav
14392 disable: function(){
14393 if(!this.disabled){
14394 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14395 this.el.un("keydown", this.relay);
14397 this.el.un("keydown", this.prepareEvent);
14398 this.el.un("keypress", this.relay);
14400 this.disabled = true;
14405 * Ext JS Library 1.1.1
14406 * Copyright(c) 2006-2007, Ext JS, LLC.
14408 * Originally Released Under LGPL - original licence link has changed is not relivant.
14411 * <script type="text/javascript">
14416 * @class Roo.KeyMap
14417 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14418 * The constructor accepts the same config object as defined by {@link #addBinding}.
14419 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14420 * combination it will call the function with this signature (if the match is a multi-key
14421 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14422 * A KeyMap can also handle a string representation of keys.<br />
14425 // map one key by key code
14426 var map = new Roo.KeyMap("my-element", {
14427 key: 13, // or Roo.EventObject.ENTER
14432 // map multiple keys to one action by string
14433 var map = new Roo.KeyMap("my-element", {
14439 // map multiple keys to multiple actions by strings and array of codes
14440 var map = new Roo.KeyMap("my-element", [
14443 fn: function(){ alert("Return was pressed"); }
14446 fn: function(){ alert('a, b or c was pressed'); }
14451 fn: function(){ alert('Control + shift + tab was pressed.'); }
14455 * <b>Note: A KeyMap starts enabled</b>
14457 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14458 * @param {Object} config The config (see {@link #addBinding})
14459 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14461 Roo.KeyMap = function(el, config, eventName){
14462 this.el = Roo.get(el);
14463 this.eventName = eventName || "keydown";
14464 this.bindings = [];
14466 this.addBinding(config);
14471 Roo.KeyMap.prototype = {
14473 * True to stop the event from bubbling and prevent the default browser action if the
14474 * key was handled by the KeyMap (defaults to false)
14480 * Add a new binding to this KeyMap. The following config object properties are supported:
14482 Property Type Description
14483 ---------- --------------- ----------------------------------------------------------------------
14484 key String/Array A single keycode or an array of keycodes to handle
14485 shift Boolean True to handle key only when shift is pressed (defaults to false)
14486 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14487 alt Boolean True to handle key only when alt is pressed (defaults to false)
14488 fn Function The function to call when KeyMap finds the expected key combination
14489 scope Object The scope of the callback function
14495 var map = new Roo.KeyMap(document, {
14496 key: Roo.EventObject.ENTER,
14501 //Add a new binding to the existing KeyMap later
14509 * @param {Object/Array} config A single KeyMap config or an array of configs
14511 addBinding : function(config){
14512 if(config instanceof Array){
14513 for(var i = 0, len = config.length; i < len; i++){
14514 this.addBinding(config[i]);
14518 var keyCode = config.key,
14519 shift = config.shift,
14520 ctrl = config.ctrl,
14523 scope = config.scope;
14524 if(typeof keyCode == "string"){
14526 var keyString = keyCode.toUpperCase();
14527 for(var j = 0, len = keyString.length; j < len; j++){
14528 ks.push(keyString.charCodeAt(j));
14532 var keyArray = keyCode instanceof Array;
14533 var handler = function(e){
14534 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14535 var k = e.getKey();
14537 for(var i = 0, len = keyCode.length; i < len; i++){
14538 if(keyCode[i] == k){
14539 if(this.stopEvent){
14542 fn.call(scope || window, k, e);
14548 if(this.stopEvent){
14551 fn.call(scope || window, k, e);
14556 this.bindings.push(handler);
14560 * Shorthand for adding a single key listener
14561 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14562 * following options:
14563 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14564 * @param {Function} fn The function to call
14565 * @param {Object} scope (optional) The scope of the function
14567 on : function(key, fn, scope){
14568 var keyCode, shift, ctrl, alt;
14569 if(typeof key == "object" && !(key instanceof Array)){
14588 handleKeyDown : function(e){
14589 if(this.enabled){ //just in case
14590 var b = this.bindings;
14591 for(var i = 0, len = b.length; i < len; i++){
14592 b[i].call(this, e);
14598 * Returns true if this KeyMap is enabled
14599 * @return {Boolean}
14601 isEnabled : function(){
14602 return this.enabled;
14606 * Enables this KeyMap
14608 enable: function(){
14610 this.el.on(this.eventName, this.handleKeyDown, this);
14611 this.enabled = true;
14616 * Disable this KeyMap
14618 disable: function(){
14620 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14621 this.enabled = false;
14626 * Ext JS Library 1.1.1
14627 * Copyright(c) 2006-2007, Ext JS, LLC.
14629 * Originally Released Under LGPL - original licence link has changed is not relivant.
14632 * <script type="text/javascript">
14637 * @class Roo.util.TextMetrics
14638 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14639 * wide, in pixels, a given block of text will be.
14642 Roo.util.TextMetrics = function(){
14646 * Measures the size of the specified text
14647 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14648 * that can affect the size of the rendered text
14649 * @param {String} text The text to measure
14650 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14651 * in order to accurately measure the text height
14652 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14654 measure : function(el, text, fixedWidth){
14656 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14659 shared.setFixedWidth(fixedWidth || 'auto');
14660 return shared.getSize(text);
14664 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14665 * the overhead of multiple calls to initialize the style properties on each measurement.
14666 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14667 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14668 * in order to accurately measure the text height
14669 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14671 createInstance : function(el, fixedWidth){
14672 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14679 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14680 var ml = new Roo.Element(document.createElement('div'));
14681 document.body.appendChild(ml.dom);
14682 ml.position('absolute');
14683 ml.setLeftTop(-1000, -1000);
14687 ml.setWidth(fixedWidth);
14692 * Returns the size of the specified text based on the internal element's style and width properties
14693 * @memberOf Roo.util.TextMetrics.Instance#
14694 * @param {String} text The text to measure
14695 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14697 getSize : function(text){
14699 var s = ml.getSize();
14705 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14706 * that can affect the size of the rendered text
14707 * @memberOf Roo.util.TextMetrics.Instance#
14708 * @param {String/HTMLElement} el The element, dom node or id
14710 bind : function(el){
14712 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14717 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14718 * to set a fixed width in order to accurately measure the text height.
14719 * @memberOf Roo.util.TextMetrics.Instance#
14720 * @param {Number} width The width to set on the element
14722 setFixedWidth : function(width){
14723 ml.setWidth(width);
14727 * Returns the measured width of the specified text
14728 * @memberOf Roo.util.TextMetrics.Instance#
14729 * @param {String} text The text to measure
14730 * @return {Number} width The width in pixels
14732 getWidth : function(text){
14733 ml.dom.style.width = 'auto';
14734 return this.getSize(text).width;
14738 * Returns the measured height of the specified text. For multiline text, be sure to call
14739 * {@link #setFixedWidth} if necessary.
14740 * @memberOf Roo.util.TextMetrics.Instance#
14741 * @param {String} text The text to measure
14742 * @return {Number} height The height in pixels
14744 getHeight : function(text){
14745 return this.getSize(text).height;
14749 instance.bind(bindTo);
14754 // backwards compat
14755 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14757 * Ext JS Library 1.1.1
14758 * Copyright(c) 2006-2007, Ext JS, LLC.
14760 * Originally Released Under LGPL - original licence link has changed is not relivant.
14763 * <script type="text/javascript">
14767 * @class Roo.state.Provider
14768 * Abstract base class for state provider implementations. This class provides methods
14769 * for encoding and decoding <b>typed</b> variables including dates and defines the
14770 * Provider interface.
14772 Roo.state.Provider = function(){
14774 * @event statechange
14775 * Fires when a state change occurs.
14776 * @param {Provider} this This state provider
14777 * @param {String} key The state key which was changed
14778 * @param {String} value The encoded value for the state
14781 "statechange": true
14784 Roo.state.Provider.superclass.constructor.call(this);
14786 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14788 * Returns the current value for a key
14789 * @param {String} name The key name
14790 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14791 * @return {Mixed} The state data
14793 get : function(name, defaultValue){
14794 return typeof this.state[name] == "undefined" ?
14795 defaultValue : this.state[name];
14799 * Clears a value from the state
14800 * @param {String} name The key name
14802 clear : function(name){
14803 delete this.state[name];
14804 this.fireEvent("statechange", this, name, null);
14808 * Sets the value for a key
14809 * @param {String} name The key name
14810 * @param {Mixed} value The value to set
14812 set : function(name, value){
14813 this.state[name] = value;
14814 this.fireEvent("statechange", this, name, value);
14818 * Decodes a string previously encoded with {@link #encodeValue}.
14819 * @param {String} value The value to decode
14820 * @return {Mixed} The decoded value
14822 decodeValue : function(cookie){
14823 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14824 var matches = re.exec(unescape(cookie));
14825 if(!matches || !matches[1]) {
14826 return; // non state cookie
14828 var type = matches[1];
14829 var v = matches[2];
14832 return parseFloat(v);
14834 return new Date(Date.parse(v));
14839 var values = v.split("^");
14840 for(var i = 0, len = values.length; i < len; i++){
14841 all.push(this.decodeValue(values[i]));
14846 var values = v.split("^");
14847 for(var i = 0, len = values.length; i < len; i++){
14848 var kv = values[i].split("=");
14849 all[kv[0]] = this.decodeValue(kv[1]);
14858 * Encodes a value including type information. Decode with {@link #decodeValue}.
14859 * @param {Mixed} value The value to encode
14860 * @return {String} The encoded value
14862 encodeValue : function(v){
14864 if(typeof v == "number"){
14866 }else if(typeof v == "boolean"){
14867 enc = "b:" + (v ? "1" : "0");
14868 }else if(v instanceof Date){
14869 enc = "d:" + v.toGMTString();
14870 }else if(v instanceof Array){
14872 for(var i = 0, len = v.length; i < len; i++){
14873 flat += this.encodeValue(v[i]);
14879 }else if(typeof v == "object"){
14882 if(typeof v[key] != "function"){
14883 flat += key + "=" + this.encodeValue(v[key]) + "^";
14886 enc = "o:" + flat.substring(0, flat.length-1);
14890 return escape(enc);
14896 * Ext JS Library 1.1.1
14897 * Copyright(c) 2006-2007, Ext JS, LLC.
14899 * Originally Released Under LGPL - original licence link has changed is not relivant.
14902 * <script type="text/javascript">
14905 * @class Roo.state.Manager
14906 * This is the global state manager. By default all components that are "state aware" check this class
14907 * for state information if you don't pass them a custom state provider. In order for this class
14908 * to be useful, it must be initialized with a provider when your application initializes.
14910 // in your initialization function
14912 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14914 // supposed you have a {@link Roo.BorderLayout}
14915 var layout = new Roo.BorderLayout(...);
14916 layout.restoreState();
14917 // or a {Roo.BasicDialog}
14918 var dialog = new Roo.BasicDialog(...);
14919 dialog.restoreState();
14923 Roo.state.Manager = function(){
14924 var provider = new Roo.state.Provider();
14928 * Configures the default state provider for your application
14929 * @param {Provider} stateProvider The state provider to set
14931 setProvider : function(stateProvider){
14932 provider = stateProvider;
14936 * Returns the current value for a key
14937 * @param {String} name The key name
14938 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14939 * @return {Mixed} The state data
14941 get : function(key, defaultValue){
14942 return provider.get(key, defaultValue);
14946 * Sets the value for a key
14947 * @param {String} name The key name
14948 * @param {Mixed} value The state data
14950 set : function(key, value){
14951 provider.set(key, value);
14955 * Clears a value from the state
14956 * @param {String} name The key name
14958 clear : function(key){
14959 provider.clear(key);
14963 * Gets the currently configured state provider
14964 * @return {Provider} The state provider
14966 getProvider : function(){
14973 * Ext JS Library 1.1.1
14974 * Copyright(c) 2006-2007, Ext JS, LLC.
14976 * Originally Released Under LGPL - original licence link has changed is not relivant.
14979 * <script type="text/javascript">
14982 * @class Roo.state.CookieProvider
14983 * @extends Roo.state.Provider
14984 * The default Provider implementation which saves state via cookies.
14987 var cp = new Roo.state.CookieProvider({
14989 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14990 domain: "roojs.com"
14992 Roo.state.Manager.setProvider(cp);
14994 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14995 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14996 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14997 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14998 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14999 * domain the page is running on including the 'www' like 'www.roojs.com')
15000 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15002 * Create a new CookieProvider
15003 * @param {Object} config The configuration object
15005 Roo.state.CookieProvider = function(config){
15006 Roo.state.CookieProvider.superclass.constructor.call(this);
15008 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15009 this.domain = null;
15010 this.secure = false;
15011 Roo.apply(this, config);
15012 this.state = this.readCookies();
15015 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15017 set : function(name, value){
15018 if(typeof value == "undefined" || value === null){
15022 this.setCookie(name, value);
15023 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15027 clear : function(name){
15028 this.clearCookie(name);
15029 Roo.state.CookieProvider.superclass.clear.call(this, name);
15033 readCookies : function(){
15035 var c = document.cookie + ";";
15036 var re = /\s?(.*?)=(.*?);/g;
15038 while((matches = re.exec(c)) != null){
15039 var name = matches[1];
15040 var value = matches[2];
15041 if(name && name.substring(0,3) == "ys-"){
15042 cookies[name.substr(3)] = this.decodeValue(value);
15049 setCookie : function(name, value){
15050 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15051 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15052 ((this.path == null) ? "" : ("; path=" + this.path)) +
15053 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15054 ((this.secure == true) ? "; secure" : "");
15058 clearCookie : function(name){
15059 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15060 ((this.path == null) ? "" : ("; path=" + this.path)) +
15061 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15062 ((this.secure == true) ? "; secure" : "");
15066 * Ext JS Library 1.1.1
15067 * Copyright(c) 2006-2007, Ext JS, LLC.
15069 * Originally Released Under LGPL - original licence link has changed is not relivant.
15072 * <script type="text/javascript">
15077 * @class Roo.ComponentMgr
15078 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15081 Roo.ComponentMgr = function(){
15082 var all = new Roo.util.MixedCollection();
15086 * Registers a component.
15087 * @param {Roo.Component} c The component
15089 register : function(c){
15094 * Unregisters a component.
15095 * @param {Roo.Component} c The component
15097 unregister : function(c){
15102 * Returns a component by id
15103 * @param {String} id The component id
15105 get : function(id){
15106 return all.get(id);
15110 * Registers a function that will be called when a specified component is added to ComponentMgr
15111 * @param {String} id The component id
15112 * @param {Funtction} fn The callback function
15113 * @param {Object} scope The scope of the callback
15115 onAvailable : function(id, fn, scope){
15116 all.on("add", function(index, o){
15118 fn.call(scope || o, o);
15119 all.un("add", fn, scope);
15126 * Ext JS Library 1.1.1
15127 * Copyright(c) 2006-2007, Ext JS, LLC.
15129 * Originally Released Under LGPL - original licence link has changed is not relivant.
15132 * <script type="text/javascript">
15136 * @class Roo.Component
15137 * @extends Roo.util.Observable
15138 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15139 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15140 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15141 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15142 * All visual components (widgets) that require rendering into a layout should subclass Component.
15144 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15145 * 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
15146 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15148 Roo.Component = function(config){
15149 config = config || {};
15150 if(config.tagName || config.dom || typeof config == "string"){ // element object
15151 config = {el: config, id: config.id || config};
15153 this.initialConfig = config;
15155 Roo.apply(this, config);
15159 * Fires after the component is disabled.
15160 * @param {Roo.Component} this
15165 * Fires after the component is enabled.
15166 * @param {Roo.Component} this
15170 * @event beforeshow
15171 * Fires before the component is shown. Return false to stop the show.
15172 * @param {Roo.Component} this
15177 * Fires after the component is shown.
15178 * @param {Roo.Component} this
15182 * @event beforehide
15183 * Fires before the component is hidden. Return false to stop the hide.
15184 * @param {Roo.Component} this
15189 * Fires after the component is hidden.
15190 * @param {Roo.Component} this
15194 * @event beforerender
15195 * Fires before the component is rendered. Return false to stop the render.
15196 * @param {Roo.Component} this
15198 beforerender : true,
15201 * Fires after the component is rendered.
15202 * @param {Roo.Component} this
15206 * @event beforedestroy
15207 * Fires before the component is destroyed. Return false to stop the destroy.
15208 * @param {Roo.Component} this
15210 beforedestroy : true,
15213 * Fires after the component is destroyed.
15214 * @param {Roo.Component} this
15219 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15221 Roo.ComponentMgr.register(this);
15222 Roo.Component.superclass.constructor.call(this);
15223 this.initComponent();
15224 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15225 this.render(this.renderTo);
15226 delete this.renderTo;
15231 Roo.Component.AUTO_ID = 1000;
15233 Roo.extend(Roo.Component, Roo.util.Observable, {
15235 * @scope Roo.Component.prototype
15237 * true if this component is hidden. Read-only.
15242 * true if this component is disabled. Read-only.
15247 * true if this component has been rendered. Read-only.
15251 /** @cfg {String} disableClass
15252 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15254 disabledClass : "x-item-disabled",
15255 /** @cfg {Boolean} allowDomMove
15256 * Whether the component can move the Dom node when rendering (defaults to true).
15258 allowDomMove : true,
15259 /** @cfg {String} hideMode (display|visibility)
15260 * How this component should hidden. Supported values are
15261 * "visibility" (css visibility), "offsets" (negative offset position) and
15262 * "display" (css display) - defaults to "display".
15264 hideMode: 'display',
15267 ctype : "Roo.Component",
15270 * @cfg {String} actionMode
15271 * which property holds the element that used for hide() / show() / disable() / enable()
15277 getActionEl : function(){
15278 return this[this.actionMode];
15281 initComponent : Roo.emptyFn,
15283 * If this is a lazy rendering component, render it to its container element.
15284 * @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.
15286 render : function(container, position){
15287 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15288 if(!container && this.el){
15289 this.el = Roo.get(this.el);
15290 container = this.el.dom.parentNode;
15291 this.allowDomMove = false;
15293 this.container = Roo.get(container);
15294 this.rendered = true;
15295 if(position !== undefined){
15296 if(typeof position == 'number'){
15297 position = this.container.dom.childNodes[position];
15299 position = Roo.getDom(position);
15302 this.onRender(this.container, position || null);
15304 this.el.addClass(this.cls);
15308 this.el.applyStyles(this.style);
15311 this.fireEvent("render", this);
15312 this.afterRender(this.container);
15324 // default function is not really useful
15325 onRender : function(ct, position){
15327 this.el = Roo.get(this.el);
15328 if(this.allowDomMove !== false){
15329 ct.dom.insertBefore(this.el.dom, position);
15335 getAutoCreate : function(){
15336 var cfg = typeof this.autoCreate == "object" ?
15337 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15338 if(this.id && !cfg.id){
15345 afterRender : Roo.emptyFn,
15348 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15349 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15351 destroy : function(){
15352 if(this.fireEvent("beforedestroy", this) !== false){
15353 this.purgeListeners();
15354 this.beforeDestroy();
15356 this.el.removeAllListeners();
15358 if(this.actionMode == "container"){
15359 this.container.remove();
15363 Roo.ComponentMgr.unregister(this);
15364 this.fireEvent("destroy", this);
15369 beforeDestroy : function(){
15374 onDestroy : function(){
15379 * Returns the underlying {@link Roo.Element}.
15380 * @return {Roo.Element} The element
15382 getEl : function(){
15387 * Returns the id of this component.
15390 getId : function(){
15395 * Try to focus this component.
15396 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15397 * @return {Roo.Component} this
15399 focus : function(selectText){
15402 if(selectText === true){
15403 this.el.dom.select();
15418 * Disable this component.
15419 * @return {Roo.Component} this
15421 disable : function(){
15425 this.disabled = true;
15426 this.fireEvent("disable", this);
15431 onDisable : function(){
15432 this.getActionEl().addClass(this.disabledClass);
15433 this.el.dom.disabled = true;
15437 * Enable this component.
15438 * @return {Roo.Component} this
15440 enable : function(){
15444 this.disabled = false;
15445 this.fireEvent("enable", this);
15450 onEnable : function(){
15451 this.getActionEl().removeClass(this.disabledClass);
15452 this.el.dom.disabled = false;
15456 * Convenience function for setting disabled/enabled by boolean.
15457 * @param {Boolean} disabled
15459 setDisabled : function(disabled){
15460 this[disabled ? "disable" : "enable"]();
15464 * Show this component.
15465 * @return {Roo.Component} this
15468 if(this.fireEvent("beforeshow", this) !== false){
15469 this.hidden = false;
15473 this.fireEvent("show", this);
15479 onShow : function(){
15480 var ae = this.getActionEl();
15481 if(this.hideMode == 'visibility'){
15482 ae.dom.style.visibility = "visible";
15483 }else if(this.hideMode == 'offsets'){
15484 ae.removeClass('x-hidden');
15486 ae.dom.style.display = "";
15491 * Hide this component.
15492 * @return {Roo.Component} this
15495 if(this.fireEvent("beforehide", this) !== false){
15496 this.hidden = true;
15500 this.fireEvent("hide", this);
15506 onHide : function(){
15507 var ae = this.getActionEl();
15508 if(this.hideMode == 'visibility'){
15509 ae.dom.style.visibility = "hidden";
15510 }else if(this.hideMode == 'offsets'){
15511 ae.addClass('x-hidden');
15513 ae.dom.style.display = "none";
15518 * Convenience function to hide or show this component by boolean.
15519 * @param {Boolean} visible True to show, false to hide
15520 * @return {Roo.Component} this
15522 setVisible: function(visible){
15532 * Returns true if this component is visible.
15534 isVisible : function(){
15535 return this.getActionEl().isVisible();
15538 cloneConfig : function(overrides){
15539 overrides = overrides || {};
15540 var id = overrides.id || Roo.id();
15541 var cfg = Roo.applyIf(overrides, this.initialConfig);
15542 cfg.id = id; // prevent dup id
15543 return new this.constructor(cfg);
15547 * Ext JS Library 1.1.1
15548 * Copyright(c) 2006-2007, Ext JS, LLC.
15550 * Originally Released Under LGPL - original licence link has changed is not relivant.
15553 * <script type="text/javascript">
15557 * @class Roo.BoxComponent
15558 * @extends Roo.Component
15559 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15560 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15561 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15562 * layout containers.
15564 * @param {Roo.Element/String/Object} config The configuration options.
15566 Roo.BoxComponent = function(config){
15567 Roo.Component.call(this, config);
15571 * Fires after the component is resized.
15572 * @param {Roo.Component} this
15573 * @param {Number} adjWidth The box-adjusted width that was set
15574 * @param {Number} adjHeight The box-adjusted height that was set
15575 * @param {Number} rawWidth The width that was originally specified
15576 * @param {Number} rawHeight The height that was originally specified
15581 * Fires after the component is moved.
15582 * @param {Roo.Component} this
15583 * @param {Number} x The new x position
15584 * @param {Number} y The new y position
15590 Roo.extend(Roo.BoxComponent, Roo.Component, {
15591 // private, set in afterRender to signify that the component has been rendered
15593 // private, used to defer height settings to subclasses
15594 deferHeight: false,
15595 /** @cfg {Number} width
15596 * width (optional) size of component
15598 /** @cfg {Number} height
15599 * height (optional) size of component
15603 * Sets the width and height of the component. This method fires the resize event. This method can accept
15604 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15605 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15606 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15607 * @return {Roo.BoxComponent} this
15609 setSize : function(w, h){
15610 // support for standard size objects
15611 if(typeof w == 'object'){
15616 if(!this.boxReady){
15622 // prevent recalcs when not needed
15623 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15626 this.lastSize = {width: w, height: h};
15628 var adj = this.adjustSize(w, h);
15629 var aw = adj.width, ah = adj.height;
15630 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15631 var rz = this.getResizeEl();
15632 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15633 rz.setSize(aw, ah);
15634 }else if(!this.deferHeight && ah !== undefined){
15636 }else if(aw !== undefined){
15639 this.onResize(aw, ah, w, h);
15640 this.fireEvent('resize', this, aw, ah, w, h);
15646 * Gets the current size of the component's underlying element.
15647 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15649 getSize : function(){
15650 return this.el.getSize();
15654 * Gets the current XY position of the component's underlying element.
15655 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15656 * @return {Array} The XY position of the element (e.g., [100, 200])
15658 getPosition : function(local){
15659 if(local === true){
15660 return [this.el.getLeft(true), this.el.getTop(true)];
15662 return this.xy || this.el.getXY();
15666 * Gets the current box measurements of the component's underlying element.
15667 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15668 * @returns {Object} box An object in the format {x, y, width, height}
15670 getBox : function(local){
15671 var s = this.el.getSize();
15673 s.x = this.el.getLeft(true);
15674 s.y = this.el.getTop(true);
15676 var xy = this.xy || this.el.getXY();
15684 * Sets the current box measurements of the component's underlying element.
15685 * @param {Object} box An object in the format {x, y, width, height}
15686 * @returns {Roo.BoxComponent} this
15688 updateBox : function(box){
15689 this.setSize(box.width, box.height);
15690 this.setPagePosition(box.x, box.y);
15695 getResizeEl : function(){
15696 return this.resizeEl || this.el;
15700 getPositionEl : function(){
15701 return this.positionEl || this.el;
15705 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15706 * This method fires the move event.
15707 * @param {Number} left The new left
15708 * @param {Number} top The new top
15709 * @returns {Roo.BoxComponent} this
15711 setPosition : function(x, y){
15714 if(!this.boxReady){
15717 var adj = this.adjustPosition(x, y);
15718 var ax = adj.x, ay = adj.y;
15720 var el = this.getPositionEl();
15721 if(ax !== undefined || ay !== undefined){
15722 if(ax !== undefined && ay !== undefined){
15723 el.setLeftTop(ax, ay);
15724 }else if(ax !== undefined){
15726 }else if(ay !== undefined){
15729 this.onPosition(ax, ay);
15730 this.fireEvent('move', this, ax, ay);
15736 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15737 * This method fires the move event.
15738 * @param {Number} x The new x position
15739 * @param {Number} y The new y position
15740 * @returns {Roo.BoxComponent} this
15742 setPagePosition : function(x, y){
15745 if(!this.boxReady){
15748 if(x === undefined || y === undefined){ // cannot translate undefined points
15751 var p = this.el.translatePoints(x, y);
15752 this.setPosition(p.left, p.top);
15757 onRender : function(ct, position){
15758 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15760 this.resizeEl = Roo.get(this.resizeEl);
15762 if(this.positionEl){
15763 this.positionEl = Roo.get(this.positionEl);
15768 afterRender : function(){
15769 Roo.BoxComponent.superclass.afterRender.call(this);
15770 this.boxReady = true;
15771 this.setSize(this.width, this.height);
15772 if(this.x || this.y){
15773 this.setPosition(this.x, this.y);
15775 if(this.pageX || this.pageY){
15776 this.setPagePosition(this.pageX, this.pageY);
15781 * Force the component's size to recalculate based on the underlying element's current height and width.
15782 * @returns {Roo.BoxComponent} this
15784 syncSize : function(){
15785 delete this.lastSize;
15786 this.setSize(this.el.getWidth(), this.el.getHeight());
15791 * Called after the component is resized, this method is empty by default but can be implemented by any
15792 * subclass that needs to perform custom logic after a resize occurs.
15793 * @param {Number} adjWidth The box-adjusted width that was set
15794 * @param {Number} adjHeight The box-adjusted height that was set
15795 * @param {Number} rawWidth The width that was originally specified
15796 * @param {Number} rawHeight The height that was originally specified
15798 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15803 * Called after the component is moved, this method is empty by default but can be implemented by any
15804 * subclass that needs to perform custom logic after a move occurs.
15805 * @param {Number} x The new x position
15806 * @param {Number} y The new y position
15808 onPosition : function(x, y){
15813 adjustSize : function(w, h){
15814 if(this.autoWidth){
15817 if(this.autoHeight){
15820 return {width : w, height: h};
15824 adjustPosition : function(x, y){
15825 return {x : x, y: y};
15828 * Original code for Roojs - LGPL
15829 * <script type="text/javascript">
15833 * @class Roo.XComponent
15834 * A delayed Element creator...
15835 * Or a way to group chunks of interface together.
15836 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15837 * used in conjunction with XComponent.build() it will create an instance of each element,
15838 * then call addxtype() to build the User interface.
15840 * Mypart.xyx = new Roo.XComponent({
15842 parent : 'Mypart.xyz', // empty == document.element.!!
15846 disabled : function() {}
15848 tree : function() { // return an tree of xtype declared components
15852 xtype : 'NestedLayoutPanel',
15859 * It can be used to build a big heiracy, with parent etc.
15860 * or you can just use this to render a single compoent to a dom element
15861 * MYPART.render(Roo.Element | String(id) | dom_element )
15868 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15869 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15871 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15873 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15874 * - if mulitple topModules exist, the last one is defined as the top module.
15878 * When the top level or multiple modules are to embedded into a existing HTML page,
15879 * the parent element can container '#id' of the element where the module will be drawn.
15883 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15884 * it relies more on a include mechanism, where sub modules are included into an outer page.
15885 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15887 * Bootstrap Roo Included elements
15889 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15890 * hence confusing the component builder as it thinks there are multiple top level elements.
15894 * @extends Roo.util.Observable
15896 * @param cfg {Object} configuration of component
15899 Roo.XComponent = function(cfg) {
15900 Roo.apply(this, cfg);
15904 * Fires when this the componnt is built
15905 * @param {Roo.XComponent} c the component
15910 this.region = this.region || 'center'; // default..
15911 Roo.XComponent.register(this);
15912 this.modules = false;
15913 this.el = false; // where the layout goes..
15917 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15920 * The created element (with Roo.factory())
15921 * @type {Roo.Layout}
15927 * for BC - use el in new code
15928 * @type {Roo.Layout}
15934 * for BC - use el in new code
15935 * @type {Roo.Layout}
15940 * @cfg {Function|boolean} disabled
15941 * If this module is disabled by some rule, return true from the funtion
15946 * @cfg {String} parent
15947 * Name of parent element which it get xtype added to..
15952 * @cfg {String} order
15953 * Used to set the order in which elements are created (usefull for multiple tabs)
15958 * @cfg {String} name
15959 * String to display while loading.
15963 * @cfg {String} region
15964 * Region to render component to (defaults to center)
15969 * @cfg {Array} items
15970 * A single item array - the first element is the root of the tree..
15971 * It's done this way to stay compatible with the Xtype system...
15977 * The method that retuns the tree of parts that make up this compoennt
15984 * render element to dom or tree
15985 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15988 render : function(el)
15992 var hp = this.parent ? 1 : 0;
15993 Roo.debug && Roo.log(this);
15995 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15996 // if parent is a '#.....' string, then let's use that..
15997 var ename = this.parent.substr(1);
15998 this.parent = false;
15999 Roo.debug && Roo.log(ename);
16001 case 'bootstrap-body' :
16002 if (typeof(Roo.bootstrap.Body) != 'undefined') {
16003 this.parent = { el : new Roo.bootstrap.Body() };
16004 Roo.debug && Roo.log("setting el to doc body");
16007 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16011 this.parent = { el : true};
16014 el = Roo.get(ename);
16019 if (!el && !this.parent) {
16020 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16024 Roo.debug && Roo.log("EL:");
16025 Roo.debug && Roo.log(el);
16026 Roo.debug && Roo.log("this.parent.el:");
16027 Roo.debug && Roo.log(this.parent.el);
16029 var tree = this._tree ? this._tree() : this.tree();
16031 // altertive root elements ??? - we need a better way to indicate these.
16032 var is_alt = Roo.XComponent.is_alt || (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16033 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16035 if (!this.parent && is_alt) {
16036 //el = Roo.get(document.body);
16037 this.parent = { el : true };
16042 if (!this.parent) {
16044 Roo.debug && Roo.log("no parent - creating one");
16046 el = el ? Roo.get(el) : false;
16048 // it's a top level one..
16050 el : new Roo.BorderLayout(el || document.body, {
16056 tabPosition: 'top',
16057 //resizeTabs: true,
16058 alwaysShowTabs: el && hp? false : true,
16059 hideTabs: el || !hp ? true : false,
16066 if (!this.parent.el) {
16067 // probably an old style ctor, which has been disabled.
16071 // The 'tree' method is '_tree now'
16073 tree.region = tree.region || this.region;
16074 var is_body = false;
16075 if (this.parent.el === true) {
16076 // bootstrap... - body..
16077 this.parent.el = Roo.factory(tree);
16081 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16082 this.fireEvent('built', this);
16084 this.panel = this.el;
16085 this.layout = this.panel.layout;
16086 this.parentLayout = this.parent.layout || false;
16092 Roo.apply(Roo.XComponent, {
16094 * @property hideProgress
16095 * true to disable the building progress bar.. usefull on single page renders.
16098 hideProgress : false,
16100 * @property buildCompleted
16101 * True when the builder has completed building the interface.
16104 buildCompleted : false,
16107 * @property topModule
16108 * the upper most module - uses document.element as it's constructor.
16115 * @property modules
16116 * array of modules to be created by registration system.
16117 * @type {Array} of Roo.XComponent
16122 * @property elmodules
16123 * array of modules to be created by which use #ID
16124 * @type {Array} of Roo.XComponent
16131 * Is an alternative Root - normally used by bootstrap or other systems,
16132 * where the top element in the tree can wrap 'body'
16133 * @type {boolean} (default false)
16138 * @property build_from_html
16139 * Build elements from html - used by bootstrap HTML stuff
16140 * - this is cleared after build is completed
16141 * @type {boolean} (default false)
16144 build_from_html : false,
16146 * Register components to be built later.
16148 * This solves the following issues
16149 * - Building is not done on page load, but after an authentication process has occured.
16150 * - Interface elements are registered on page load
16151 * - Parent Interface elements may not be loaded before child, so this handles that..
16158 module : 'Pman.Tab.projectMgr',
16160 parent : 'Pman.layout',
16161 disabled : false, // or use a function..
16164 * * @param {Object} details about module
16166 register : function(obj) {
16168 Roo.XComponent.event.fireEvent('register', obj);
16169 switch(typeof(obj.disabled) ) {
16175 if ( obj.disabled() ) {
16181 if (obj.disabled) {
16187 this.modules.push(obj);
16191 * convert a string to an object..
16192 * eg. 'AAA.BBB' -> finds AAA.BBB
16196 toObject : function(str)
16198 if (!str || typeof(str) == 'object') {
16201 if (str.substring(0,1) == '#') {
16205 var ar = str.split('.');
16210 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16212 throw "Module not found : " + str;
16216 throw "Module not found : " + str;
16218 Roo.each(ar, function(e) {
16219 if (typeof(o[e]) == 'undefined') {
16220 throw "Module not found : " + str;
16231 * move modules into their correct place in the tree..
16234 preBuild : function ()
16237 Roo.each(this.modules , function (obj)
16239 Roo.XComponent.event.fireEvent('beforebuild', obj);
16241 var opar = obj.parent;
16243 obj.parent = this.toObject(opar);
16245 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16250 Roo.debug && Roo.log("GOT top level module");
16251 Roo.debug && Roo.log(obj);
16252 obj.modules = new Roo.util.MixedCollection(false,
16253 function(o) { return o.order + '' }
16255 this.topModule = obj;
16258 // parent is a string (usually a dom element name..)
16259 if (typeof(obj.parent) == 'string') {
16260 this.elmodules.push(obj);
16263 if (obj.parent.constructor != Roo.XComponent) {
16264 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16266 if (!obj.parent.modules) {
16267 obj.parent.modules = new Roo.util.MixedCollection(false,
16268 function(o) { return o.order + '' }
16271 if (obj.parent.disabled) {
16272 obj.disabled = true;
16274 obj.parent.modules.add(obj);
16279 * make a list of modules to build.
16280 * @return {Array} list of modules.
16283 buildOrder : function()
16286 var cmp = function(a,b) {
16287 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16289 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16290 throw "No top level modules to build";
16293 // make a flat list in order of modules to build.
16294 var mods = this.topModule ? [ this.topModule ] : [];
16297 // elmodules (is a list of DOM based modules )
16298 Roo.each(this.elmodules, function(e) {
16300 if (!this.topModule &&
16301 typeof(e.parent) == 'string' &&
16302 e.parent.substring(0,1) == '#' &&
16303 Roo.get(e.parent.substr(1))
16306 _this.topModule = e;
16312 // add modules to their parents..
16313 var addMod = function(m) {
16314 Roo.debug && Roo.log("build Order: add: " + m.name);
16317 if (m.modules && !m.disabled) {
16318 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16319 m.modules.keySort('ASC', cmp );
16320 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16322 m.modules.each(addMod);
16324 Roo.debug && Roo.log("build Order: no child modules");
16326 // not sure if this is used any more..
16328 m.finalize.name = m.name + " (clean up) ";
16329 mods.push(m.finalize);
16333 if (this.topModule && this.topModule.modules) {
16334 this.topModule.modules.keySort('ASC', cmp );
16335 this.topModule.modules.each(addMod);
16341 * Build the registered modules.
16342 * @param {Object} parent element.
16343 * @param {Function} optional method to call after module has been added.
16347 build : function(opts)
16350 if (typeof(opts) != 'undefined') {
16351 Roo.apply(this,opts);
16355 var mods = this.buildOrder();
16357 //this.allmods = mods;
16358 //Roo.debug && Roo.log(mods);
16360 if (!mods.length) { // should not happen
16361 throw "NO modules!!!";
16365 var msg = "Building Interface...";
16366 // flash it up as modal - so we store the mask!?
16367 if (!this.hideProgress && Roo.MessageBox) {
16368 Roo.MessageBox.show({ title: 'loading' });
16369 Roo.MessageBox.show({
16370 title: "Please wait...",
16379 var total = mods.length;
16382 var progressRun = function() {
16383 if (!mods.length) {
16384 Roo.debug && Roo.log('hide?');
16385 if (!this.hideProgress && Roo.MessageBox) {
16386 Roo.MessageBox.hide();
16388 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16390 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16396 var m = mods.shift();
16399 Roo.debug && Roo.log(m);
16400 // not sure if this is supported any more.. - modules that are are just function
16401 if (typeof(m) == 'function') {
16403 return progressRun.defer(10, _this);
16407 msg = "Building Interface " + (total - mods.length) +
16409 (m.name ? (' - ' + m.name) : '');
16410 Roo.debug && Roo.log(msg);
16411 if (!this.hideProgress && Roo.MessageBox) {
16412 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16416 // is the module disabled?
16417 var disabled = (typeof(m.disabled) == 'function') ?
16418 m.disabled.call(m.module.disabled) : m.disabled;
16422 return progressRun(); // we do not update the display!
16430 // it's 10 on top level, and 1 on others??? why...
16431 return progressRun.defer(10, _this);
16434 progressRun.defer(1, _this);
16448 * wrapper for event.on - aliased later..
16449 * Typically use to register a event handler for register:
16451 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16460 Roo.XComponent.event = new Roo.util.Observable({
16464 * Fires when an Component is registered,
16465 * set the disable property on the Component to stop registration.
16466 * @param {Roo.XComponent} c the component being registerd.
16471 * @event beforebuild
16472 * Fires before each Component is built
16473 * can be used to apply permissions.
16474 * @param {Roo.XComponent} c the component being registerd.
16477 'beforebuild' : true,
16479 * @event buildcomplete
16480 * Fires on the top level element when all elements have been built
16481 * @param {Roo.XComponent} the top level component.
16483 'buildcomplete' : true
16488 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16491 * marked - a markdown parser
16492 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16493 * https://github.com/chjj/marked
16499 * Roo.Markdown - is a very crude wrapper around marked..
16503 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16505 * Note: move the sample code to the bottom of this
16506 * file before uncommenting it.
16511 Roo.Markdown.toHtml = function(text) {
16513 var c = new Roo.Markdown.marked.setOptions({
16514 renderer: new Roo.Markdown.marked.Renderer(),
16525 text = text.replace(/\\\n/g,' ');
16526 return Roo.Markdown.marked(text);
16531 // Wraps all "globals" so that the only thing
16532 // exposed is makeHtml().
16537 * Block-Level Grammar
16542 code: /^( {4}[^\n]+\n*)+/,
16544 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16545 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16547 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16548 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16549 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16550 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16551 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16553 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16557 block.bullet = /(?:[*+-]|\d+\.)/;
16558 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16559 block.item = replace(block.item, 'gm')
16560 (/bull/g, block.bullet)
16563 block.list = replace(block.list)
16564 (/bull/g, block.bullet)
16565 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16566 ('def', '\\n+(?=' + block.def.source + ')')
16569 block.blockquote = replace(block.blockquote)
16573 block._tag = '(?!(?:'
16574 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16575 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16576 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16578 block.html = replace(block.html)
16579 ('comment', /<!--[\s\S]*?-->/)
16580 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16581 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16582 (/tag/g, block._tag)
16585 block.paragraph = replace(block.paragraph)
16587 ('heading', block.heading)
16588 ('lheading', block.lheading)
16589 ('blockquote', block.blockquote)
16590 ('tag', '<' + block._tag)
16595 * Normal Block Grammar
16598 block.normal = merge({}, block);
16601 * GFM Block Grammar
16604 block.gfm = merge({}, block.normal, {
16605 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16607 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16610 block.gfm.paragraph = replace(block.paragraph)
16612 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16613 + block.list.source.replace('\\1', '\\3') + '|')
16617 * GFM + Tables Block Grammar
16620 block.tables = merge({}, block.gfm, {
16621 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16622 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16629 function Lexer(options) {
16631 this.tokens.links = {};
16632 this.options = options || marked.defaults;
16633 this.rules = block.normal;
16635 if (this.options.gfm) {
16636 if (this.options.tables) {
16637 this.rules = block.tables;
16639 this.rules = block.gfm;
16645 * Expose Block Rules
16648 Lexer.rules = block;
16651 * Static Lex Method
16654 Lexer.lex = function(src, options) {
16655 var lexer = new Lexer(options);
16656 return lexer.lex(src);
16663 Lexer.prototype.lex = function(src) {
16665 .replace(/\r\n|\r/g, '\n')
16666 .replace(/\t/g, ' ')
16667 .replace(/\u00a0/g, ' ')
16668 .replace(/\u2424/g, '\n');
16670 return this.token(src, true);
16677 Lexer.prototype.token = function(src, top, bq) {
16678 var src = src.replace(/^ +$/gm, '')
16691 if (cap = this.rules.newline.exec(src)) {
16692 src = src.substring(cap[0].length);
16693 if (cap[0].length > 1) {
16701 if (cap = this.rules.code.exec(src)) {
16702 src = src.substring(cap[0].length);
16703 cap = cap[0].replace(/^ {4}/gm, '');
16706 text: !this.options.pedantic
16707 ? cap.replace(/\n+$/, '')
16714 if (cap = this.rules.fences.exec(src)) {
16715 src = src.substring(cap[0].length);
16725 if (cap = this.rules.heading.exec(src)) {
16726 src = src.substring(cap[0].length);
16729 depth: cap[1].length,
16735 // table no leading pipe (gfm)
16736 if (top && (cap = this.rules.nptable.exec(src))) {
16737 src = src.substring(cap[0].length);
16741 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16742 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16743 cells: cap[3].replace(/\n$/, '').split('\n')
16746 for (i = 0; i < item.align.length; i++) {
16747 if (/^ *-+: *$/.test(item.align[i])) {
16748 item.align[i] = 'right';
16749 } else if (/^ *:-+: *$/.test(item.align[i])) {
16750 item.align[i] = 'center';
16751 } else if (/^ *:-+ *$/.test(item.align[i])) {
16752 item.align[i] = 'left';
16754 item.align[i] = null;
16758 for (i = 0; i < item.cells.length; i++) {
16759 item.cells[i] = item.cells[i].split(/ *\| */);
16762 this.tokens.push(item);
16768 if (cap = this.rules.lheading.exec(src)) {
16769 src = src.substring(cap[0].length);
16772 depth: cap[2] === '=' ? 1 : 2,
16779 if (cap = this.rules.hr.exec(src)) {
16780 src = src.substring(cap[0].length);
16788 if (cap = this.rules.blockquote.exec(src)) {
16789 src = src.substring(cap[0].length);
16792 type: 'blockquote_start'
16795 cap = cap[0].replace(/^ *> ?/gm, '');
16797 // Pass `top` to keep the current
16798 // "toplevel" state. This is exactly
16799 // how markdown.pl works.
16800 this.token(cap, top, true);
16803 type: 'blockquote_end'
16810 if (cap = this.rules.list.exec(src)) {
16811 src = src.substring(cap[0].length);
16815 type: 'list_start',
16816 ordered: bull.length > 1
16819 // Get each top-level item.
16820 cap = cap[0].match(this.rules.item);
16826 for (; i < l; i++) {
16829 // Remove the list item's bullet
16830 // so it is seen as the next token.
16831 space = item.length;
16832 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16834 // Outdent whatever the
16835 // list item contains. Hacky.
16836 if (~item.indexOf('\n ')) {
16837 space -= item.length;
16838 item = !this.options.pedantic
16839 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16840 : item.replace(/^ {1,4}/gm, '');
16843 // Determine whether the next list item belongs here.
16844 // Backpedal if it does not belong in this list.
16845 if (this.options.smartLists && i !== l - 1) {
16846 b = block.bullet.exec(cap[i + 1])[0];
16847 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16848 src = cap.slice(i + 1).join('\n') + src;
16853 // Determine whether item is loose or not.
16854 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16855 // for discount behavior.
16856 loose = next || /\n\n(?!\s*$)/.test(item);
16858 next = item.charAt(item.length - 1) === '\n';
16859 if (!loose) { loose = next; }
16864 ? 'loose_item_start'
16865 : 'list_item_start'
16869 this.token(item, false, bq);
16872 type: 'list_item_end'
16884 if (cap = this.rules.html.exec(src)) {
16885 src = src.substring(cap[0].length);
16887 type: this.options.sanitize
16890 pre: !this.options.sanitizer
16891 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
16898 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
16899 src = src.substring(cap[0].length);
16900 this.tokens.links[cap[1].toLowerCase()] = {
16908 if (top && (cap = this.rules.table.exec(src))) {
16909 src = src.substring(cap[0].length);
16913 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16914 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16915 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
16918 for (i = 0; i < item.align.length; i++) {
16919 if (/^ *-+: *$/.test(item.align[i])) {
16920 item.align[i] = 'right';
16921 } else if (/^ *:-+: *$/.test(item.align[i])) {
16922 item.align[i] = 'center';
16923 } else if (/^ *:-+ *$/.test(item.align[i])) {
16924 item.align[i] = 'left';
16926 item.align[i] = null;
16930 for (i = 0; i < item.cells.length; i++) {
16931 item.cells[i] = item.cells[i]
16932 .replace(/^ *\| *| *\| *$/g, '')
16936 this.tokens.push(item);
16941 // top-level paragraph
16942 if (top && (cap = this.rules.paragraph.exec(src))) {
16943 src = src.substring(cap[0].length);
16946 text: cap[1].charAt(cap[1].length - 1) === '\n'
16947 ? cap[1].slice(0, -1)
16954 if (cap = this.rules.text.exec(src)) {
16955 // Top-level should never reach here.
16956 src = src.substring(cap[0].length);
16966 Error('Infinite loop on byte: ' + src.charCodeAt(0));
16970 return this.tokens;
16974 * Inline-Level Grammar
16978 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
16979 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
16981 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
16982 link: /^!?\[(inside)\]\(href\)/,
16983 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
16984 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
16985 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
16986 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
16987 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
16988 br: /^ {2,}\n(?!\s*$)/,
16990 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
16993 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
16994 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
16996 inline.link = replace(inline.link)
16997 ('inside', inline._inside)
16998 ('href', inline._href)
17001 inline.reflink = replace(inline.reflink)
17002 ('inside', inline._inside)
17006 * Normal Inline Grammar
17009 inline.normal = merge({}, inline);
17012 * Pedantic Inline Grammar
17015 inline.pedantic = merge({}, inline.normal, {
17016 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17017 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17021 * GFM Inline Grammar
17024 inline.gfm = merge({}, inline.normal, {
17025 escape: replace(inline.escape)('])', '~|])')(),
17026 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17027 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17028 text: replace(inline.text)
17030 ('|', '|https?://|')
17035 * GFM + Line Breaks Inline Grammar
17038 inline.breaks = merge({}, inline.gfm, {
17039 br: replace(inline.br)('{2,}', '*')(),
17040 text: replace(inline.gfm.text)('{2,}', '*')()
17044 * Inline Lexer & Compiler
17047 function InlineLexer(links, options) {
17048 this.options = options || marked.defaults;
17049 this.links = links;
17050 this.rules = inline.normal;
17051 this.renderer = this.options.renderer || new Renderer;
17052 this.renderer.options = this.options;
17056 Error('Tokens array requires a `links` property.');
17059 if (this.options.gfm) {
17060 if (this.options.breaks) {
17061 this.rules = inline.breaks;
17063 this.rules = inline.gfm;
17065 } else if (this.options.pedantic) {
17066 this.rules = inline.pedantic;
17071 * Expose Inline Rules
17074 InlineLexer.rules = inline;
17077 * Static Lexing/Compiling Method
17080 InlineLexer.output = function(src, links, options) {
17081 var inline = new InlineLexer(links, options);
17082 return inline.output(src);
17089 InlineLexer.prototype.output = function(src) {
17098 if (cap = this.rules.escape.exec(src)) {
17099 src = src.substring(cap[0].length);
17105 if (cap = this.rules.autolink.exec(src)) {
17106 src = src.substring(cap[0].length);
17107 if (cap[2] === '@') {
17108 text = cap[1].charAt(6) === ':'
17109 ? this.mangle(cap[1].substring(7))
17110 : this.mangle(cap[1]);
17111 href = this.mangle('mailto:') + text;
17113 text = escape(cap[1]);
17116 out += this.renderer.link(href, null, text);
17121 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17122 src = src.substring(cap[0].length);
17123 text = escape(cap[1]);
17125 out += this.renderer.link(href, null, text);
17130 if (cap = this.rules.tag.exec(src)) {
17131 if (!this.inLink && /^<a /i.test(cap[0])) {
17132 this.inLink = true;
17133 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17134 this.inLink = false;
17136 src = src.substring(cap[0].length);
17137 out += this.options.sanitize
17138 ? this.options.sanitizer
17139 ? this.options.sanitizer(cap[0])
17146 if (cap = this.rules.link.exec(src)) {
17147 src = src.substring(cap[0].length);
17148 this.inLink = true;
17149 out += this.outputLink(cap, {
17153 this.inLink = false;
17158 if ((cap = this.rules.reflink.exec(src))
17159 || (cap = this.rules.nolink.exec(src))) {
17160 src = src.substring(cap[0].length);
17161 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17162 link = this.links[link.toLowerCase()];
17163 if (!link || !link.href) {
17164 out += cap[0].charAt(0);
17165 src = cap[0].substring(1) + src;
17168 this.inLink = true;
17169 out += this.outputLink(cap, link);
17170 this.inLink = false;
17175 if (cap = this.rules.strong.exec(src)) {
17176 src = src.substring(cap[0].length);
17177 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17182 if (cap = this.rules.em.exec(src)) {
17183 src = src.substring(cap[0].length);
17184 out += this.renderer.em(this.output(cap[2] || cap[1]));
17189 if (cap = this.rules.code.exec(src)) {
17190 src = src.substring(cap[0].length);
17191 out += this.renderer.codespan(escape(cap[2], true));
17196 if (cap = this.rules.br.exec(src)) {
17197 src = src.substring(cap[0].length);
17198 out += this.renderer.br();
17203 if (cap = this.rules.del.exec(src)) {
17204 src = src.substring(cap[0].length);
17205 out += this.renderer.del(this.output(cap[1]));
17210 if (cap = this.rules.text.exec(src)) {
17211 src = src.substring(cap[0].length);
17212 out += this.renderer.text(escape(this.smartypants(cap[0])));
17218 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17229 InlineLexer.prototype.outputLink = function(cap, link) {
17230 var href = escape(link.href)
17231 , title = link.title ? escape(link.title) : null;
17233 return cap[0].charAt(0) !== '!'
17234 ? this.renderer.link(href, title, this.output(cap[1]))
17235 : this.renderer.image(href, title, escape(cap[1]));
17239 * Smartypants Transformations
17242 InlineLexer.prototype.smartypants = function(text) {
17243 if (!this.options.smartypants) { return text; }
17246 .replace(/---/g, '\u2014')
17248 .replace(/--/g, '\u2013')
17250 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17251 // closing singles & apostrophes
17252 .replace(/'/g, '\u2019')
17254 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17256 .replace(/"/g, '\u201d')
17258 .replace(/\.{3}/g, '\u2026');
17265 InlineLexer.prototype.mangle = function(text) {
17266 if (!this.options.mangle) { return text; }
17272 for (; i < l; i++) {
17273 ch = text.charCodeAt(i);
17274 if (Math.random() > 0.5) {
17275 ch = 'x' + ch.toString(16);
17277 out += '&#' + ch + ';';
17287 function Renderer(options) {
17288 this.options = options || {};
17291 Renderer.prototype.code = function(code, lang, escaped) {
17292 if (this.options.highlight) {
17293 var out = this.options.highlight(code, lang);
17294 if (out != null && out !== code) {
17299 // hack!!! - it's already escapeD?
17304 return '<pre><code>'
17305 + (escaped ? code : escape(code, true))
17306 + '\n</code></pre>';
17309 return '<pre><code class="'
17310 + this.options.langPrefix
17311 + escape(lang, true)
17313 + (escaped ? code : escape(code, true))
17314 + '\n</code></pre>\n';
17317 Renderer.prototype.blockquote = function(quote) {
17318 return '<blockquote>\n' + quote + '</blockquote>\n';
17321 Renderer.prototype.html = function(html) {
17325 Renderer.prototype.heading = function(text, level, raw) {
17329 + this.options.headerPrefix
17330 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17338 Renderer.prototype.hr = function() {
17339 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17342 Renderer.prototype.list = function(body, ordered) {
17343 var type = ordered ? 'ol' : 'ul';
17344 return '<' + type + '>\n' + body + '</' + type + '>\n';
17347 Renderer.prototype.listitem = function(text) {
17348 return '<li>' + text + '</li>\n';
17351 Renderer.prototype.paragraph = function(text) {
17352 return '<p>' + text + '</p>\n';
17355 Renderer.prototype.table = function(header, body) {
17366 Renderer.prototype.tablerow = function(content) {
17367 return '<tr>\n' + content + '</tr>\n';
17370 Renderer.prototype.tablecell = function(content, flags) {
17371 var type = flags.header ? 'th' : 'td';
17372 var tag = flags.align
17373 ? '<' + type + ' style="text-align:' + flags.align + '">'
17374 : '<' + type + '>';
17375 return tag + content + '</' + type + '>\n';
17378 // span level renderer
17379 Renderer.prototype.strong = function(text) {
17380 return '<strong>' + text + '</strong>';
17383 Renderer.prototype.em = function(text) {
17384 return '<em>' + text + '</em>';
17387 Renderer.prototype.codespan = function(text) {
17388 return '<code>' + text + '</code>';
17391 Renderer.prototype.br = function() {
17392 return this.options.xhtml ? '<br/>' : '<br>';
17395 Renderer.prototype.del = function(text) {
17396 return '<del>' + text + '</del>';
17399 Renderer.prototype.link = function(href, title, text) {
17400 if (this.options.sanitize) {
17402 var prot = decodeURIComponent(unescape(href))
17403 .replace(/[^\w:]/g, '')
17408 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17412 var out = '<a href="' + href + '"';
17414 out += ' title="' + title + '"';
17416 out += '>' + text + '</a>';
17420 Renderer.prototype.image = function(href, title, text) {
17421 var out = '<img src="' + href + '" alt="' + text + '"';
17423 out += ' title="' + title + '"';
17425 out += this.options.xhtml ? '/>' : '>';
17429 Renderer.prototype.text = function(text) {
17434 * Parsing & Compiling
17437 function Parser(options) {
17440 this.options = options || marked.defaults;
17441 this.options.renderer = this.options.renderer || new Renderer;
17442 this.renderer = this.options.renderer;
17443 this.renderer.options = this.options;
17447 * Static Parse Method
17450 Parser.parse = function(src, options, renderer) {
17451 var parser = new Parser(options, renderer);
17452 return parser.parse(src);
17459 Parser.prototype.parse = function(src) {
17460 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17461 this.tokens = src.reverse();
17464 while (this.next()) {
17475 Parser.prototype.next = function() {
17476 return this.token = this.tokens.pop();
17480 * Preview Next Token
17483 Parser.prototype.peek = function() {
17484 return this.tokens[this.tokens.length - 1] || 0;
17488 * Parse Text Tokens
17491 Parser.prototype.parseText = function() {
17492 var body = this.token.text;
17494 while (this.peek().type === 'text') {
17495 body += '\n' + this.next().text;
17498 return this.inline.output(body);
17502 * Parse Current Token
17505 Parser.prototype.tok = function() {
17506 switch (this.token.type) {
17511 return this.renderer.hr();
17514 return this.renderer.heading(
17515 this.inline.output(this.token.text),
17520 return this.renderer.code(this.token.text,
17522 this.token.escaped);
17535 for (i = 0; i < this.token.header.length; i++) {
17536 flags = { header: true, align: this.token.align[i] };
17537 cell += this.renderer.tablecell(
17538 this.inline.output(this.token.header[i]),
17539 { header: true, align: this.token.align[i] }
17542 header += this.renderer.tablerow(cell);
17544 for (i = 0; i < this.token.cells.length; i++) {
17545 row = this.token.cells[i];
17548 for (j = 0; j < row.length; j++) {
17549 cell += this.renderer.tablecell(
17550 this.inline.output(row[j]),
17551 { header: false, align: this.token.align[j] }
17555 body += this.renderer.tablerow(cell);
17557 return this.renderer.table(header, body);
17559 case 'blockquote_start': {
17562 while (this.next().type !== 'blockquote_end') {
17563 body += this.tok();
17566 return this.renderer.blockquote(body);
17568 case 'list_start': {
17570 , ordered = this.token.ordered;
17572 while (this.next().type !== 'list_end') {
17573 body += this.tok();
17576 return this.renderer.list(body, ordered);
17578 case 'list_item_start': {
17581 while (this.next().type !== 'list_item_end') {
17582 body += this.token.type === 'text'
17587 return this.renderer.listitem(body);
17589 case 'loose_item_start': {
17592 while (this.next().type !== 'list_item_end') {
17593 body += this.tok();
17596 return this.renderer.listitem(body);
17599 var html = !this.token.pre && !this.options.pedantic
17600 ? this.inline.output(this.token.text)
17602 return this.renderer.html(html);
17604 case 'paragraph': {
17605 return this.renderer.paragraph(this.inline.output(this.token.text));
17608 return this.renderer.paragraph(this.parseText());
17617 function escape(html, encode) {
17619 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17620 .replace(/</g, '<')
17621 .replace(/>/g, '>')
17622 .replace(/"/g, '"')
17623 .replace(/'/g, ''');
17626 function unescape(html) {
17627 // explicitly match decimal, hex, and named HTML entities
17628 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17629 n = n.toLowerCase();
17630 if (n === 'colon') { return ':'; }
17631 if (n.charAt(0) === '#') {
17632 return n.charAt(1) === 'x'
17633 ? String.fromCharCode(parseInt(n.substring(2), 16))
17634 : String.fromCharCode(+n.substring(1));
17640 function replace(regex, opt) {
17641 regex = regex.source;
17643 return function self(name, val) {
17644 if (!name) { return new RegExp(regex, opt); }
17645 val = val.source || val;
17646 val = val.replace(/(^|[^\[])\^/g, '$1');
17647 regex = regex.replace(name, val);
17655 function merge(obj) {
17660 for (; i < arguments.length; i++) {
17661 target = arguments[i];
17662 for (key in target) {
17663 if (Object.prototype.hasOwnProperty.call(target, key)) {
17664 obj[key] = target[key];
17677 function marked(src, opt, callback) {
17678 if (callback || typeof opt === 'function') {
17684 opt = merge({}, marked.defaults, opt || {});
17686 var highlight = opt.highlight
17692 tokens = Lexer.lex(src, opt)
17694 return callback(e);
17697 pending = tokens.length;
17699 var done = function(err) {
17701 opt.highlight = highlight;
17702 return callback(err);
17708 out = Parser.parse(tokens, opt);
17713 opt.highlight = highlight;
17717 : callback(null, out);
17720 if (!highlight || highlight.length < 3) {
17724 delete opt.highlight;
17726 if (!pending) { return done(); }
17728 for (; i < tokens.length; i++) {
17730 if (token.type !== 'code') {
17731 return --pending || done();
17733 return highlight(token.text, token.lang, function(err, code) {
17734 if (err) { return done(err); }
17735 if (code == null || code === token.text) {
17736 return --pending || done();
17739 token.escaped = true;
17740 --pending || done();
17748 if (opt) { opt = merge({}, marked.defaults, opt); }
17749 return Parser.parse(Lexer.lex(src, opt), opt);
17751 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17752 if ((opt || marked.defaults).silent) {
17753 return '<p>An error occured:</p><pre>'
17754 + escape(e.message + '', true)
17766 marked.setOptions = function(opt) {
17767 merge(marked.defaults, opt);
17771 marked.defaults = {
17782 langPrefix: 'lang-',
17783 smartypants: false,
17785 renderer: new Renderer,
17793 marked.Parser = Parser;
17794 marked.parser = Parser.parse;
17796 marked.Renderer = Renderer;
17798 marked.Lexer = Lexer;
17799 marked.lexer = Lexer.lex;
17801 marked.InlineLexer = InlineLexer;
17802 marked.inlineLexer = InlineLexer.output;
17804 marked.parse = marked;
17806 Roo.Markdown.marked = marked;
17810 * Ext JS Library 1.1.1
17811 * Copyright(c) 2006-2007, Ext JS, LLC.
17813 * Originally Released Under LGPL - original licence link has changed is not relivant.
17816 * <script type="text/javascript">
17822 * These classes are derivatives of the similarly named classes in the YUI Library.
17823 * The original license:
17824 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17825 * Code licensed under the BSD License:
17826 * http://developer.yahoo.net/yui/license.txt
17831 var Event=Roo.EventManager;
17832 var Dom=Roo.lib.Dom;
17835 * @class Roo.dd.DragDrop
17836 * @extends Roo.util.Observable
17837 * Defines the interface and base operation of items that that can be
17838 * dragged or can be drop targets. It was designed to be extended, overriding
17839 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17840 * Up to three html elements can be associated with a DragDrop instance:
17842 * <li>linked element: the element that is passed into the constructor.
17843 * This is the element which defines the boundaries for interaction with
17844 * other DragDrop objects.</li>
17845 * <li>handle element(s): The drag operation only occurs if the element that
17846 * was clicked matches a handle element. By default this is the linked
17847 * element, but there are times that you will want only a portion of the
17848 * linked element to initiate the drag operation, and the setHandleElId()
17849 * method provides a way to define this.</li>
17850 * <li>drag element: this represents the element that would be moved along
17851 * with the cursor during a drag operation. By default, this is the linked
17852 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
17853 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17856 * This class should not be instantiated until the onload event to ensure that
17857 * the associated elements are available.
17858 * The following would define a DragDrop obj that would interact with any
17859 * other DragDrop obj in the "group1" group:
17861 * dd = new Roo.dd.DragDrop("div1", "group1");
17863 * Since none of the event handlers have been implemented, nothing would
17864 * actually happen if you were to run the code above. Normally you would
17865 * override this class or one of the default implementations, but you can
17866 * also override the methods you want on an instance of the class...
17868 * dd.onDragDrop = function(e, id) {
17869 * alert("dd was dropped on " + id);
17873 * @param {String} id of the element that is linked to this instance
17874 * @param {String} sGroup the group of related DragDrop objects
17875 * @param {object} config an object containing configurable attributes
17876 * Valid properties for DragDrop:
17877 * padding, isTarget, maintainOffset, primaryButtonOnly
17879 Roo.dd.DragDrop = function(id, sGroup, config) {
17881 this.init(id, sGroup, config);
17886 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
17889 * The id of the element associated with this object. This is what we
17890 * refer to as the "linked element" because the size and position of
17891 * this element is used to determine when the drag and drop objects have
17899 * Configuration attributes passed into the constructor
17906 * The id of the element that will be dragged. By default this is same
17907 * as the linked element , but could be changed to another element. Ex:
17909 * @property dragElId
17916 * the id of the element that initiates the drag operation. By default
17917 * this is the linked element, but could be changed to be a child of this
17918 * element. This lets us do things like only starting the drag when the
17919 * header element within the linked html element is clicked.
17920 * @property handleElId
17927 * An associative array of HTML tags that will be ignored if clicked.
17928 * @property invalidHandleTypes
17929 * @type {string: string}
17931 invalidHandleTypes: null,
17934 * An associative array of ids for elements that will be ignored if clicked
17935 * @property invalidHandleIds
17936 * @type {string: string}
17938 invalidHandleIds: null,
17941 * An indexted array of css class names for elements that will be ignored
17943 * @property invalidHandleClasses
17946 invalidHandleClasses: null,
17949 * The linked element's absolute X position at the time the drag was
17951 * @property startPageX
17958 * The linked element's absolute X position at the time the drag was
17960 * @property startPageY
17967 * The group defines a logical collection of DragDrop objects that are
17968 * related. Instances only get events when interacting with other
17969 * DragDrop object in the same group. This lets us define multiple
17970 * groups using a single DragDrop subclass if we want.
17972 * @type {string: string}
17977 * Individual drag/drop instances can be locked. This will prevent
17978 * onmousedown start drag.
17986 * Lock this instance
17989 lock: function() { this.locked = true; },
17992 * Unlock this instace
17995 unlock: function() { this.locked = false; },
17998 * By default, all insances can be a drop target. This can be disabled by
17999 * setting isTarget to false.
18006 * The padding configured for this drag and drop object for calculating
18007 * the drop zone intersection with this object.
18014 * Cached reference to the linked element
18015 * @property _domRef
18021 * Internal typeof flag
18022 * @property __ygDragDrop
18025 __ygDragDrop: true,
18028 * Set to true when horizontal contraints are applied
18029 * @property constrainX
18036 * Set to true when vertical contraints are applied
18037 * @property constrainY
18044 * The left constraint
18052 * The right constraint
18060 * The up constraint
18069 * The down constraint
18077 * Maintain offsets when we resetconstraints. Set to true when you want
18078 * the position of the element relative to its parent to stay the same
18079 * when the page changes
18081 * @property maintainOffset
18084 maintainOffset: false,
18087 * Array of pixel locations the element will snap to if we specified a
18088 * horizontal graduation/interval. This array is generated automatically
18089 * when you define a tick interval.
18096 * Array of pixel locations the element will snap to if we specified a
18097 * vertical graduation/interval. This array is generated automatically
18098 * when you define a tick interval.
18105 * By default the drag and drop instance will only respond to the primary
18106 * button click (left button for a right-handed mouse). Set to true to
18107 * allow drag and drop to start with any mouse click that is propogated
18109 * @property primaryButtonOnly
18112 primaryButtonOnly: true,
18115 * The availabe property is false until the linked dom element is accessible.
18116 * @property available
18122 * By default, drags can only be initiated if the mousedown occurs in the
18123 * region the linked element is. This is done in part to work around a
18124 * bug in some browsers that mis-report the mousedown if the previous
18125 * mouseup happened outside of the window. This property is set to true
18126 * if outer handles are defined.
18128 * @property hasOuterHandles
18132 hasOuterHandles: false,
18135 * Code that executes immediately before the startDrag event
18136 * @method b4StartDrag
18139 b4StartDrag: function(x, y) { },
18142 * Abstract method called after a drag/drop object is clicked
18143 * and the drag or mousedown time thresholds have beeen met.
18144 * @method startDrag
18145 * @param {int} X click location
18146 * @param {int} Y click location
18148 startDrag: function(x, y) { /* override this */ },
18151 * Code that executes immediately before the onDrag event
18155 b4Drag: function(e) { },
18158 * Abstract method called during the onMouseMove event while dragging an
18161 * @param {Event} e the mousemove event
18163 onDrag: function(e) { /* override this */ },
18166 * Abstract method called when this element fist begins hovering over
18167 * another DragDrop obj
18168 * @method onDragEnter
18169 * @param {Event} e the mousemove event
18170 * @param {String|DragDrop[]} id In POINT mode, the element
18171 * id this is hovering over. In INTERSECT mode, an array of one or more
18172 * dragdrop items being hovered over.
18174 onDragEnter: function(e, id) { /* override this */ },
18177 * Code that executes immediately before the onDragOver event
18178 * @method b4DragOver
18181 b4DragOver: function(e) { },
18184 * Abstract method called when this element is hovering over another
18186 * @method onDragOver
18187 * @param {Event} e the mousemove event
18188 * @param {String|DragDrop[]} id In POINT mode, the element
18189 * id this is hovering over. In INTERSECT mode, an array of dd items
18190 * being hovered over.
18192 onDragOver: function(e, id) { /* override this */ },
18195 * Code that executes immediately before the onDragOut event
18196 * @method b4DragOut
18199 b4DragOut: function(e) { },
18202 * Abstract method called when we are no longer hovering over an element
18203 * @method onDragOut
18204 * @param {Event} e the mousemove event
18205 * @param {String|DragDrop[]} id In POINT mode, the element
18206 * id this was hovering over. In INTERSECT mode, an array of dd items
18207 * that the mouse is no longer over.
18209 onDragOut: function(e, id) { /* override this */ },
18212 * Code that executes immediately before the onDragDrop event
18213 * @method b4DragDrop
18216 b4DragDrop: function(e) { },
18219 * Abstract method called when this item is dropped on another DragDrop
18221 * @method onDragDrop
18222 * @param {Event} e the mouseup event
18223 * @param {String|DragDrop[]} id In POINT mode, the element
18224 * id this was dropped on. In INTERSECT mode, an array of dd items this
18227 onDragDrop: function(e, id) { /* override this */ },
18230 * Abstract method called when this item is dropped on an area with no
18232 * @method onInvalidDrop
18233 * @param {Event} e the mouseup event
18235 onInvalidDrop: function(e) { /* override this */ },
18238 * Code that executes immediately before the endDrag event
18239 * @method b4EndDrag
18242 b4EndDrag: function(e) { },
18245 * Fired when we are done dragging the object
18247 * @param {Event} e the mouseup event
18249 endDrag: function(e) { /* override this */ },
18252 * Code executed immediately before the onMouseDown event
18253 * @method b4MouseDown
18254 * @param {Event} e the mousedown event
18257 b4MouseDown: function(e) { },
18260 * Event handler that fires when a drag/drop obj gets a mousedown
18261 * @method onMouseDown
18262 * @param {Event} e the mousedown event
18264 onMouseDown: function(e) { /* override this */ },
18267 * Event handler that fires when a drag/drop obj gets a mouseup
18268 * @method onMouseUp
18269 * @param {Event} e the mouseup event
18271 onMouseUp: function(e) { /* override this */ },
18274 * Override the onAvailable method to do what is needed after the initial
18275 * position was determined.
18276 * @method onAvailable
18278 onAvailable: function () {
18282 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18285 defaultPadding : {left:0, right:0, top:0, bottom:0},
18288 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18292 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18293 { dragElId: "existingProxyDiv" });
18294 dd.startDrag = function(){
18295 this.constrainTo("parent-id");
18298 * Or you can initalize it using the {@link Roo.Element} object:
18300 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18301 startDrag : function(){
18302 this.constrainTo("parent-id");
18306 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18307 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18308 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18309 * an object containing the sides to pad. For example: {right:10, bottom:10}
18310 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18312 constrainTo : function(constrainTo, pad, inContent){
18313 if(typeof pad == "number"){
18314 pad = {left: pad, right:pad, top:pad, bottom:pad};
18316 pad = pad || this.defaultPadding;
18317 var b = Roo.get(this.getEl()).getBox();
18318 var ce = Roo.get(constrainTo);
18319 var s = ce.getScroll();
18320 var c, cd = ce.dom;
18321 if(cd == document.body){
18322 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18325 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18329 var topSpace = b.y - c.y;
18330 var leftSpace = b.x - c.x;
18332 this.resetConstraints();
18333 this.setXConstraint(leftSpace - (pad.left||0), // left
18334 c.width - leftSpace - b.width - (pad.right||0) //right
18336 this.setYConstraint(topSpace - (pad.top||0), //top
18337 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18342 * Returns a reference to the linked element
18344 * @return {HTMLElement} the html element
18346 getEl: function() {
18347 if (!this._domRef) {
18348 this._domRef = Roo.getDom(this.id);
18351 return this._domRef;
18355 * Returns a reference to the actual element to drag. By default this is
18356 * the same as the html element, but it can be assigned to another
18357 * element. An example of this can be found in Roo.dd.DDProxy
18358 * @method getDragEl
18359 * @return {HTMLElement} the html element
18361 getDragEl: function() {
18362 return Roo.getDom(this.dragElId);
18366 * Sets up the DragDrop object. Must be called in the constructor of any
18367 * Roo.dd.DragDrop subclass
18369 * @param id the id of the linked element
18370 * @param {String} sGroup the group of related items
18371 * @param {object} config configuration attributes
18373 init: function(id, sGroup, config) {
18374 this.initTarget(id, sGroup, config);
18375 if (!Roo.isTouch) {
18376 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18378 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18379 // Event.on(this.id, "selectstart", Event.preventDefault);
18383 * Initializes Targeting functionality only... the object does not
18384 * get a mousedown handler.
18385 * @method initTarget
18386 * @param id the id of the linked element
18387 * @param {String} sGroup the group of related items
18388 * @param {object} config configuration attributes
18390 initTarget: function(id, sGroup, config) {
18392 // configuration attributes
18393 this.config = config || {};
18395 // create a local reference to the drag and drop manager
18396 this.DDM = Roo.dd.DDM;
18397 // initialize the groups array
18400 // assume that we have an element reference instead of an id if the
18401 // parameter is not a string
18402 if (typeof id !== "string") {
18409 // add to an interaction group
18410 this.addToGroup((sGroup) ? sGroup : "default");
18412 // We don't want to register this as the handle with the manager
18413 // so we just set the id rather than calling the setter.
18414 this.handleElId = id;
18416 // the linked element is the element that gets dragged by default
18417 this.setDragElId(id);
18419 // by default, clicked anchors will not start drag operations.
18420 this.invalidHandleTypes = { A: "A" };
18421 this.invalidHandleIds = {};
18422 this.invalidHandleClasses = [];
18424 this.applyConfig();
18426 this.handleOnAvailable();
18430 * Applies the configuration parameters that were passed into the constructor.
18431 * This is supposed to happen at each level through the inheritance chain. So
18432 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18433 * DragDrop in order to get all of the parameters that are available in
18435 * @method applyConfig
18437 applyConfig: function() {
18439 // configurable properties:
18440 // padding, isTarget, maintainOffset, primaryButtonOnly
18441 this.padding = this.config.padding || [0, 0, 0, 0];
18442 this.isTarget = (this.config.isTarget !== false);
18443 this.maintainOffset = (this.config.maintainOffset);
18444 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18449 * Executed when the linked element is available
18450 * @method handleOnAvailable
18453 handleOnAvailable: function() {
18454 this.available = true;
18455 this.resetConstraints();
18456 this.onAvailable();
18460 * Configures the padding for the target zone in px. Effectively expands
18461 * (or reduces) the virtual object size for targeting calculations.
18462 * Supports css-style shorthand; if only one parameter is passed, all sides
18463 * will have that padding, and if only two are passed, the top and bottom
18464 * will have the first param, the left and right the second.
18465 * @method setPadding
18466 * @param {int} iTop Top pad
18467 * @param {int} iRight Right pad
18468 * @param {int} iBot Bot pad
18469 * @param {int} iLeft Left pad
18471 setPadding: function(iTop, iRight, iBot, iLeft) {
18472 // this.padding = [iLeft, iRight, iTop, iBot];
18473 if (!iRight && 0 !== iRight) {
18474 this.padding = [iTop, iTop, iTop, iTop];
18475 } else if (!iBot && 0 !== iBot) {
18476 this.padding = [iTop, iRight, iTop, iRight];
18478 this.padding = [iTop, iRight, iBot, iLeft];
18483 * Stores the initial placement of the linked element.
18484 * @method setInitialPosition
18485 * @param {int} diffX the X offset, default 0
18486 * @param {int} diffY the Y offset, default 0
18488 setInitPosition: function(diffX, diffY) {
18489 var el = this.getEl();
18491 if (!this.DDM.verifyEl(el)) {
18495 var dx = diffX || 0;
18496 var dy = diffY || 0;
18498 var p = Dom.getXY( el );
18500 this.initPageX = p[0] - dx;
18501 this.initPageY = p[1] - dy;
18503 this.lastPageX = p[0];
18504 this.lastPageY = p[1];
18507 this.setStartPosition(p);
18511 * Sets the start position of the element. This is set when the obj
18512 * is initialized, the reset when a drag is started.
18513 * @method setStartPosition
18514 * @param pos current position (from previous lookup)
18517 setStartPosition: function(pos) {
18518 var p = pos || Dom.getXY( this.getEl() );
18519 this.deltaSetXY = null;
18521 this.startPageX = p[0];
18522 this.startPageY = p[1];
18526 * Add this instance to a group of related drag/drop objects. All
18527 * instances belong to at least one group, and can belong to as many
18528 * groups as needed.
18529 * @method addToGroup
18530 * @param sGroup {string} the name of the group
18532 addToGroup: function(sGroup) {
18533 this.groups[sGroup] = true;
18534 this.DDM.regDragDrop(this, sGroup);
18538 * Remove's this instance from the supplied interaction group
18539 * @method removeFromGroup
18540 * @param {string} sGroup The group to drop
18542 removeFromGroup: function(sGroup) {
18543 if (this.groups[sGroup]) {
18544 delete this.groups[sGroup];
18547 this.DDM.removeDDFromGroup(this, sGroup);
18551 * Allows you to specify that an element other than the linked element
18552 * will be moved with the cursor during a drag
18553 * @method setDragElId
18554 * @param id {string} the id of the element that will be used to initiate the drag
18556 setDragElId: function(id) {
18557 this.dragElId = id;
18561 * Allows you to specify a child of the linked element that should be
18562 * used to initiate the drag operation. An example of this would be if
18563 * you have a content div with text and links. Clicking anywhere in the
18564 * content area would normally start the drag operation. Use this method
18565 * to specify that an element inside of the content div is the element
18566 * that starts the drag operation.
18567 * @method setHandleElId
18568 * @param id {string} the id of the element that will be used to
18569 * initiate the drag.
18571 setHandleElId: function(id) {
18572 if (typeof id !== "string") {
18575 this.handleElId = id;
18576 this.DDM.regHandle(this.id, id);
18580 * Allows you to set an element outside of the linked element as a drag
18582 * @method setOuterHandleElId
18583 * @param id the id of the element that will be used to initiate the drag
18585 setOuterHandleElId: function(id) {
18586 if (typeof id !== "string") {
18589 Event.on(id, "mousedown",
18590 this.handleMouseDown, this);
18591 this.setHandleElId(id);
18593 this.hasOuterHandles = true;
18597 * Remove all drag and drop hooks for this element
18600 unreg: function() {
18601 Event.un(this.id, "mousedown",
18602 this.handleMouseDown);
18603 Event.un(this.id, "touchstart",
18604 this.handleMouseDown);
18605 this._domRef = null;
18606 this.DDM._remove(this);
18609 destroy : function(){
18614 * Returns true if this instance is locked, or the drag drop mgr is locked
18615 * (meaning that all drag/drop is disabled on the page.)
18617 * @return {boolean} true if this obj or all drag/drop is locked, else
18620 isLocked: function() {
18621 return (this.DDM.isLocked() || this.locked);
18625 * Fired when this object is clicked
18626 * @method handleMouseDown
18628 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18631 handleMouseDown: function(e, oDD){
18633 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18634 //Roo.log('not touch/ button !=0');
18637 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18638 return; // double touch..
18642 if (this.isLocked()) {
18643 //Roo.log('locked');
18647 this.DDM.refreshCache(this.groups);
18648 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18649 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18650 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18651 //Roo.log('no outer handes or not over target');
18654 // Roo.log('check validator');
18655 if (this.clickValidator(e)) {
18656 // Roo.log('validate success');
18657 // set the initial element position
18658 this.setStartPosition();
18661 this.b4MouseDown(e);
18662 this.onMouseDown(e);
18664 this.DDM.handleMouseDown(e, this);
18666 this.DDM.stopEvent(e);
18674 clickValidator: function(e) {
18675 var target = e.getTarget();
18676 return ( this.isValidHandleChild(target) &&
18677 (this.id == this.handleElId ||
18678 this.DDM.handleWasClicked(target, this.id)) );
18682 * Allows you to specify a tag name that should not start a drag operation
18683 * when clicked. This is designed to facilitate embedding links within a
18684 * drag handle that do something other than start the drag.
18685 * @method addInvalidHandleType
18686 * @param {string} tagName the type of element to exclude
18688 addInvalidHandleType: function(tagName) {
18689 var type = tagName.toUpperCase();
18690 this.invalidHandleTypes[type] = type;
18694 * Lets you to specify an element id for a child of a drag handle
18695 * that should not initiate a drag
18696 * @method addInvalidHandleId
18697 * @param {string} id the element id of the element you wish to ignore
18699 addInvalidHandleId: function(id) {
18700 if (typeof id !== "string") {
18703 this.invalidHandleIds[id] = id;
18707 * Lets you specify a css class of elements that will not initiate a drag
18708 * @method addInvalidHandleClass
18709 * @param {string} cssClass the class of the elements you wish to ignore
18711 addInvalidHandleClass: function(cssClass) {
18712 this.invalidHandleClasses.push(cssClass);
18716 * Unsets an excluded tag name set by addInvalidHandleType
18717 * @method removeInvalidHandleType
18718 * @param {string} tagName the type of element to unexclude
18720 removeInvalidHandleType: function(tagName) {
18721 var type = tagName.toUpperCase();
18722 // this.invalidHandleTypes[type] = null;
18723 delete this.invalidHandleTypes[type];
18727 * Unsets an invalid handle id
18728 * @method removeInvalidHandleId
18729 * @param {string} id the id of the element to re-enable
18731 removeInvalidHandleId: function(id) {
18732 if (typeof id !== "string") {
18735 delete this.invalidHandleIds[id];
18739 * Unsets an invalid css class
18740 * @method removeInvalidHandleClass
18741 * @param {string} cssClass the class of the element(s) you wish to
18744 removeInvalidHandleClass: function(cssClass) {
18745 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18746 if (this.invalidHandleClasses[i] == cssClass) {
18747 delete this.invalidHandleClasses[i];
18753 * Checks the tag exclusion list to see if this click should be ignored
18754 * @method isValidHandleChild
18755 * @param {HTMLElement} node the HTMLElement to evaluate
18756 * @return {boolean} true if this is a valid tag type, false if not
18758 isValidHandleChild: function(node) {
18761 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18764 nodeName = node.nodeName.toUpperCase();
18766 nodeName = node.nodeName;
18768 valid = valid && !this.invalidHandleTypes[nodeName];
18769 valid = valid && !this.invalidHandleIds[node.id];
18771 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18772 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18781 * Create the array of horizontal tick marks if an interval was specified
18782 * in setXConstraint().
18783 * @method setXTicks
18786 setXTicks: function(iStartX, iTickSize) {
18788 this.xTickSize = iTickSize;
18792 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18794 this.xTicks[this.xTicks.length] = i;
18799 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18801 this.xTicks[this.xTicks.length] = i;
18806 this.xTicks.sort(this.DDM.numericSort) ;
18810 * Create the array of vertical tick marks if an interval was specified in
18811 * setYConstraint().
18812 * @method setYTicks
18815 setYTicks: function(iStartY, iTickSize) {
18817 this.yTickSize = iTickSize;
18821 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18823 this.yTicks[this.yTicks.length] = i;
18828 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18830 this.yTicks[this.yTicks.length] = i;
18835 this.yTicks.sort(this.DDM.numericSort) ;
18839 * By default, the element can be dragged any place on the screen. Use
18840 * this method to limit the horizontal travel of the element. Pass in
18841 * 0,0 for the parameters if you want to lock the drag to the y axis.
18842 * @method setXConstraint
18843 * @param {int} iLeft the number of pixels the element can move to the left
18844 * @param {int} iRight the number of pixels the element can move to the
18846 * @param {int} iTickSize optional parameter for specifying that the
18848 * should move iTickSize pixels at a time.
18850 setXConstraint: function(iLeft, iRight, iTickSize) {
18851 this.leftConstraint = iLeft;
18852 this.rightConstraint = iRight;
18854 this.minX = this.initPageX - iLeft;
18855 this.maxX = this.initPageX + iRight;
18856 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18858 this.constrainX = true;
18862 * Clears any constraints applied to this instance. Also clears ticks
18863 * since they can't exist independent of a constraint at this time.
18864 * @method clearConstraints
18866 clearConstraints: function() {
18867 this.constrainX = false;
18868 this.constrainY = false;
18873 * Clears any tick interval defined for this instance
18874 * @method clearTicks
18876 clearTicks: function() {
18877 this.xTicks = null;
18878 this.yTicks = null;
18879 this.xTickSize = 0;
18880 this.yTickSize = 0;
18884 * By default, the element can be dragged any place on the screen. Set
18885 * this to limit the vertical travel of the element. Pass in 0,0 for the
18886 * parameters if you want to lock the drag to the x axis.
18887 * @method setYConstraint
18888 * @param {int} iUp the number of pixels the element can move up
18889 * @param {int} iDown the number of pixels the element can move down
18890 * @param {int} iTickSize optional parameter for specifying that the
18891 * element should move iTickSize pixels at a time.
18893 setYConstraint: function(iUp, iDown, iTickSize) {
18894 this.topConstraint = iUp;
18895 this.bottomConstraint = iDown;
18897 this.minY = this.initPageY - iUp;
18898 this.maxY = this.initPageY + iDown;
18899 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
18901 this.constrainY = true;
18906 * resetConstraints must be called if you manually reposition a dd element.
18907 * @method resetConstraints
18908 * @param {boolean} maintainOffset
18910 resetConstraints: function() {
18913 // Maintain offsets if necessary
18914 if (this.initPageX || this.initPageX === 0) {
18915 // figure out how much this thing has moved
18916 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
18917 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
18919 this.setInitPosition(dx, dy);
18921 // This is the first time we have detected the element's position
18923 this.setInitPosition();
18926 if (this.constrainX) {
18927 this.setXConstraint( this.leftConstraint,
18928 this.rightConstraint,
18932 if (this.constrainY) {
18933 this.setYConstraint( this.topConstraint,
18934 this.bottomConstraint,
18940 * Normally the drag element is moved pixel by pixel, but we can specify
18941 * that it move a number of pixels at a time. This method resolves the
18942 * location when we have it set up like this.
18944 * @param {int} val where we want to place the object
18945 * @param {int[]} tickArray sorted array of valid points
18946 * @return {int} the closest tick
18949 getTick: function(val, tickArray) {
18952 // If tick interval is not defined, it is effectively 1 pixel,
18953 // so we return the value passed to us.
18955 } else if (tickArray[0] >= val) {
18956 // The value is lower than the first tick, so we return the first
18958 return tickArray[0];
18960 for (var i=0, len=tickArray.length; i<len; ++i) {
18962 if (tickArray[next] && tickArray[next] >= val) {
18963 var diff1 = val - tickArray[i];
18964 var diff2 = tickArray[next] - val;
18965 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
18969 // The value is larger than the last tick, so we return the last
18971 return tickArray[tickArray.length - 1];
18978 * @return {string} string representation of the dd obj
18980 toString: function() {
18981 return ("DragDrop " + this.id);
18989 * Ext JS Library 1.1.1
18990 * Copyright(c) 2006-2007, Ext JS, LLC.
18992 * Originally Released Under LGPL - original licence link has changed is not relivant.
18995 * <script type="text/javascript">
19000 * The drag and drop utility provides a framework for building drag and drop
19001 * applications. In addition to enabling drag and drop for specific elements,
19002 * the drag and drop elements are tracked by the manager class, and the
19003 * interactions between the various elements are tracked during the drag and
19004 * the implementing code is notified about these important moments.
19007 // Only load the library once. Rewriting the manager class would orphan
19008 // existing drag and drop instances.
19009 if (!Roo.dd.DragDropMgr) {
19012 * @class Roo.dd.DragDropMgr
19013 * DragDropMgr is a singleton that tracks the element interaction for
19014 * all DragDrop items in the window. Generally, you will not call
19015 * this class directly, but it does have helper methods that could
19016 * be useful in your DragDrop implementations.
19019 Roo.dd.DragDropMgr = function() {
19021 var Event = Roo.EventManager;
19026 * Two dimensional Array of registered DragDrop objects. The first
19027 * dimension is the DragDrop item group, the second the DragDrop
19030 * @type {string: string}
19037 * Array of element ids defined as drag handles. Used to determine
19038 * if the element that generated the mousedown event is actually the
19039 * handle and not the html element itself.
19040 * @property handleIds
19041 * @type {string: string}
19048 * the DragDrop object that is currently being dragged
19049 * @property dragCurrent
19057 * the DragDrop object(s) that are being hovered over
19058 * @property dragOvers
19066 * the X distance between the cursor and the object being dragged
19075 * the Y distance between the cursor and the object being dragged
19084 * Flag to determine if we should prevent the default behavior of the
19085 * events we define. By default this is true, but this can be set to
19086 * false if you need the default behavior (not recommended)
19087 * @property preventDefault
19091 preventDefault: true,
19094 * Flag to determine if we should stop the propagation of the events
19095 * we generate. This is true by default but you may want to set it to
19096 * false if the html element contains other features that require the
19098 * @property stopPropagation
19102 stopPropagation: true,
19105 * Internal flag that is set to true when drag and drop has been
19107 * @property initialized
19114 * All drag and drop can be disabled.
19122 * Called the first time an element is registered.
19128 this.initialized = true;
19132 * In point mode, drag and drop interaction is defined by the
19133 * location of the cursor during the drag/drop
19141 * In intersect mode, drag and drop interactio nis defined by the
19142 * overlap of two or more drag and drop objects.
19143 * @property INTERSECT
19150 * The current drag and drop mode. Default: POINT
19158 * Runs method on all drag and drop objects
19159 * @method _execOnAll
19163 _execOnAll: function(sMethod, args) {
19164 for (var i in this.ids) {
19165 for (var j in this.ids[i]) {
19166 var oDD = this.ids[i][j];
19167 if (! this.isTypeOfDD(oDD)) {
19170 oDD[sMethod].apply(oDD, args);
19176 * Drag and drop initialization. Sets up the global event handlers
19181 _onLoad: function() {
19185 if (!Roo.isTouch) {
19186 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19187 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19189 Event.on(document, "touchend", this.handleMouseUp, this, true);
19190 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19192 Event.on(window, "unload", this._onUnload, this, true);
19193 Event.on(window, "resize", this._onResize, this, true);
19194 // Event.on(window, "mouseout", this._test);
19199 * Reset constraints on all drag and drop objs
19200 * @method _onResize
19204 _onResize: function(e) {
19205 this._execOnAll("resetConstraints", []);
19209 * Lock all drag and drop functionality
19213 lock: function() { this.locked = true; },
19216 * Unlock all drag and drop functionality
19220 unlock: function() { this.locked = false; },
19223 * Is drag and drop locked?
19225 * @return {boolean} True if drag and drop is locked, false otherwise.
19228 isLocked: function() { return this.locked; },
19231 * Location cache that is set for all drag drop objects when a drag is
19232 * initiated, cleared when the drag is finished.
19233 * @property locationCache
19240 * Set useCache to false if you want to force object the lookup of each
19241 * drag and drop linked element constantly during a drag.
19242 * @property useCache
19249 * The number of pixels that the mouse needs to move after the
19250 * mousedown before the drag is initiated. Default=3;
19251 * @property clickPixelThresh
19255 clickPixelThresh: 3,
19258 * The number of milliseconds after the mousedown event to initiate the
19259 * drag if we don't get a mouseup event. Default=1000
19260 * @property clickTimeThresh
19264 clickTimeThresh: 350,
19267 * Flag that indicates that either the drag pixel threshold or the
19268 * mousdown time threshold has been met
19269 * @property dragThreshMet
19274 dragThreshMet: false,
19277 * Timeout used for the click time threshold
19278 * @property clickTimeout
19283 clickTimeout: null,
19286 * The X position of the mousedown event stored for later use when a
19287 * drag threshold is met.
19296 * The Y position of the mousedown event stored for later use when a
19297 * drag threshold is met.
19306 * Each DragDrop instance must be registered with the DragDropMgr.
19307 * This is executed in DragDrop.init()
19308 * @method regDragDrop
19309 * @param {DragDrop} oDD the DragDrop object to register
19310 * @param {String} sGroup the name of the group this element belongs to
19313 regDragDrop: function(oDD, sGroup) {
19314 if (!this.initialized) { this.init(); }
19316 if (!this.ids[sGroup]) {
19317 this.ids[sGroup] = {};
19319 this.ids[sGroup][oDD.id] = oDD;
19323 * Removes the supplied dd instance from the supplied group. Executed
19324 * by DragDrop.removeFromGroup, so don't call this function directly.
19325 * @method removeDDFromGroup
19329 removeDDFromGroup: function(oDD, sGroup) {
19330 if (!this.ids[sGroup]) {
19331 this.ids[sGroup] = {};
19334 var obj = this.ids[sGroup];
19335 if (obj && obj[oDD.id]) {
19336 delete obj[oDD.id];
19341 * Unregisters a drag and drop item. This is executed in
19342 * DragDrop.unreg, use that method instead of calling this directly.
19347 _remove: function(oDD) {
19348 for (var g in oDD.groups) {
19349 if (g && this.ids[g][oDD.id]) {
19350 delete this.ids[g][oDD.id];
19353 delete this.handleIds[oDD.id];
19357 * Each DragDrop handle element must be registered. This is done
19358 * automatically when executing DragDrop.setHandleElId()
19359 * @method regHandle
19360 * @param {String} sDDId the DragDrop id this element is a handle for
19361 * @param {String} sHandleId the id of the element that is the drag
19365 regHandle: function(sDDId, sHandleId) {
19366 if (!this.handleIds[sDDId]) {
19367 this.handleIds[sDDId] = {};
19369 this.handleIds[sDDId][sHandleId] = sHandleId;
19373 * Utility function to determine if a given element has been
19374 * registered as a drag drop item.
19375 * @method isDragDrop
19376 * @param {String} id the element id to check
19377 * @return {boolean} true if this element is a DragDrop item,
19381 isDragDrop: function(id) {
19382 return ( this.getDDById(id) ) ? true : false;
19386 * Returns the drag and drop instances that are in all groups the
19387 * passed in instance belongs to.
19388 * @method getRelated
19389 * @param {DragDrop} p_oDD the obj to get related data for
19390 * @param {boolean} bTargetsOnly if true, only return targetable objs
19391 * @return {DragDrop[]} the related instances
19394 getRelated: function(p_oDD, bTargetsOnly) {
19396 for (var i in p_oDD.groups) {
19397 for (j in this.ids[i]) {
19398 var dd = this.ids[i][j];
19399 if (! this.isTypeOfDD(dd)) {
19402 if (!bTargetsOnly || dd.isTarget) {
19403 oDDs[oDDs.length] = dd;
19412 * Returns true if the specified dd target is a legal target for
19413 * the specifice drag obj
19414 * @method isLegalTarget
19415 * @param {DragDrop} the drag obj
19416 * @param {DragDrop} the target
19417 * @return {boolean} true if the target is a legal target for the
19421 isLegalTarget: function (oDD, oTargetDD) {
19422 var targets = this.getRelated(oDD, true);
19423 for (var i=0, len=targets.length;i<len;++i) {
19424 if (targets[i].id == oTargetDD.id) {
19433 * My goal is to be able to transparently determine if an object is
19434 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19435 * returns "object", oDD.constructor.toString() always returns
19436 * "DragDrop" and not the name of the subclass. So for now it just
19437 * evaluates a well-known variable in DragDrop.
19438 * @method isTypeOfDD
19439 * @param {Object} the object to evaluate
19440 * @return {boolean} true if typeof oDD = DragDrop
19443 isTypeOfDD: function (oDD) {
19444 return (oDD && oDD.__ygDragDrop);
19448 * Utility function to determine if a given element has been
19449 * registered as a drag drop handle for the given Drag Drop object.
19451 * @param {String} id the element id to check
19452 * @return {boolean} true if this element is a DragDrop handle, false
19456 isHandle: function(sDDId, sHandleId) {
19457 return ( this.handleIds[sDDId] &&
19458 this.handleIds[sDDId][sHandleId] );
19462 * Returns the DragDrop instance for a given id
19463 * @method getDDById
19464 * @param {String} id the id of the DragDrop object
19465 * @return {DragDrop} the drag drop object, null if it is not found
19468 getDDById: function(id) {
19469 for (var i in this.ids) {
19470 if (this.ids[i][id]) {
19471 return this.ids[i][id];
19478 * Fired after a registered DragDrop object gets the mousedown event.
19479 * Sets up the events required to track the object being dragged
19480 * @method handleMouseDown
19481 * @param {Event} e the event
19482 * @param oDD the DragDrop object being dragged
19486 handleMouseDown: function(e, oDD) {
19488 Roo.QuickTips.disable();
19490 this.currentTarget = e.getTarget();
19492 this.dragCurrent = oDD;
19494 var el = oDD.getEl();
19496 // track start position
19497 this.startX = e.getPageX();
19498 this.startY = e.getPageY();
19500 this.deltaX = this.startX - el.offsetLeft;
19501 this.deltaY = this.startY - el.offsetTop;
19503 this.dragThreshMet = false;
19505 this.clickTimeout = setTimeout(
19507 var DDM = Roo.dd.DDM;
19508 DDM.startDrag(DDM.startX, DDM.startY);
19510 this.clickTimeThresh );
19514 * Fired when either the drag pixel threshol or the mousedown hold
19515 * time threshold has been met.
19516 * @method startDrag
19517 * @param x {int} the X position of the original mousedown
19518 * @param y {int} the Y position of the original mousedown
19521 startDrag: function(x, y) {
19522 clearTimeout(this.clickTimeout);
19523 if (this.dragCurrent) {
19524 this.dragCurrent.b4StartDrag(x, y);
19525 this.dragCurrent.startDrag(x, y);
19527 this.dragThreshMet = true;
19531 * Internal function to handle the mouseup event. Will be invoked
19532 * from the context of the document.
19533 * @method handleMouseUp
19534 * @param {Event} e the event
19538 handleMouseUp: function(e) {
19541 Roo.QuickTips.enable();
19543 if (! this.dragCurrent) {
19547 clearTimeout(this.clickTimeout);
19549 if (this.dragThreshMet) {
19550 this.fireEvents(e, true);
19560 * Utility to stop event propagation and event default, if these
19561 * features are turned on.
19562 * @method stopEvent
19563 * @param {Event} e the event as returned by this.getEvent()
19566 stopEvent: function(e){
19567 if(this.stopPropagation) {
19568 e.stopPropagation();
19571 if (this.preventDefault) {
19572 e.preventDefault();
19577 * Internal function to clean up event handlers after the drag
19578 * operation is complete
19580 * @param {Event} e the event
19584 stopDrag: function(e) {
19585 // Fire the drag end event for the item that was dragged
19586 if (this.dragCurrent) {
19587 if (this.dragThreshMet) {
19588 this.dragCurrent.b4EndDrag(e);
19589 this.dragCurrent.endDrag(e);
19592 this.dragCurrent.onMouseUp(e);
19595 this.dragCurrent = null;
19596 this.dragOvers = {};
19600 * Internal function to handle the mousemove event. Will be invoked
19601 * from the context of the html element.
19603 * @TODO figure out what we can do about mouse events lost when the
19604 * user drags objects beyond the window boundary. Currently we can
19605 * detect this in internet explorer by verifying that the mouse is
19606 * down during the mousemove event. Firefox doesn't give us the
19607 * button state on the mousemove event.
19608 * @method handleMouseMove
19609 * @param {Event} e the event
19613 handleMouseMove: function(e) {
19614 if (! this.dragCurrent) {
19618 // var button = e.which || e.button;
19620 // check for IE mouseup outside of page boundary
19621 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19623 return this.handleMouseUp(e);
19626 if (!this.dragThreshMet) {
19627 var diffX = Math.abs(this.startX - e.getPageX());
19628 var diffY = Math.abs(this.startY - e.getPageY());
19629 if (diffX > this.clickPixelThresh ||
19630 diffY > this.clickPixelThresh) {
19631 this.startDrag(this.startX, this.startY);
19635 if (this.dragThreshMet) {
19636 this.dragCurrent.b4Drag(e);
19637 this.dragCurrent.onDrag(e);
19638 if(!this.dragCurrent.moveOnly){
19639 this.fireEvents(e, false);
19649 * Iterates over all of the DragDrop elements to find ones we are
19650 * hovering over or dropping on
19651 * @method fireEvents
19652 * @param {Event} e the event
19653 * @param {boolean} isDrop is this a drop op or a mouseover op?
19657 fireEvents: function(e, isDrop) {
19658 var dc = this.dragCurrent;
19660 // If the user did the mouse up outside of the window, we could
19661 // get here even though we have ended the drag.
19662 if (!dc || dc.isLocked()) {
19666 var pt = e.getPoint();
19668 // cache the previous dragOver array
19674 var enterEvts = [];
19676 // Check to see if the object(s) we were hovering over is no longer
19677 // being hovered over so we can fire the onDragOut event
19678 for (var i in this.dragOvers) {
19680 var ddo = this.dragOvers[i];
19682 if (! this.isTypeOfDD(ddo)) {
19686 if (! this.isOverTarget(pt, ddo, this.mode)) {
19687 outEvts.push( ddo );
19690 oldOvers[i] = true;
19691 delete this.dragOvers[i];
19694 for (var sGroup in dc.groups) {
19696 if ("string" != typeof sGroup) {
19700 for (i in this.ids[sGroup]) {
19701 var oDD = this.ids[sGroup][i];
19702 if (! this.isTypeOfDD(oDD)) {
19706 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19707 if (this.isOverTarget(pt, oDD, this.mode)) {
19708 // look for drop interactions
19710 dropEvts.push( oDD );
19711 // look for drag enter and drag over interactions
19714 // initial drag over: dragEnter fires
19715 if (!oldOvers[oDD.id]) {
19716 enterEvts.push( oDD );
19717 // subsequent drag overs: dragOver fires
19719 overEvts.push( oDD );
19722 this.dragOvers[oDD.id] = oDD;
19730 if (outEvts.length) {
19731 dc.b4DragOut(e, outEvts);
19732 dc.onDragOut(e, outEvts);
19735 if (enterEvts.length) {
19736 dc.onDragEnter(e, enterEvts);
19739 if (overEvts.length) {
19740 dc.b4DragOver(e, overEvts);
19741 dc.onDragOver(e, overEvts);
19744 if (dropEvts.length) {
19745 dc.b4DragDrop(e, dropEvts);
19746 dc.onDragDrop(e, dropEvts);
19750 // fire dragout events
19752 for (i=0, len=outEvts.length; i<len; ++i) {
19753 dc.b4DragOut(e, outEvts[i].id);
19754 dc.onDragOut(e, outEvts[i].id);
19757 // fire enter events
19758 for (i=0,len=enterEvts.length; i<len; ++i) {
19759 // dc.b4DragEnter(e, oDD.id);
19760 dc.onDragEnter(e, enterEvts[i].id);
19763 // fire over events
19764 for (i=0,len=overEvts.length; i<len; ++i) {
19765 dc.b4DragOver(e, overEvts[i].id);
19766 dc.onDragOver(e, overEvts[i].id);
19769 // fire drop events
19770 for (i=0, len=dropEvts.length; i<len; ++i) {
19771 dc.b4DragDrop(e, dropEvts[i].id);
19772 dc.onDragDrop(e, dropEvts[i].id);
19777 // notify about a drop that did not find a target
19778 if (isDrop && !dropEvts.length) {
19779 dc.onInvalidDrop(e);
19785 * Helper function for getting the best match from the list of drag
19786 * and drop objects returned by the drag and drop events when we are
19787 * in INTERSECT mode. It returns either the first object that the
19788 * cursor is over, or the object that has the greatest overlap with
19789 * the dragged element.
19790 * @method getBestMatch
19791 * @param {DragDrop[]} dds The array of drag and drop objects
19793 * @return {DragDrop} The best single match
19796 getBestMatch: function(dds) {
19798 // Return null if the input is not what we expect
19799 //if (!dds || !dds.length || dds.length == 0) {
19801 // If there is only one item, it wins
19802 //} else if (dds.length == 1) {
19804 var len = dds.length;
19809 // Loop through the targeted items
19810 for (var i=0; i<len; ++i) {
19812 // If the cursor is over the object, it wins. If the
19813 // cursor is over multiple matches, the first one we come
19815 if (dd.cursorIsOver) {
19818 // Otherwise the object with the most overlap wins
19821 winner.overlap.getArea() < dd.overlap.getArea()) {
19832 * Refreshes the cache of the top-left and bottom-right points of the
19833 * drag and drop objects in the specified group(s). This is in the
19834 * format that is stored in the drag and drop instance, so typical
19837 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19841 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19843 * @TODO this really should be an indexed array. Alternatively this
19844 * method could accept both.
19845 * @method refreshCache
19846 * @param {Object} groups an associative array of groups to refresh
19849 refreshCache: function(groups) {
19850 for (var sGroup in groups) {
19851 if ("string" != typeof sGroup) {
19854 for (var i in this.ids[sGroup]) {
19855 var oDD = this.ids[sGroup][i];
19857 if (this.isTypeOfDD(oDD)) {
19858 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19859 var loc = this.getLocation(oDD);
19861 this.locationCache[oDD.id] = loc;
19863 delete this.locationCache[oDD.id];
19864 // this will unregister the drag and drop object if
19865 // the element is not in a usable state
19874 * This checks to make sure an element exists and is in the DOM. The
19875 * main purpose is to handle cases where innerHTML is used to remove
19876 * drag and drop objects from the DOM. IE provides an 'unspecified
19877 * error' when trying to access the offsetParent of such an element
19879 * @param {HTMLElement} el the element to check
19880 * @return {boolean} true if the element looks usable
19883 verifyEl: function(el) {
19888 parent = el.offsetParent;
19891 parent = el.offsetParent;
19902 * Returns a Region object containing the drag and drop element's position
19903 * and size, including the padding configured for it
19904 * @method getLocation
19905 * @param {DragDrop} oDD the drag and drop object to get the
19907 * @return {Roo.lib.Region} a Region object representing the total area
19908 * the element occupies, including any padding
19909 * the instance is configured for.
19912 getLocation: function(oDD) {
19913 if (! this.isTypeOfDD(oDD)) {
19917 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
19920 pos= Roo.lib.Dom.getXY(el);
19928 x2 = x1 + el.offsetWidth;
19930 y2 = y1 + el.offsetHeight;
19932 t = y1 - oDD.padding[0];
19933 r = x2 + oDD.padding[1];
19934 b = y2 + oDD.padding[2];
19935 l = x1 - oDD.padding[3];
19937 return new Roo.lib.Region( t, r, b, l );
19941 * Checks the cursor location to see if it over the target
19942 * @method isOverTarget
19943 * @param {Roo.lib.Point} pt The point to evaluate
19944 * @param {DragDrop} oTarget the DragDrop object we are inspecting
19945 * @return {boolean} true if the mouse is over the target
19949 isOverTarget: function(pt, oTarget, intersect) {
19950 // use cache if available
19951 var loc = this.locationCache[oTarget.id];
19952 if (!loc || !this.useCache) {
19953 loc = this.getLocation(oTarget);
19954 this.locationCache[oTarget.id] = loc;
19962 oTarget.cursorIsOver = loc.contains( pt );
19964 // DragDrop is using this as a sanity check for the initial mousedown
19965 // in this case we are done. In POINT mode, if the drag obj has no
19966 // contraints, we are also done. Otherwise we need to evaluate the
19967 // location of the target as related to the actual location of the
19968 // dragged element.
19969 var dc = this.dragCurrent;
19970 if (!dc || !dc.getTargetCoord ||
19971 (!intersect && !dc.constrainX && !dc.constrainY)) {
19972 return oTarget.cursorIsOver;
19975 oTarget.overlap = null;
19977 // Get the current location of the drag element, this is the
19978 // location of the mouse event less the delta that represents
19979 // where the original mousedown happened on the element. We
19980 // need to consider constraints and ticks as well.
19981 var pos = dc.getTargetCoord(pt.x, pt.y);
19983 var el = dc.getDragEl();
19984 var curRegion = new Roo.lib.Region( pos.y,
19985 pos.x + el.offsetWidth,
19986 pos.y + el.offsetHeight,
19989 var overlap = curRegion.intersect(loc);
19992 oTarget.overlap = overlap;
19993 return (intersect) ? true : oTarget.cursorIsOver;
20000 * unload event handler
20001 * @method _onUnload
20005 _onUnload: function(e, me) {
20006 Roo.dd.DragDropMgr.unregAll();
20010 * Cleans up the drag and drop events and objects.
20015 unregAll: function() {
20017 if (this.dragCurrent) {
20019 this.dragCurrent = null;
20022 this._execOnAll("unreg", []);
20024 for (i in this.elementCache) {
20025 delete this.elementCache[i];
20028 this.elementCache = {};
20033 * A cache of DOM elements
20034 * @property elementCache
20041 * Get the wrapper for the DOM element specified
20042 * @method getElWrapper
20043 * @param {String} id the id of the element to get
20044 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20046 * @deprecated This wrapper isn't that useful
20049 getElWrapper: function(id) {
20050 var oWrapper = this.elementCache[id];
20051 if (!oWrapper || !oWrapper.el) {
20052 oWrapper = this.elementCache[id] =
20053 new this.ElementWrapper(Roo.getDom(id));
20059 * Returns the actual DOM element
20060 * @method getElement
20061 * @param {String} id the id of the elment to get
20062 * @return {Object} The element
20063 * @deprecated use Roo.getDom instead
20066 getElement: function(id) {
20067 return Roo.getDom(id);
20071 * Returns the style property for the DOM element (i.e.,
20072 * document.getElById(id).style)
20074 * @param {String} id the id of the elment to get
20075 * @return {Object} The style property of the element
20076 * @deprecated use Roo.getDom instead
20079 getCss: function(id) {
20080 var el = Roo.getDom(id);
20081 return (el) ? el.style : null;
20085 * Inner class for cached elements
20086 * @class DragDropMgr.ElementWrapper
20091 ElementWrapper: function(el) {
20096 this.el = el || null;
20101 this.id = this.el && el.id;
20103 * A reference to the style property
20106 this.css = this.el && el.style;
20110 * Returns the X position of an html element
20112 * @param el the element for which to get the position
20113 * @return {int} the X coordinate
20115 * @deprecated use Roo.lib.Dom.getX instead
20118 getPosX: function(el) {
20119 return Roo.lib.Dom.getX(el);
20123 * Returns the Y position of an html element
20125 * @param el the element for which to get the position
20126 * @return {int} the Y coordinate
20127 * @deprecated use Roo.lib.Dom.getY instead
20130 getPosY: function(el) {
20131 return Roo.lib.Dom.getY(el);
20135 * Swap two nodes. In IE, we use the native method, for others we
20136 * emulate the IE behavior
20138 * @param n1 the first node to swap
20139 * @param n2 the other node to swap
20142 swapNode: function(n1, n2) {
20146 var p = n2.parentNode;
20147 var s = n2.nextSibling;
20150 p.insertBefore(n1, n2);
20151 } else if (n2 == n1.nextSibling) {
20152 p.insertBefore(n2, n1);
20154 n1.parentNode.replaceChild(n2, n1);
20155 p.insertBefore(n1, s);
20161 * Returns the current scroll position
20162 * @method getScroll
20166 getScroll: function () {
20167 var t, l, dde=document.documentElement, db=document.body;
20168 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20170 l = dde.scrollLeft;
20177 return { top: t, left: l };
20181 * Returns the specified element style property
20183 * @param {HTMLElement} el the element
20184 * @param {string} styleProp the style property
20185 * @return {string} The value of the style property
20186 * @deprecated use Roo.lib.Dom.getStyle
20189 getStyle: function(el, styleProp) {
20190 return Roo.fly(el).getStyle(styleProp);
20194 * Gets the scrollTop
20195 * @method getScrollTop
20196 * @return {int} the document's scrollTop
20199 getScrollTop: function () { return this.getScroll().top; },
20202 * Gets the scrollLeft
20203 * @method getScrollLeft
20204 * @return {int} the document's scrollTop
20207 getScrollLeft: function () { return this.getScroll().left; },
20210 * Sets the x/y position of an element to the location of the
20213 * @param {HTMLElement} moveEl The element to move
20214 * @param {HTMLElement} targetEl The position reference element
20217 moveToEl: function (moveEl, targetEl) {
20218 var aCoord = Roo.lib.Dom.getXY(targetEl);
20219 Roo.lib.Dom.setXY(moveEl, aCoord);
20223 * Numeric array sort function
20224 * @method numericSort
20227 numericSort: function(a, b) { return (a - b); },
20231 * @property _timeoutCount
20238 * Trying to make the load order less important. Without this we get
20239 * an error if this file is loaded before the Event Utility.
20240 * @method _addListeners
20244 _addListeners: function() {
20245 var DDM = Roo.dd.DDM;
20246 if ( Roo.lib.Event && document ) {
20249 if (DDM._timeoutCount > 2000) {
20251 setTimeout(DDM._addListeners, 10);
20252 if (document && document.body) {
20253 DDM._timeoutCount += 1;
20260 * Recursively searches the immediate parent and all child nodes for
20261 * the handle element in order to determine wheter or not it was
20263 * @method handleWasClicked
20264 * @param node the html element to inspect
20267 handleWasClicked: function(node, id) {
20268 if (this.isHandle(id, node.id)) {
20271 // check to see if this is a text node child of the one we want
20272 var p = node.parentNode;
20275 if (this.isHandle(id, p.id)) {
20290 // shorter alias, save a few bytes
20291 Roo.dd.DDM = Roo.dd.DragDropMgr;
20292 Roo.dd.DDM._addListeners();
20296 * Ext JS Library 1.1.1
20297 * Copyright(c) 2006-2007, Ext JS, LLC.
20299 * Originally Released Under LGPL - original licence link has changed is not relivant.
20302 * <script type="text/javascript">
20307 * A DragDrop implementation where the linked element follows the
20308 * mouse cursor during a drag.
20309 * @extends Roo.dd.DragDrop
20311 * @param {String} id the id of the linked element
20312 * @param {String} sGroup the group of related DragDrop items
20313 * @param {object} config an object containing configurable attributes
20314 * Valid properties for DD:
20317 Roo.dd.DD = function(id, sGroup, config) {
20319 this.init(id, sGroup, config);
20323 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20326 * When set to true, the utility automatically tries to scroll the browser
20327 * window wehn a drag and drop element is dragged near the viewport boundary.
20328 * Defaults to true.
20335 * Sets the pointer offset to the distance between the linked element's top
20336 * left corner and the location the element was clicked
20337 * @method autoOffset
20338 * @param {int} iPageX the X coordinate of the click
20339 * @param {int} iPageY the Y coordinate of the click
20341 autoOffset: function(iPageX, iPageY) {
20342 var x = iPageX - this.startPageX;
20343 var y = iPageY - this.startPageY;
20344 this.setDelta(x, y);
20348 * Sets the pointer offset. You can call this directly to force the
20349 * offset to be in a particular location (e.g., pass in 0,0 to set it
20350 * to the center of the object)
20352 * @param {int} iDeltaX the distance from the left
20353 * @param {int} iDeltaY the distance from the top
20355 setDelta: function(iDeltaX, iDeltaY) {
20356 this.deltaX = iDeltaX;
20357 this.deltaY = iDeltaY;
20361 * Sets the drag element to the location of the mousedown or click event,
20362 * maintaining the cursor location relative to the location on the element
20363 * that was clicked. Override this if you want to place the element in a
20364 * location other than where the cursor is.
20365 * @method setDragElPos
20366 * @param {int} iPageX the X coordinate of the mousedown or drag event
20367 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20369 setDragElPos: function(iPageX, iPageY) {
20370 // the first time we do this, we are going to check to make sure
20371 // the element has css positioning
20373 var el = this.getDragEl();
20374 this.alignElWithMouse(el, iPageX, iPageY);
20378 * Sets the element to the location of the mousedown or click event,
20379 * maintaining the cursor location relative to the location on the element
20380 * that was clicked. Override this if you want to place the element in a
20381 * location other than where the cursor is.
20382 * @method alignElWithMouse
20383 * @param {HTMLElement} el the element to move
20384 * @param {int} iPageX the X coordinate of the mousedown or drag event
20385 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20387 alignElWithMouse: function(el, iPageX, iPageY) {
20388 var oCoord = this.getTargetCoord(iPageX, iPageY);
20389 var fly = el.dom ? el : Roo.fly(el);
20390 if (!this.deltaSetXY) {
20391 var aCoord = [oCoord.x, oCoord.y];
20393 var newLeft = fly.getLeft(true);
20394 var newTop = fly.getTop(true);
20395 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20397 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20400 this.cachePosition(oCoord.x, oCoord.y);
20401 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20406 * Saves the most recent position so that we can reset the constraints and
20407 * tick marks on-demand. We need to know this so that we can calculate the
20408 * number of pixels the element is offset from its original position.
20409 * @method cachePosition
20410 * @param iPageX the current x position (optional, this just makes it so we
20411 * don't have to look it up again)
20412 * @param iPageY the current y position (optional, this just makes it so we
20413 * don't have to look it up again)
20415 cachePosition: function(iPageX, iPageY) {
20417 this.lastPageX = iPageX;
20418 this.lastPageY = iPageY;
20420 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20421 this.lastPageX = aCoord[0];
20422 this.lastPageY = aCoord[1];
20427 * Auto-scroll the window if the dragged object has been moved beyond the
20428 * visible window boundary.
20429 * @method autoScroll
20430 * @param {int} x the drag element's x position
20431 * @param {int} y the drag element's y position
20432 * @param {int} h the height of the drag element
20433 * @param {int} w the width of the drag element
20436 autoScroll: function(x, y, h, w) {
20439 // The client height
20440 var clientH = Roo.lib.Dom.getViewWidth();
20442 // The client width
20443 var clientW = Roo.lib.Dom.getViewHeight();
20445 // The amt scrolled down
20446 var st = this.DDM.getScrollTop();
20448 // The amt scrolled right
20449 var sl = this.DDM.getScrollLeft();
20451 // Location of the bottom of the element
20454 // Location of the right of the element
20457 // The distance from the cursor to the bottom of the visible area,
20458 // adjusted so that we don't scroll if the cursor is beyond the
20459 // element drag constraints
20460 var toBot = (clientH + st - y - this.deltaY);
20462 // The distance from the cursor to the right of the visible area
20463 var toRight = (clientW + sl - x - this.deltaX);
20466 // How close to the edge the cursor must be before we scroll
20467 // var thresh = (document.all) ? 100 : 40;
20470 // How many pixels to scroll per autoscroll op. This helps to reduce
20471 // clunky scrolling. IE is more sensitive about this ... it needs this
20472 // value to be higher.
20473 var scrAmt = (document.all) ? 80 : 30;
20475 // Scroll down if we are near the bottom of the visible page and the
20476 // obj extends below the crease
20477 if ( bot > clientH && toBot < thresh ) {
20478 window.scrollTo(sl, st + scrAmt);
20481 // Scroll up if the window is scrolled down and the top of the object
20482 // goes above the top border
20483 if ( y < st && st > 0 && y - st < thresh ) {
20484 window.scrollTo(sl, st - scrAmt);
20487 // Scroll right if the obj is beyond the right border and the cursor is
20488 // near the border.
20489 if ( right > clientW && toRight < thresh ) {
20490 window.scrollTo(sl + scrAmt, st);
20493 // Scroll left if the window has been scrolled to the right and the obj
20494 // extends past the left border
20495 if ( x < sl && sl > 0 && x - sl < thresh ) {
20496 window.scrollTo(sl - scrAmt, st);
20502 * Finds the location the element should be placed if we want to move
20503 * it to where the mouse location less the click offset would place us.
20504 * @method getTargetCoord
20505 * @param {int} iPageX the X coordinate of the click
20506 * @param {int} iPageY the Y coordinate of the click
20507 * @return an object that contains the coordinates (Object.x and Object.y)
20510 getTargetCoord: function(iPageX, iPageY) {
20513 var x = iPageX - this.deltaX;
20514 var y = iPageY - this.deltaY;
20516 if (this.constrainX) {
20517 if (x < this.minX) { x = this.minX; }
20518 if (x > this.maxX) { x = this.maxX; }
20521 if (this.constrainY) {
20522 if (y < this.minY) { y = this.minY; }
20523 if (y > this.maxY) { y = this.maxY; }
20526 x = this.getTick(x, this.xTicks);
20527 y = this.getTick(y, this.yTicks);
20534 * Sets up config options specific to this class. Overrides
20535 * Roo.dd.DragDrop, but all versions of this method through the
20536 * inheritance chain are called
20538 applyConfig: function() {
20539 Roo.dd.DD.superclass.applyConfig.call(this);
20540 this.scroll = (this.config.scroll !== false);
20544 * Event that fires prior to the onMouseDown event. Overrides
20547 b4MouseDown: function(e) {
20548 // this.resetConstraints();
20549 this.autoOffset(e.getPageX(),
20554 * Event that fires prior to the onDrag event. Overrides
20557 b4Drag: function(e) {
20558 this.setDragElPos(e.getPageX(),
20562 toString: function() {
20563 return ("DD " + this.id);
20566 //////////////////////////////////////////////////////////////////////////
20567 // Debugging ygDragDrop events that can be overridden
20568 //////////////////////////////////////////////////////////////////////////
20570 startDrag: function(x, y) {
20573 onDrag: function(e) {
20576 onDragEnter: function(e, id) {
20579 onDragOver: function(e, id) {
20582 onDragOut: function(e, id) {
20585 onDragDrop: function(e, id) {
20588 endDrag: function(e) {
20595 * Ext JS Library 1.1.1
20596 * Copyright(c) 2006-2007, Ext JS, LLC.
20598 * Originally Released Under LGPL - original licence link has changed is not relivant.
20601 * <script type="text/javascript">
20605 * @class Roo.dd.DDProxy
20606 * A DragDrop implementation that inserts an empty, bordered div into
20607 * the document that follows the cursor during drag operations. At the time of
20608 * the click, the frame div is resized to the dimensions of the linked html
20609 * element, and moved to the exact location of the linked element.
20611 * References to the "frame" element refer to the single proxy element that
20612 * was created to be dragged in place of all DDProxy elements on the
20615 * @extends Roo.dd.DD
20617 * @param {String} id the id of the linked html element
20618 * @param {String} sGroup the group of related DragDrop objects
20619 * @param {object} config an object containing configurable attributes
20620 * Valid properties for DDProxy in addition to those in DragDrop:
20621 * resizeFrame, centerFrame, dragElId
20623 Roo.dd.DDProxy = function(id, sGroup, config) {
20625 this.init(id, sGroup, config);
20631 * The default drag frame div id
20632 * @property Roo.dd.DDProxy.dragElId
20636 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20638 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20641 * By default we resize the drag frame to be the same size as the element
20642 * we want to drag (this is to get the frame effect). We can turn it off
20643 * if we want a different behavior.
20644 * @property resizeFrame
20650 * By default the frame is positioned exactly where the drag element is, so
20651 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20652 * you do not have constraints on the obj is to have the drag frame centered
20653 * around the cursor. Set centerFrame to true for this effect.
20654 * @property centerFrame
20657 centerFrame: false,
20660 * Creates the proxy element if it does not yet exist
20661 * @method createFrame
20663 createFrame: function() {
20665 var body = document.body;
20667 if (!body || !body.firstChild) {
20668 setTimeout( function() { self.createFrame(); }, 50 );
20672 var div = this.getDragEl();
20675 div = document.createElement("div");
20676 div.id = this.dragElId;
20679 s.position = "absolute";
20680 s.visibility = "hidden";
20682 s.border = "2px solid #aaa";
20685 // appendChild can blow up IE if invoked prior to the window load event
20686 // while rendering a table. It is possible there are other scenarios
20687 // that would cause this to happen as well.
20688 body.insertBefore(div, body.firstChild);
20693 * Initialization for the drag frame element. Must be called in the
20694 * constructor of all subclasses
20695 * @method initFrame
20697 initFrame: function() {
20698 this.createFrame();
20701 applyConfig: function() {
20702 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20704 this.resizeFrame = (this.config.resizeFrame !== false);
20705 this.centerFrame = (this.config.centerFrame);
20706 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20710 * Resizes the drag frame to the dimensions of the clicked object, positions
20711 * it over the object, and finally displays it
20712 * @method showFrame
20713 * @param {int} iPageX X click position
20714 * @param {int} iPageY Y click position
20717 showFrame: function(iPageX, iPageY) {
20718 var el = this.getEl();
20719 var dragEl = this.getDragEl();
20720 var s = dragEl.style;
20722 this._resizeProxy();
20724 if (this.centerFrame) {
20725 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20726 Math.round(parseInt(s.height, 10)/2) );
20729 this.setDragElPos(iPageX, iPageY);
20731 Roo.fly(dragEl).show();
20735 * The proxy is automatically resized to the dimensions of the linked
20736 * element when a drag is initiated, unless resizeFrame is set to false
20737 * @method _resizeProxy
20740 _resizeProxy: function() {
20741 if (this.resizeFrame) {
20742 var el = this.getEl();
20743 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20747 // overrides Roo.dd.DragDrop
20748 b4MouseDown: function(e) {
20749 var x = e.getPageX();
20750 var y = e.getPageY();
20751 this.autoOffset(x, y);
20752 this.setDragElPos(x, y);
20755 // overrides Roo.dd.DragDrop
20756 b4StartDrag: function(x, y) {
20757 // show the drag frame
20758 this.showFrame(x, y);
20761 // overrides Roo.dd.DragDrop
20762 b4EndDrag: function(e) {
20763 Roo.fly(this.getDragEl()).hide();
20766 // overrides Roo.dd.DragDrop
20767 // By default we try to move the element to the last location of the frame.
20768 // This is so that the default behavior mirrors that of Roo.dd.DD.
20769 endDrag: function(e) {
20771 var lel = this.getEl();
20772 var del = this.getDragEl();
20774 // Show the drag frame briefly so we can get its position
20775 del.style.visibility = "";
20778 // Hide the linked element before the move to get around a Safari
20780 lel.style.visibility = "hidden";
20781 Roo.dd.DDM.moveToEl(lel, del);
20782 del.style.visibility = "hidden";
20783 lel.style.visibility = "";
20788 beforeMove : function(){
20792 afterDrag : function(){
20796 toString: function() {
20797 return ("DDProxy " + this.id);
20803 * Ext JS Library 1.1.1
20804 * Copyright(c) 2006-2007, Ext JS, LLC.
20806 * Originally Released Under LGPL - original licence link has changed is not relivant.
20809 * <script type="text/javascript">
20813 * @class Roo.dd.DDTarget
20814 * A DragDrop implementation that does not move, but can be a drop
20815 * target. You would get the same result by simply omitting implementation
20816 * for the event callbacks, but this way we reduce the processing cost of the
20817 * event listener and the callbacks.
20818 * @extends Roo.dd.DragDrop
20820 * @param {String} id the id of the element that is a drop target
20821 * @param {String} sGroup the group of related DragDrop objects
20822 * @param {object} config an object containing configurable attributes
20823 * Valid properties for DDTarget in addition to those in
20827 Roo.dd.DDTarget = function(id, sGroup, config) {
20829 this.initTarget(id, sGroup, config);
20831 if (config.listeners || config.events) {
20832 Roo.dd.DragDrop.superclass.constructor.call(this, {
20833 listeners : config.listeners || {},
20834 events : config.events || {}
20839 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20840 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20841 toString: function() {
20842 return ("DDTarget " + this.id);
20847 * Ext JS Library 1.1.1
20848 * Copyright(c) 2006-2007, Ext JS, LLC.
20850 * Originally Released Under LGPL - original licence link has changed is not relivant.
20853 * <script type="text/javascript">
20858 * @class Roo.dd.ScrollManager
20859 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20860 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
20863 Roo.dd.ScrollManager = function(){
20864 var ddm = Roo.dd.DragDropMgr;
20871 var onStop = function(e){
20876 var triggerRefresh = function(){
20877 if(ddm.dragCurrent){
20878 ddm.refreshCache(ddm.dragCurrent.groups);
20882 var doScroll = function(){
20883 if(ddm.dragCurrent){
20884 var dds = Roo.dd.ScrollManager;
20886 if(proc.el.scroll(proc.dir, dds.increment)){
20890 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
20895 var clearProc = function(){
20897 clearInterval(proc.id);
20904 var startProc = function(el, dir){
20905 Roo.log('scroll startproc');
20909 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
20912 var onFire = function(e, isDrop){
20914 if(isDrop || !ddm.dragCurrent){ return; }
20915 var dds = Roo.dd.ScrollManager;
20916 if(!dragEl || dragEl != ddm.dragCurrent){
20917 dragEl = ddm.dragCurrent;
20918 // refresh regions on drag start
20919 dds.refreshCache();
20922 var xy = Roo.lib.Event.getXY(e);
20923 var pt = new Roo.lib.Point(xy[0], xy[1]);
20924 for(var id in els){
20925 var el = els[id], r = el._region;
20926 if(r && r.contains(pt) && el.isScrollable()){
20927 if(r.bottom - pt.y <= dds.thresh){
20929 startProc(el, "down");
20932 }else if(r.right - pt.x <= dds.thresh){
20934 startProc(el, "left");
20937 }else if(pt.y - r.top <= dds.thresh){
20939 startProc(el, "up");
20942 }else if(pt.x - r.left <= dds.thresh){
20944 startProc(el, "right");
20953 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
20954 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
20958 * Registers new overflow element(s) to auto scroll
20959 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
20961 register : function(el){
20962 if(el instanceof Array){
20963 for(var i = 0, len = el.length; i < len; i++) {
20964 this.register(el[i]);
20970 Roo.dd.ScrollManager.els = els;
20974 * Unregisters overflow element(s) so they are no longer scrolled
20975 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
20977 unregister : function(el){
20978 if(el instanceof Array){
20979 for(var i = 0, len = el.length; i < len; i++) {
20980 this.unregister(el[i]);
20989 * The number of pixels from the edge of a container the pointer needs to be to
20990 * trigger scrolling (defaults to 25)
20996 * The number of pixels to scroll in each scroll increment (defaults to 50)
21002 * The frequency of scrolls in milliseconds (defaults to 500)
21008 * True to animate the scroll (defaults to true)
21014 * The animation duration in seconds -
21015 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21021 * Manually trigger a cache refresh.
21023 refreshCache : function(){
21024 for(var id in els){
21025 if(typeof els[id] == 'object'){ // for people extending the object prototype
21026 els[id]._region = els[id].getRegion();
21033 * Ext JS Library 1.1.1
21034 * Copyright(c) 2006-2007, Ext JS, LLC.
21036 * Originally Released Under LGPL - original licence link has changed is not relivant.
21039 * <script type="text/javascript">
21044 * @class Roo.dd.Registry
21045 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21046 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21049 Roo.dd.Registry = function(){
21052 var autoIdSeed = 0;
21054 var getId = function(el, autogen){
21055 if(typeof el == "string"){
21059 if(!id && autogen !== false){
21060 id = "roodd-" + (++autoIdSeed);
21068 * Register a drag drop element
21069 * @param {String|HTMLElement} element The id or DOM node to register
21070 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21071 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21072 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21073 * populated in the data object (if applicable):
21075 Value Description<br />
21076 --------- ------------------------------------------<br />
21077 handles Array of DOM nodes that trigger dragging<br />
21078 for the element being registered<br />
21079 isHandle True if the element passed in triggers<br />
21080 dragging itself, else false
21083 register : function(el, data){
21085 if(typeof el == "string"){
21086 el = document.getElementById(el);
21089 elements[getId(el)] = data;
21090 if(data.isHandle !== false){
21091 handles[data.ddel.id] = data;
21094 var hs = data.handles;
21095 for(var i = 0, len = hs.length; i < len; i++){
21096 handles[getId(hs[i])] = data;
21102 * Unregister a drag drop element
21103 * @param {String|HTMLElement} element The id or DOM node to unregister
21105 unregister : function(el){
21106 var id = getId(el, false);
21107 var data = elements[id];
21109 delete elements[id];
21111 var hs = data.handles;
21112 for(var i = 0, len = hs.length; i < len; i++){
21113 delete handles[getId(hs[i], false)];
21120 * Returns the handle registered for a DOM Node by id
21121 * @param {String|HTMLElement} id The DOM node or id to look up
21122 * @return {Object} handle The custom handle data
21124 getHandle : function(id){
21125 if(typeof id != "string"){ // must be element?
21128 return handles[id];
21132 * Returns the handle that is registered for the DOM node that is the target of the event
21133 * @param {Event} e The event
21134 * @return {Object} handle The custom handle data
21136 getHandleFromEvent : function(e){
21137 var t = Roo.lib.Event.getTarget(e);
21138 return t ? handles[t.id] : null;
21142 * Returns a custom data object that is registered for a DOM node by id
21143 * @param {String|HTMLElement} id The DOM node or id to look up
21144 * @return {Object} data The custom data
21146 getTarget : function(id){
21147 if(typeof id != "string"){ // must be element?
21150 return elements[id];
21154 * Returns a custom data object that is registered for the DOM node that is the target of the event
21155 * @param {Event} e The event
21156 * @return {Object} data The custom data
21158 getTargetFromEvent : function(e){
21159 var t = Roo.lib.Event.getTarget(e);
21160 return t ? elements[t.id] || handles[t.id] : null;
21165 * Ext JS Library 1.1.1
21166 * Copyright(c) 2006-2007, Ext JS, LLC.
21168 * Originally Released Under LGPL - original licence link has changed is not relivant.
21171 * <script type="text/javascript">
21176 * @class Roo.dd.StatusProxy
21177 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21178 * default drag proxy used by all Roo.dd components.
21180 * @param {Object} config
21182 Roo.dd.StatusProxy = function(config){
21183 Roo.apply(this, config);
21184 this.id = this.id || Roo.id();
21185 this.el = new Roo.Layer({
21187 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21188 {tag: "div", cls: "x-dd-drop-icon"},
21189 {tag: "div", cls: "x-dd-drag-ghost"}
21192 shadow: !config || config.shadow !== false
21194 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21195 this.dropStatus = this.dropNotAllowed;
21198 Roo.dd.StatusProxy.prototype = {
21200 * @cfg {String} dropAllowed
21201 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21203 dropAllowed : "x-dd-drop-ok",
21205 * @cfg {String} dropNotAllowed
21206 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21208 dropNotAllowed : "x-dd-drop-nodrop",
21211 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21212 * over the current target element.
21213 * @param {String} cssClass The css class for the new drop status indicator image
21215 setStatus : function(cssClass){
21216 cssClass = cssClass || this.dropNotAllowed;
21217 if(this.dropStatus != cssClass){
21218 this.el.replaceClass(this.dropStatus, cssClass);
21219 this.dropStatus = cssClass;
21224 * Resets the status indicator to the default dropNotAllowed value
21225 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21227 reset : function(clearGhost){
21228 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21229 this.dropStatus = this.dropNotAllowed;
21231 this.ghost.update("");
21236 * Updates the contents of the ghost element
21237 * @param {String} html The html that will replace the current innerHTML of the ghost element
21239 update : function(html){
21240 if(typeof html == "string"){
21241 this.ghost.update(html);
21243 this.ghost.update("");
21244 html.style.margin = "0";
21245 this.ghost.dom.appendChild(html);
21247 // ensure float = none set?? cant remember why though.
21248 var el = this.ghost.dom.firstChild;
21250 Roo.fly(el).setStyle('float', 'none');
21255 * Returns the underlying proxy {@link Roo.Layer}
21256 * @return {Roo.Layer} el
21258 getEl : function(){
21263 * Returns the ghost element
21264 * @return {Roo.Element} el
21266 getGhost : function(){
21272 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21274 hide : function(clear){
21282 * Stops the repair animation if it's currently running
21285 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21291 * Displays this proxy
21298 * Force the Layer to sync its shadow and shim positions to the element
21305 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21306 * invalid drop operation by the item being dragged.
21307 * @param {Array} xy The XY position of the element ([x, y])
21308 * @param {Function} callback The function to call after the repair is complete
21309 * @param {Object} scope The scope in which to execute the callback
21311 repair : function(xy, callback, scope){
21312 this.callback = callback;
21313 this.scope = scope;
21314 if(xy && this.animRepair !== false){
21315 this.el.addClass("x-dd-drag-repair");
21316 this.el.hideUnders(true);
21317 this.anim = this.el.shift({
21318 duration: this.repairDuration || .5,
21322 callback: this.afterRepair,
21326 this.afterRepair();
21331 afterRepair : function(){
21333 if(typeof this.callback == "function"){
21334 this.callback.call(this.scope || this);
21336 this.callback = null;
21341 * Ext JS Library 1.1.1
21342 * Copyright(c) 2006-2007, Ext JS, LLC.
21344 * Originally Released Under LGPL - original licence link has changed is not relivant.
21347 * <script type="text/javascript">
21351 * @class Roo.dd.DragSource
21352 * @extends Roo.dd.DDProxy
21353 * A simple class that provides the basic implementation needed to make any element draggable.
21355 * @param {String/HTMLElement/Element} el The container element
21356 * @param {Object} config
21358 Roo.dd.DragSource = function(el, config){
21359 this.el = Roo.get(el);
21360 this.dragData = {};
21362 Roo.apply(this, config);
21365 this.proxy = new Roo.dd.StatusProxy();
21368 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21369 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21371 this.dragging = false;
21374 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21376 * @cfg {String} dropAllowed
21377 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21379 dropAllowed : "x-dd-drop-ok",
21381 * @cfg {String} dropNotAllowed
21382 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21384 dropNotAllowed : "x-dd-drop-nodrop",
21387 * Returns the data object associated with this drag source
21388 * @return {Object} data An object containing arbitrary data
21390 getDragData : function(e){
21391 return this.dragData;
21395 onDragEnter : function(e, id){
21396 var target = Roo.dd.DragDropMgr.getDDById(id);
21397 this.cachedTarget = target;
21398 if(this.beforeDragEnter(target, e, id) !== false){
21399 if(target.isNotifyTarget){
21400 var status = target.notifyEnter(this, e, this.dragData);
21401 this.proxy.setStatus(status);
21403 this.proxy.setStatus(this.dropAllowed);
21406 if(this.afterDragEnter){
21408 * An empty function by default, but provided so that you can perform a custom action
21409 * when the dragged item enters the drop target by providing an implementation.
21410 * @param {Roo.dd.DragDrop} target The drop target
21411 * @param {Event} e The event object
21412 * @param {String} id The id of the dragged element
21413 * @method afterDragEnter
21415 this.afterDragEnter(target, e, id);
21421 * An empty function by default, but provided so that you can perform a custom action
21422 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21423 * @param {Roo.dd.DragDrop} target The drop target
21424 * @param {Event} e The event object
21425 * @param {String} id The id of the dragged element
21426 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21428 beforeDragEnter : function(target, e, id){
21433 alignElWithMouse: function() {
21434 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21439 onDragOver : function(e, id){
21440 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21441 if(this.beforeDragOver(target, e, id) !== false){
21442 if(target.isNotifyTarget){
21443 var status = target.notifyOver(this, e, this.dragData);
21444 this.proxy.setStatus(status);
21447 if(this.afterDragOver){
21449 * An empty function by default, but provided so that you can perform a custom action
21450 * while the dragged item is over the drop target by providing an implementation.
21451 * @param {Roo.dd.DragDrop} target The drop target
21452 * @param {Event} e The event object
21453 * @param {String} id The id of the dragged element
21454 * @method afterDragOver
21456 this.afterDragOver(target, e, id);
21462 * An empty function by default, but provided so that you can perform a custom action
21463 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21464 * @param {Roo.dd.DragDrop} target The drop target
21465 * @param {Event} e The event object
21466 * @param {String} id The id of the dragged element
21467 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21469 beforeDragOver : function(target, e, id){
21474 onDragOut : function(e, id){
21475 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21476 if(this.beforeDragOut(target, e, id) !== false){
21477 if(target.isNotifyTarget){
21478 target.notifyOut(this, e, this.dragData);
21480 this.proxy.reset();
21481 if(this.afterDragOut){
21483 * An empty function by default, but provided so that you can perform a custom action
21484 * after the dragged item is dragged out of the target without dropping.
21485 * @param {Roo.dd.DragDrop} target The drop target
21486 * @param {Event} e The event object
21487 * @param {String} id The id of the dragged element
21488 * @method afterDragOut
21490 this.afterDragOut(target, e, id);
21493 this.cachedTarget = null;
21497 * An empty function by default, but provided so that you can perform a custom action before the dragged
21498 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21499 * @param {Roo.dd.DragDrop} target The drop target
21500 * @param {Event} e The event object
21501 * @param {String} id The id of the dragged element
21502 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21504 beforeDragOut : function(target, e, id){
21509 onDragDrop : function(e, id){
21510 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21511 if(this.beforeDragDrop(target, e, id) !== false){
21512 if(target.isNotifyTarget){
21513 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21514 this.onValidDrop(target, e, id);
21516 this.onInvalidDrop(target, e, id);
21519 this.onValidDrop(target, e, id);
21522 if(this.afterDragDrop){
21524 * An empty function by default, but provided so that you can perform a custom action
21525 * after a valid drag drop has occurred by providing an implementation.
21526 * @param {Roo.dd.DragDrop} target The drop target
21527 * @param {Event} e The event object
21528 * @param {String} id The id of the dropped element
21529 * @method afterDragDrop
21531 this.afterDragDrop(target, e, id);
21534 delete this.cachedTarget;
21538 * An empty function by default, but provided so that you can perform a custom action before the dragged
21539 * item is dropped onto the target and optionally cancel the onDragDrop.
21540 * @param {Roo.dd.DragDrop} target The drop target
21541 * @param {Event} e The event object
21542 * @param {String} id The id of the dragged element
21543 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21545 beforeDragDrop : function(target, e, id){
21550 onValidDrop : function(target, e, id){
21552 if(this.afterValidDrop){
21554 * An empty function by default, but provided so that you can perform a custom action
21555 * after a valid drop has occurred by providing an implementation.
21556 * @param {Object} target The target DD
21557 * @param {Event} e The event object
21558 * @param {String} id The id of the dropped element
21559 * @method afterInvalidDrop
21561 this.afterValidDrop(target, e, id);
21566 getRepairXY : function(e, data){
21567 return this.el.getXY();
21571 onInvalidDrop : function(target, e, id){
21572 this.beforeInvalidDrop(target, e, id);
21573 if(this.cachedTarget){
21574 if(this.cachedTarget.isNotifyTarget){
21575 this.cachedTarget.notifyOut(this, e, this.dragData);
21577 this.cacheTarget = null;
21579 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21581 if(this.afterInvalidDrop){
21583 * An empty function by default, but provided so that you can perform a custom action
21584 * after an invalid drop has occurred by providing an implementation.
21585 * @param {Event} e The event object
21586 * @param {String} id The id of the dropped element
21587 * @method afterInvalidDrop
21589 this.afterInvalidDrop(e, id);
21594 afterRepair : function(){
21596 this.el.highlight(this.hlColor || "c3daf9");
21598 this.dragging = false;
21602 * An empty function by default, but provided so that you can perform a custom action after an invalid
21603 * drop has occurred.
21604 * @param {Roo.dd.DragDrop} target The drop target
21605 * @param {Event} e The event object
21606 * @param {String} id The id of the dragged element
21607 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21609 beforeInvalidDrop : function(target, e, id){
21614 handleMouseDown : function(e){
21615 if(this.dragging) {
21618 var data = this.getDragData(e);
21619 if(data && this.onBeforeDrag(data, e) !== false){
21620 this.dragData = data;
21622 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21627 * An empty function by default, but provided so that you can perform a custom action before the initial
21628 * drag event begins and optionally cancel it.
21629 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21630 * @param {Event} e The event object
21631 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21633 onBeforeDrag : function(data, e){
21638 * An empty function by default, but provided so that you can perform a custom action once the initial
21639 * drag event has begun. The drag cannot be canceled from this function.
21640 * @param {Number} x The x position of the click on the dragged object
21641 * @param {Number} y The y position of the click on the dragged object
21643 onStartDrag : Roo.emptyFn,
21645 // private - YUI override
21646 startDrag : function(x, y){
21647 this.proxy.reset();
21648 this.dragging = true;
21649 this.proxy.update("");
21650 this.onInitDrag(x, y);
21655 onInitDrag : function(x, y){
21656 var clone = this.el.dom.cloneNode(true);
21657 clone.id = Roo.id(); // prevent duplicate ids
21658 this.proxy.update(clone);
21659 this.onStartDrag(x, y);
21664 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21665 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21667 getProxy : function(){
21672 * Hides the drag source's {@link Roo.dd.StatusProxy}
21674 hideProxy : function(){
21676 this.proxy.reset(true);
21677 this.dragging = false;
21681 triggerCacheRefresh : function(){
21682 Roo.dd.DDM.refreshCache(this.groups);
21685 // private - override to prevent hiding
21686 b4EndDrag: function(e) {
21689 // private - override to prevent moving
21690 endDrag : function(e){
21691 this.onEndDrag(this.dragData, e);
21695 onEndDrag : function(data, e){
21698 // private - pin to cursor
21699 autoOffset : function(x, y) {
21700 this.setDelta(-12, -20);
21704 * Ext JS Library 1.1.1
21705 * Copyright(c) 2006-2007, Ext JS, LLC.
21707 * Originally Released Under LGPL - original licence link has changed is not relivant.
21710 * <script type="text/javascript">
21715 * @class Roo.dd.DropTarget
21716 * @extends Roo.dd.DDTarget
21717 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21718 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21720 * @param {String/HTMLElement/Element} el The container element
21721 * @param {Object} config
21723 Roo.dd.DropTarget = function(el, config){
21724 this.el = Roo.get(el);
21726 var listeners = false; ;
21727 if (config && config.listeners) {
21728 listeners= config.listeners;
21729 delete config.listeners;
21731 Roo.apply(this, config);
21733 if(this.containerScroll){
21734 Roo.dd.ScrollManager.register(this.el);
21738 * @scope Roo.dd.DropTarget
21743 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21744 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21745 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21747 * IMPORTANT : it should set this.overClass and this.dropAllowed
21749 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21750 * @param {Event} e The event
21751 * @param {Object} data An object containing arbitrary data supplied by the drag source
21757 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21758 * This method will be called on every mouse movement while the drag source is over the drop target.
21759 * This default implementation simply returns the dropAllowed config value.
21761 * IMPORTANT : it should set this.dropAllowed
21763 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21764 * @param {Event} e The event
21765 * @param {Object} data An object containing arbitrary data supplied by the drag source
21771 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21772 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21773 * overClass (if any) from the drop element.
21775 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21776 * @param {Event} e The event
21777 * @param {Object} data An object containing arbitrary data supplied by the drag source
21783 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21784 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21785 * implementation that does something to process the drop event and returns true so that the drag source's
21786 * repair action does not run.
21788 * IMPORTANT : it should set this.success
21790 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21791 * @param {Event} e The event
21792 * @param {Object} data An object containing arbitrary data supplied by the drag source
21798 Roo.dd.DropTarget.superclass.constructor.call( this,
21800 this.ddGroup || this.group,
21803 listeners : listeners || {}
21811 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21813 * @cfg {String} overClass
21814 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21817 * @cfg {String} ddGroup
21818 * The drag drop group to handle drop events for
21822 * @cfg {String} dropAllowed
21823 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21825 dropAllowed : "x-dd-drop-ok",
21827 * @cfg {String} dropNotAllowed
21828 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21830 dropNotAllowed : "x-dd-drop-nodrop",
21832 * @cfg {boolean} success
21833 * set this after drop listener..
21837 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21838 * if the drop point is valid for over/enter..
21845 isNotifyTarget : true,
21850 notifyEnter : function(dd, e, data)
21853 this.fireEvent('enter', dd, e, data);
21854 if(this.overClass){
21855 this.el.addClass(this.overClass);
21857 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21858 this.valid ? this.dropAllowed : this.dropNotAllowed
21865 notifyOver : function(dd, e, data)
21868 this.fireEvent('over', dd, e, data);
21869 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21870 this.valid ? this.dropAllowed : this.dropNotAllowed
21877 notifyOut : function(dd, e, data)
21879 this.fireEvent('out', dd, e, data);
21880 if(this.overClass){
21881 this.el.removeClass(this.overClass);
21888 notifyDrop : function(dd, e, data)
21890 this.success = false;
21891 this.fireEvent('drop', dd, e, data);
21892 return this.success;
21896 * Ext JS Library 1.1.1
21897 * Copyright(c) 2006-2007, Ext JS, LLC.
21899 * Originally Released Under LGPL - original licence link has changed is not relivant.
21902 * <script type="text/javascript">
21907 * @class Roo.dd.DragZone
21908 * @extends Roo.dd.DragSource
21909 * This class provides a container DD instance that proxies for multiple child node sources.<br />
21910 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
21912 * @param {String/HTMLElement/Element} el The container element
21913 * @param {Object} config
21915 Roo.dd.DragZone = function(el, config){
21916 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
21917 if(this.containerScroll){
21918 Roo.dd.ScrollManager.register(this.el);
21922 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
21924 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
21925 * for auto scrolling during drag operations.
21928 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
21929 * method after a failed drop (defaults to "c3daf9" - light blue)
21933 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
21934 * for a valid target to drag based on the mouse down. Override this method
21935 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
21936 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
21937 * @param {EventObject} e The mouse down event
21938 * @return {Object} The dragData
21940 getDragData : function(e){
21941 return Roo.dd.Registry.getHandleFromEvent(e);
21945 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
21946 * this.dragData.ddel
21947 * @param {Number} x The x position of the click on the dragged object
21948 * @param {Number} y The y position of the click on the dragged object
21949 * @return {Boolean} true to continue the drag, false to cancel
21951 onInitDrag : function(x, y){
21952 this.proxy.update(this.dragData.ddel.cloneNode(true));
21953 this.onStartDrag(x, y);
21958 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
21960 afterRepair : function(){
21962 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
21964 this.dragging = false;
21968 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
21969 * the XY of this.dragData.ddel
21970 * @param {EventObject} e The mouse up event
21971 * @return {Array} The xy location (e.g. [100, 200])
21973 getRepairXY : function(e){
21974 return Roo.Element.fly(this.dragData.ddel).getXY();
21978 * Ext JS Library 1.1.1
21979 * Copyright(c) 2006-2007, Ext JS, LLC.
21981 * Originally Released Under LGPL - original licence link has changed is not relivant.
21984 * <script type="text/javascript">
21987 * @class Roo.dd.DropZone
21988 * @extends Roo.dd.DropTarget
21989 * This class provides a container DD instance that proxies for multiple child node targets.<br />
21990 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
21992 * @param {String/HTMLElement/Element} el The container element
21993 * @param {Object} config
21995 Roo.dd.DropZone = function(el, config){
21996 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
21999 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22001 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22002 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22003 * provide your own custom lookup.
22004 * @param {Event} e The event
22005 * @return {Object} data The custom data
22007 getTargetFromEvent : function(e){
22008 return Roo.dd.Registry.getTargetFromEvent(e);
22012 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22013 * that it has registered. This method has no default implementation and should be overridden to provide
22014 * node-specific processing if necessary.
22015 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22016 * {@link #getTargetFromEvent} for this node)
22017 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22018 * @param {Event} e The event
22019 * @param {Object} data An object containing arbitrary data supplied by the drag source
22021 onNodeEnter : function(n, dd, e, data){
22026 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22027 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22028 * overridden to provide the proper feedback.
22029 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22030 * {@link #getTargetFromEvent} for this node)
22031 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22032 * @param {Event} e The event
22033 * @param {Object} data An object containing arbitrary data supplied by the drag source
22034 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22035 * underlying {@link Roo.dd.StatusProxy} can be updated
22037 onNodeOver : function(n, dd, e, data){
22038 return this.dropAllowed;
22042 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22043 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22044 * node-specific processing if necessary.
22045 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22046 * {@link #getTargetFromEvent} for this node)
22047 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22048 * @param {Event} e The event
22049 * @param {Object} data An object containing arbitrary data supplied by the drag source
22051 onNodeOut : function(n, dd, e, data){
22056 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22057 * the drop node. The default implementation returns false, so it should be overridden to provide the
22058 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22059 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22060 * {@link #getTargetFromEvent} for this node)
22061 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22062 * @param {Event} e The event
22063 * @param {Object} data An object containing arbitrary data supplied by the drag source
22064 * @return {Boolean} True if the drop was valid, else false
22066 onNodeDrop : function(n, dd, e, data){
22071 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22072 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22073 * it should be overridden to provide the proper feedback if necessary.
22074 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22075 * @param {Event} e The event
22076 * @param {Object} data An object containing arbitrary data supplied by the drag source
22077 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22078 * underlying {@link Roo.dd.StatusProxy} can be updated
22080 onContainerOver : function(dd, e, data){
22081 return this.dropNotAllowed;
22085 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22086 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22087 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22088 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22089 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22090 * @param {Event} e The event
22091 * @param {Object} data An object containing arbitrary data supplied by the drag source
22092 * @return {Boolean} True if the drop was valid, else false
22094 onContainerDrop : function(dd, e, data){
22099 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22100 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22101 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22102 * you should override this method and provide a custom implementation.
22103 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22104 * @param {Event} e The event
22105 * @param {Object} data An object containing arbitrary data supplied by the drag source
22106 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22107 * underlying {@link Roo.dd.StatusProxy} can be updated
22109 notifyEnter : function(dd, e, data){
22110 return this.dropNotAllowed;
22114 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22115 * This method will be called on every mouse movement while the drag source is over the drop zone.
22116 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22117 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22118 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22119 * registered node, it will call {@link #onContainerOver}.
22120 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22121 * @param {Event} e The event
22122 * @param {Object} data An object containing arbitrary data supplied by the drag source
22123 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22124 * underlying {@link Roo.dd.StatusProxy} can be updated
22126 notifyOver : function(dd, e, data){
22127 var n = this.getTargetFromEvent(e);
22128 if(!n){ // not over valid drop target
22129 if(this.lastOverNode){
22130 this.onNodeOut(this.lastOverNode, dd, e, data);
22131 this.lastOverNode = null;
22133 return this.onContainerOver(dd, e, data);
22135 if(this.lastOverNode != n){
22136 if(this.lastOverNode){
22137 this.onNodeOut(this.lastOverNode, dd, e, data);
22139 this.onNodeEnter(n, dd, e, data);
22140 this.lastOverNode = n;
22142 return this.onNodeOver(n, dd, e, data);
22146 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22147 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22148 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22149 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22150 * @param {Event} e The event
22151 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22153 notifyOut : function(dd, e, data){
22154 if(this.lastOverNode){
22155 this.onNodeOut(this.lastOverNode, dd, e, data);
22156 this.lastOverNode = null;
22161 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22162 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22163 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22164 * otherwise it will call {@link #onContainerDrop}.
22165 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22166 * @param {Event} e The event
22167 * @param {Object} data An object containing arbitrary data supplied by the drag source
22168 * @return {Boolean} True if the drop was valid, else false
22170 notifyDrop : function(dd, e, data){
22171 if(this.lastOverNode){
22172 this.onNodeOut(this.lastOverNode, dd, e, data);
22173 this.lastOverNode = null;
22175 var n = this.getTargetFromEvent(e);
22177 this.onNodeDrop(n, dd, e, data) :
22178 this.onContainerDrop(dd, e, data);
22182 triggerCacheRefresh : function(){
22183 Roo.dd.DDM.refreshCache(this.groups);
22187 * Ext JS Library 1.1.1
22188 * Copyright(c) 2006-2007, Ext JS, LLC.
22190 * Originally Released Under LGPL - original licence link has changed is not relivant.
22193 * <script type="text/javascript">
22198 * @class Roo.data.SortTypes
22200 * Defines the default sorting (casting?) comparison functions used when sorting data.
22202 Roo.data.SortTypes = {
22204 * Default sort that does nothing
22205 * @param {Mixed} s The value being converted
22206 * @return {Mixed} The comparison value
22208 none : function(s){
22213 * The regular expression used to strip tags
22217 stripTagsRE : /<\/?[^>]+>/gi,
22220 * Strips all HTML tags to sort on text only
22221 * @param {Mixed} s The value being converted
22222 * @return {String} The comparison value
22224 asText : function(s){
22225 return String(s).replace(this.stripTagsRE, "");
22229 * Strips all HTML tags to sort on text only - Case insensitive
22230 * @param {Mixed} s The value being converted
22231 * @return {String} The comparison value
22233 asUCText : function(s){
22234 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22238 * Case insensitive string
22239 * @param {Mixed} s The value being converted
22240 * @return {String} The comparison value
22242 asUCString : function(s) {
22243 return String(s).toUpperCase();
22248 * @param {Mixed} s The value being converted
22249 * @return {Number} The comparison value
22251 asDate : function(s) {
22255 if(s instanceof Date){
22256 return s.getTime();
22258 return Date.parse(String(s));
22263 * @param {Mixed} s The value being converted
22264 * @return {Float} The comparison value
22266 asFloat : function(s) {
22267 var val = parseFloat(String(s).replace(/,/g, ""));
22276 * @param {Mixed} s The value being converted
22277 * @return {Number} The comparison value
22279 asInt : function(s) {
22280 var val = parseInt(String(s).replace(/,/g, ""));
22288 * Ext JS Library 1.1.1
22289 * Copyright(c) 2006-2007, Ext JS, LLC.
22291 * Originally Released Under LGPL - original licence link has changed is not relivant.
22294 * <script type="text/javascript">
22298 * @class Roo.data.Record
22299 * Instances of this class encapsulate both record <em>definition</em> information, and record
22300 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22301 * to access Records cached in an {@link Roo.data.Store} object.<br>
22303 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22304 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22307 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22309 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22310 * {@link #create}. The parameters are the same.
22311 * @param {Array} data An associative Array of data values keyed by the field name.
22312 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22313 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22314 * not specified an integer id is generated.
22316 Roo.data.Record = function(data, id){
22317 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22322 * Generate a constructor for a specific record layout.
22323 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22324 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22325 * Each field definition object may contain the following properties: <ul>
22326 * <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,
22327 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22328 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22329 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22330 * is being used, then this is a string containing the javascript expression to reference the data relative to
22331 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22332 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22333 * this may be omitted.</p></li>
22334 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22335 * <ul><li>auto (Default, implies no conversion)</li>
22340 * <li>date</li></ul></p></li>
22341 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22342 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22343 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22344 * by the Reader into an object that will be stored in the Record. It is passed the
22345 * following parameters:<ul>
22346 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22348 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22350 * <br>usage:<br><pre><code>
22351 var TopicRecord = Roo.data.Record.create(
22352 {name: 'title', mapping: 'topic_title'},
22353 {name: 'author', mapping: 'username'},
22354 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22355 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22356 {name: 'lastPoster', mapping: 'user2'},
22357 {name: 'excerpt', mapping: 'post_text'}
22360 var myNewRecord = new TopicRecord({
22361 title: 'Do my job please',
22364 lastPost: new Date(),
22365 lastPoster: 'Animal',
22366 excerpt: 'No way dude!'
22368 myStore.add(myNewRecord);
22373 Roo.data.Record.create = function(o){
22374 var f = function(){
22375 f.superclass.constructor.apply(this, arguments);
22377 Roo.extend(f, Roo.data.Record);
22378 var p = f.prototype;
22379 p.fields = new Roo.util.MixedCollection(false, function(field){
22382 for(var i = 0, len = o.length; i < len; i++){
22383 p.fields.add(new Roo.data.Field(o[i]));
22385 f.getField = function(name){
22386 return p.fields.get(name);
22391 Roo.data.Record.AUTO_ID = 1000;
22392 Roo.data.Record.EDIT = 'edit';
22393 Roo.data.Record.REJECT = 'reject';
22394 Roo.data.Record.COMMIT = 'commit';
22396 Roo.data.Record.prototype = {
22398 * Readonly flag - true if this record has been modified.
22407 join : function(store){
22408 this.store = store;
22412 * Set the named field to the specified value.
22413 * @param {String} name The name of the field to set.
22414 * @param {Object} value The value to set the field to.
22416 set : function(name, value){
22417 if(this.data[name] == value){
22421 if(!this.modified){
22422 this.modified = {};
22424 if(typeof this.modified[name] == 'undefined'){
22425 this.modified[name] = this.data[name];
22427 this.data[name] = value;
22428 if(!this.editing && this.store){
22429 this.store.afterEdit(this);
22434 * Get the value of the named field.
22435 * @param {String} name The name of the field to get the value of.
22436 * @return {Object} The value of the field.
22438 get : function(name){
22439 return this.data[name];
22443 beginEdit : function(){
22444 this.editing = true;
22445 this.modified = {};
22449 cancelEdit : function(){
22450 this.editing = false;
22451 delete this.modified;
22455 endEdit : function(){
22456 this.editing = false;
22457 if(this.dirty && this.store){
22458 this.store.afterEdit(this);
22463 * Usually called by the {@link Roo.data.Store} which owns the Record.
22464 * Rejects all changes made to the Record since either creation, or the last commit operation.
22465 * Modified fields are reverted to their original values.
22467 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22468 * of reject operations.
22470 reject : function(){
22471 var m = this.modified;
22473 if(typeof m[n] != "function"){
22474 this.data[n] = m[n];
22477 this.dirty = false;
22478 delete this.modified;
22479 this.editing = false;
22481 this.store.afterReject(this);
22486 * Usually called by the {@link Roo.data.Store} which owns the Record.
22487 * Commits all changes made to the Record since either creation, or the last commit operation.
22489 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22490 * of commit operations.
22492 commit : function(){
22493 this.dirty = false;
22494 delete this.modified;
22495 this.editing = false;
22497 this.store.afterCommit(this);
22502 hasError : function(){
22503 return this.error != null;
22507 clearError : function(){
22512 * Creates a copy of this record.
22513 * @param {String} id (optional) A new record id if you don't want to use this record's id
22516 copy : function(newId) {
22517 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22521 * Ext JS Library 1.1.1
22522 * Copyright(c) 2006-2007, Ext JS, LLC.
22524 * Originally Released Under LGPL - original licence link has changed is not relivant.
22527 * <script type="text/javascript">
22533 * @class Roo.data.Store
22534 * @extends Roo.util.Observable
22535 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22536 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22538 * 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
22539 * has no knowledge of the format of the data returned by the Proxy.<br>
22541 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22542 * instances from the data object. These records are cached and made available through accessor functions.
22544 * Creates a new Store.
22545 * @param {Object} config A config object containing the objects needed for the Store to access data,
22546 * and read the data into Records.
22548 Roo.data.Store = function(config){
22549 this.data = new Roo.util.MixedCollection(false);
22550 this.data.getKey = function(o){
22553 this.baseParams = {};
22555 this.paramNames = {
22560 "multisort" : "_multisort"
22563 if(config && config.data){
22564 this.inlineData = config.data;
22565 delete config.data;
22568 Roo.apply(this, config);
22570 if(this.reader){ // reader passed
22571 this.reader = Roo.factory(this.reader, Roo.data);
22572 this.reader.xmodule = this.xmodule || false;
22573 if(!this.recordType){
22574 this.recordType = this.reader.recordType;
22576 if(this.reader.onMetaChange){
22577 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22581 if(this.recordType){
22582 this.fields = this.recordType.prototype.fields;
22584 this.modified = [];
22588 * @event datachanged
22589 * Fires when the data cache has changed, and a widget which is using this Store
22590 * as a Record cache should refresh its view.
22591 * @param {Store} this
22593 datachanged : true,
22595 * @event metachange
22596 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22597 * @param {Store} this
22598 * @param {Object} meta The JSON metadata
22603 * Fires when Records have been added to the Store
22604 * @param {Store} this
22605 * @param {Roo.data.Record[]} records The array of Records added
22606 * @param {Number} index The index at which the record(s) were added
22611 * Fires when a Record has been removed from the Store
22612 * @param {Store} this
22613 * @param {Roo.data.Record} record The Record that was removed
22614 * @param {Number} index The index at which the record was removed
22619 * Fires when a Record has been updated
22620 * @param {Store} this
22621 * @param {Roo.data.Record} record The Record that was updated
22622 * @param {String} operation The update operation being performed. Value may be one of:
22624 Roo.data.Record.EDIT
22625 Roo.data.Record.REJECT
22626 Roo.data.Record.COMMIT
22632 * Fires when the data cache has been cleared.
22633 * @param {Store} this
22637 * @event beforeload
22638 * Fires before a request is made for a new data object. If the beforeload handler returns false
22639 * the load action will be canceled.
22640 * @param {Store} this
22641 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22645 * @event beforeloadadd
22646 * Fires after a new set of Records has been loaded.
22647 * @param {Store} this
22648 * @param {Roo.data.Record[]} records The Records that were loaded
22649 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22651 beforeloadadd : true,
22654 * Fires after a new set of Records has been loaded, before they are added to the store.
22655 * @param {Store} this
22656 * @param {Roo.data.Record[]} records The Records that were loaded
22657 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22658 * @params {Object} return from reader
22662 * @event loadexception
22663 * Fires if an exception occurs in the Proxy during loading.
22664 * Called with the signature of the Proxy's "loadexception" event.
22665 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22668 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22669 * @param {Object} load options
22670 * @param {Object} jsonData from your request (normally this contains the Exception)
22672 loadexception : true
22676 this.proxy = Roo.factory(this.proxy, Roo.data);
22677 this.proxy.xmodule = this.xmodule || false;
22678 this.relayEvents(this.proxy, ["loadexception"]);
22680 this.sortToggle = {};
22681 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22683 Roo.data.Store.superclass.constructor.call(this);
22685 if(this.inlineData){
22686 this.loadData(this.inlineData);
22687 delete this.inlineData;
22691 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22693 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22694 * without a remote query - used by combo/forms at present.
22698 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22701 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22704 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22705 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22708 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22709 * on any HTTP request
22712 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22715 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22719 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22720 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22722 remoteSort : false,
22725 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22726 * loaded or when a record is removed. (defaults to false).
22728 pruneModifiedRecords : false,
22731 lastOptions : null,
22734 * Add Records to the Store and fires the add event.
22735 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22737 add : function(records){
22738 records = [].concat(records);
22739 for(var i = 0, len = records.length; i < len; i++){
22740 records[i].join(this);
22742 var index = this.data.length;
22743 this.data.addAll(records);
22744 this.fireEvent("add", this, records, index);
22748 * Remove a Record from the Store and fires the remove event.
22749 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
22751 remove : function(record){
22752 var index = this.data.indexOf(record);
22753 this.data.removeAt(index);
22754 if(this.pruneModifiedRecords){
22755 this.modified.remove(record);
22757 this.fireEvent("remove", this, record, index);
22761 * Remove all Records from the Store and fires the clear event.
22763 removeAll : function(){
22765 if(this.pruneModifiedRecords){
22766 this.modified = [];
22768 this.fireEvent("clear", this);
22772 * Inserts Records to the Store at the given index and fires the add event.
22773 * @param {Number} index The start index at which to insert the passed Records.
22774 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22776 insert : function(index, records){
22777 records = [].concat(records);
22778 for(var i = 0, len = records.length; i < len; i++){
22779 this.data.insert(index, records[i]);
22780 records[i].join(this);
22782 this.fireEvent("add", this, records, index);
22786 * Get the index within the cache of the passed Record.
22787 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
22788 * @return {Number} The index of the passed Record. Returns -1 if not found.
22790 indexOf : function(record){
22791 return this.data.indexOf(record);
22795 * Get the index within the cache of the Record with the passed id.
22796 * @param {String} id The id of the Record to find.
22797 * @return {Number} The index of the Record. Returns -1 if not found.
22799 indexOfId : function(id){
22800 return this.data.indexOfKey(id);
22804 * Get the Record with the specified id.
22805 * @param {String} id The id of the Record to find.
22806 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
22808 getById : function(id){
22809 return this.data.key(id);
22813 * Get the Record at the specified index.
22814 * @param {Number} index The index of the Record to find.
22815 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
22817 getAt : function(index){
22818 return this.data.itemAt(index);
22822 * Returns a range of Records between specified indices.
22823 * @param {Number} startIndex (optional) The starting index (defaults to 0)
22824 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
22825 * @return {Roo.data.Record[]} An array of Records
22827 getRange : function(start, end){
22828 return this.data.getRange(start, end);
22832 storeOptions : function(o){
22833 o = Roo.apply({}, o);
22836 this.lastOptions = o;
22840 * Loads the Record cache from the configured Proxy using the configured Reader.
22842 * If using remote paging, then the first load call must specify the <em>start</em>
22843 * and <em>limit</em> properties in the options.params property to establish the initial
22844 * position within the dataset, and the number of Records to cache on each read from the Proxy.
22846 * <strong>It is important to note that for remote data sources, loading is asynchronous,
22847 * and this call will return before the new data has been loaded. Perform any post-processing
22848 * in a callback function, or in a "load" event handler.</strong>
22850 * @param {Object} options An object containing properties which control loading options:<ul>
22851 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
22852 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
22853 * passed the following arguments:<ul>
22854 * <li>r : Roo.data.Record[]</li>
22855 * <li>options: Options object from the load call</li>
22856 * <li>success: Boolean success indicator</li></ul></li>
22857 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
22858 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
22861 load : function(options){
22862 options = options || {};
22863 if(this.fireEvent("beforeload", this, options) !== false){
22864 this.storeOptions(options);
22865 var p = Roo.apply(options.params || {}, this.baseParams);
22866 // if meta was not loaded from remote source.. try requesting it.
22867 if (!this.reader.metaFromRemote) {
22868 p._requestMeta = 1;
22870 if(this.sortInfo && this.remoteSort){
22871 var pn = this.paramNames;
22872 p[pn["sort"]] = this.sortInfo.field;
22873 p[pn["dir"]] = this.sortInfo.direction;
22875 if (this.multiSort) {
22876 var pn = this.paramNames;
22877 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
22880 this.proxy.load(p, this.reader, this.loadRecords, this, options);
22885 * Reloads the Record cache from the configured Proxy using the configured Reader and
22886 * the options from the last load operation performed.
22887 * @param {Object} options (optional) An object containing properties which may override the options
22888 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
22889 * the most recently used options are reused).
22891 reload : function(options){
22892 this.load(Roo.applyIf(options||{}, this.lastOptions));
22896 // Called as a callback by the Reader during a load operation.
22897 loadRecords : function(o, options, success){
22898 if(!o || success === false){
22899 if(success !== false){
22900 this.fireEvent("load", this, [], options, o);
22902 if(options.callback){
22903 options.callback.call(options.scope || this, [], options, false);
22907 // if data returned failure - throw an exception.
22908 if (o.success === false) {
22909 // show a message if no listener is registered.
22910 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
22911 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
22913 // loadmask wil be hooked into this..
22914 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
22917 var r = o.records, t = o.totalRecords || r.length;
22919 this.fireEvent("beforeloadadd", this, r, options, o);
22921 if(!options || options.add !== true){
22922 if(this.pruneModifiedRecords){
22923 this.modified = [];
22925 for(var i = 0, len = r.length; i < len; i++){
22929 this.data = this.snapshot;
22930 delete this.snapshot;
22933 this.data.addAll(r);
22934 this.totalLength = t;
22936 this.fireEvent("datachanged", this);
22938 this.totalLength = Math.max(t, this.data.length+r.length);
22941 this.fireEvent("load", this, r, options, o);
22942 if(options.callback){
22943 options.callback.call(options.scope || this, r, options, true);
22949 * Loads data from a passed data block. A Reader which understands the format of the data
22950 * must have been configured in the constructor.
22951 * @param {Object} data The data block from which to read the Records. The format of the data expected
22952 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
22953 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
22955 loadData : function(o, append){
22956 var r = this.reader.readRecords(o);
22957 this.loadRecords(r, {add: append}, true);
22961 * Gets the number of cached records.
22963 * <em>If using paging, this may not be the total size of the dataset. If the data object
22964 * used by the Reader contains the dataset size, then the getTotalCount() function returns
22965 * the data set size</em>
22967 getCount : function(){
22968 return this.data.length || 0;
22972 * Gets the total number of records in the dataset as returned by the server.
22974 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
22975 * the dataset size</em>
22977 getTotalCount : function(){
22978 return this.totalLength || 0;
22982 * Returns the sort state of the Store as an object with two properties:
22984 field {String} The name of the field by which the Records are sorted
22985 direction {String} The sort order, "ASC" or "DESC"
22988 getSortState : function(){
22989 return this.sortInfo;
22993 applySort : function(){
22994 if(this.sortInfo && !this.remoteSort){
22995 var s = this.sortInfo, f = s.field;
22996 var st = this.fields.get(f).sortType;
22997 var fn = function(r1, r2){
22998 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
22999 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23001 this.data.sort(s.direction, fn);
23002 if(this.snapshot && this.snapshot != this.data){
23003 this.snapshot.sort(s.direction, fn);
23009 * Sets the default sort column and order to be used by the next load operation.
23010 * @param {String} fieldName The name of the field to sort by.
23011 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23013 setDefaultSort : function(field, dir){
23014 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23018 * Sort the Records.
23019 * If remote sorting is used, the sort is performed on the server, and the cache is
23020 * reloaded. If local sorting is used, the cache is sorted internally.
23021 * @param {String} fieldName The name of the field to sort by.
23022 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23024 sort : function(fieldName, dir){
23025 var f = this.fields.get(fieldName);
23027 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23029 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23030 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23035 this.sortToggle[f.name] = dir;
23036 this.sortInfo = {field: f.name, direction: dir};
23037 if(!this.remoteSort){
23039 this.fireEvent("datachanged", this);
23041 this.load(this.lastOptions);
23046 * Calls the specified function for each of the Records in the cache.
23047 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23048 * Returning <em>false</em> aborts and exits the iteration.
23049 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23051 each : function(fn, scope){
23052 this.data.each(fn, scope);
23056 * Gets all records modified since the last commit. Modified records are persisted across load operations
23057 * (e.g., during paging).
23058 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23060 getModifiedRecords : function(){
23061 return this.modified;
23065 createFilterFn : function(property, value, anyMatch){
23066 if(!value.exec){ // not a regex
23067 value = String(value);
23068 if(value.length == 0){
23071 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23073 return function(r){
23074 return value.test(r.data[property]);
23079 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23080 * @param {String} property A field on your records
23081 * @param {Number} start The record index to start at (defaults to 0)
23082 * @param {Number} end The last record index to include (defaults to length - 1)
23083 * @return {Number} The sum
23085 sum : function(property, start, end){
23086 var rs = this.data.items, v = 0;
23087 start = start || 0;
23088 end = (end || end === 0) ? end : rs.length-1;
23090 for(var i = start; i <= end; i++){
23091 v += (rs[i].data[property] || 0);
23097 * Filter the records by a specified property.
23098 * @param {String} field A field on your records
23099 * @param {String/RegExp} value Either a string that the field
23100 * should start with or a RegExp to test against the field
23101 * @param {Boolean} anyMatch True to match any part not just the beginning
23103 filter : function(property, value, anyMatch){
23104 var fn = this.createFilterFn(property, value, anyMatch);
23105 return fn ? this.filterBy(fn) : this.clearFilter();
23109 * Filter by a function. The specified function will be called with each
23110 * record in this data source. If the function returns true the record is included,
23111 * otherwise it is filtered.
23112 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23113 * @param {Object} scope (optional) The scope of the function (defaults to this)
23115 filterBy : function(fn, scope){
23116 this.snapshot = this.snapshot || this.data;
23117 this.data = this.queryBy(fn, scope||this);
23118 this.fireEvent("datachanged", this);
23122 * Query the records by a specified property.
23123 * @param {String} field A field on your records
23124 * @param {String/RegExp} value Either a string that the field
23125 * should start with or a RegExp to test against the field
23126 * @param {Boolean} anyMatch True to match any part not just the beginning
23127 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23129 query : function(property, value, anyMatch){
23130 var fn = this.createFilterFn(property, value, anyMatch);
23131 return fn ? this.queryBy(fn) : this.data.clone();
23135 * Query by a function. The specified function will be called with each
23136 * record in this data source. If the function returns true the record is included
23138 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23139 * @param {Object} scope (optional) The scope of the function (defaults to this)
23140 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23142 queryBy : function(fn, scope){
23143 var data = this.snapshot || this.data;
23144 return data.filterBy(fn, scope||this);
23148 * Collects unique values for a particular dataIndex from this store.
23149 * @param {String} dataIndex The property to collect
23150 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23151 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23152 * @return {Array} An array of the unique values
23154 collect : function(dataIndex, allowNull, bypassFilter){
23155 var d = (bypassFilter === true && this.snapshot) ?
23156 this.snapshot.items : this.data.items;
23157 var v, sv, r = [], l = {};
23158 for(var i = 0, len = d.length; i < len; i++){
23159 v = d[i].data[dataIndex];
23161 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23170 * Revert to a view of the Record cache with no filtering applied.
23171 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23173 clearFilter : function(suppressEvent){
23174 if(this.snapshot && this.snapshot != this.data){
23175 this.data = this.snapshot;
23176 delete this.snapshot;
23177 if(suppressEvent !== true){
23178 this.fireEvent("datachanged", this);
23184 afterEdit : function(record){
23185 if(this.modified.indexOf(record) == -1){
23186 this.modified.push(record);
23188 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23192 afterReject : function(record){
23193 this.modified.remove(record);
23194 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23198 afterCommit : function(record){
23199 this.modified.remove(record);
23200 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23204 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23205 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23207 commitChanges : function(){
23208 var m = this.modified.slice(0);
23209 this.modified = [];
23210 for(var i = 0, len = m.length; i < len; i++){
23216 * Cancel outstanding changes on all changed records.
23218 rejectChanges : function(){
23219 var m = this.modified.slice(0);
23220 this.modified = [];
23221 for(var i = 0, len = m.length; i < len; i++){
23226 onMetaChange : function(meta, rtype, o){
23227 this.recordType = rtype;
23228 this.fields = rtype.prototype.fields;
23229 delete this.snapshot;
23230 this.sortInfo = meta.sortInfo || this.sortInfo;
23231 this.modified = [];
23232 this.fireEvent('metachange', this, this.reader.meta);
23235 moveIndex : function(data, type)
23237 var index = this.indexOf(data);
23239 var newIndex = index + type;
23243 this.insert(newIndex, data);
23248 * Ext JS Library 1.1.1
23249 * Copyright(c) 2006-2007, Ext JS, LLC.
23251 * Originally Released Under LGPL - original licence link has changed is not relivant.
23254 * <script type="text/javascript">
23258 * @class Roo.data.SimpleStore
23259 * @extends Roo.data.Store
23260 * Small helper class to make creating Stores from Array data easier.
23261 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23262 * @cfg {Array} fields An array of field definition objects, or field name strings.
23263 * @cfg {Array} data The multi-dimensional array of data
23265 * @param {Object} config
23267 Roo.data.SimpleStore = function(config){
23268 Roo.data.SimpleStore.superclass.constructor.call(this, {
23270 reader: new Roo.data.ArrayReader({
23273 Roo.data.Record.create(config.fields)
23275 proxy : new Roo.data.MemoryProxy(config.data)
23279 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23281 * Ext JS Library 1.1.1
23282 * Copyright(c) 2006-2007, Ext JS, LLC.
23284 * Originally Released Under LGPL - original licence link has changed is not relivant.
23287 * <script type="text/javascript">
23292 * @extends Roo.data.Store
23293 * @class Roo.data.JsonStore
23294 * Small helper class to make creating Stores for JSON data easier. <br/>
23296 var store = new Roo.data.JsonStore({
23297 url: 'get-images.php',
23299 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23302 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23303 * JsonReader and HttpProxy (unless inline data is provided).</b>
23304 * @cfg {Array} fields An array of field definition objects, or field name strings.
23306 * @param {Object} config
23308 Roo.data.JsonStore = function(c){
23309 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23310 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23311 reader: new Roo.data.JsonReader(c, c.fields)
23314 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23316 * Ext JS Library 1.1.1
23317 * Copyright(c) 2006-2007, Ext JS, LLC.
23319 * Originally Released Under LGPL - original licence link has changed is not relivant.
23322 * <script type="text/javascript">
23326 Roo.data.Field = function(config){
23327 if(typeof config == "string"){
23328 config = {name: config};
23330 Roo.apply(this, config);
23333 this.type = "auto";
23336 var st = Roo.data.SortTypes;
23337 // named sortTypes are supported, here we look them up
23338 if(typeof this.sortType == "string"){
23339 this.sortType = st[this.sortType];
23342 // set default sortType for strings and dates
23343 if(!this.sortType){
23346 this.sortType = st.asUCString;
23349 this.sortType = st.asDate;
23352 this.sortType = st.none;
23357 var stripRe = /[\$,%]/g;
23359 // prebuilt conversion function for this field, instead of
23360 // switching every time we're reading a value
23362 var cv, dateFormat = this.dateFormat;
23367 cv = function(v){ return v; };
23370 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23374 return v !== undefined && v !== null && v !== '' ?
23375 parseInt(String(v).replace(stripRe, ""), 10) : '';
23380 return v !== undefined && v !== null && v !== '' ?
23381 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23386 cv = function(v){ return v === true || v === "true" || v == 1; };
23393 if(v instanceof Date){
23397 if(dateFormat == "timestamp"){
23398 return new Date(v*1000);
23400 return Date.parseDate(v, dateFormat);
23402 var parsed = Date.parse(v);
23403 return parsed ? new Date(parsed) : null;
23412 Roo.data.Field.prototype = {
23420 * Ext JS Library 1.1.1
23421 * Copyright(c) 2006-2007, Ext JS, LLC.
23423 * Originally Released Under LGPL - original licence link has changed is not relivant.
23426 * <script type="text/javascript">
23429 // Base class for reading structured data from a data source. This class is intended to be
23430 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23433 * @class Roo.data.DataReader
23434 * Base class for reading structured data from a data source. This class is intended to be
23435 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23438 Roo.data.DataReader = function(meta, recordType){
23442 this.recordType = recordType instanceof Array ?
23443 Roo.data.Record.create(recordType) : recordType;
23446 Roo.data.DataReader.prototype = {
23448 * Create an empty record
23449 * @param {Object} data (optional) - overlay some values
23450 * @return {Roo.data.Record} record created.
23452 newRow : function(d) {
23454 this.recordType.prototype.fields.each(function(c) {
23456 case 'int' : da[c.name] = 0; break;
23457 case 'date' : da[c.name] = new Date(); break;
23458 case 'float' : da[c.name] = 0.0; break;
23459 case 'boolean' : da[c.name] = false; break;
23460 default : da[c.name] = ""; break;
23464 return new this.recordType(Roo.apply(da, d));
23469 * Ext JS Library 1.1.1
23470 * Copyright(c) 2006-2007, Ext JS, LLC.
23472 * Originally Released Under LGPL - original licence link has changed is not relivant.
23475 * <script type="text/javascript">
23479 * @class Roo.data.DataProxy
23480 * @extends Roo.data.Observable
23481 * This class is an abstract base class for implementations which provide retrieval of
23482 * unformatted data objects.<br>
23484 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23485 * (of the appropriate type which knows how to parse the data object) to provide a block of
23486 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23488 * Custom implementations must implement the load method as described in
23489 * {@link Roo.data.HttpProxy#load}.
23491 Roo.data.DataProxy = function(){
23494 * @event beforeload
23495 * Fires before a network request is made to retrieve a data object.
23496 * @param {Object} This DataProxy object.
23497 * @param {Object} params The params parameter to the load function.
23502 * Fires before the load method's callback is called.
23503 * @param {Object} This DataProxy object.
23504 * @param {Object} o The data object.
23505 * @param {Object} arg The callback argument object passed to the load function.
23509 * @event loadexception
23510 * Fires if an Exception occurs during data retrieval.
23511 * @param {Object} This DataProxy object.
23512 * @param {Object} o The data object.
23513 * @param {Object} arg The callback argument object passed to the load function.
23514 * @param {Object} e The Exception.
23516 loadexception : true
23518 Roo.data.DataProxy.superclass.constructor.call(this);
23521 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23524 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23528 * Ext JS Library 1.1.1
23529 * Copyright(c) 2006-2007, Ext JS, LLC.
23531 * Originally Released Under LGPL - original licence link has changed is not relivant.
23534 * <script type="text/javascript">
23537 * @class Roo.data.MemoryProxy
23538 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23539 * to the Reader when its load method is called.
23541 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23543 Roo.data.MemoryProxy = function(data){
23547 Roo.data.MemoryProxy.superclass.constructor.call(this);
23551 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23553 * Load data from the requested source (in this case an in-memory
23554 * data object passed to the constructor), read the data object into
23555 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23556 * process that block using the passed callback.
23557 * @param {Object} params This parameter is not used by the MemoryProxy class.
23558 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23559 * object into a block of Roo.data.Records.
23560 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23561 * The function must be passed <ul>
23562 * <li>The Record block object</li>
23563 * <li>The "arg" argument from the load function</li>
23564 * <li>A boolean success indicator</li>
23566 * @param {Object} scope The scope in which to call the callback
23567 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23569 load : function(params, reader, callback, scope, arg){
23570 params = params || {};
23573 result = reader.readRecords(this.data);
23575 this.fireEvent("loadexception", this, arg, null, e);
23576 callback.call(scope, null, arg, false);
23579 callback.call(scope, result, arg, true);
23583 update : function(params, records){
23588 * Ext JS Library 1.1.1
23589 * Copyright(c) 2006-2007, Ext JS, LLC.
23591 * Originally Released Under LGPL - original licence link has changed is not relivant.
23594 * <script type="text/javascript">
23597 * @class Roo.data.HttpProxy
23598 * @extends Roo.data.DataProxy
23599 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23600 * configured to reference a certain URL.<br><br>
23602 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23603 * from which the running page was served.<br><br>
23605 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23607 * Be aware that to enable the browser to parse an XML document, the server must set
23608 * the Content-Type header in the HTTP response to "text/xml".
23610 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23611 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23612 * will be used to make the request.
23614 Roo.data.HttpProxy = function(conn){
23615 Roo.data.HttpProxy.superclass.constructor.call(this);
23616 // is conn a conn config or a real conn?
23618 this.useAjax = !conn || !conn.events;
23622 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23623 // thse are take from connection...
23626 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23629 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23630 * extra parameters to each request made by this object. (defaults to undefined)
23633 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23634 * to each request made by this object. (defaults to undefined)
23637 * @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)
23640 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23643 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23649 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23653 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23654 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23655 * a finer-grained basis than the DataProxy events.
23657 getConnection : function(){
23658 return this.useAjax ? Roo.Ajax : this.conn;
23662 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23663 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23664 * process that block using the passed callback.
23665 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23666 * for the request to the remote server.
23667 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23668 * object into a block of Roo.data.Records.
23669 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23670 * The function must be passed <ul>
23671 * <li>The Record block object</li>
23672 * <li>The "arg" argument from the load function</li>
23673 * <li>A boolean success indicator</li>
23675 * @param {Object} scope The scope in which to call the callback
23676 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23678 load : function(params, reader, callback, scope, arg){
23679 if(this.fireEvent("beforeload", this, params) !== false){
23681 params : params || {},
23683 callback : callback,
23688 callback : this.loadResponse,
23692 Roo.applyIf(o, this.conn);
23693 if(this.activeRequest){
23694 Roo.Ajax.abort(this.activeRequest);
23696 this.activeRequest = Roo.Ajax.request(o);
23698 this.conn.request(o);
23701 callback.call(scope||this, null, arg, false);
23706 loadResponse : function(o, success, response){
23707 delete this.activeRequest;
23709 this.fireEvent("loadexception", this, o, response);
23710 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23715 result = o.reader.read(response);
23717 this.fireEvent("loadexception", this, o, response, e);
23718 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23722 this.fireEvent("load", this, o, o.request.arg);
23723 o.request.callback.call(o.request.scope, result, o.request.arg, true);
23727 update : function(dataSet){
23732 updateResponse : function(dataSet){
23737 * Ext JS Library 1.1.1
23738 * Copyright(c) 2006-2007, Ext JS, LLC.
23740 * Originally Released Under LGPL - original licence link has changed is not relivant.
23743 * <script type="text/javascript">
23747 * @class Roo.data.ScriptTagProxy
23748 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
23749 * other than the originating domain of the running page.<br><br>
23751 * <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
23752 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
23754 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
23755 * source code that is used as the source inside a <script> tag.<br><br>
23757 * In order for the browser to process the returned data, the server must wrap the data object
23758 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
23759 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
23760 * depending on whether the callback name was passed:
23763 boolean scriptTag = false;
23764 String cb = request.getParameter("callback");
23767 response.setContentType("text/javascript");
23769 response.setContentType("application/x-json");
23771 Writer out = response.getWriter();
23773 out.write(cb + "(");
23775 out.print(dataBlock.toJsonString());
23782 * @param {Object} config A configuration object.
23784 Roo.data.ScriptTagProxy = function(config){
23785 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
23786 Roo.apply(this, config);
23787 this.head = document.getElementsByTagName("head")[0];
23790 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
23792 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
23794 * @cfg {String} url The URL from which to request the data object.
23797 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
23801 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
23802 * the server the name of the callback function set up by the load call to process the returned data object.
23803 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
23804 * javascript output which calls this named function passing the data object as its only parameter.
23806 callbackParam : "callback",
23808 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
23809 * name to the request.
23814 * Load data from the configured URL, read the data object into
23815 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23816 * process that block using the passed callback.
23817 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23818 * for the request to the remote server.
23819 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23820 * object into a block of Roo.data.Records.
23821 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23822 * The function must be passed <ul>
23823 * <li>The Record block object</li>
23824 * <li>The "arg" argument from the load function</li>
23825 * <li>A boolean success indicator</li>
23827 * @param {Object} scope The scope in which to call the callback
23828 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23830 load : function(params, reader, callback, scope, arg){
23831 if(this.fireEvent("beforeload", this, params) !== false){
23833 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
23835 var url = this.url;
23836 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
23838 url += "&_dc=" + (new Date().getTime());
23840 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
23843 cb : "stcCallback"+transId,
23844 scriptId : "stcScript"+transId,
23848 callback : callback,
23854 window[trans.cb] = function(o){
23855 conn.handleResponse(o, trans);
23858 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
23860 if(this.autoAbort !== false){
23864 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
23866 var script = document.createElement("script");
23867 script.setAttribute("src", url);
23868 script.setAttribute("type", "text/javascript");
23869 script.setAttribute("id", trans.scriptId);
23870 this.head.appendChild(script);
23872 this.trans = trans;
23874 callback.call(scope||this, null, arg, false);
23879 isLoading : function(){
23880 return this.trans ? true : false;
23884 * Abort the current server request.
23886 abort : function(){
23887 if(this.isLoading()){
23888 this.destroyTrans(this.trans);
23893 destroyTrans : function(trans, isLoaded){
23894 this.head.removeChild(document.getElementById(trans.scriptId));
23895 clearTimeout(trans.timeoutId);
23897 window[trans.cb] = undefined;
23899 delete window[trans.cb];
23902 // if hasn't been loaded, wait for load to remove it to prevent script error
23903 window[trans.cb] = function(){
23904 window[trans.cb] = undefined;
23906 delete window[trans.cb];
23913 handleResponse : function(o, trans){
23914 this.trans = false;
23915 this.destroyTrans(trans, true);
23918 result = trans.reader.readRecords(o);
23920 this.fireEvent("loadexception", this, o, trans.arg, e);
23921 trans.callback.call(trans.scope||window, null, trans.arg, false);
23924 this.fireEvent("load", this, o, trans.arg);
23925 trans.callback.call(trans.scope||window, result, trans.arg, true);
23929 handleFailure : function(trans){
23930 this.trans = false;
23931 this.destroyTrans(trans, false);
23932 this.fireEvent("loadexception", this, null, trans.arg);
23933 trans.callback.call(trans.scope||window, null, trans.arg, false);
23937 * Ext JS Library 1.1.1
23938 * Copyright(c) 2006-2007, Ext JS, LLC.
23940 * Originally Released Under LGPL - original licence link has changed is not relivant.
23943 * <script type="text/javascript">
23947 * @class Roo.data.JsonReader
23948 * @extends Roo.data.DataReader
23949 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
23950 * based on mappings in a provided Roo.data.Record constructor.
23952 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
23953 * in the reply previously.
23958 var RecordDef = Roo.data.Record.create([
23959 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
23960 {name: 'occupation'} // This field will use "occupation" as the mapping.
23962 var myReader = new Roo.data.JsonReader({
23963 totalProperty: "results", // The property which contains the total dataset size (optional)
23964 root: "rows", // The property which contains an Array of row objects
23965 id: "id" // The property within each row object that provides an ID for the record (optional)
23969 * This would consume a JSON file like this:
23971 { 'results': 2, 'rows': [
23972 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
23973 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
23976 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
23977 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
23978 * paged from the remote server.
23979 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
23980 * @cfg {String} root name of the property which contains the Array of row objects.
23981 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
23982 * @cfg {Array} fields Array of field definition objects
23984 * Create a new JsonReader
23985 * @param {Object} meta Metadata configuration options
23986 * @param {Object} recordType Either an Array of field definition objects,
23987 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
23989 Roo.data.JsonReader = function(meta, recordType){
23992 // set some defaults:
23993 Roo.applyIf(meta, {
23994 totalProperty: 'total',
23995 successProperty : 'success',
24000 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24002 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24005 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24006 * Used by Store query builder to append _requestMeta to params.
24009 metaFromRemote : false,
24011 * This method is only used by a DataProxy which has retrieved data from a remote server.
24012 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24013 * @return {Object} data A data block which is used by an Roo.data.Store object as
24014 * a cache of Roo.data.Records.
24016 read : function(response){
24017 var json = response.responseText;
24019 var o = /* eval:var:o */ eval("("+json+")");
24021 throw {message: "JsonReader.read: Json object not found"};
24027 this.metaFromRemote = true;
24028 this.meta = o.metaData;
24029 this.recordType = Roo.data.Record.create(o.metaData.fields);
24030 this.onMetaChange(this.meta, this.recordType, o);
24032 return this.readRecords(o);
24035 // private function a store will implement
24036 onMetaChange : function(meta, recordType, o){
24043 simpleAccess: function(obj, subsc) {
24050 getJsonAccessor: function(){
24052 return function(expr) {
24054 return(re.test(expr))
24055 ? new Function("obj", "return obj." + expr)
24060 return Roo.emptyFn;
24065 * Create a data block containing Roo.data.Records from an XML document.
24066 * @param {Object} o An object which contains an Array of row objects in the property specified
24067 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24068 * which contains the total size of the dataset.
24069 * @return {Object} data A data block which is used by an Roo.data.Store object as
24070 * a cache of Roo.data.Records.
24072 readRecords : function(o){
24074 * After any data loads, the raw JSON data is available for further custom processing.
24078 var s = this.meta, Record = this.recordType,
24079 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24081 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24083 if(s.totalProperty) {
24084 this.getTotal = this.getJsonAccessor(s.totalProperty);
24086 if(s.successProperty) {
24087 this.getSuccess = this.getJsonAccessor(s.successProperty);
24089 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24091 var g = this.getJsonAccessor(s.id);
24092 this.getId = function(rec) {
24094 return (r === undefined || r === "") ? null : r;
24097 this.getId = function(){return null;};
24100 for(var jj = 0; jj < fl; jj++){
24102 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24103 this.ef[jj] = this.getJsonAccessor(map);
24107 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24108 if(s.totalProperty){
24109 var vt = parseInt(this.getTotal(o), 10);
24114 if(s.successProperty){
24115 var vs = this.getSuccess(o);
24116 if(vs === false || vs === 'false'){
24121 for(var i = 0; i < c; i++){
24124 var id = this.getId(n);
24125 for(var j = 0; j < fl; j++){
24127 var v = this.ef[j](n);
24129 Roo.log('missing convert for ' + f.name);
24133 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24135 var record = new Record(values, id);
24137 records[i] = record;
24143 totalRecords : totalRecords
24148 * Ext JS Library 1.1.1
24149 * Copyright(c) 2006-2007, Ext JS, LLC.
24151 * Originally Released Under LGPL - original licence link has changed is not relivant.
24154 * <script type="text/javascript">
24158 * @class Roo.data.XmlReader
24159 * @extends Roo.data.DataReader
24160 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24161 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24163 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24164 * header in the HTTP response must be set to "text/xml".</em>
24168 var RecordDef = Roo.data.Record.create([
24169 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24170 {name: 'occupation'} // This field will use "occupation" as the mapping.
24172 var myReader = new Roo.data.XmlReader({
24173 totalRecords: "results", // The element which contains the total dataset size (optional)
24174 record: "row", // The repeated element which contains row information
24175 id: "id" // The element within the row that provides an ID for the record (optional)
24179 * This would consume an XML file like this:
24183 <results>2</results>
24186 <name>Bill</name>
24187 <occupation>Gardener</occupation>
24191 <name>Ben</name>
24192 <occupation>Horticulturalist</occupation>
24196 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24197 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24198 * paged from the remote server.
24199 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24200 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24201 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24202 * a record identifier value.
24204 * Create a new XmlReader
24205 * @param {Object} meta Metadata configuration options
24206 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24207 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24208 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24210 Roo.data.XmlReader = function(meta, recordType){
24212 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24214 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24216 * This method is only used by a DataProxy which has retrieved data from a remote server.
24217 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24218 * to contain a method called 'responseXML' that returns an XML document object.
24219 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24220 * a cache of Roo.data.Records.
24222 read : function(response){
24223 var doc = response.responseXML;
24225 throw {message: "XmlReader.read: XML Document not available"};
24227 return this.readRecords(doc);
24231 * Create a data block containing Roo.data.Records from an XML document.
24232 * @param {Object} doc A parsed XML document.
24233 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24234 * a cache of Roo.data.Records.
24236 readRecords : function(doc){
24238 * After any data loads/reads, the raw XML Document is available for further custom processing.
24239 * @type XMLDocument
24241 this.xmlData = doc;
24242 var root = doc.documentElement || doc;
24243 var q = Roo.DomQuery;
24244 var recordType = this.recordType, fields = recordType.prototype.fields;
24245 var sid = this.meta.id;
24246 var totalRecords = 0, success = true;
24247 if(this.meta.totalRecords){
24248 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24251 if(this.meta.success){
24252 var sv = q.selectValue(this.meta.success, root, true);
24253 success = sv !== false && sv !== 'false';
24256 var ns = q.select(this.meta.record, root);
24257 for(var i = 0, len = ns.length; i < len; i++) {
24260 var id = sid ? q.selectValue(sid, n) : undefined;
24261 for(var j = 0, jlen = fields.length; j < jlen; j++){
24262 var f = fields.items[j];
24263 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24265 values[f.name] = v;
24267 var record = new recordType(values, id);
24269 records[records.length] = record;
24275 totalRecords : totalRecords || records.length
24280 * Ext JS Library 1.1.1
24281 * Copyright(c) 2006-2007, Ext JS, LLC.
24283 * Originally Released Under LGPL - original licence link has changed is not relivant.
24286 * <script type="text/javascript">
24290 * @class Roo.data.ArrayReader
24291 * @extends Roo.data.DataReader
24292 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24293 * Each element of that Array represents a row of data fields. The
24294 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24295 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24299 var RecordDef = Roo.data.Record.create([
24300 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24301 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24303 var myReader = new Roo.data.ArrayReader({
24304 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24308 * This would consume an Array like this:
24310 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24312 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24314 * Create a new JsonReader
24315 * @param {Object} meta Metadata configuration options.
24316 * @param {Object} recordType Either an Array of field definition objects
24317 * as specified to {@link Roo.data.Record#create},
24318 * or an {@link Roo.data.Record} object
24319 * created using {@link Roo.data.Record#create}.
24321 Roo.data.ArrayReader = function(meta, recordType){
24322 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24325 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24327 * Create a data block containing Roo.data.Records from an XML document.
24328 * @param {Object} o An Array of row objects which represents the dataset.
24329 * @return {Object} data A data block which is used by an Roo.data.Store object as
24330 * a cache of Roo.data.Records.
24332 readRecords : function(o){
24333 var sid = this.meta ? this.meta.id : null;
24334 var recordType = this.recordType, fields = recordType.prototype.fields;
24337 for(var i = 0; i < root.length; i++){
24340 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24341 for(var j = 0, jlen = fields.length; j < jlen; j++){
24342 var f = fields.items[j];
24343 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24344 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24346 values[f.name] = v;
24348 var record = new recordType(values, id);
24350 records[records.length] = record;
24354 totalRecords : records.length
24359 * Ext JS Library 1.1.1
24360 * Copyright(c) 2006-2007, Ext JS, LLC.
24362 * Originally Released Under LGPL - original licence link has changed is not relivant.
24365 * <script type="text/javascript">
24370 * @class Roo.data.Tree
24371 * @extends Roo.util.Observable
24372 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24373 * in the tree have most standard DOM functionality.
24375 * @param {Node} root (optional) The root node
24377 Roo.data.Tree = function(root){
24378 this.nodeHash = {};
24380 * The root node for this tree
24385 this.setRootNode(root);
24390 * Fires when a new child node is appended to a node in this tree.
24391 * @param {Tree} tree The owner tree
24392 * @param {Node} parent The parent node
24393 * @param {Node} node The newly appended node
24394 * @param {Number} index The index of the newly appended node
24399 * Fires when a child node is removed from a node in this tree.
24400 * @param {Tree} tree The owner tree
24401 * @param {Node} parent The parent node
24402 * @param {Node} node The child node removed
24407 * Fires when a node is moved to a new location in the tree
24408 * @param {Tree} tree The owner tree
24409 * @param {Node} node The node moved
24410 * @param {Node} oldParent The old parent of this node
24411 * @param {Node} newParent The new parent of this node
24412 * @param {Number} index The index it was moved to
24417 * Fires when a new child node is inserted in a node in this tree.
24418 * @param {Tree} tree The owner tree
24419 * @param {Node} parent The parent node
24420 * @param {Node} node The child node inserted
24421 * @param {Node} refNode The child node the node was inserted before
24425 * @event beforeappend
24426 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24427 * @param {Tree} tree The owner tree
24428 * @param {Node} parent The parent node
24429 * @param {Node} node The child node to be appended
24431 "beforeappend" : true,
24433 * @event beforeremove
24434 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24435 * @param {Tree} tree The owner tree
24436 * @param {Node} parent The parent node
24437 * @param {Node} node The child node to be removed
24439 "beforeremove" : true,
24441 * @event beforemove
24442 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24443 * @param {Tree} tree The owner tree
24444 * @param {Node} node The node being moved
24445 * @param {Node} oldParent The parent of the node
24446 * @param {Node} newParent The new parent the node is moving to
24447 * @param {Number} index The index it is being moved to
24449 "beforemove" : true,
24451 * @event beforeinsert
24452 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24453 * @param {Tree} tree The owner tree
24454 * @param {Node} parent The parent node
24455 * @param {Node} node The child node to be inserted
24456 * @param {Node} refNode The child node the node is being inserted before
24458 "beforeinsert" : true
24461 Roo.data.Tree.superclass.constructor.call(this);
24464 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24465 pathSeparator: "/",
24467 proxyNodeEvent : function(){
24468 return this.fireEvent.apply(this, arguments);
24472 * Returns the root node for this tree.
24475 getRootNode : function(){
24480 * Sets the root node for this tree.
24481 * @param {Node} node
24484 setRootNode : function(node){
24486 node.ownerTree = this;
24487 node.isRoot = true;
24488 this.registerNode(node);
24493 * Gets a node in this tree by its id.
24494 * @param {String} id
24497 getNodeById : function(id){
24498 return this.nodeHash[id];
24501 registerNode : function(node){
24502 this.nodeHash[node.id] = node;
24505 unregisterNode : function(node){
24506 delete this.nodeHash[node.id];
24509 toString : function(){
24510 return "[Tree"+(this.id?" "+this.id:"")+"]";
24515 * @class Roo.data.Node
24516 * @extends Roo.util.Observable
24517 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24518 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24520 * @param {Object} attributes The attributes/config for the node
24522 Roo.data.Node = function(attributes){
24524 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24527 this.attributes = attributes || {};
24528 this.leaf = this.attributes.leaf;
24530 * The node id. @type String
24532 this.id = this.attributes.id;
24534 this.id = Roo.id(null, "ynode-");
24535 this.attributes.id = this.id;
24540 * All child nodes of this node. @type Array
24542 this.childNodes = [];
24543 if(!this.childNodes.indexOf){ // indexOf is a must
24544 this.childNodes.indexOf = function(o){
24545 for(var i = 0, len = this.length; i < len; i++){
24554 * The parent node for this node. @type Node
24556 this.parentNode = null;
24558 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24560 this.firstChild = null;
24562 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24564 this.lastChild = null;
24566 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24568 this.previousSibling = null;
24570 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24572 this.nextSibling = null;
24577 * Fires when a new child node is appended
24578 * @param {Tree} tree The owner tree
24579 * @param {Node} this This node
24580 * @param {Node} node The newly appended node
24581 * @param {Number} index The index of the newly appended node
24586 * Fires when a child node is removed
24587 * @param {Tree} tree The owner tree
24588 * @param {Node} this This node
24589 * @param {Node} node The removed node
24594 * Fires when this node is moved to a new location in the tree
24595 * @param {Tree} tree The owner tree
24596 * @param {Node} this This node
24597 * @param {Node} oldParent The old parent of this node
24598 * @param {Node} newParent The new parent of this node
24599 * @param {Number} index The index it was moved to
24604 * Fires when a new child node is inserted.
24605 * @param {Tree} tree The owner tree
24606 * @param {Node} this This node
24607 * @param {Node} node The child node inserted
24608 * @param {Node} refNode The child node the node was inserted before
24612 * @event beforeappend
24613 * Fires before a new child is appended, return false to cancel the append.
24614 * @param {Tree} tree The owner tree
24615 * @param {Node} this This node
24616 * @param {Node} node The child node to be appended
24618 "beforeappend" : true,
24620 * @event beforeremove
24621 * Fires before a child is removed, return false to cancel the remove.
24622 * @param {Tree} tree The owner tree
24623 * @param {Node} this This node
24624 * @param {Node} node The child node to be removed
24626 "beforeremove" : true,
24628 * @event beforemove
24629 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24630 * @param {Tree} tree The owner tree
24631 * @param {Node} this This node
24632 * @param {Node} oldParent The parent of this node
24633 * @param {Node} newParent The new parent this node is moving to
24634 * @param {Number} index The index it is being moved to
24636 "beforemove" : true,
24638 * @event beforeinsert
24639 * Fires before a new child is inserted, return false to cancel the insert.
24640 * @param {Tree} tree The owner tree
24641 * @param {Node} this This node
24642 * @param {Node} node The child node to be inserted
24643 * @param {Node} refNode The child node the node is being inserted before
24645 "beforeinsert" : true
24647 this.listeners = this.attributes.listeners;
24648 Roo.data.Node.superclass.constructor.call(this);
24651 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24652 fireEvent : function(evtName){
24653 // first do standard event for this node
24654 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24657 // then bubble it up to the tree if the event wasn't cancelled
24658 var ot = this.getOwnerTree();
24660 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24668 * Returns true if this node is a leaf
24669 * @return {Boolean}
24671 isLeaf : function(){
24672 return this.leaf === true;
24676 setFirstChild : function(node){
24677 this.firstChild = node;
24681 setLastChild : function(node){
24682 this.lastChild = node;
24687 * Returns true if this node is the last child of its parent
24688 * @return {Boolean}
24690 isLast : function(){
24691 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24695 * Returns true if this node is the first child of its parent
24696 * @return {Boolean}
24698 isFirst : function(){
24699 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24702 hasChildNodes : function(){
24703 return !this.isLeaf() && this.childNodes.length > 0;
24707 * Insert node(s) as the last child node of this node.
24708 * @param {Node/Array} node The node or Array of nodes to append
24709 * @return {Node} The appended node if single append, or null if an array was passed
24711 appendChild : function(node){
24713 if(node instanceof Array){
24715 }else if(arguments.length > 1){
24718 // if passed an array or multiple args do them one by one
24720 for(var i = 0, len = multi.length; i < len; i++) {
24721 this.appendChild(multi[i]);
24724 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
24727 var index = this.childNodes.length;
24728 var oldParent = node.parentNode;
24729 // it's a move, make sure we move it cleanly
24731 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
24734 oldParent.removeChild(node);
24736 index = this.childNodes.length;
24738 this.setFirstChild(node);
24740 this.childNodes.push(node);
24741 node.parentNode = this;
24742 var ps = this.childNodes[index-1];
24744 node.previousSibling = ps;
24745 ps.nextSibling = node;
24747 node.previousSibling = null;
24749 node.nextSibling = null;
24750 this.setLastChild(node);
24751 node.setOwnerTree(this.getOwnerTree());
24752 this.fireEvent("append", this.ownerTree, this, node, index);
24754 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
24761 * Removes a child node from this node.
24762 * @param {Node} node The node to remove
24763 * @return {Node} The removed node
24765 removeChild : function(node){
24766 var index = this.childNodes.indexOf(node);
24770 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
24774 // remove it from childNodes collection
24775 this.childNodes.splice(index, 1);
24778 if(node.previousSibling){
24779 node.previousSibling.nextSibling = node.nextSibling;
24781 if(node.nextSibling){
24782 node.nextSibling.previousSibling = node.previousSibling;
24785 // update child refs
24786 if(this.firstChild == node){
24787 this.setFirstChild(node.nextSibling);
24789 if(this.lastChild == node){
24790 this.setLastChild(node.previousSibling);
24793 node.setOwnerTree(null);
24794 // clear any references from the node
24795 node.parentNode = null;
24796 node.previousSibling = null;
24797 node.nextSibling = null;
24798 this.fireEvent("remove", this.ownerTree, this, node);
24803 * Inserts the first node before the second node in this nodes childNodes collection.
24804 * @param {Node} node The node to insert
24805 * @param {Node} refNode The node to insert before (if null the node is appended)
24806 * @return {Node} The inserted node
24808 insertBefore : function(node, refNode){
24809 if(!refNode){ // like standard Dom, refNode can be null for append
24810 return this.appendChild(node);
24813 if(node == refNode){
24817 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
24820 var index = this.childNodes.indexOf(refNode);
24821 var oldParent = node.parentNode;
24822 var refIndex = index;
24824 // when moving internally, indexes will change after remove
24825 if(oldParent == this && this.childNodes.indexOf(node) < index){
24829 // it's a move, make sure we move it cleanly
24831 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
24834 oldParent.removeChild(node);
24837 this.setFirstChild(node);
24839 this.childNodes.splice(refIndex, 0, node);
24840 node.parentNode = this;
24841 var ps = this.childNodes[refIndex-1];
24843 node.previousSibling = ps;
24844 ps.nextSibling = node;
24846 node.previousSibling = null;
24848 node.nextSibling = refNode;
24849 refNode.previousSibling = node;
24850 node.setOwnerTree(this.getOwnerTree());
24851 this.fireEvent("insert", this.ownerTree, this, node, refNode);
24853 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
24859 * Returns the child node at the specified index.
24860 * @param {Number} index
24863 item : function(index){
24864 return this.childNodes[index];
24868 * Replaces one child node in this node with another.
24869 * @param {Node} newChild The replacement node
24870 * @param {Node} oldChild The node to replace
24871 * @return {Node} The replaced node
24873 replaceChild : function(newChild, oldChild){
24874 this.insertBefore(newChild, oldChild);
24875 this.removeChild(oldChild);
24880 * Returns the index of a child node
24881 * @param {Node} node
24882 * @return {Number} The index of the node or -1 if it was not found
24884 indexOf : function(child){
24885 return this.childNodes.indexOf(child);
24889 * Returns the tree this node is in.
24892 getOwnerTree : function(){
24893 // if it doesn't have one, look for one
24894 if(!this.ownerTree){
24898 this.ownerTree = p.ownerTree;
24904 return this.ownerTree;
24908 * Returns depth of this node (the root node has a depth of 0)
24911 getDepth : function(){
24914 while(p.parentNode){
24922 setOwnerTree : function(tree){
24923 // if it's move, we need to update everyone
24924 if(tree != this.ownerTree){
24925 if(this.ownerTree){
24926 this.ownerTree.unregisterNode(this);
24928 this.ownerTree = tree;
24929 var cs = this.childNodes;
24930 for(var i = 0, len = cs.length; i < len; i++) {
24931 cs[i].setOwnerTree(tree);
24934 tree.registerNode(this);
24940 * Returns the path for this node. The path can be used to expand or select this node programmatically.
24941 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
24942 * @return {String} The path
24944 getPath : function(attr){
24945 attr = attr || "id";
24946 var p = this.parentNode;
24947 var b = [this.attributes[attr]];
24949 b.unshift(p.attributes[attr]);
24952 var sep = this.getOwnerTree().pathSeparator;
24953 return sep + b.join(sep);
24957 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
24958 * function call will be the scope provided or the current node. The arguments to the function
24959 * will be the args provided or the current node. If the function returns false at any point,
24960 * the bubble is stopped.
24961 * @param {Function} fn The function to call
24962 * @param {Object} scope (optional) The scope of the function (defaults to current node)
24963 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
24965 bubble : function(fn, scope, args){
24968 if(fn.call(scope || p, args || p) === false){
24976 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
24977 * function call will be the scope provided or the current node. The arguments to the function
24978 * will be the args provided or the current node. If the function returns false at any point,
24979 * the cascade is stopped on that branch.
24980 * @param {Function} fn The function to call
24981 * @param {Object} scope (optional) The scope of the function (defaults to current node)
24982 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
24984 cascade : function(fn, scope, args){
24985 if(fn.call(scope || this, args || this) !== false){
24986 var cs = this.childNodes;
24987 for(var i = 0, len = cs.length; i < len; i++) {
24988 cs[i].cascade(fn, scope, args);
24994 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
24995 * function call will be the scope provided or the current node. The arguments to the function
24996 * will be the args provided or the current node. If the function returns false at any point,
24997 * the iteration stops.
24998 * @param {Function} fn The function to call
24999 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25000 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25002 eachChild : function(fn, scope, args){
25003 var cs = this.childNodes;
25004 for(var i = 0, len = cs.length; i < len; i++) {
25005 if(fn.call(scope || this, args || cs[i]) === false){
25012 * Finds the first child that has the attribute with the specified value.
25013 * @param {String} attribute The attribute name
25014 * @param {Mixed} value The value to search for
25015 * @return {Node} The found child or null if none was found
25017 findChild : function(attribute, value){
25018 var cs = this.childNodes;
25019 for(var i = 0, len = cs.length; i < len; i++) {
25020 if(cs[i].attributes[attribute] == value){
25028 * Finds the first child by a custom function. The child matches if the function passed
25030 * @param {Function} fn
25031 * @param {Object} scope (optional)
25032 * @return {Node} The found child or null if none was found
25034 findChildBy : function(fn, scope){
25035 var cs = this.childNodes;
25036 for(var i = 0, len = cs.length; i < len; i++) {
25037 if(fn.call(scope||cs[i], cs[i]) === true){
25045 * Sorts this nodes children using the supplied sort function
25046 * @param {Function} fn
25047 * @param {Object} scope (optional)
25049 sort : function(fn, scope){
25050 var cs = this.childNodes;
25051 var len = cs.length;
25053 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25055 for(var i = 0; i < len; i++){
25057 n.previousSibling = cs[i-1];
25058 n.nextSibling = cs[i+1];
25060 this.setFirstChild(n);
25063 this.setLastChild(n);
25070 * Returns true if this node is an ancestor (at any point) of the passed node.
25071 * @param {Node} node
25072 * @return {Boolean}
25074 contains : function(node){
25075 return node.isAncestor(this);
25079 * Returns true if the passed node is an ancestor (at any point) of this node.
25080 * @param {Node} node
25081 * @return {Boolean}
25083 isAncestor : function(node){
25084 var p = this.parentNode;
25094 toString : function(){
25095 return "[Node"+(this.id?" "+this.id:"")+"]";
25099 * Ext JS Library 1.1.1
25100 * Copyright(c) 2006-2007, Ext JS, LLC.
25102 * Originally Released Under LGPL - original licence link has changed is not relivant.
25105 * <script type="text/javascript">
25110 * @extends Roo.Element
25111 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25112 * automatic maintaining of shadow/shim positions.
25113 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25114 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25115 * you can pass a string with a CSS class name. False turns off the shadow.
25116 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25117 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25118 * @cfg {String} cls CSS class to add to the element
25119 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25120 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25122 * @param {Object} config An object with config options.
25123 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25126 Roo.Layer = function(config, existingEl){
25127 config = config || {};
25128 var dh = Roo.DomHelper;
25129 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25131 this.dom = Roo.getDom(existingEl);
25134 var o = config.dh || {tag: "div", cls: "x-layer"};
25135 this.dom = dh.append(pel, o);
25138 this.addClass(config.cls);
25140 this.constrain = config.constrain !== false;
25141 this.visibilityMode = Roo.Element.VISIBILITY;
25143 this.id = this.dom.id = config.id;
25145 this.id = Roo.id(this.dom);
25147 this.zindex = config.zindex || this.getZIndex();
25148 this.position("absolute", this.zindex);
25150 this.shadowOffset = config.shadowOffset || 4;
25151 this.shadow = new Roo.Shadow({
25152 offset : this.shadowOffset,
25153 mode : config.shadow
25156 this.shadowOffset = 0;
25158 this.useShim = config.shim !== false && Roo.useShims;
25159 this.useDisplay = config.useDisplay;
25163 var supr = Roo.Element.prototype;
25165 // shims are shared among layer to keep from having 100 iframes
25168 Roo.extend(Roo.Layer, Roo.Element, {
25170 getZIndex : function(){
25171 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25174 getShim : function(){
25181 var shim = shims.shift();
25183 shim = this.createShim();
25184 shim.enableDisplayMode('block');
25185 shim.dom.style.display = 'none';
25186 shim.dom.style.visibility = 'visible';
25188 var pn = this.dom.parentNode;
25189 if(shim.dom.parentNode != pn){
25190 pn.insertBefore(shim.dom, this.dom);
25192 shim.setStyle('z-index', this.getZIndex()-2);
25197 hideShim : function(){
25199 this.shim.setDisplayed(false);
25200 shims.push(this.shim);
25205 disableShadow : function(){
25207 this.shadowDisabled = true;
25208 this.shadow.hide();
25209 this.lastShadowOffset = this.shadowOffset;
25210 this.shadowOffset = 0;
25214 enableShadow : function(show){
25216 this.shadowDisabled = false;
25217 this.shadowOffset = this.lastShadowOffset;
25218 delete this.lastShadowOffset;
25226 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25227 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25228 sync : function(doShow){
25229 var sw = this.shadow;
25230 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25231 var sh = this.getShim();
25233 var w = this.getWidth(),
25234 h = this.getHeight();
25236 var l = this.getLeft(true),
25237 t = this.getTop(true);
25239 if(sw && !this.shadowDisabled){
25240 if(doShow && !sw.isVisible()){
25243 sw.realign(l, t, w, h);
25249 // fit the shim behind the shadow, so it is shimmed too
25250 var a = sw.adjusts, s = sh.dom.style;
25251 s.left = (Math.min(l, l+a.l))+"px";
25252 s.top = (Math.min(t, t+a.t))+"px";
25253 s.width = (w+a.w)+"px";
25254 s.height = (h+a.h)+"px";
25261 sh.setLeftTop(l, t);
25268 destroy : function(){
25271 this.shadow.hide();
25273 this.removeAllListeners();
25274 var pn = this.dom.parentNode;
25276 pn.removeChild(this.dom);
25278 Roo.Element.uncache(this.id);
25281 remove : function(){
25286 beginUpdate : function(){
25287 this.updating = true;
25291 endUpdate : function(){
25292 this.updating = false;
25297 hideUnders : function(negOffset){
25299 this.shadow.hide();
25305 constrainXY : function(){
25306 if(this.constrain){
25307 var vw = Roo.lib.Dom.getViewWidth(),
25308 vh = Roo.lib.Dom.getViewHeight();
25309 var s = Roo.get(document).getScroll();
25311 var xy = this.getXY();
25312 var x = xy[0], y = xy[1];
25313 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25314 // only move it if it needs it
25316 // first validate right/bottom
25317 if((x + w) > vw+s.left){
25318 x = vw - w - this.shadowOffset;
25321 if((y + h) > vh+s.top){
25322 y = vh - h - this.shadowOffset;
25325 // then make sure top/left isn't negative
25336 var ay = this.avoidY;
25337 if(y <= ay && (y+h) >= ay){
25343 supr.setXY.call(this, xy);
25349 isVisible : function(){
25350 return this.visible;
25354 showAction : function(){
25355 this.visible = true; // track visibility to prevent getStyle calls
25356 if(this.useDisplay === true){
25357 this.setDisplayed("");
25358 }else if(this.lastXY){
25359 supr.setXY.call(this, this.lastXY);
25360 }else if(this.lastLT){
25361 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25366 hideAction : function(){
25367 this.visible = false;
25368 if(this.useDisplay === true){
25369 this.setDisplayed(false);
25371 this.setLeftTop(-10000,-10000);
25375 // overridden Element method
25376 setVisible : function(v, a, d, c, e){
25381 var cb = function(){
25386 }.createDelegate(this);
25387 supr.setVisible.call(this, true, true, d, cb, e);
25390 this.hideUnders(true);
25399 }.createDelegate(this);
25401 supr.setVisible.call(this, v, a, d, cb, e);
25410 storeXY : function(xy){
25411 delete this.lastLT;
25415 storeLeftTop : function(left, top){
25416 delete this.lastXY;
25417 this.lastLT = [left, top];
25421 beforeFx : function(){
25422 this.beforeAction();
25423 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25427 afterFx : function(){
25428 Roo.Layer.superclass.afterFx.apply(this, arguments);
25429 this.sync(this.isVisible());
25433 beforeAction : function(){
25434 if(!this.updating && this.shadow){
25435 this.shadow.hide();
25439 // overridden Element method
25440 setLeft : function(left){
25441 this.storeLeftTop(left, this.getTop(true));
25442 supr.setLeft.apply(this, arguments);
25446 setTop : function(top){
25447 this.storeLeftTop(this.getLeft(true), top);
25448 supr.setTop.apply(this, arguments);
25452 setLeftTop : function(left, top){
25453 this.storeLeftTop(left, top);
25454 supr.setLeftTop.apply(this, arguments);
25458 setXY : function(xy, a, d, c, e){
25460 this.beforeAction();
25462 var cb = this.createCB(c);
25463 supr.setXY.call(this, xy, a, d, cb, e);
25470 createCB : function(c){
25481 // overridden Element method
25482 setX : function(x, a, d, c, e){
25483 this.setXY([x, this.getY()], a, d, c, e);
25486 // overridden Element method
25487 setY : function(y, a, d, c, e){
25488 this.setXY([this.getX(), y], a, d, c, e);
25491 // overridden Element method
25492 setSize : function(w, h, a, d, c, e){
25493 this.beforeAction();
25494 var cb = this.createCB(c);
25495 supr.setSize.call(this, w, h, a, d, cb, e);
25501 // overridden Element method
25502 setWidth : function(w, a, d, c, e){
25503 this.beforeAction();
25504 var cb = this.createCB(c);
25505 supr.setWidth.call(this, w, a, d, cb, e);
25511 // overridden Element method
25512 setHeight : function(h, a, d, c, e){
25513 this.beforeAction();
25514 var cb = this.createCB(c);
25515 supr.setHeight.call(this, h, a, d, cb, e);
25521 // overridden Element method
25522 setBounds : function(x, y, w, h, a, d, c, e){
25523 this.beforeAction();
25524 var cb = this.createCB(c);
25526 this.storeXY([x, y]);
25527 supr.setXY.call(this, [x, y]);
25528 supr.setSize.call(this, w, h, a, d, cb, e);
25531 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25537 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25538 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25539 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25540 * @param {Number} zindex The new z-index to set
25541 * @return {this} The Layer
25543 setZIndex : function(zindex){
25544 this.zindex = zindex;
25545 this.setStyle("z-index", zindex + 2);
25547 this.shadow.setZIndex(zindex + 1);
25550 this.shim.setStyle("z-index", zindex);
25556 * Ext JS Library 1.1.1
25557 * Copyright(c) 2006-2007, Ext JS, LLC.
25559 * Originally Released Under LGPL - original licence link has changed is not relivant.
25562 * <script type="text/javascript">
25567 * @class Roo.Shadow
25568 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25569 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25570 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25572 * Create a new Shadow
25573 * @param {Object} config The config object
25575 Roo.Shadow = function(config){
25576 Roo.apply(this, config);
25577 if(typeof this.mode != "string"){
25578 this.mode = this.defaultMode;
25580 var o = this.offset, a = {h: 0};
25581 var rad = Math.floor(this.offset/2);
25582 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25588 a.l -= this.offset + rad;
25589 a.t -= this.offset + rad;
25600 a.l -= (this.offset - rad);
25601 a.t -= this.offset + rad;
25603 a.w -= (this.offset - rad)*2;
25614 a.l -= (this.offset - rad);
25615 a.t -= (this.offset - rad);
25617 a.w -= (this.offset + rad + 1);
25618 a.h -= (this.offset + rad);
25627 Roo.Shadow.prototype = {
25629 * @cfg {String} mode
25630 * The shadow display mode. Supports the following options:<br />
25631 * sides: Shadow displays on both sides and bottom only<br />
25632 * frame: Shadow displays equally on all four sides<br />
25633 * drop: Traditional bottom-right drop shadow (default)
25636 * @cfg {String} offset
25637 * The number of pixels to offset the shadow from the element (defaults to 4)
25642 defaultMode: "drop",
25645 * Displays the shadow under the target element
25646 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25648 show : function(target){
25649 target = Roo.get(target);
25651 this.el = Roo.Shadow.Pool.pull();
25652 if(this.el.dom.nextSibling != target.dom){
25653 this.el.insertBefore(target);
25656 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25658 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25661 target.getLeft(true),
25662 target.getTop(true),
25666 this.el.dom.style.display = "block";
25670 * Returns true if the shadow is visible, else false
25672 isVisible : function(){
25673 return this.el ? true : false;
25677 * Direct alignment when values are already available. Show must be called at least once before
25678 * calling this method to ensure it is initialized.
25679 * @param {Number} left The target element left position
25680 * @param {Number} top The target element top position
25681 * @param {Number} width The target element width
25682 * @param {Number} height The target element height
25684 realign : function(l, t, w, h){
25688 var a = this.adjusts, d = this.el.dom, s = d.style;
25690 s.left = (l+a.l)+"px";
25691 s.top = (t+a.t)+"px";
25692 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25694 if(s.width != sws || s.height != shs){
25698 var cn = d.childNodes;
25699 var sww = Math.max(0, (sw-12))+"px";
25700 cn[0].childNodes[1].style.width = sww;
25701 cn[1].childNodes[1].style.width = sww;
25702 cn[2].childNodes[1].style.width = sww;
25703 cn[1].style.height = Math.max(0, (sh-12))+"px";
25709 * Hides this shadow
25713 this.el.dom.style.display = "none";
25714 Roo.Shadow.Pool.push(this.el);
25720 * Adjust the z-index of this shadow
25721 * @param {Number} zindex The new z-index
25723 setZIndex : function(z){
25726 this.el.setStyle("z-index", z);
25731 // Private utility class that manages the internal Shadow cache
25732 Roo.Shadow.Pool = function(){
25734 var markup = Roo.isIE ?
25735 '<div class="x-ie-shadow"></div>' :
25736 '<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>';
25739 var sh = p.shift();
25741 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
25742 sh.autoBoxAdjust = false;
25747 push : function(sh){
25753 * Ext JS Library 1.1.1
25754 * Copyright(c) 2006-2007, Ext JS, LLC.
25756 * Originally Released Under LGPL - original licence link has changed is not relivant.
25759 * <script type="text/javascript">
25764 * @class Roo.SplitBar
25765 * @extends Roo.util.Observable
25766 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
25770 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
25771 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
25772 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
25773 split.minSize = 100;
25774 split.maxSize = 600;
25775 split.animate = true;
25776 split.on('moved', splitterMoved);
25779 * Create a new SplitBar
25780 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
25781 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
25782 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25783 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
25784 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
25785 position of the SplitBar).
25787 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
25790 this.el = Roo.get(dragElement, true);
25791 this.el.dom.unselectable = "on";
25793 this.resizingEl = Roo.get(resizingElement, true);
25797 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25798 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
25801 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
25804 * The minimum size of the resizing element. (Defaults to 0)
25810 * The maximum size of the resizing element. (Defaults to 2000)
25813 this.maxSize = 2000;
25816 * Whether to animate the transition to the new size
25819 this.animate = false;
25822 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
25825 this.useShim = false;
25830 if(!existingProxy){
25832 this.proxy = Roo.SplitBar.createProxy(this.orientation);
25834 this.proxy = Roo.get(existingProxy).dom;
25837 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
25840 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
25843 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
25846 this.dragSpecs = {};
25849 * @private The adapter to use to positon and resize elements
25851 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
25852 this.adapter.init(this);
25854 if(this.orientation == Roo.SplitBar.HORIZONTAL){
25856 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
25857 this.el.addClass("x-splitbar-h");
25860 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
25861 this.el.addClass("x-splitbar-v");
25867 * Fires when the splitter is moved (alias for {@link #event-moved})
25868 * @param {Roo.SplitBar} this
25869 * @param {Number} newSize the new width or height
25874 * Fires when the splitter is moved
25875 * @param {Roo.SplitBar} this
25876 * @param {Number} newSize the new width or height
25880 * @event beforeresize
25881 * Fires before the splitter is dragged
25882 * @param {Roo.SplitBar} this
25884 "beforeresize" : true,
25886 "beforeapply" : true
25889 Roo.util.Observable.call(this);
25892 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
25893 onStartProxyDrag : function(x, y){
25894 this.fireEvent("beforeresize", this);
25896 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
25898 o.enableDisplayMode("block");
25899 // all splitbars share the same overlay
25900 Roo.SplitBar.prototype.overlay = o;
25902 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
25903 this.overlay.show();
25904 Roo.get(this.proxy).setDisplayed("block");
25905 var size = this.adapter.getElementSize(this);
25906 this.activeMinSize = this.getMinimumSize();;
25907 this.activeMaxSize = this.getMaximumSize();;
25908 var c1 = size - this.activeMinSize;
25909 var c2 = Math.max(this.activeMaxSize - size, 0);
25910 if(this.orientation == Roo.SplitBar.HORIZONTAL){
25911 this.dd.resetConstraints();
25912 this.dd.setXConstraint(
25913 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
25914 this.placement == Roo.SplitBar.LEFT ? c2 : c1
25916 this.dd.setYConstraint(0, 0);
25918 this.dd.resetConstraints();
25919 this.dd.setXConstraint(0, 0);
25920 this.dd.setYConstraint(
25921 this.placement == Roo.SplitBar.TOP ? c1 : c2,
25922 this.placement == Roo.SplitBar.TOP ? c2 : c1
25925 this.dragSpecs.startSize = size;
25926 this.dragSpecs.startPoint = [x, y];
25927 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
25931 * @private Called after the drag operation by the DDProxy
25933 onEndProxyDrag : function(e){
25934 Roo.get(this.proxy).setDisplayed(false);
25935 var endPoint = Roo.lib.Event.getXY(e);
25937 this.overlay.hide();
25940 if(this.orientation == Roo.SplitBar.HORIZONTAL){
25941 newSize = this.dragSpecs.startSize +
25942 (this.placement == Roo.SplitBar.LEFT ?
25943 endPoint[0] - this.dragSpecs.startPoint[0] :
25944 this.dragSpecs.startPoint[0] - endPoint[0]
25947 newSize = this.dragSpecs.startSize +
25948 (this.placement == Roo.SplitBar.TOP ?
25949 endPoint[1] - this.dragSpecs.startPoint[1] :
25950 this.dragSpecs.startPoint[1] - endPoint[1]
25953 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
25954 if(newSize != this.dragSpecs.startSize){
25955 if(this.fireEvent('beforeapply', this, newSize) !== false){
25956 this.adapter.setElementSize(this, newSize);
25957 this.fireEvent("moved", this, newSize);
25958 this.fireEvent("resize", this, newSize);
25964 * Get the adapter this SplitBar uses
25965 * @return The adapter object
25967 getAdapter : function(){
25968 return this.adapter;
25972 * Set the adapter this SplitBar uses
25973 * @param {Object} adapter A SplitBar adapter object
25975 setAdapter : function(adapter){
25976 this.adapter = adapter;
25977 this.adapter.init(this);
25981 * Gets the minimum size for the resizing element
25982 * @return {Number} The minimum size
25984 getMinimumSize : function(){
25985 return this.minSize;
25989 * Sets the minimum size for the resizing element
25990 * @param {Number} minSize The minimum size
25992 setMinimumSize : function(minSize){
25993 this.minSize = minSize;
25997 * Gets the maximum size for the resizing element
25998 * @return {Number} The maximum size
26000 getMaximumSize : function(){
26001 return this.maxSize;
26005 * Sets the maximum size for the resizing element
26006 * @param {Number} maxSize The maximum size
26008 setMaximumSize : function(maxSize){
26009 this.maxSize = maxSize;
26013 * Sets the initialize size for the resizing element
26014 * @param {Number} size The initial size
26016 setCurrentSize : function(size){
26017 var oldAnimate = this.animate;
26018 this.animate = false;
26019 this.adapter.setElementSize(this, size);
26020 this.animate = oldAnimate;
26024 * Destroy this splitbar.
26025 * @param {Boolean} removeEl True to remove the element
26027 destroy : function(removeEl){
26029 this.shim.remove();
26032 this.proxy.parentNode.removeChild(this.proxy);
26040 * @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.
26042 Roo.SplitBar.createProxy = function(dir){
26043 var proxy = new Roo.Element(document.createElement("div"));
26044 proxy.unselectable();
26045 var cls = 'x-splitbar-proxy';
26046 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26047 document.body.appendChild(proxy.dom);
26052 * @class Roo.SplitBar.BasicLayoutAdapter
26053 * Default Adapter. It assumes the splitter and resizing element are not positioned
26054 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26056 Roo.SplitBar.BasicLayoutAdapter = function(){
26059 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26060 // do nothing for now
26061 init : function(s){
26065 * Called before drag operations to get the current size of the resizing element.
26066 * @param {Roo.SplitBar} s The SplitBar using this adapter
26068 getElementSize : function(s){
26069 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26070 return s.resizingEl.getWidth();
26072 return s.resizingEl.getHeight();
26077 * Called after drag operations to set the size of the resizing element.
26078 * @param {Roo.SplitBar} s The SplitBar using this adapter
26079 * @param {Number} newSize The new size to set
26080 * @param {Function} onComplete A function to be invoked when resizing is complete
26082 setElementSize : function(s, newSize, onComplete){
26083 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26085 s.resizingEl.setWidth(newSize);
26087 onComplete(s, newSize);
26090 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26095 s.resizingEl.setHeight(newSize);
26097 onComplete(s, newSize);
26100 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26107 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26108 * @extends Roo.SplitBar.BasicLayoutAdapter
26109 * Adapter that moves the splitter element to align with the resized sizing element.
26110 * Used with an absolute positioned SplitBar.
26111 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26112 * document.body, make sure you assign an id to the body element.
26114 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26115 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26116 this.container = Roo.get(container);
26119 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26120 init : function(s){
26121 this.basic.init(s);
26124 getElementSize : function(s){
26125 return this.basic.getElementSize(s);
26128 setElementSize : function(s, newSize, onComplete){
26129 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26132 moveSplitter : function(s){
26133 var yes = Roo.SplitBar;
26134 switch(s.placement){
26136 s.el.setX(s.resizingEl.getRight());
26139 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26142 s.el.setY(s.resizingEl.getBottom());
26145 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26152 * Orientation constant - Create a vertical SplitBar
26156 Roo.SplitBar.VERTICAL = 1;
26159 * Orientation constant - Create a horizontal SplitBar
26163 Roo.SplitBar.HORIZONTAL = 2;
26166 * Placement constant - The resizing element is to the left of the splitter element
26170 Roo.SplitBar.LEFT = 1;
26173 * Placement constant - The resizing element is to the right of the splitter element
26177 Roo.SplitBar.RIGHT = 2;
26180 * Placement constant - The resizing element is positioned above the splitter element
26184 Roo.SplitBar.TOP = 3;
26187 * Placement constant - The resizing element is positioned under splitter element
26191 Roo.SplitBar.BOTTOM = 4;
26194 * Ext JS Library 1.1.1
26195 * Copyright(c) 2006-2007, Ext JS, LLC.
26197 * Originally Released Under LGPL - original licence link has changed is not relivant.
26200 * <script type="text/javascript">
26205 * @extends Roo.util.Observable
26206 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26207 * This class also supports single and multi selection modes. <br>
26208 * Create a data model bound view:
26210 var store = new Roo.data.Store(...);
26212 var view = new Roo.View({
26214 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26216 singleSelect: true,
26217 selectedClass: "ydataview-selected",
26221 // listen for node click?
26222 view.on("click", function(vw, index, node, e){
26223 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26227 dataModel.load("foobar.xml");
26229 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26231 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26232 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26234 * Note: old style constructor is still suported (container, template, config)
26237 * Create a new View
26238 * @param {Object} config The config object
26241 Roo.View = function(config, depreciated_tpl, depreciated_config){
26243 this.parent = false;
26245 if (typeof(depreciated_tpl) == 'undefined') {
26246 // new way.. - universal constructor.
26247 Roo.apply(this, config);
26248 this.el = Roo.get(this.el);
26251 this.el = Roo.get(config);
26252 this.tpl = depreciated_tpl;
26253 Roo.apply(this, depreciated_config);
26255 this.wrapEl = this.el.wrap().wrap();
26256 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26259 if(typeof(this.tpl) == "string"){
26260 this.tpl = new Roo.Template(this.tpl);
26262 // support xtype ctors..
26263 this.tpl = new Roo.factory(this.tpl, Roo);
26267 this.tpl.compile();
26272 * @event beforeclick
26273 * Fires before a click is processed. Returns false to cancel the default action.
26274 * @param {Roo.View} this
26275 * @param {Number} index The index of the target node
26276 * @param {HTMLElement} node The target node
26277 * @param {Roo.EventObject} e The raw event object
26279 "beforeclick" : true,
26282 * Fires when a template node is clicked.
26283 * @param {Roo.View} this
26284 * @param {Number} index The index of the target node
26285 * @param {HTMLElement} node The target node
26286 * @param {Roo.EventObject} e The raw event object
26291 * Fires when a template node is double clicked.
26292 * @param {Roo.View} this
26293 * @param {Number} index The index of the target node
26294 * @param {HTMLElement} node The target node
26295 * @param {Roo.EventObject} e The raw event object
26299 * @event contextmenu
26300 * Fires when a template node is right clicked.
26301 * @param {Roo.View} this
26302 * @param {Number} index The index of the target node
26303 * @param {HTMLElement} node The target node
26304 * @param {Roo.EventObject} e The raw event object
26306 "contextmenu" : true,
26308 * @event selectionchange
26309 * Fires when the selected nodes change.
26310 * @param {Roo.View} this
26311 * @param {Array} selections Array of the selected nodes
26313 "selectionchange" : true,
26316 * @event beforeselect
26317 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26318 * @param {Roo.View} this
26319 * @param {HTMLElement} node The node to be selected
26320 * @param {Array} selections Array of currently selected nodes
26322 "beforeselect" : true,
26324 * @event preparedata
26325 * Fires on every row to render, to allow you to change the data.
26326 * @param {Roo.View} this
26327 * @param {Object} data to be rendered (change this)
26329 "preparedata" : true
26337 "click": this.onClick,
26338 "dblclick": this.onDblClick,
26339 "contextmenu": this.onContextMenu,
26343 this.selections = [];
26345 this.cmp = new Roo.CompositeElementLite([]);
26347 this.store = Roo.factory(this.store, Roo.data);
26348 this.setStore(this.store, true);
26351 if ( this.footer && this.footer.xtype) {
26353 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26355 this.footer.dataSource = this.store;
26356 this.footer.container = fctr;
26357 this.footer = Roo.factory(this.footer, Roo);
26358 fctr.insertFirst(this.el);
26360 // this is a bit insane - as the paging toolbar seems to detach the el..
26361 // dom.parentNode.parentNode.parentNode
26362 // they get detached?
26366 Roo.View.superclass.constructor.call(this);
26371 Roo.extend(Roo.View, Roo.util.Observable, {
26374 * @cfg {Roo.data.Store} store Data store to load data from.
26379 * @cfg {String|Roo.Element} el The container element.
26384 * @cfg {String|Roo.Template} tpl The template used by this View
26388 * @cfg {String} dataName the named area of the template to use as the data area
26389 * Works with domtemplates roo-name="name"
26393 * @cfg {String} selectedClass The css class to add to selected nodes
26395 selectedClass : "x-view-selected",
26397 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26402 * @cfg {String} text to display on mask (default Loading)
26406 * @cfg {Boolean} multiSelect Allow multiple selection
26408 multiSelect : false,
26410 * @cfg {Boolean} singleSelect Allow single selection
26412 singleSelect: false,
26415 * @cfg {Boolean} toggleSelect - selecting
26417 toggleSelect : false,
26420 * @cfg {Boolean} tickable - selecting
26425 * Returns the element this view is bound to.
26426 * @return {Roo.Element}
26428 getEl : function(){
26429 return this.wrapEl;
26435 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26437 refresh : function(){
26438 //Roo.log('refresh');
26441 // if we are using something like 'domtemplate', then
26442 // the what gets used is:
26443 // t.applySubtemplate(NAME, data, wrapping data..)
26444 // the outer template then get' applied with
26445 // the store 'extra data'
26446 // and the body get's added to the
26447 // roo-name="data" node?
26448 // <span class='roo-tpl-{name}'></span> ?????
26452 this.clearSelections();
26453 this.el.update("");
26455 var records = this.store.getRange();
26456 if(records.length < 1) {
26458 // is this valid?? = should it render a template??
26460 this.el.update(this.emptyText);
26464 if (this.dataName) {
26465 this.el.update(t.apply(this.store.meta)); //????
26466 el = this.el.child('.roo-tpl-' + this.dataName);
26469 for(var i = 0, len = records.length; i < len; i++){
26470 var data = this.prepareData(records[i].data, i, records[i]);
26471 this.fireEvent("preparedata", this, data, i, records[i]);
26473 var d = Roo.apply({}, data);
26476 Roo.apply(d, {'roo-id' : Roo.id()});
26480 Roo.each(this.parent.item, function(item){
26481 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26484 Roo.apply(d, {'roo-data-checked' : 'checked'});
26488 html[html.length] = Roo.util.Format.trim(
26490 t.applySubtemplate(this.dataName, d, this.store.meta) :
26497 el.update(html.join(""));
26498 this.nodes = el.dom.childNodes;
26499 this.updateIndexes(0);
26504 * Function to override to reformat the data that is sent to
26505 * the template for each node.
26506 * DEPRICATED - use the preparedata event handler.
26507 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26508 * a JSON object for an UpdateManager bound view).
26510 prepareData : function(data, index, record)
26512 this.fireEvent("preparedata", this, data, index, record);
26516 onUpdate : function(ds, record){
26517 // Roo.log('on update');
26518 this.clearSelections();
26519 var index = this.store.indexOf(record);
26520 var n = this.nodes[index];
26521 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26522 n.parentNode.removeChild(n);
26523 this.updateIndexes(index, index);
26529 onAdd : function(ds, records, index)
26531 //Roo.log(['on Add', ds, records, index] );
26532 this.clearSelections();
26533 if(this.nodes.length == 0){
26537 var n = this.nodes[index];
26538 for(var i = 0, len = records.length; i < len; i++){
26539 var d = this.prepareData(records[i].data, i, records[i]);
26541 this.tpl.insertBefore(n, d);
26544 this.tpl.append(this.el, d);
26547 this.updateIndexes(index);
26550 onRemove : function(ds, record, index){
26551 // Roo.log('onRemove');
26552 this.clearSelections();
26553 var el = this.dataName ?
26554 this.el.child('.roo-tpl-' + this.dataName) :
26557 el.dom.removeChild(this.nodes[index]);
26558 this.updateIndexes(index);
26562 * Refresh an individual node.
26563 * @param {Number} index
26565 refreshNode : function(index){
26566 this.onUpdate(this.store, this.store.getAt(index));
26569 updateIndexes : function(startIndex, endIndex){
26570 var ns = this.nodes;
26571 startIndex = startIndex || 0;
26572 endIndex = endIndex || ns.length - 1;
26573 for(var i = startIndex; i <= endIndex; i++){
26574 ns[i].nodeIndex = i;
26579 * Changes the data store this view uses and refresh the view.
26580 * @param {Store} store
26582 setStore : function(store, initial){
26583 if(!initial && this.store){
26584 this.store.un("datachanged", this.refresh);
26585 this.store.un("add", this.onAdd);
26586 this.store.un("remove", this.onRemove);
26587 this.store.un("update", this.onUpdate);
26588 this.store.un("clear", this.refresh);
26589 this.store.un("beforeload", this.onBeforeLoad);
26590 this.store.un("load", this.onLoad);
26591 this.store.un("loadexception", this.onLoad);
26595 store.on("datachanged", this.refresh, this);
26596 store.on("add", this.onAdd, this);
26597 store.on("remove", this.onRemove, this);
26598 store.on("update", this.onUpdate, this);
26599 store.on("clear", this.refresh, this);
26600 store.on("beforeload", this.onBeforeLoad, this);
26601 store.on("load", this.onLoad, this);
26602 store.on("loadexception", this.onLoad, this);
26610 * onbeforeLoad - masks the loading area.
26613 onBeforeLoad : function(store,opts)
26615 //Roo.log('onBeforeLoad');
26617 this.el.update("");
26619 this.el.mask(this.mask ? this.mask : "Loading" );
26621 onLoad : function ()
26628 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26629 * @param {HTMLElement} node
26630 * @return {HTMLElement} The template node
26632 findItemFromChild : function(node){
26633 var el = this.dataName ?
26634 this.el.child('.roo-tpl-' + this.dataName,true) :
26637 if(!node || node.parentNode == el){
26640 var p = node.parentNode;
26641 while(p && p != el){
26642 if(p.parentNode == el){
26651 onClick : function(e){
26652 var item = this.findItemFromChild(e.getTarget());
26654 var index = this.indexOf(item);
26655 if(this.onItemClick(item, index, e) !== false){
26656 this.fireEvent("click", this, index, item, e);
26659 this.clearSelections();
26664 onContextMenu : function(e){
26665 var item = this.findItemFromChild(e.getTarget());
26667 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26672 onDblClick : function(e){
26673 var item = this.findItemFromChild(e.getTarget());
26675 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26679 onItemClick : function(item, index, e)
26681 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26684 if (this.toggleSelect) {
26685 var m = this.isSelected(item) ? 'unselect' : 'select';
26688 _t[m](item, true, false);
26691 if(this.multiSelect || this.singleSelect){
26692 if(this.multiSelect && e.shiftKey && this.lastSelection){
26693 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26695 this.select(item, this.multiSelect && e.ctrlKey);
26696 this.lastSelection = item;
26699 if(!this.tickable){
26700 e.preventDefault();
26708 * Get the number of selected nodes.
26711 getSelectionCount : function(){
26712 return this.selections.length;
26716 * Get the currently selected nodes.
26717 * @return {Array} An array of HTMLElements
26719 getSelectedNodes : function(){
26720 return this.selections;
26724 * Get the indexes of the selected nodes.
26727 getSelectedIndexes : function(){
26728 var indexes = [], s = this.selections;
26729 for(var i = 0, len = s.length; i < len; i++){
26730 indexes.push(s[i].nodeIndex);
26736 * Clear all selections
26737 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
26739 clearSelections : function(suppressEvent){
26740 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
26741 this.cmp.elements = this.selections;
26742 this.cmp.removeClass(this.selectedClass);
26743 this.selections = [];
26744 if(!suppressEvent){
26745 this.fireEvent("selectionchange", this, this.selections);
26751 * Returns true if the passed node is selected
26752 * @param {HTMLElement/Number} node The node or node index
26753 * @return {Boolean}
26755 isSelected : function(node){
26756 var s = this.selections;
26760 node = this.getNode(node);
26761 return s.indexOf(node) !== -1;
26766 * @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
26767 * @param {Boolean} keepExisting (optional) true to keep existing selections
26768 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26770 select : function(nodeInfo, keepExisting, suppressEvent){
26771 if(nodeInfo instanceof Array){
26773 this.clearSelections(true);
26775 for(var i = 0, len = nodeInfo.length; i < len; i++){
26776 this.select(nodeInfo[i], true, true);
26780 var node = this.getNode(nodeInfo);
26781 if(!node || this.isSelected(node)){
26782 return; // already selected.
26785 this.clearSelections(true);
26788 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
26789 Roo.fly(node).addClass(this.selectedClass);
26790 this.selections.push(node);
26791 if(!suppressEvent){
26792 this.fireEvent("selectionchange", this, this.selections);
26800 * @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
26801 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
26802 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26804 unselect : function(nodeInfo, keepExisting, suppressEvent)
26806 if(nodeInfo instanceof Array){
26807 Roo.each(this.selections, function(s) {
26808 this.unselect(s, nodeInfo);
26812 var node = this.getNode(nodeInfo);
26813 if(!node || !this.isSelected(node)){
26814 //Roo.log("not selected");
26815 return; // not selected.
26819 Roo.each(this.selections, function(s) {
26821 Roo.fly(node).removeClass(this.selectedClass);
26828 this.selections= ns;
26829 this.fireEvent("selectionchange", this, this.selections);
26833 * Gets a template node.
26834 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26835 * @return {HTMLElement} The node or null if it wasn't found
26837 getNode : function(nodeInfo){
26838 if(typeof nodeInfo == "string"){
26839 return document.getElementById(nodeInfo);
26840 }else if(typeof nodeInfo == "number"){
26841 return this.nodes[nodeInfo];
26847 * Gets a range template nodes.
26848 * @param {Number} startIndex
26849 * @param {Number} endIndex
26850 * @return {Array} An array of nodes
26852 getNodes : function(start, end){
26853 var ns = this.nodes;
26854 start = start || 0;
26855 end = typeof end == "undefined" ? ns.length - 1 : end;
26858 for(var i = start; i <= end; i++){
26862 for(var i = start; i >= end; i--){
26870 * Finds the index of the passed node
26871 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26872 * @return {Number} The index of the node or -1
26874 indexOf : function(node){
26875 node = this.getNode(node);
26876 if(typeof node.nodeIndex == "number"){
26877 return node.nodeIndex;
26879 var ns = this.nodes;
26880 for(var i = 0, len = ns.length; i < len; i++){
26890 * Ext JS Library 1.1.1
26891 * Copyright(c) 2006-2007, Ext JS, LLC.
26893 * Originally Released Under LGPL - original licence link has changed is not relivant.
26896 * <script type="text/javascript">
26900 * @class Roo.JsonView
26901 * @extends Roo.View
26902 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
26904 var view = new Roo.JsonView({
26905 container: "my-element",
26906 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
26911 // listen for node click?
26912 view.on("click", function(vw, index, node, e){
26913 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26916 // direct load of JSON data
26917 view.load("foobar.php");
26919 // Example from my blog list
26920 var tpl = new Roo.Template(
26921 '<div class="entry">' +
26922 '<a class="entry-title" href="{link}">{title}</a>' +
26923 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
26924 "</div><hr />"
26927 var moreView = new Roo.JsonView({
26928 container : "entry-list",
26932 moreView.on("beforerender", this.sortEntries, this);
26934 url: "/blog/get-posts.php",
26935 params: "allposts=true",
26936 text: "Loading Blog Entries..."
26940 * Note: old code is supported with arguments : (container, template, config)
26944 * Create a new JsonView
26946 * @param {Object} config The config object
26949 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
26952 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
26954 var um = this.el.getUpdateManager();
26955 um.setRenderer(this);
26956 um.on("update", this.onLoad, this);
26957 um.on("failure", this.onLoadException, this);
26960 * @event beforerender
26961 * Fires before rendering of the downloaded JSON data.
26962 * @param {Roo.JsonView} this
26963 * @param {Object} data The JSON data loaded
26967 * Fires when data is loaded.
26968 * @param {Roo.JsonView} this
26969 * @param {Object} data The JSON data loaded
26970 * @param {Object} response The raw Connect response object
26973 * @event loadexception
26974 * Fires when loading fails.
26975 * @param {Roo.JsonView} this
26976 * @param {Object} response The raw Connect response object
26979 'beforerender' : true,
26981 'loadexception' : true
26984 Roo.extend(Roo.JsonView, Roo.View, {
26986 * @type {String} The root property in the loaded JSON object that contains the data
26991 * Refreshes the view.
26993 refresh : function(){
26994 this.clearSelections();
26995 this.el.update("");
26997 var o = this.jsonData;
26998 if(o && o.length > 0){
26999 for(var i = 0, len = o.length; i < len; i++){
27000 var data = this.prepareData(o[i], i, o);
27001 html[html.length] = this.tpl.apply(data);
27004 html.push(this.emptyText);
27006 this.el.update(html.join(""));
27007 this.nodes = this.el.dom.childNodes;
27008 this.updateIndexes(0);
27012 * 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.
27013 * @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:
27016 url: "your-url.php",
27017 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27018 callback: yourFunction,
27019 scope: yourObject, //(optional scope)
27022 text: "Loading...",
27027 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27028 * 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.
27029 * @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}
27030 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27031 * @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.
27034 var um = this.el.getUpdateManager();
27035 um.update.apply(um, arguments);
27038 render : function(el, response){
27039 this.clearSelections();
27040 this.el.update("");
27043 o = Roo.util.JSON.decode(response.responseText);
27046 o = o[this.jsonRoot];
27051 * The current JSON data or null
27054 this.beforeRender();
27059 * Get the number of records in the current JSON dataset
27062 getCount : function(){
27063 return this.jsonData ? this.jsonData.length : 0;
27067 * Returns the JSON object for the specified node(s)
27068 * @param {HTMLElement/Array} node The node or an array of nodes
27069 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27070 * you get the JSON object for the node
27072 getNodeData : function(node){
27073 if(node instanceof Array){
27075 for(var i = 0, len = node.length; i < len; i++){
27076 data.push(this.getNodeData(node[i]));
27080 return this.jsonData[this.indexOf(node)] || null;
27083 beforeRender : function(){
27084 this.snapshot = this.jsonData;
27086 this.sort.apply(this, this.sortInfo);
27088 this.fireEvent("beforerender", this, this.jsonData);
27091 onLoad : function(el, o){
27092 this.fireEvent("load", this, this.jsonData, o);
27095 onLoadException : function(el, o){
27096 this.fireEvent("loadexception", this, o);
27100 * Filter the data by a specific property.
27101 * @param {String} property A property on your JSON objects
27102 * @param {String/RegExp} value Either string that the property values
27103 * should start with, or a RegExp to test against the property
27105 filter : function(property, value){
27108 var ss = this.snapshot;
27109 if(typeof value == "string"){
27110 var vlen = value.length;
27112 this.clearFilter();
27115 value = value.toLowerCase();
27116 for(var i = 0, len = ss.length; i < len; i++){
27118 if(o[property].substr(0, vlen).toLowerCase() == value){
27122 } else if(value.exec){ // regex?
27123 for(var i = 0, len = ss.length; i < len; i++){
27125 if(value.test(o[property])){
27132 this.jsonData = data;
27138 * Filter by a function. The passed function will be called with each
27139 * object in the current dataset. If the function returns true the value is kept,
27140 * otherwise it is filtered.
27141 * @param {Function} fn
27142 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27144 filterBy : function(fn, scope){
27147 var ss = this.snapshot;
27148 for(var i = 0, len = ss.length; i < len; i++){
27150 if(fn.call(scope || this, o)){
27154 this.jsonData = data;
27160 * Clears the current filter.
27162 clearFilter : function(){
27163 if(this.snapshot && this.jsonData != this.snapshot){
27164 this.jsonData = this.snapshot;
27171 * Sorts the data for this view and refreshes it.
27172 * @param {String} property A property on your JSON objects to sort on
27173 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27174 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27176 sort : function(property, dir, sortType){
27177 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27180 var dsc = dir && dir.toLowerCase() == "desc";
27181 var f = function(o1, o2){
27182 var v1 = sortType ? sortType(o1[p]) : o1[p];
27183 var v2 = sortType ? sortType(o2[p]) : o2[p];
27186 return dsc ? +1 : -1;
27187 } else if(v1 > v2){
27188 return dsc ? -1 : +1;
27193 this.jsonData.sort(f);
27195 if(this.jsonData != this.snapshot){
27196 this.snapshot.sort(f);
27202 * Ext JS Library 1.1.1
27203 * Copyright(c) 2006-2007, Ext JS, LLC.
27205 * Originally Released Under LGPL - original licence link has changed is not relivant.
27208 * <script type="text/javascript">
27213 * @class Roo.ColorPalette
27214 * @extends Roo.Component
27215 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27216 * Here's an example of typical usage:
27218 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27219 cp.render('my-div');
27221 cp.on('select', function(palette, selColor){
27222 // do something with selColor
27226 * Create a new ColorPalette
27227 * @param {Object} config The config object
27229 Roo.ColorPalette = function(config){
27230 Roo.ColorPalette.superclass.constructor.call(this, config);
27234 * Fires when a color is selected
27235 * @param {ColorPalette} this
27236 * @param {String} color The 6-digit color hex code (without the # symbol)
27242 this.on("select", this.handler, this.scope, true);
27245 Roo.extend(Roo.ColorPalette, Roo.Component, {
27247 * @cfg {String} itemCls
27248 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27250 itemCls : "x-color-palette",
27252 * @cfg {String} value
27253 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27254 * the hex codes are case-sensitive.
27257 clickEvent:'click',
27259 ctype: "Roo.ColorPalette",
27262 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27264 allowReselect : false,
27267 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27268 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27269 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27270 * of colors with the width setting until the box is symmetrical.</p>
27271 * <p>You can override individual colors if needed:</p>
27273 var cp = new Roo.ColorPalette();
27274 cp.colors[0] = "FF0000"; // change the first box to red
27277 Or you can provide a custom array of your own for complete control:
27279 var cp = new Roo.ColorPalette();
27280 cp.colors = ["000000", "993300", "333300"];
27285 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27286 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27287 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27288 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27289 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27293 onRender : function(container, position){
27294 var t = new Roo.MasterTemplate(
27295 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27297 var c = this.colors;
27298 for(var i = 0, len = c.length; i < len; i++){
27301 var el = document.createElement("div");
27302 el.className = this.itemCls;
27304 container.dom.insertBefore(el, position);
27305 this.el = Roo.get(el);
27306 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27307 if(this.clickEvent != 'click'){
27308 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27313 afterRender : function(){
27314 Roo.ColorPalette.superclass.afterRender.call(this);
27316 var s = this.value;
27323 handleClick : function(e, t){
27324 e.preventDefault();
27325 if(!this.disabled){
27326 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27327 this.select(c.toUpperCase());
27332 * Selects the specified color in the palette (fires the select event)
27333 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27335 select : function(color){
27336 color = color.replace("#", "");
27337 if(color != this.value || this.allowReselect){
27340 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27342 el.child("a.color-"+color).addClass("x-color-palette-sel");
27343 this.value = color;
27344 this.fireEvent("select", this, color);
27349 * Ext JS Library 1.1.1
27350 * Copyright(c) 2006-2007, Ext JS, LLC.
27352 * Originally Released Under LGPL - original licence link has changed is not relivant.
27355 * <script type="text/javascript">
27359 * @class Roo.DatePicker
27360 * @extends Roo.Component
27361 * Simple date picker class.
27363 * Create a new DatePicker
27364 * @param {Object} config The config object
27366 Roo.DatePicker = function(config){
27367 Roo.DatePicker.superclass.constructor.call(this, config);
27369 this.value = config && config.value ?
27370 config.value.clearTime() : new Date().clearTime();
27375 * Fires when a date is selected
27376 * @param {DatePicker} this
27377 * @param {Date} date The selected date
27381 * @event monthchange
27382 * Fires when the displayed month changes
27383 * @param {DatePicker} this
27384 * @param {Date} date The selected month
27386 'monthchange': true
27390 this.on("select", this.handler, this.scope || this);
27392 // build the disabledDatesRE
27393 if(!this.disabledDatesRE && this.disabledDates){
27394 var dd = this.disabledDates;
27396 for(var i = 0; i < dd.length; i++){
27398 if(i != dd.length-1) {
27402 this.disabledDatesRE = new RegExp(re + ")");
27406 Roo.extend(Roo.DatePicker, Roo.Component, {
27408 * @cfg {String} todayText
27409 * The text to display on the button that selects the current date (defaults to "Today")
27411 todayText : "Today",
27413 * @cfg {String} okText
27414 * The text to display on the ok button
27416 okText : " OK ", //   to give the user extra clicking room
27418 * @cfg {String} cancelText
27419 * The text to display on the cancel button
27421 cancelText : "Cancel",
27423 * @cfg {String} todayTip
27424 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27426 todayTip : "{0} (Spacebar)",
27428 * @cfg {Date} minDate
27429 * Minimum allowable date (JavaScript date object, defaults to null)
27433 * @cfg {Date} maxDate
27434 * Maximum allowable date (JavaScript date object, defaults to null)
27438 * @cfg {String} minText
27439 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27441 minText : "This date is before the minimum date",
27443 * @cfg {String} maxText
27444 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27446 maxText : "This date is after the maximum date",
27448 * @cfg {String} format
27449 * The default date format string which can be overriden for localization support. The format must be
27450 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27454 * @cfg {Array} disabledDays
27455 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27457 disabledDays : null,
27459 * @cfg {String} disabledDaysText
27460 * The tooltip to display when the date falls on a disabled day (defaults to "")
27462 disabledDaysText : "",
27464 * @cfg {RegExp} disabledDatesRE
27465 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27467 disabledDatesRE : null,
27469 * @cfg {String} disabledDatesText
27470 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27472 disabledDatesText : "",
27474 * @cfg {Boolean} constrainToViewport
27475 * True to constrain the date picker to the viewport (defaults to true)
27477 constrainToViewport : true,
27479 * @cfg {Array} monthNames
27480 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27482 monthNames : Date.monthNames,
27484 * @cfg {Array} dayNames
27485 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27487 dayNames : Date.dayNames,
27489 * @cfg {String} nextText
27490 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27492 nextText: 'Next Month (Control+Right)',
27494 * @cfg {String} prevText
27495 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27497 prevText: 'Previous Month (Control+Left)',
27499 * @cfg {String} monthYearText
27500 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27502 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27504 * @cfg {Number} startDay
27505 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27509 * @cfg {Bool} showClear
27510 * Show a clear button (usefull for date form elements that can be blank.)
27516 * Sets the value of the date field
27517 * @param {Date} value The date to set
27519 setValue : function(value){
27520 var old = this.value;
27522 if (typeof(value) == 'string') {
27524 value = Date.parseDate(value, this.format);
27527 value = new Date();
27530 this.value = value.clearTime(true);
27532 this.update(this.value);
27537 * Gets the current selected value of the date field
27538 * @return {Date} The selected date
27540 getValue : function(){
27545 focus : function(){
27547 this.update(this.activeDate);
27552 onRender : function(container, position){
27555 '<table cellspacing="0">',
27556 '<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>',
27557 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27558 var dn = this.dayNames;
27559 for(var i = 0; i < 7; i++){
27560 var d = this.startDay+i;
27564 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27566 m[m.length] = "</tr></thead><tbody><tr>";
27567 for(var i = 0; i < 42; i++) {
27568 if(i % 7 == 0 && i != 0){
27569 m[m.length] = "</tr><tr>";
27571 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27573 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27574 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27576 var el = document.createElement("div");
27577 el.className = "x-date-picker";
27578 el.innerHTML = m.join("");
27580 container.dom.insertBefore(el, position);
27582 this.el = Roo.get(el);
27583 this.eventEl = Roo.get(el.firstChild);
27585 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27586 handler: this.showPrevMonth,
27588 preventDefault:true,
27592 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27593 handler: this.showNextMonth,
27595 preventDefault:true,
27599 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27601 this.monthPicker = this.el.down('div.x-date-mp');
27602 this.monthPicker.enableDisplayMode('block');
27604 var kn = new Roo.KeyNav(this.eventEl, {
27605 "left" : function(e){
27607 this.showPrevMonth() :
27608 this.update(this.activeDate.add("d", -1));
27611 "right" : function(e){
27613 this.showNextMonth() :
27614 this.update(this.activeDate.add("d", 1));
27617 "up" : function(e){
27619 this.showNextYear() :
27620 this.update(this.activeDate.add("d", -7));
27623 "down" : function(e){
27625 this.showPrevYear() :
27626 this.update(this.activeDate.add("d", 7));
27629 "pageUp" : function(e){
27630 this.showNextMonth();
27633 "pageDown" : function(e){
27634 this.showPrevMonth();
27637 "enter" : function(e){
27638 e.stopPropagation();
27645 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27647 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27649 this.el.unselectable();
27651 this.cells = this.el.select("table.x-date-inner tbody td");
27652 this.textNodes = this.el.query("table.x-date-inner tbody span");
27654 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27656 tooltip: this.monthYearText
27659 this.mbtn.on('click', this.showMonthPicker, this);
27660 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27663 var today = (new Date()).dateFormat(this.format);
27665 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27666 if (this.showClear) {
27667 baseTb.add( new Roo.Toolbar.Fill());
27670 text: String.format(this.todayText, today),
27671 tooltip: String.format(this.todayTip, today),
27672 handler: this.selectToday,
27676 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27679 if (this.showClear) {
27681 baseTb.add( new Roo.Toolbar.Fill());
27684 cls: 'x-btn-icon x-btn-clear',
27685 handler: function() {
27687 this.fireEvent("select", this, '');
27697 this.update(this.value);
27700 createMonthPicker : function(){
27701 if(!this.monthPicker.dom.firstChild){
27702 var buf = ['<table border="0" cellspacing="0">'];
27703 for(var i = 0; i < 6; i++){
27705 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27706 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27708 '<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>' :
27709 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27713 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27715 '</button><button type="button" class="x-date-mp-cancel">',
27717 '</button></td></tr>',
27720 this.monthPicker.update(buf.join(''));
27721 this.monthPicker.on('click', this.onMonthClick, this);
27722 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
27724 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
27725 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
27727 this.mpMonths.each(function(m, a, i){
27730 m.dom.xmonth = 5 + Math.round(i * .5);
27732 m.dom.xmonth = Math.round((i-1) * .5);
27738 showMonthPicker : function(){
27739 this.createMonthPicker();
27740 var size = this.el.getSize();
27741 this.monthPicker.setSize(size);
27742 this.monthPicker.child('table').setSize(size);
27744 this.mpSelMonth = (this.activeDate || this.value).getMonth();
27745 this.updateMPMonth(this.mpSelMonth);
27746 this.mpSelYear = (this.activeDate || this.value).getFullYear();
27747 this.updateMPYear(this.mpSelYear);
27749 this.monthPicker.slideIn('t', {duration:.2});
27752 updateMPYear : function(y){
27754 var ys = this.mpYears.elements;
27755 for(var i = 1; i <= 10; i++){
27756 var td = ys[i-1], y2;
27758 y2 = y + Math.round(i * .5);
27759 td.firstChild.innerHTML = y2;
27762 y2 = y - (5-Math.round(i * .5));
27763 td.firstChild.innerHTML = y2;
27766 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
27770 updateMPMonth : function(sm){
27771 this.mpMonths.each(function(m, a, i){
27772 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
27776 selectMPMonth: function(m){
27780 onMonthClick : function(e, t){
27782 var el = new Roo.Element(t), pn;
27783 if(el.is('button.x-date-mp-cancel')){
27784 this.hideMonthPicker();
27786 else if(el.is('button.x-date-mp-ok')){
27787 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27788 this.hideMonthPicker();
27790 else if(pn = el.up('td.x-date-mp-month', 2)){
27791 this.mpMonths.removeClass('x-date-mp-sel');
27792 pn.addClass('x-date-mp-sel');
27793 this.mpSelMonth = pn.dom.xmonth;
27795 else if(pn = el.up('td.x-date-mp-year', 2)){
27796 this.mpYears.removeClass('x-date-mp-sel');
27797 pn.addClass('x-date-mp-sel');
27798 this.mpSelYear = pn.dom.xyear;
27800 else if(el.is('a.x-date-mp-prev')){
27801 this.updateMPYear(this.mpyear-10);
27803 else if(el.is('a.x-date-mp-next')){
27804 this.updateMPYear(this.mpyear+10);
27808 onMonthDblClick : function(e, t){
27810 var el = new Roo.Element(t), pn;
27811 if(pn = el.up('td.x-date-mp-month', 2)){
27812 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
27813 this.hideMonthPicker();
27815 else if(pn = el.up('td.x-date-mp-year', 2)){
27816 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27817 this.hideMonthPicker();
27821 hideMonthPicker : function(disableAnim){
27822 if(this.monthPicker){
27823 if(disableAnim === true){
27824 this.monthPicker.hide();
27826 this.monthPicker.slideOut('t', {duration:.2});
27832 showPrevMonth : function(e){
27833 this.update(this.activeDate.add("mo", -1));
27837 showNextMonth : function(e){
27838 this.update(this.activeDate.add("mo", 1));
27842 showPrevYear : function(){
27843 this.update(this.activeDate.add("y", -1));
27847 showNextYear : function(){
27848 this.update(this.activeDate.add("y", 1));
27852 handleMouseWheel : function(e){
27853 var delta = e.getWheelDelta();
27855 this.showPrevMonth();
27857 } else if(delta < 0){
27858 this.showNextMonth();
27864 handleDateClick : function(e, t){
27866 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
27867 this.setValue(new Date(t.dateValue));
27868 this.fireEvent("select", this, this.value);
27873 selectToday : function(){
27874 this.setValue(new Date().clearTime());
27875 this.fireEvent("select", this, this.value);
27879 update : function(date)
27881 var vd = this.activeDate;
27882 this.activeDate = date;
27884 var t = date.getTime();
27885 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
27886 this.cells.removeClass("x-date-selected");
27887 this.cells.each(function(c){
27888 if(c.dom.firstChild.dateValue == t){
27889 c.addClass("x-date-selected");
27890 setTimeout(function(){
27891 try{c.dom.firstChild.focus();}catch(e){}
27900 var days = date.getDaysInMonth();
27901 var firstOfMonth = date.getFirstDateOfMonth();
27902 var startingPos = firstOfMonth.getDay()-this.startDay;
27904 if(startingPos <= this.startDay){
27908 var pm = date.add("mo", -1);
27909 var prevStart = pm.getDaysInMonth()-startingPos;
27911 var cells = this.cells.elements;
27912 var textEls = this.textNodes;
27913 days += startingPos;
27915 // convert everything to numbers so it's fast
27916 var day = 86400000;
27917 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
27918 var today = new Date().clearTime().getTime();
27919 var sel = date.clearTime().getTime();
27920 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
27921 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
27922 var ddMatch = this.disabledDatesRE;
27923 var ddText = this.disabledDatesText;
27924 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
27925 var ddaysText = this.disabledDaysText;
27926 var format = this.format;
27928 var setCellClass = function(cal, cell){
27930 var t = d.getTime();
27931 cell.firstChild.dateValue = t;
27933 cell.className += " x-date-today";
27934 cell.title = cal.todayText;
27937 cell.className += " x-date-selected";
27938 setTimeout(function(){
27939 try{cell.firstChild.focus();}catch(e){}
27944 cell.className = " x-date-disabled";
27945 cell.title = cal.minText;
27949 cell.className = " x-date-disabled";
27950 cell.title = cal.maxText;
27954 if(ddays.indexOf(d.getDay()) != -1){
27955 cell.title = ddaysText;
27956 cell.className = " x-date-disabled";
27959 if(ddMatch && format){
27960 var fvalue = d.dateFormat(format);
27961 if(ddMatch.test(fvalue)){
27962 cell.title = ddText.replace("%0", fvalue);
27963 cell.className = " x-date-disabled";
27969 for(; i < startingPos; i++) {
27970 textEls[i].innerHTML = (++prevStart);
27971 d.setDate(d.getDate()+1);
27972 cells[i].className = "x-date-prevday";
27973 setCellClass(this, cells[i]);
27975 for(; i < days; i++){
27976 intDay = i - startingPos + 1;
27977 textEls[i].innerHTML = (intDay);
27978 d.setDate(d.getDate()+1);
27979 cells[i].className = "x-date-active";
27980 setCellClass(this, cells[i]);
27983 for(; i < 42; i++) {
27984 textEls[i].innerHTML = (++extraDays);
27985 d.setDate(d.getDate()+1);
27986 cells[i].className = "x-date-nextday";
27987 setCellClass(this, cells[i]);
27990 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
27991 this.fireEvent('monthchange', this, date);
27993 if(!this.internalRender){
27994 var main = this.el.dom.firstChild;
27995 var w = main.offsetWidth;
27996 this.el.setWidth(w + this.el.getBorderWidth("lr"));
27997 Roo.fly(main).setWidth(w);
27998 this.internalRender = true;
27999 // opera does not respect the auto grow header center column
28000 // then, after it gets a width opera refuses to recalculate
28001 // without a second pass
28002 if(Roo.isOpera && !this.secondPass){
28003 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28004 this.secondPass = true;
28005 this.update.defer(10, this, [date]);
28013 * Ext JS Library 1.1.1
28014 * Copyright(c) 2006-2007, Ext JS, LLC.
28016 * Originally Released Under LGPL - original licence link has changed is not relivant.
28019 * <script type="text/javascript">
28022 * @class Roo.TabPanel
28023 * @extends Roo.util.Observable
28024 * A lightweight tab container.
28028 // basic tabs 1, built from existing content
28029 var tabs = new Roo.TabPanel("tabs1");
28030 tabs.addTab("script", "View Script");
28031 tabs.addTab("markup", "View Markup");
28032 tabs.activate("script");
28034 // more advanced tabs, built from javascript
28035 var jtabs = new Roo.TabPanel("jtabs");
28036 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28038 // set up the UpdateManager
28039 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28040 var updater = tab2.getUpdateManager();
28041 updater.setDefaultUrl("ajax1.htm");
28042 tab2.on('activate', updater.refresh, updater, true);
28044 // Use setUrl for Ajax loading
28045 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28046 tab3.setUrl("ajax2.htm", null, true);
28049 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28052 jtabs.activate("jtabs-1");
28055 * Create a new TabPanel.
28056 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28057 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28059 Roo.TabPanel = function(container, config){
28061 * The container element for this TabPanel.
28062 * @type Roo.Element
28064 this.el = Roo.get(container, true);
28066 if(typeof config == "boolean"){
28067 this.tabPosition = config ? "bottom" : "top";
28069 Roo.apply(this, config);
28072 if(this.tabPosition == "bottom"){
28073 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28074 this.el.addClass("x-tabs-bottom");
28076 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28077 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28078 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28080 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28082 if(this.tabPosition != "bottom"){
28083 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28084 * @type Roo.Element
28086 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28087 this.el.addClass("x-tabs-top");
28091 this.bodyEl.setStyle("position", "relative");
28093 this.active = null;
28094 this.activateDelegate = this.activate.createDelegate(this);
28099 * Fires when the active tab changes
28100 * @param {Roo.TabPanel} this
28101 * @param {Roo.TabPanelItem} activePanel The new active tab
28105 * @event beforetabchange
28106 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28107 * @param {Roo.TabPanel} this
28108 * @param {Object} e Set cancel to true on this object to cancel the tab change
28109 * @param {Roo.TabPanelItem} tab The tab being changed to
28111 "beforetabchange" : true
28114 Roo.EventManager.onWindowResize(this.onResize, this);
28115 this.cpad = this.el.getPadding("lr");
28116 this.hiddenCount = 0;
28119 // toolbar on the tabbar support...
28120 if (this.toolbar) {
28121 var tcfg = this.toolbar;
28122 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28123 this.toolbar = new Roo.Toolbar(tcfg);
28124 if (Roo.isSafari) {
28125 var tbl = tcfg.container.child('table', true);
28126 tbl.setAttribute('width', '100%');
28133 Roo.TabPanel.superclass.constructor.call(this);
28136 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28138 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28140 tabPosition : "top",
28142 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28144 currentTabWidth : 0,
28146 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28150 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28154 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28156 preferredTabWidth : 175,
28158 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28160 resizeTabs : false,
28162 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28164 monitorResize : true,
28166 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28171 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28172 * @param {String} id The id of the div to use <b>or create</b>
28173 * @param {String} text The text for the tab
28174 * @param {String} content (optional) Content to put in the TabPanelItem body
28175 * @param {Boolean} closable (optional) True to create a close icon on the tab
28176 * @return {Roo.TabPanelItem} The created TabPanelItem
28178 addTab : function(id, text, content, closable){
28179 var item = new Roo.TabPanelItem(this, id, text, closable);
28180 this.addTabItem(item);
28182 item.setContent(content);
28188 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28189 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28190 * @return {Roo.TabPanelItem}
28192 getTab : function(id){
28193 return this.items[id];
28197 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28198 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28200 hideTab : function(id){
28201 var t = this.items[id];
28204 this.hiddenCount++;
28205 this.autoSizeTabs();
28210 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28211 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28213 unhideTab : function(id){
28214 var t = this.items[id];
28216 t.setHidden(false);
28217 this.hiddenCount--;
28218 this.autoSizeTabs();
28223 * Adds an existing {@link Roo.TabPanelItem}.
28224 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28226 addTabItem : function(item){
28227 this.items[item.id] = item;
28228 this.items.push(item);
28229 if(this.resizeTabs){
28230 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28231 this.autoSizeTabs();
28238 * Removes a {@link Roo.TabPanelItem}.
28239 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28241 removeTab : function(id){
28242 var items = this.items;
28243 var tab = items[id];
28244 if(!tab) { return; }
28245 var index = items.indexOf(tab);
28246 if(this.active == tab && items.length > 1){
28247 var newTab = this.getNextAvailable(index);
28252 this.stripEl.dom.removeChild(tab.pnode.dom);
28253 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28254 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28256 items.splice(index, 1);
28257 delete this.items[tab.id];
28258 tab.fireEvent("close", tab);
28259 tab.purgeListeners();
28260 this.autoSizeTabs();
28263 getNextAvailable : function(start){
28264 var items = this.items;
28266 // look for a next tab that will slide over to
28267 // replace the one being removed
28268 while(index < items.length){
28269 var item = items[++index];
28270 if(item && !item.isHidden()){
28274 // if one isn't found select the previous tab (on the left)
28277 var item = items[--index];
28278 if(item && !item.isHidden()){
28286 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28287 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28289 disableTab : function(id){
28290 var tab = this.items[id];
28291 if(tab && this.active != tab){
28297 * Enables a {@link Roo.TabPanelItem} that is disabled.
28298 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28300 enableTab : function(id){
28301 var tab = this.items[id];
28306 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28307 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28308 * @return {Roo.TabPanelItem} The TabPanelItem.
28310 activate : function(id){
28311 var tab = this.items[id];
28315 if(tab == this.active || tab.disabled){
28319 this.fireEvent("beforetabchange", this, e, tab);
28320 if(e.cancel !== true && !tab.disabled){
28322 this.active.hide();
28324 this.active = this.items[id];
28325 this.active.show();
28326 this.fireEvent("tabchange", this, this.active);
28332 * Gets the active {@link Roo.TabPanelItem}.
28333 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28335 getActiveTab : function(){
28336 return this.active;
28340 * Updates the tab body element to fit the height of the container element
28341 * for overflow scrolling
28342 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28344 syncHeight : function(targetHeight){
28345 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28346 var bm = this.bodyEl.getMargins();
28347 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28348 this.bodyEl.setHeight(newHeight);
28352 onResize : function(){
28353 if(this.monitorResize){
28354 this.autoSizeTabs();
28359 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28361 beginUpdate : function(){
28362 this.updating = true;
28366 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28368 endUpdate : function(){
28369 this.updating = false;
28370 this.autoSizeTabs();
28374 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28376 autoSizeTabs : function(){
28377 var count = this.items.length;
28378 var vcount = count - this.hiddenCount;
28379 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28382 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28383 var availWidth = Math.floor(w / vcount);
28384 var b = this.stripBody;
28385 if(b.getWidth() > w){
28386 var tabs = this.items;
28387 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28388 if(availWidth < this.minTabWidth){
28389 /*if(!this.sleft){ // incomplete scrolling code
28390 this.createScrollButtons();
28393 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28396 if(this.currentTabWidth < this.preferredTabWidth){
28397 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28403 * Returns the number of tabs in this TabPanel.
28406 getCount : function(){
28407 return this.items.length;
28411 * Resizes all the tabs to the passed width
28412 * @param {Number} The new width
28414 setTabWidth : function(width){
28415 this.currentTabWidth = width;
28416 for(var i = 0, len = this.items.length; i < len; i++) {
28417 if(!this.items[i].isHidden()) {
28418 this.items[i].setWidth(width);
28424 * Destroys this TabPanel
28425 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28427 destroy : function(removeEl){
28428 Roo.EventManager.removeResizeListener(this.onResize, this);
28429 for(var i = 0, len = this.items.length; i < len; i++){
28430 this.items[i].purgeListeners();
28432 if(removeEl === true){
28433 this.el.update("");
28440 * @class Roo.TabPanelItem
28441 * @extends Roo.util.Observable
28442 * Represents an individual item (tab plus body) in a TabPanel.
28443 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28444 * @param {String} id The id of this TabPanelItem
28445 * @param {String} text The text for the tab of this TabPanelItem
28446 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28448 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28450 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28451 * @type Roo.TabPanel
28453 this.tabPanel = tabPanel;
28455 * The id for this TabPanelItem
28460 this.disabled = false;
28464 this.loaded = false;
28465 this.closable = closable;
28468 * The body element for this TabPanelItem.
28469 * @type Roo.Element
28471 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28472 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28473 this.bodyEl.setStyle("display", "block");
28474 this.bodyEl.setStyle("zoom", "1");
28477 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28479 this.el = Roo.get(els.el, true);
28480 this.inner = Roo.get(els.inner, true);
28481 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28482 this.pnode = Roo.get(els.el.parentNode, true);
28483 this.el.on("mousedown", this.onTabMouseDown, this);
28484 this.el.on("click", this.onTabClick, this);
28487 var c = Roo.get(els.close, true);
28488 c.dom.title = this.closeText;
28489 c.addClassOnOver("close-over");
28490 c.on("click", this.closeClick, this);
28496 * Fires when this tab becomes the active tab.
28497 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28498 * @param {Roo.TabPanelItem} this
28502 * @event beforeclose
28503 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28504 * @param {Roo.TabPanelItem} this
28505 * @param {Object} e Set cancel to true on this object to cancel the close.
28507 "beforeclose": true,
28510 * Fires when this tab is closed.
28511 * @param {Roo.TabPanelItem} this
28515 * @event deactivate
28516 * Fires when this tab is no longer the active tab.
28517 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28518 * @param {Roo.TabPanelItem} this
28520 "deactivate" : true
28522 this.hidden = false;
28524 Roo.TabPanelItem.superclass.constructor.call(this);
28527 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28528 purgeListeners : function(){
28529 Roo.util.Observable.prototype.purgeListeners.call(this);
28530 this.el.removeAllListeners();
28533 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28536 this.pnode.addClass("on");
28539 this.tabPanel.stripWrap.repaint();
28541 this.fireEvent("activate", this.tabPanel, this);
28545 * Returns true if this tab is the active tab.
28546 * @return {Boolean}
28548 isActive : function(){
28549 return this.tabPanel.getActiveTab() == this;
28553 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28556 this.pnode.removeClass("on");
28558 this.fireEvent("deactivate", this.tabPanel, this);
28561 hideAction : function(){
28562 this.bodyEl.hide();
28563 this.bodyEl.setStyle("position", "absolute");
28564 this.bodyEl.setLeft("-20000px");
28565 this.bodyEl.setTop("-20000px");
28568 showAction : function(){
28569 this.bodyEl.setStyle("position", "relative");
28570 this.bodyEl.setTop("");
28571 this.bodyEl.setLeft("");
28572 this.bodyEl.show();
28576 * Set the tooltip for the tab.
28577 * @param {String} tooltip The tab's tooltip
28579 setTooltip : function(text){
28580 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28581 this.textEl.dom.qtip = text;
28582 this.textEl.dom.removeAttribute('title');
28584 this.textEl.dom.title = text;
28588 onTabClick : function(e){
28589 e.preventDefault();
28590 this.tabPanel.activate(this.id);
28593 onTabMouseDown : function(e){
28594 e.preventDefault();
28595 this.tabPanel.activate(this.id);
28598 getWidth : function(){
28599 return this.inner.getWidth();
28602 setWidth : function(width){
28603 var iwidth = width - this.pnode.getPadding("lr");
28604 this.inner.setWidth(iwidth);
28605 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28606 this.pnode.setWidth(width);
28610 * Show or hide the tab
28611 * @param {Boolean} hidden True to hide or false to show.
28613 setHidden : function(hidden){
28614 this.hidden = hidden;
28615 this.pnode.setStyle("display", hidden ? "none" : "");
28619 * Returns true if this tab is "hidden"
28620 * @return {Boolean}
28622 isHidden : function(){
28623 return this.hidden;
28627 * Returns the text for this tab
28630 getText : function(){
28634 autoSize : function(){
28635 //this.el.beginMeasure();
28636 this.textEl.setWidth(1);
28638 * #2804 [new] Tabs in Roojs
28639 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28641 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28642 //this.el.endMeasure();
28646 * Sets the text for the tab (Note: this also sets the tooltip text)
28647 * @param {String} text The tab's text and tooltip
28649 setText : function(text){
28651 this.textEl.update(text);
28652 this.setTooltip(text);
28653 if(!this.tabPanel.resizeTabs){
28658 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28660 activate : function(){
28661 this.tabPanel.activate(this.id);
28665 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28667 disable : function(){
28668 if(this.tabPanel.active != this){
28669 this.disabled = true;
28670 this.pnode.addClass("disabled");
28675 * Enables this TabPanelItem if it was previously disabled.
28677 enable : function(){
28678 this.disabled = false;
28679 this.pnode.removeClass("disabled");
28683 * Sets the content for this TabPanelItem.
28684 * @param {String} content The content
28685 * @param {Boolean} loadScripts true to look for and load scripts
28687 setContent : function(content, loadScripts){
28688 this.bodyEl.update(content, loadScripts);
28692 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28693 * @return {Roo.UpdateManager} The UpdateManager
28695 getUpdateManager : function(){
28696 return this.bodyEl.getUpdateManager();
28700 * Set a URL to be used to load the content for this TabPanelItem.
28701 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28702 * @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)
28703 * @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)
28704 * @return {Roo.UpdateManager} The UpdateManager
28706 setUrl : function(url, params, loadOnce){
28707 if(this.refreshDelegate){
28708 this.un('activate', this.refreshDelegate);
28710 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28711 this.on("activate", this.refreshDelegate);
28712 return this.bodyEl.getUpdateManager();
28716 _handleRefresh : function(url, params, loadOnce){
28717 if(!loadOnce || !this.loaded){
28718 var updater = this.bodyEl.getUpdateManager();
28719 updater.update(url, params, this._setLoaded.createDelegate(this));
28724 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
28725 * Will fail silently if the setUrl method has not been called.
28726 * This does not activate the panel, just updates its content.
28728 refresh : function(){
28729 if(this.refreshDelegate){
28730 this.loaded = false;
28731 this.refreshDelegate();
28736 _setLoaded : function(){
28737 this.loaded = true;
28741 closeClick : function(e){
28744 this.fireEvent("beforeclose", this, o);
28745 if(o.cancel !== true){
28746 this.tabPanel.removeTab(this.id);
28750 * The text displayed in the tooltip for the close icon.
28753 closeText : "Close this tab"
28757 Roo.TabPanel.prototype.createStrip = function(container){
28758 var strip = document.createElement("div");
28759 strip.className = "x-tabs-wrap";
28760 container.appendChild(strip);
28764 Roo.TabPanel.prototype.createStripList = function(strip){
28765 // div wrapper for retard IE
28766 // returns the "tr" element.
28767 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
28768 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
28769 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
28770 return strip.firstChild.firstChild.firstChild.firstChild;
28773 Roo.TabPanel.prototype.createBody = function(container){
28774 var body = document.createElement("div");
28775 Roo.id(body, "tab-body");
28776 Roo.fly(body).addClass("x-tabs-body");
28777 container.appendChild(body);
28781 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
28782 var body = Roo.getDom(id);
28784 body = document.createElement("div");
28787 Roo.fly(body).addClass("x-tabs-item-body");
28788 bodyEl.insertBefore(body, bodyEl.firstChild);
28792 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
28793 var td = document.createElement("td");
28794 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
28795 //stripEl.appendChild(td);
28797 td.className = "x-tabs-closable";
28798 if(!this.closeTpl){
28799 this.closeTpl = new Roo.Template(
28800 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28801 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
28802 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
28805 var el = this.closeTpl.overwrite(td, {"text": text});
28806 var close = el.getElementsByTagName("div")[0];
28807 var inner = el.getElementsByTagName("em")[0];
28808 return {"el": el, "close": close, "inner": inner};
28811 this.tabTpl = new Roo.Template(
28812 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28813 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
28816 var el = this.tabTpl.overwrite(td, {"text": text});
28817 var inner = el.getElementsByTagName("em")[0];
28818 return {"el": el, "inner": inner};
28822 * Ext JS Library 1.1.1
28823 * Copyright(c) 2006-2007, Ext JS, LLC.
28825 * Originally Released Under LGPL - original licence link has changed is not relivant.
28828 * <script type="text/javascript">
28832 * @class Roo.Button
28833 * @extends Roo.util.Observable
28834 * Simple Button class
28835 * @cfg {String} text The button text
28836 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
28837 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
28838 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
28839 * @cfg {Object} scope The scope of the handler
28840 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
28841 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
28842 * @cfg {Boolean} hidden True to start hidden (defaults to false)
28843 * @cfg {Boolean} disabled True to start disabled (defaults to false)
28844 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
28845 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
28846 applies if enableToggle = true)
28847 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
28848 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
28849 an {@link Roo.util.ClickRepeater} config object (defaults to false).
28851 * Create a new button
28852 * @param {Object} config The config object
28854 Roo.Button = function(renderTo, config)
28858 renderTo = config.renderTo || false;
28861 Roo.apply(this, config);
28865 * Fires when this button is clicked
28866 * @param {Button} this
28867 * @param {EventObject} e The click event
28872 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
28873 * @param {Button} this
28874 * @param {Boolean} pressed
28879 * Fires when the mouse hovers over the button
28880 * @param {Button} this
28881 * @param {Event} e The event object
28883 'mouseover' : true,
28886 * Fires when the mouse exits the button
28887 * @param {Button} this
28888 * @param {Event} e The event object
28893 * Fires when the button is rendered
28894 * @param {Button} this
28899 this.menu = Roo.menu.MenuMgr.get(this.menu);
28901 // register listeners first!! - so render can be captured..
28902 Roo.util.Observable.call(this);
28904 this.render(renderTo);
28910 Roo.extend(Roo.Button, Roo.util.Observable, {
28916 * Read-only. True if this button is hidden
28921 * Read-only. True if this button is disabled
28926 * Read-only. True if this button is pressed (only if enableToggle = true)
28932 * @cfg {Number} tabIndex
28933 * The DOM tabIndex for this button (defaults to undefined)
28935 tabIndex : undefined,
28938 * @cfg {Boolean} enableToggle
28939 * True to enable pressed/not pressed toggling (defaults to false)
28941 enableToggle: false,
28943 * @cfg {Mixed} menu
28944 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
28948 * @cfg {String} menuAlign
28949 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
28951 menuAlign : "tl-bl?",
28954 * @cfg {String} iconCls
28955 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
28957 iconCls : undefined,
28959 * @cfg {String} type
28960 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
28965 menuClassTarget: 'tr',
28968 * @cfg {String} clickEvent
28969 * The type of event to map to the button's event handler (defaults to 'click')
28971 clickEvent : 'click',
28974 * @cfg {Boolean} handleMouseEvents
28975 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
28977 handleMouseEvents : true,
28980 * @cfg {String} tooltipType
28981 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
28983 tooltipType : 'qtip',
28986 * @cfg {String} cls
28987 * A CSS class to apply to the button's main element.
28991 * @cfg {Roo.Template} template (Optional)
28992 * An {@link Roo.Template} with which to create the Button's main element. This Template must
28993 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
28994 * require code modifications if required elements (e.g. a button) aren't present.
28998 render : function(renderTo){
29000 if(this.hideParent){
29001 this.parentEl = Roo.get(renderTo);
29003 if(!this.dhconfig){
29004 if(!this.template){
29005 if(!Roo.Button.buttonTemplate){
29006 // hideous table template
29007 Roo.Button.buttonTemplate = new Roo.Template(
29008 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29009 '<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>',
29010 "</tr></tbody></table>");
29012 this.template = Roo.Button.buttonTemplate;
29014 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29015 var btnEl = btn.child("button:first");
29016 btnEl.on('focus', this.onFocus, this);
29017 btnEl.on('blur', this.onBlur, this);
29019 btn.addClass(this.cls);
29022 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29025 btnEl.addClass(this.iconCls);
29027 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29030 if(this.tabIndex !== undefined){
29031 btnEl.dom.tabIndex = this.tabIndex;
29034 if(typeof this.tooltip == 'object'){
29035 Roo.QuickTips.tips(Roo.apply({
29039 btnEl.dom[this.tooltipType] = this.tooltip;
29043 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29047 this.el.dom.id = this.el.id = this.id;
29050 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29051 this.menu.on("show", this.onMenuShow, this);
29052 this.menu.on("hide", this.onMenuHide, this);
29054 btn.addClass("x-btn");
29055 if(Roo.isIE && !Roo.isIE7){
29056 this.autoWidth.defer(1, this);
29060 if(this.handleMouseEvents){
29061 btn.on("mouseover", this.onMouseOver, this);
29062 btn.on("mouseout", this.onMouseOut, this);
29063 btn.on("mousedown", this.onMouseDown, this);
29065 btn.on(this.clickEvent, this.onClick, this);
29066 //btn.on("mouseup", this.onMouseUp, this);
29073 Roo.ButtonToggleMgr.register(this);
29075 this.el.addClass("x-btn-pressed");
29078 var repeater = new Roo.util.ClickRepeater(btn,
29079 typeof this.repeat == "object" ? this.repeat : {}
29081 repeater.on("click", this.onClick, this);
29084 this.fireEvent('render', this);
29088 * Returns the button's underlying element
29089 * @return {Roo.Element} The element
29091 getEl : function(){
29096 * Destroys this Button and removes any listeners.
29098 destroy : function(){
29099 Roo.ButtonToggleMgr.unregister(this);
29100 this.el.removeAllListeners();
29101 this.purgeListeners();
29106 autoWidth : function(){
29108 this.el.setWidth("auto");
29109 if(Roo.isIE7 && Roo.isStrict){
29110 var ib = this.el.child('button');
29111 if(ib && ib.getWidth() > 20){
29113 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29118 this.el.beginMeasure();
29120 if(this.el.getWidth() < this.minWidth){
29121 this.el.setWidth(this.minWidth);
29124 this.el.endMeasure();
29131 * Assigns this button's click handler
29132 * @param {Function} handler The function to call when the button is clicked
29133 * @param {Object} scope (optional) Scope for the function passed in
29135 setHandler : function(handler, scope){
29136 this.handler = handler;
29137 this.scope = scope;
29141 * Sets this button's text
29142 * @param {String} text The button text
29144 setText : function(text){
29147 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29153 * Gets the text for this button
29154 * @return {String} The button text
29156 getText : function(){
29164 this.hidden = false;
29166 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29174 this.hidden = true;
29176 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29181 * Convenience function for boolean show/hide
29182 * @param {Boolean} visible True to show, false to hide
29184 setVisible: function(visible){
29193 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29194 * @param {Boolean} state (optional) Force a particular state
29196 toggle : function(state){
29197 state = state === undefined ? !this.pressed : state;
29198 if(state != this.pressed){
29200 this.el.addClass("x-btn-pressed");
29201 this.pressed = true;
29202 this.fireEvent("toggle", this, true);
29204 this.el.removeClass("x-btn-pressed");
29205 this.pressed = false;
29206 this.fireEvent("toggle", this, false);
29208 if(this.toggleHandler){
29209 this.toggleHandler.call(this.scope || this, this, state);
29217 focus : function(){
29218 this.el.child('button:first').focus();
29222 * Disable this button
29224 disable : function(){
29226 this.el.addClass("x-btn-disabled");
29228 this.disabled = true;
29232 * Enable this button
29234 enable : function(){
29236 this.el.removeClass("x-btn-disabled");
29238 this.disabled = false;
29242 * Convenience function for boolean enable/disable
29243 * @param {Boolean} enabled True to enable, false to disable
29245 setDisabled : function(v){
29246 this[v !== true ? "enable" : "disable"]();
29250 onClick : function(e)
29253 e.preventDefault();
29258 if(!this.disabled){
29259 if(this.enableToggle){
29262 if(this.menu && !this.menu.isVisible()){
29263 this.menu.show(this.el, this.menuAlign);
29265 this.fireEvent("click", this, e);
29267 this.el.removeClass("x-btn-over");
29268 this.handler.call(this.scope || this, this, e);
29273 onMouseOver : function(e){
29274 if(!this.disabled){
29275 this.el.addClass("x-btn-over");
29276 this.fireEvent('mouseover', this, e);
29280 onMouseOut : function(e){
29281 if(!e.within(this.el, true)){
29282 this.el.removeClass("x-btn-over");
29283 this.fireEvent('mouseout', this, e);
29287 onFocus : function(e){
29288 if(!this.disabled){
29289 this.el.addClass("x-btn-focus");
29293 onBlur : function(e){
29294 this.el.removeClass("x-btn-focus");
29297 onMouseDown : function(e){
29298 if(!this.disabled && e.button == 0){
29299 this.el.addClass("x-btn-click");
29300 Roo.get(document).on('mouseup', this.onMouseUp, this);
29304 onMouseUp : function(e){
29306 this.el.removeClass("x-btn-click");
29307 Roo.get(document).un('mouseup', this.onMouseUp, this);
29311 onMenuShow : function(e){
29312 this.el.addClass("x-btn-menu-active");
29315 onMenuHide : function(e){
29316 this.el.removeClass("x-btn-menu-active");
29320 // Private utility class used by Button
29321 Roo.ButtonToggleMgr = function(){
29324 function toggleGroup(btn, state){
29326 var g = groups[btn.toggleGroup];
29327 for(var i = 0, l = g.length; i < l; i++){
29329 g[i].toggle(false);
29336 register : function(btn){
29337 if(!btn.toggleGroup){
29340 var g = groups[btn.toggleGroup];
29342 g = groups[btn.toggleGroup] = [];
29345 btn.on("toggle", toggleGroup);
29348 unregister : function(btn){
29349 if(!btn.toggleGroup){
29352 var g = groups[btn.toggleGroup];
29355 btn.un("toggle", toggleGroup);
29361 * Ext JS Library 1.1.1
29362 * Copyright(c) 2006-2007, Ext JS, LLC.
29364 * Originally Released Under LGPL - original licence link has changed is not relivant.
29367 * <script type="text/javascript">
29371 * @class Roo.SplitButton
29372 * @extends Roo.Button
29373 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29374 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29375 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29376 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29377 * @cfg {String} arrowTooltip The title attribute of the arrow
29379 * Create a new menu button
29380 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29381 * @param {Object} config The config object
29383 Roo.SplitButton = function(renderTo, config){
29384 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29386 * @event arrowclick
29387 * Fires when this button's arrow is clicked
29388 * @param {SplitButton} this
29389 * @param {EventObject} e The click event
29391 this.addEvents({"arrowclick":true});
29394 Roo.extend(Roo.SplitButton, Roo.Button, {
29395 render : function(renderTo){
29396 // this is one sweet looking template!
29397 var tpl = new Roo.Template(
29398 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29399 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29400 '<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>',
29401 "</tbody></table></td><td>",
29402 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29403 '<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>',
29404 "</tbody></table></td></tr></table>"
29406 var btn = tpl.append(renderTo, [this.text, this.type], true);
29407 var btnEl = btn.child("button");
29409 btn.addClass(this.cls);
29412 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29415 btnEl.addClass(this.iconCls);
29417 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29421 if(this.handleMouseEvents){
29422 btn.on("mouseover", this.onMouseOver, this);
29423 btn.on("mouseout", this.onMouseOut, this);
29424 btn.on("mousedown", this.onMouseDown, this);
29425 btn.on("mouseup", this.onMouseUp, this);
29427 btn.on(this.clickEvent, this.onClick, this);
29429 if(typeof this.tooltip == 'object'){
29430 Roo.QuickTips.tips(Roo.apply({
29434 btnEl.dom[this.tooltipType] = this.tooltip;
29437 if(this.arrowTooltip){
29438 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29447 this.el.addClass("x-btn-pressed");
29449 if(Roo.isIE && !Roo.isIE7){
29450 this.autoWidth.defer(1, this);
29455 this.menu.on("show", this.onMenuShow, this);
29456 this.menu.on("hide", this.onMenuHide, this);
29458 this.fireEvent('render', this);
29462 autoWidth : function(){
29464 var tbl = this.el.child("table:first");
29465 var tbl2 = this.el.child("table:last");
29466 this.el.setWidth("auto");
29467 tbl.setWidth("auto");
29468 if(Roo.isIE7 && Roo.isStrict){
29469 var ib = this.el.child('button:first');
29470 if(ib && ib.getWidth() > 20){
29472 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29477 this.el.beginMeasure();
29479 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29480 tbl.setWidth(this.minWidth-tbl2.getWidth());
29483 this.el.endMeasure();
29486 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29490 * Sets this button's click handler
29491 * @param {Function} handler The function to call when the button is clicked
29492 * @param {Object} scope (optional) Scope for the function passed above
29494 setHandler : function(handler, scope){
29495 this.handler = handler;
29496 this.scope = scope;
29500 * Sets this button's arrow click handler
29501 * @param {Function} handler The function to call when the arrow is clicked
29502 * @param {Object} scope (optional) Scope for the function passed above
29504 setArrowHandler : function(handler, scope){
29505 this.arrowHandler = handler;
29506 this.scope = scope;
29512 focus : function(){
29514 this.el.child("button:first").focus();
29519 onClick : function(e){
29520 e.preventDefault();
29521 if(!this.disabled){
29522 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29523 if(this.menu && !this.menu.isVisible()){
29524 this.menu.show(this.el, this.menuAlign);
29526 this.fireEvent("arrowclick", this, e);
29527 if(this.arrowHandler){
29528 this.arrowHandler.call(this.scope || this, this, e);
29531 this.fireEvent("click", this, e);
29533 this.handler.call(this.scope || this, this, e);
29539 onMouseDown : function(e){
29540 if(!this.disabled){
29541 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29545 onMouseUp : function(e){
29546 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29551 // backwards compat
29552 Roo.MenuButton = Roo.SplitButton;/*
29554 * Ext JS Library 1.1.1
29555 * Copyright(c) 2006-2007, Ext JS, LLC.
29557 * Originally Released Under LGPL - original licence link has changed is not relivant.
29560 * <script type="text/javascript">
29564 * @class Roo.Toolbar
29565 * Basic Toolbar class.
29567 * Creates a new Toolbar
29568 * @param {Object} container The config object
29570 Roo.Toolbar = function(container, buttons, config)
29572 /// old consturctor format still supported..
29573 if(container instanceof Array){ // omit the container for later rendering
29574 buttons = container;
29578 if (typeof(container) == 'object' && container.xtype) {
29579 config = container;
29580 container = config.container;
29581 buttons = config.buttons || []; // not really - use items!!
29584 if (config && config.items) {
29585 xitems = config.items;
29586 delete config.items;
29588 Roo.apply(this, config);
29589 this.buttons = buttons;
29592 this.render(container);
29594 this.xitems = xitems;
29595 Roo.each(xitems, function(b) {
29601 Roo.Toolbar.prototype = {
29603 * @cfg {Array} items
29604 * array of button configs or elements to add (will be converted to a MixedCollection)
29608 * @cfg {String/HTMLElement/Element} container
29609 * The id or element that will contain the toolbar
29612 render : function(ct){
29613 this.el = Roo.get(ct);
29615 this.el.addClass(this.cls);
29617 // using a table allows for vertical alignment
29618 // 100% width is needed by Safari...
29619 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29620 this.tr = this.el.child("tr", true);
29622 this.items = new Roo.util.MixedCollection(false, function(o){
29623 return o.id || ("item" + (++autoId));
29626 this.add.apply(this, this.buttons);
29627 delete this.buttons;
29632 * Adds element(s) to the toolbar -- this function takes a variable number of
29633 * arguments of mixed type and adds them to the toolbar.
29634 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29636 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29637 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29638 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29639 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29640 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29641 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29642 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29643 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29644 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29646 * @param {Mixed} arg2
29647 * @param {Mixed} etc.
29650 var a = arguments, l = a.length;
29651 for(var i = 0; i < l; i++){
29656 _add : function(el) {
29659 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29662 if (el.applyTo){ // some kind of form field
29663 return this.addField(el);
29665 if (el.render){ // some kind of Toolbar.Item
29666 return this.addItem(el);
29668 if (typeof el == "string"){ // string
29669 if(el == "separator" || el == "-"){
29670 return this.addSeparator();
29673 return this.addSpacer();
29676 return this.addFill();
29678 return this.addText(el);
29681 if(el.tagName){ // element
29682 return this.addElement(el);
29684 if(typeof el == "object"){ // must be button config?
29685 return this.addButton(el);
29687 // and now what?!?!
29693 * Add an Xtype element
29694 * @param {Object} xtype Xtype Object
29695 * @return {Object} created Object
29697 addxtype : function(e){
29698 return this.add(e);
29702 * Returns the Element for this toolbar.
29703 * @return {Roo.Element}
29705 getEl : function(){
29711 * @return {Roo.Toolbar.Item} The separator item
29713 addSeparator : function(){
29714 return this.addItem(new Roo.Toolbar.Separator());
29718 * Adds a spacer element
29719 * @return {Roo.Toolbar.Spacer} The spacer item
29721 addSpacer : function(){
29722 return this.addItem(new Roo.Toolbar.Spacer());
29726 * Adds a fill element that forces subsequent additions to the right side of the toolbar
29727 * @return {Roo.Toolbar.Fill} The fill item
29729 addFill : function(){
29730 return this.addItem(new Roo.Toolbar.Fill());
29734 * Adds any standard HTML element to the toolbar
29735 * @param {String/HTMLElement/Element} el The element or id of the element to add
29736 * @return {Roo.Toolbar.Item} The element's item
29738 addElement : function(el){
29739 return this.addItem(new Roo.Toolbar.Item(el));
29742 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
29743 * @type Roo.util.MixedCollection
29748 * Adds any Toolbar.Item or subclass
29749 * @param {Roo.Toolbar.Item} item
29750 * @return {Roo.Toolbar.Item} The item
29752 addItem : function(item){
29753 var td = this.nextBlock();
29755 this.items.add(item);
29760 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
29761 * @param {Object/Array} config A button config or array of configs
29762 * @return {Roo.Toolbar.Button/Array}
29764 addButton : function(config){
29765 if(config instanceof Array){
29767 for(var i = 0, len = config.length; i < len; i++) {
29768 buttons.push(this.addButton(config[i]));
29773 if(!(config instanceof Roo.Toolbar.Button)){
29775 new Roo.Toolbar.SplitButton(config) :
29776 new Roo.Toolbar.Button(config);
29778 var td = this.nextBlock();
29785 * Adds text to the toolbar
29786 * @param {String} text The text to add
29787 * @return {Roo.Toolbar.Item} The element's item
29789 addText : function(text){
29790 return this.addItem(new Roo.Toolbar.TextItem(text));
29794 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
29795 * @param {Number} index The index where the item is to be inserted
29796 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
29797 * @return {Roo.Toolbar.Button/Item}
29799 insertButton : function(index, item){
29800 if(item instanceof Array){
29802 for(var i = 0, len = item.length; i < len; i++) {
29803 buttons.push(this.insertButton(index + i, item[i]));
29807 if (!(item instanceof Roo.Toolbar.Button)){
29808 item = new Roo.Toolbar.Button(item);
29810 var td = document.createElement("td");
29811 this.tr.insertBefore(td, this.tr.childNodes[index]);
29813 this.items.insert(index, item);
29818 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
29819 * @param {Object} config
29820 * @return {Roo.Toolbar.Item} The element's item
29822 addDom : function(config, returnEl){
29823 var td = this.nextBlock();
29824 Roo.DomHelper.overwrite(td, config);
29825 var ti = new Roo.Toolbar.Item(td.firstChild);
29827 this.items.add(ti);
29832 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
29833 * @type Roo.util.MixedCollection
29838 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
29839 * Note: the field should not have been rendered yet. For a field that has already been
29840 * rendered, use {@link #addElement}.
29841 * @param {Roo.form.Field} field
29842 * @return {Roo.ToolbarItem}
29846 addField : function(field) {
29847 if (!this.fields) {
29849 this.fields = new Roo.util.MixedCollection(false, function(o){
29850 return o.id || ("item" + (++autoId));
29855 var td = this.nextBlock();
29857 var ti = new Roo.Toolbar.Item(td.firstChild);
29859 this.items.add(ti);
29860 this.fields.add(field);
29871 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
29872 this.el.child('div').hide();
29880 this.el.child('div').show();
29884 nextBlock : function(){
29885 var td = document.createElement("td");
29886 this.tr.appendChild(td);
29891 destroy : function(){
29892 if(this.items){ // rendered?
29893 Roo.destroy.apply(Roo, this.items.items);
29895 if(this.fields){ // rendered?
29896 Roo.destroy.apply(Roo, this.fields.items);
29898 Roo.Element.uncache(this.el, this.tr);
29903 * @class Roo.Toolbar.Item
29904 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
29906 * Creates a new Item
29907 * @param {HTMLElement} el
29909 Roo.Toolbar.Item = function(el){
29911 if (typeof (el.xtype) != 'undefined') {
29916 this.el = Roo.getDom(el);
29917 this.id = Roo.id(this.el);
29918 this.hidden = false;
29923 * Fires when the button is rendered
29924 * @param {Button} this
29928 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
29930 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
29931 //Roo.Toolbar.Item.prototype = {
29934 * Get this item's HTML Element
29935 * @return {HTMLElement}
29937 getEl : function(){
29942 render : function(td){
29945 td.appendChild(this.el);
29947 this.fireEvent('render', this);
29951 * Removes and destroys this item.
29953 destroy : function(){
29954 this.td.parentNode.removeChild(this.td);
29961 this.hidden = false;
29962 this.td.style.display = "";
29969 this.hidden = true;
29970 this.td.style.display = "none";
29974 * Convenience function for boolean show/hide.
29975 * @param {Boolean} visible true to show/false to hide
29977 setVisible: function(visible){
29986 * Try to focus this item.
29988 focus : function(){
29989 Roo.fly(this.el).focus();
29993 * Disables this item.
29995 disable : function(){
29996 Roo.fly(this.td).addClass("x-item-disabled");
29997 this.disabled = true;
29998 this.el.disabled = true;
30002 * Enables this item.
30004 enable : function(){
30005 Roo.fly(this.td).removeClass("x-item-disabled");
30006 this.disabled = false;
30007 this.el.disabled = false;
30013 * @class Roo.Toolbar.Separator
30014 * @extends Roo.Toolbar.Item
30015 * A simple toolbar separator class
30017 * Creates a new Separator
30019 Roo.Toolbar.Separator = function(cfg){
30021 var s = document.createElement("span");
30022 s.className = "ytb-sep";
30027 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30029 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30030 enable:Roo.emptyFn,
30031 disable:Roo.emptyFn,
30036 * @class Roo.Toolbar.Spacer
30037 * @extends Roo.Toolbar.Item
30038 * A simple element that adds extra horizontal space to a toolbar.
30040 * Creates a new Spacer
30042 Roo.Toolbar.Spacer = function(cfg){
30043 var s = document.createElement("div");
30044 s.className = "ytb-spacer";
30048 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30050 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30051 enable:Roo.emptyFn,
30052 disable:Roo.emptyFn,
30057 * @class Roo.Toolbar.Fill
30058 * @extends Roo.Toolbar.Spacer
30059 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30061 * Creates a new Spacer
30063 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30065 render : function(td){
30066 td.style.width = '100%';
30067 Roo.Toolbar.Fill.superclass.render.call(this, td);
30072 * @class Roo.Toolbar.TextItem
30073 * @extends Roo.Toolbar.Item
30074 * A simple class that renders text directly into a toolbar.
30076 * Creates a new TextItem
30077 * @param {String} text
30079 Roo.Toolbar.TextItem = function(cfg){
30080 var text = cfg || "";
30081 if (typeof(cfg) == 'object') {
30082 text = cfg.text || "";
30086 var s = document.createElement("span");
30087 s.className = "ytb-text";
30088 s.innerHTML = text;
30093 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30095 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30098 enable:Roo.emptyFn,
30099 disable:Roo.emptyFn,
30104 * @class Roo.Toolbar.Button
30105 * @extends Roo.Button
30106 * A button that renders into a toolbar.
30108 * Creates a new Button
30109 * @param {Object} config A standard {@link Roo.Button} config object
30111 Roo.Toolbar.Button = function(config){
30112 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30114 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30115 render : function(td){
30117 Roo.Toolbar.Button.superclass.render.call(this, td);
30121 * Removes and destroys this button
30123 destroy : function(){
30124 Roo.Toolbar.Button.superclass.destroy.call(this);
30125 this.td.parentNode.removeChild(this.td);
30129 * Shows this button
30132 this.hidden = false;
30133 this.td.style.display = "";
30137 * Hides this button
30140 this.hidden = true;
30141 this.td.style.display = "none";
30145 * Disables this item
30147 disable : function(){
30148 Roo.fly(this.td).addClass("x-item-disabled");
30149 this.disabled = true;
30153 * Enables this item
30155 enable : function(){
30156 Roo.fly(this.td).removeClass("x-item-disabled");
30157 this.disabled = false;
30160 // backwards compat
30161 Roo.ToolbarButton = Roo.Toolbar.Button;
30164 * @class Roo.Toolbar.SplitButton
30165 * @extends Roo.SplitButton
30166 * A menu button that renders into a toolbar.
30168 * Creates a new SplitButton
30169 * @param {Object} config A standard {@link Roo.SplitButton} config object
30171 Roo.Toolbar.SplitButton = function(config){
30172 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30174 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30175 render : function(td){
30177 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30181 * Removes and destroys this button
30183 destroy : function(){
30184 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30185 this.td.parentNode.removeChild(this.td);
30189 * Shows this button
30192 this.hidden = false;
30193 this.td.style.display = "";
30197 * Hides this button
30200 this.hidden = true;
30201 this.td.style.display = "none";
30205 // backwards compat
30206 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30208 * Ext JS Library 1.1.1
30209 * Copyright(c) 2006-2007, Ext JS, LLC.
30211 * Originally Released Under LGPL - original licence link has changed is not relivant.
30214 * <script type="text/javascript">
30218 * @class Roo.PagingToolbar
30219 * @extends Roo.Toolbar
30220 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30222 * Create a new PagingToolbar
30223 * @param {Object} config The config object
30225 Roo.PagingToolbar = function(el, ds, config)
30227 // old args format still supported... - xtype is prefered..
30228 if (typeof(el) == 'object' && el.xtype) {
30229 // created from xtype...
30231 ds = el.dataSource;
30232 el = config.container;
30235 if (config.items) {
30236 items = config.items;
30240 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30243 this.renderButtons(this.el);
30246 // supprot items array.
30248 Roo.each(items, function(e) {
30249 this.add(Roo.factory(e));
30254 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30256 * @cfg {Roo.data.Store} dataSource
30257 * The underlying data store providing the paged data
30260 * @cfg {String/HTMLElement/Element} container
30261 * container The id or element that will contain the toolbar
30264 * @cfg {Boolean} displayInfo
30265 * True to display the displayMsg (defaults to false)
30268 * @cfg {Number} pageSize
30269 * The number of records to display per page (defaults to 20)
30273 * @cfg {String} displayMsg
30274 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30276 displayMsg : 'Displaying {0} - {1} of {2}',
30278 * @cfg {String} emptyMsg
30279 * The message to display when no records are found (defaults to "No data to display")
30281 emptyMsg : 'No data to display',
30283 * Customizable piece of the default paging text (defaults to "Page")
30286 beforePageText : "Page",
30288 * Customizable piece of the default paging text (defaults to "of %0")
30291 afterPageText : "of {0}",
30293 * Customizable piece of the default paging text (defaults to "First Page")
30296 firstText : "First Page",
30298 * Customizable piece of the default paging text (defaults to "Previous Page")
30301 prevText : "Previous Page",
30303 * Customizable piece of the default paging text (defaults to "Next Page")
30306 nextText : "Next Page",
30308 * Customizable piece of the default paging text (defaults to "Last Page")
30311 lastText : "Last Page",
30313 * Customizable piece of the default paging text (defaults to "Refresh")
30316 refreshText : "Refresh",
30319 renderButtons : function(el){
30320 Roo.PagingToolbar.superclass.render.call(this, el);
30321 this.first = this.addButton({
30322 tooltip: this.firstText,
30323 cls: "x-btn-icon x-grid-page-first",
30325 handler: this.onClick.createDelegate(this, ["first"])
30327 this.prev = this.addButton({
30328 tooltip: this.prevText,
30329 cls: "x-btn-icon x-grid-page-prev",
30331 handler: this.onClick.createDelegate(this, ["prev"])
30333 //this.addSeparator();
30334 this.add(this.beforePageText);
30335 this.field = Roo.get(this.addDom({
30340 cls: "x-grid-page-number"
30342 this.field.on("keydown", this.onPagingKeydown, this);
30343 this.field.on("focus", function(){this.dom.select();});
30344 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30345 this.field.setHeight(18);
30346 //this.addSeparator();
30347 this.next = this.addButton({
30348 tooltip: this.nextText,
30349 cls: "x-btn-icon x-grid-page-next",
30351 handler: this.onClick.createDelegate(this, ["next"])
30353 this.last = this.addButton({
30354 tooltip: this.lastText,
30355 cls: "x-btn-icon x-grid-page-last",
30357 handler: this.onClick.createDelegate(this, ["last"])
30359 //this.addSeparator();
30360 this.loading = this.addButton({
30361 tooltip: this.refreshText,
30362 cls: "x-btn-icon x-grid-loading",
30363 handler: this.onClick.createDelegate(this, ["refresh"])
30366 if(this.displayInfo){
30367 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30372 updateInfo : function(){
30373 if(this.displayEl){
30374 var count = this.ds.getCount();
30375 var msg = count == 0 ?
30379 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30381 this.displayEl.update(msg);
30386 onLoad : function(ds, r, o){
30387 this.cursor = o.params ? o.params.start : 0;
30388 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30390 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30391 this.field.dom.value = ap;
30392 this.first.setDisabled(ap == 1);
30393 this.prev.setDisabled(ap == 1);
30394 this.next.setDisabled(ap == ps);
30395 this.last.setDisabled(ap == ps);
30396 this.loading.enable();
30401 getPageData : function(){
30402 var total = this.ds.getTotalCount();
30405 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30406 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30411 onLoadError : function(){
30412 this.loading.enable();
30416 onPagingKeydown : function(e){
30417 var k = e.getKey();
30418 var d = this.getPageData();
30420 var v = this.field.dom.value, pageNum;
30421 if(!v || isNaN(pageNum = parseInt(v, 10))){
30422 this.field.dom.value = d.activePage;
30425 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30426 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30429 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))
30431 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30432 this.field.dom.value = pageNum;
30433 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30436 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30438 var v = this.field.dom.value, pageNum;
30439 var increment = (e.shiftKey) ? 10 : 1;
30440 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30443 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30444 this.field.dom.value = d.activePage;
30447 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30449 this.field.dom.value = parseInt(v, 10) + increment;
30450 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30451 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30458 beforeLoad : function(){
30460 this.loading.disable();
30465 onClick : function(which){
30469 ds.load({params:{start: 0, limit: this.pageSize}});
30472 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30475 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30478 var total = ds.getTotalCount();
30479 var extra = total % this.pageSize;
30480 var lastStart = extra ? (total - extra) : total-this.pageSize;
30481 ds.load({params:{start: lastStart, limit: this.pageSize}});
30484 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30490 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30491 * @param {Roo.data.Store} store The data store to unbind
30493 unbind : function(ds){
30494 ds.un("beforeload", this.beforeLoad, this);
30495 ds.un("load", this.onLoad, this);
30496 ds.un("loadexception", this.onLoadError, this);
30497 ds.un("remove", this.updateInfo, this);
30498 ds.un("add", this.updateInfo, this);
30499 this.ds = undefined;
30503 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30504 * @param {Roo.data.Store} store The data store to bind
30506 bind : function(ds){
30507 ds.on("beforeload", this.beforeLoad, this);
30508 ds.on("load", this.onLoad, this);
30509 ds.on("loadexception", this.onLoadError, this);
30510 ds.on("remove", this.updateInfo, this);
30511 ds.on("add", this.updateInfo, this);
30516 * Ext JS Library 1.1.1
30517 * Copyright(c) 2006-2007, Ext JS, LLC.
30519 * Originally Released Under LGPL - original licence link has changed is not relivant.
30522 * <script type="text/javascript">
30526 * @class Roo.Resizable
30527 * @extends Roo.util.Observable
30528 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30529 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30530 * 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
30531 * the element will be wrapped for you automatically.</p>
30532 * <p>Here is the list of valid resize handles:</p>
30535 ------ -------------------
30544 'hd' horizontal drag
30547 * <p>Here's an example showing the creation of a typical Resizable:</p>
30549 var resizer = new Roo.Resizable("element-id", {
30557 resizer.on("resize", myHandler);
30559 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30560 * resizer.east.setDisplayed(false);</p>
30561 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30562 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30563 * resize operation's new size (defaults to [0, 0])
30564 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30565 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30566 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30567 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30568 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30569 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30570 * @cfg {Number} width The width of the element in pixels (defaults to null)
30571 * @cfg {Number} height The height of the element in pixels (defaults to null)
30572 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30573 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30574 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30575 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30576 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30577 * in favor of the handles config option (defaults to false)
30578 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30579 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30580 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30581 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30582 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30583 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30584 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30585 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30586 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30587 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30588 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30590 * Create a new resizable component
30591 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30592 * @param {Object} config configuration options
30594 Roo.Resizable = function(el, config)
30596 this.el = Roo.get(el);
30598 if(config && config.wrap){
30599 config.resizeChild = this.el;
30600 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30601 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30602 this.el.setStyle("overflow", "hidden");
30603 this.el.setPositioning(config.resizeChild.getPositioning());
30604 config.resizeChild.clearPositioning();
30605 if(!config.width || !config.height){
30606 var csize = config.resizeChild.getSize();
30607 this.el.setSize(csize.width, csize.height);
30609 if(config.pinned && !config.adjustments){
30610 config.adjustments = "auto";
30614 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30615 this.proxy.unselectable();
30616 this.proxy.enableDisplayMode('block');
30618 Roo.apply(this, config);
30621 this.disableTrackOver = true;
30622 this.el.addClass("x-resizable-pinned");
30624 // if the element isn't positioned, make it relative
30625 var position = this.el.getStyle("position");
30626 if(position != "absolute" && position != "fixed"){
30627 this.el.setStyle("position", "relative");
30629 if(!this.handles){ // no handles passed, must be legacy style
30630 this.handles = 's,e,se';
30631 if(this.multiDirectional){
30632 this.handles += ',n,w';
30635 if(this.handles == "all"){
30636 this.handles = "n s e w ne nw se sw";
30638 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30639 var ps = Roo.Resizable.positions;
30640 for(var i = 0, len = hs.length; i < len; i++){
30641 if(hs[i] && ps[hs[i]]){
30642 var pos = ps[hs[i]];
30643 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30647 this.corner = this.southeast;
30649 // updateBox = the box can move..
30650 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30651 this.updateBox = true;
30654 this.activeHandle = null;
30656 if(this.resizeChild){
30657 if(typeof this.resizeChild == "boolean"){
30658 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30660 this.resizeChild = Roo.get(this.resizeChild, true);
30664 if(this.adjustments == "auto"){
30665 var rc = this.resizeChild;
30666 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30667 if(rc && (hw || hn)){
30668 rc.position("relative");
30669 rc.setLeft(hw ? hw.el.getWidth() : 0);
30670 rc.setTop(hn ? hn.el.getHeight() : 0);
30672 this.adjustments = [
30673 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30674 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30678 if(this.draggable){
30679 this.dd = this.dynamic ?
30680 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30681 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30687 * @event beforeresize
30688 * Fired before resize is allowed. Set enabled to false to cancel resize.
30689 * @param {Roo.Resizable} this
30690 * @param {Roo.EventObject} e The mousedown event
30692 "beforeresize" : true,
30695 * Fired a resizing.
30696 * @param {Roo.Resizable} this
30697 * @param {Number} x The new x position
30698 * @param {Number} y The new y position
30699 * @param {Number} w The new w width
30700 * @param {Number} h The new h hight
30701 * @param {Roo.EventObject} e The mouseup event
30706 * Fired after a resize.
30707 * @param {Roo.Resizable} this
30708 * @param {Number} width The new width
30709 * @param {Number} height The new height
30710 * @param {Roo.EventObject} e The mouseup event
30715 if(this.width !== null && this.height !== null){
30716 this.resizeTo(this.width, this.height);
30718 this.updateChildSize();
30721 this.el.dom.style.zoom = 1;
30723 Roo.Resizable.superclass.constructor.call(this);
30726 Roo.extend(Roo.Resizable, Roo.util.Observable, {
30727 resizeChild : false,
30728 adjustments : [0, 0],
30738 multiDirectional : false,
30739 disableTrackOver : false,
30740 easing : 'easeOutStrong',
30741 widthIncrement : 0,
30742 heightIncrement : 0,
30746 preserveRatio : false,
30747 transparent: false,
30753 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
30755 constrainTo: undefined,
30757 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
30759 resizeRegion: undefined,
30763 * Perform a manual resize
30764 * @param {Number} width
30765 * @param {Number} height
30767 resizeTo : function(width, height){
30768 this.el.setSize(width, height);
30769 this.updateChildSize();
30770 this.fireEvent("resize", this, width, height, null);
30774 startSizing : function(e, handle){
30775 this.fireEvent("beforeresize", this, e);
30776 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
30779 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
30780 this.overlay.unselectable();
30781 this.overlay.enableDisplayMode("block");
30782 this.overlay.on("mousemove", this.onMouseMove, this);
30783 this.overlay.on("mouseup", this.onMouseUp, this);
30785 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
30787 this.resizing = true;
30788 this.startBox = this.el.getBox();
30789 this.startPoint = e.getXY();
30790 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
30791 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
30793 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30794 this.overlay.show();
30796 if(this.constrainTo) {
30797 var ct = Roo.get(this.constrainTo);
30798 this.resizeRegion = ct.getRegion().adjust(
30799 ct.getFrameWidth('t'),
30800 ct.getFrameWidth('l'),
30801 -ct.getFrameWidth('b'),
30802 -ct.getFrameWidth('r')
30806 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
30808 this.proxy.setBox(this.startBox);
30810 this.proxy.setStyle('visibility', 'visible');
30816 onMouseDown : function(handle, e){
30819 this.activeHandle = handle;
30820 this.startSizing(e, handle);
30825 onMouseUp : function(e){
30826 var size = this.resizeElement();
30827 this.resizing = false;
30829 this.overlay.hide();
30831 this.fireEvent("resize", this, size.width, size.height, e);
30835 updateChildSize : function(){
30837 if(this.resizeChild){
30839 var child = this.resizeChild;
30840 var adj = this.adjustments;
30841 if(el.dom.offsetWidth){
30842 var b = el.getSize(true);
30843 child.setSize(b.width+adj[0], b.height+adj[1]);
30845 // Second call here for IE
30846 // The first call enables instant resizing and
30847 // the second call corrects scroll bars if they
30850 setTimeout(function(){
30851 if(el.dom.offsetWidth){
30852 var b = el.getSize(true);
30853 child.setSize(b.width+adj[0], b.height+adj[1]);
30861 snap : function(value, inc, min){
30862 if(!inc || !value) {
30865 var newValue = value;
30866 var m = value % inc;
30869 newValue = value + (inc-m);
30871 newValue = value - m;
30874 return Math.max(min, newValue);
30878 resizeElement : function(){
30879 var box = this.proxy.getBox();
30880 if(this.updateBox){
30881 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
30883 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
30885 this.updateChildSize();
30893 constrain : function(v, diff, m, mx){
30896 }else if(v - diff > mx){
30903 onMouseMove : function(e){
30906 try{// try catch so if something goes wrong the user doesn't get hung
30908 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
30912 //var curXY = this.startPoint;
30913 var curSize = this.curSize || this.startBox;
30914 var x = this.startBox.x, y = this.startBox.y;
30915 var ox = x, oy = y;
30916 var w = curSize.width, h = curSize.height;
30917 var ow = w, oh = h;
30918 var mw = this.minWidth, mh = this.minHeight;
30919 var mxw = this.maxWidth, mxh = this.maxHeight;
30920 var wi = this.widthIncrement;
30921 var hi = this.heightIncrement;
30923 var eventXY = e.getXY();
30924 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
30925 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
30927 var pos = this.activeHandle.position;
30932 w = Math.min(Math.max(mw, w), mxw);
30937 h = Math.min(Math.max(mh, h), mxh);
30942 w = Math.min(Math.max(mw, w), mxw);
30943 h = Math.min(Math.max(mh, h), mxh);
30946 diffY = this.constrain(h, diffY, mh, mxh);
30953 var adiffX = Math.abs(diffX);
30954 var sub = (adiffX % wi); // how much
30955 if (sub > (wi/2)) { // far enough to snap
30956 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
30958 // remove difference..
30959 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
30963 x = Math.max(this.minX, x);
30966 diffX = this.constrain(w, diffX, mw, mxw);
30972 w = Math.min(Math.max(mw, w), mxw);
30973 diffY = this.constrain(h, diffY, mh, mxh);
30978 diffX = this.constrain(w, diffX, mw, mxw);
30979 diffY = this.constrain(h, diffY, mh, mxh);
30986 diffX = this.constrain(w, diffX, mw, mxw);
30988 h = Math.min(Math.max(mh, h), mxh);
30994 var sw = this.snap(w, wi, mw);
30995 var sh = this.snap(h, hi, mh);
30996 if(sw != w || sh != h){
31019 if(this.preserveRatio){
31024 h = Math.min(Math.max(mh, h), mxh);
31029 w = Math.min(Math.max(mw, w), mxw);
31034 w = Math.min(Math.max(mw, w), mxw);
31040 w = Math.min(Math.max(mw, w), mxw);
31046 h = Math.min(Math.max(mh, h), mxh);
31054 h = Math.min(Math.max(mh, h), mxh);
31064 h = Math.min(Math.max(mh, h), mxh);
31072 if (pos == 'hdrag') {
31075 this.proxy.setBounds(x, y, w, h);
31077 this.resizeElement();
31081 this.fireEvent("resizing", this, x, y, w, h, e);
31085 handleOver : function(){
31087 this.el.addClass("x-resizable-over");
31092 handleOut : function(){
31093 if(!this.resizing){
31094 this.el.removeClass("x-resizable-over");
31099 * Returns the element this component is bound to.
31100 * @return {Roo.Element}
31102 getEl : function(){
31107 * Returns the resizeChild element (or null).
31108 * @return {Roo.Element}
31110 getResizeChild : function(){
31111 return this.resizeChild;
31113 groupHandler : function()
31118 * Destroys this resizable. If the element was wrapped and
31119 * removeEl is not true then the element remains.
31120 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31122 destroy : function(removeEl){
31123 this.proxy.remove();
31125 this.overlay.removeAllListeners();
31126 this.overlay.remove();
31128 var ps = Roo.Resizable.positions;
31130 if(typeof ps[k] != "function" && this[ps[k]]){
31131 var h = this[ps[k]];
31132 h.el.removeAllListeners();
31137 this.el.update("");
31144 // hash to map config positions to true positions
31145 Roo.Resizable.positions = {
31146 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31151 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31153 // only initialize the template if resizable is used
31154 var tpl = Roo.DomHelper.createTemplate(
31155 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31158 Roo.Resizable.Handle.prototype.tpl = tpl;
31160 this.position = pos;
31162 // show north drag fro topdra
31163 var handlepos = pos == 'hdrag' ? 'north' : pos;
31165 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31166 if (pos == 'hdrag') {
31167 this.el.setStyle('cursor', 'pointer');
31169 this.el.unselectable();
31171 this.el.setOpacity(0);
31173 this.el.on("mousedown", this.onMouseDown, this);
31174 if(!disableTrackOver){
31175 this.el.on("mouseover", this.onMouseOver, this);
31176 this.el.on("mouseout", this.onMouseOut, this);
31181 Roo.Resizable.Handle.prototype = {
31182 afterResize : function(rz){
31187 onMouseDown : function(e){
31188 this.rz.onMouseDown(this, e);
31191 onMouseOver : function(e){
31192 this.rz.handleOver(this, e);
31195 onMouseOut : function(e){
31196 this.rz.handleOut(this, e);
31200 * Ext JS Library 1.1.1
31201 * Copyright(c) 2006-2007, Ext JS, LLC.
31203 * Originally Released Under LGPL - original licence link has changed is not relivant.
31206 * <script type="text/javascript">
31210 * @class Roo.Editor
31211 * @extends Roo.Component
31212 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31214 * Create a new Editor
31215 * @param {Roo.form.Field} field The Field object (or descendant)
31216 * @param {Object} config The config object
31218 Roo.Editor = function(field, config){
31219 Roo.Editor.superclass.constructor.call(this, config);
31220 this.field = field;
31223 * @event beforestartedit
31224 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31225 * false from the handler of this event.
31226 * @param {Editor} this
31227 * @param {Roo.Element} boundEl The underlying element bound to this editor
31228 * @param {Mixed} value The field value being set
31230 "beforestartedit" : true,
31233 * Fires when this editor is displayed
31234 * @param {Roo.Element} boundEl The underlying element bound to this editor
31235 * @param {Mixed} value The starting field value
31237 "startedit" : true,
31239 * @event beforecomplete
31240 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31241 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31242 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31243 * event will not fire since no edit actually occurred.
31244 * @param {Editor} this
31245 * @param {Mixed} value The current field value
31246 * @param {Mixed} startValue The original field value
31248 "beforecomplete" : true,
31251 * Fires after editing is complete and any changed value has been written to the underlying field.
31252 * @param {Editor} this
31253 * @param {Mixed} value The current field value
31254 * @param {Mixed} startValue The original field value
31258 * @event specialkey
31259 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31260 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31261 * @param {Roo.form.Field} this
31262 * @param {Roo.EventObject} e The event object
31264 "specialkey" : true
31268 Roo.extend(Roo.Editor, Roo.Component, {
31270 * @cfg {Boolean/String} autosize
31271 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31272 * or "height" to adopt the height only (defaults to false)
31275 * @cfg {Boolean} revertInvalid
31276 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31277 * validation fails (defaults to true)
31280 * @cfg {Boolean} ignoreNoChange
31281 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31282 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31283 * will never be ignored.
31286 * @cfg {Boolean} hideEl
31287 * False to keep the bound element visible while the editor is displayed (defaults to true)
31290 * @cfg {Mixed} value
31291 * The data value of the underlying field (defaults to "")
31295 * @cfg {String} alignment
31296 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31300 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31301 * for bottom-right shadow (defaults to "frame")
31305 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31309 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31311 completeOnEnter : false,
31313 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31315 cancelOnEsc : false,
31317 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31322 onRender : function(ct, position){
31323 this.el = new Roo.Layer({
31324 shadow: this.shadow,
31330 constrain: this.constrain
31332 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31333 if(this.field.msgTarget != 'title'){
31334 this.field.msgTarget = 'qtip';
31336 this.field.render(this.el);
31338 this.field.el.dom.setAttribute('autocomplete', 'off');
31340 this.field.on("specialkey", this.onSpecialKey, this);
31341 if(this.swallowKeys){
31342 this.field.el.swallowEvent(['keydown','keypress']);
31345 this.field.on("blur", this.onBlur, this);
31346 if(this.field.grow){
31347 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31351 onSpecialKey : function(field, e)
31353 //Roo.log('editor onSpecialKey');
31354 if(this.completeOnEnter && e.getKey() == e.ENTER){
31356 this.completeEdit();
31359 // do not fire special key otherwise it might hide close the editor...
31360 if(e.getKey() == e.ENTER){
31363 if(this.cancelOnEsc && e.getKey() == e.ESC){
31367 this.fireEvent('specialkey', field, e);
31372 * Starts the editing process and shows the editor.
31373 * @param {String/HTMLElement/Element} el The element to edit
31374 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31375 * to the innerHTML of el.
31377 startEdit : function(el, value){
31379 this.completeEdit();
31381 this.boundEl = Roo.get(el);
31382 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31383 if(!this.rendered){
31384 this.render(this.parentEl || document.body);
31386 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31389 this.startValue = v;
31390 this.field.setValue(v);
31392 var sz = this.boundEl.getSize();
31393 switch(this.autoSize){
31395 this.setSize(sz.width, "");
31398 this.setSize("", sz.height);
31401 this.setSize(sz.width, sz.height);
31404 this.el.alignTo(this.boundEl, this.alignment);
31405 this.editing = true;
31407 Roo.QuickTips.disable();
31413 * Sets the height and width of this editor.
31414 * @param {Number} width The new width
31415 * @param {Number} height The new height
31417 setSize : function(w, h){
31418 this.field.setSize(w, h);
31425 * Realigns the editor to the bound field based on the current alignment config value.
31427 realign : function(){
31428 this.el.alignTo(this.boundEl, this.alignment);
31432 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31433 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31435 completeEdit : function(remainVisible){
31439 var v = this.getValue();
31440 if(this.revertInvalid !== false && !this.field.isValid()){
31441 v = this.startValue;
31442 this.cancelEdit(true);
31444 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31445 this.editing = false;
31449 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31450 this.editing = false;
31451 if(this.updateEl && this.boundEl){
31452 this.boundEl.update(v);
31454 if(remainVisible !== true){
31457 this.fireEvent("complete", this, v, this.startValue);
31462 onShow : function(){
31464 if(this.hideEl !== false){
31465 this.boundEl.hide();
31468 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31469 this.fixIEFocus = true;
31470 this.deferredFocus.defer(50, this);
31472 this.field.focus();
31474 this.fireEvent("startedit", this.boundEl, this.startValue);
31477 deferredFocus : function(){
31479 this.field.focus();
31484 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31485 * reverted to the original starting value.
31486 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31487 * cancel (defaults to false)
31489 cancelEdit : function(remainVisible){
31491 this.setValue(this.startValue);
31492 if(remainVisible !== true){
31499 onBlur : function(){
31500 if(this.allowBlur !== true && this.editing){
31501 this.completeEdit();
31506 onHide : function(){
31508 this.completeEdit();
31512 if(this.field.collapse){
31513 this.field.collapse();
31516 if(this.hideEl !== false){
31517 this.boundEl.show();
31520 Roo.QuickTips.enable();
31525 * Sets the data value of the editor
31526 * @param {Mixed} value Any valid value supported by the underlying field
31528 setValue : function(v){
31529 this.field.setValue(v);
31533 * Gets the data value of the editor
31534 * @return {Mixed} The data value
31536 getValue : function(){
31537 return this.field.getValue();
31541 * Ext JS Library 1.1.1
31542 * Copyright(c) 2006-2007, Ext JS, LLC.
31544 * Originally Released Under LGPL - original licence link has changed is not relivant.
31547 * <script type="text/javascript">
31551 * @class Roo.BasicDialog
31552 * @extends Roo.util.Observable
31553 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31555 var dlg = new Roo.BasicDialog("my-dlg", {
31564 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31565 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31566 dlg.addButton('Cancel', dlg.hide, dlg);
31569 <b>A Dialog should always be a direct child of the body element.</b>
31570 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31571 * @cfg {String} title Default text to display in the title bar (defaults to null)
31572 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31573 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31574 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31575 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31576 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31577 * (defaults to null with no animation)
31578 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31579 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31580 * property for valid values (defaults to 'all')
31581 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31582 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31583 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31584 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31585 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31586 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31587 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31588 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31589 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31590 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31591 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31592 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31593 * draggable = true (defaults to false)
31594 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31595 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31596 * shadow (defaults to false)
31597 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31598 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31599 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31600 * @cfg {Array} buttons Array of buttons
31601 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31603 * Create a new BasicDialog.
31604 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31605 * @param {Object} config Configuration options
31607 Roo.BasicDialog = function(el, config){
31608 this.el = Roo.get(el);
31609 var dh = Roo.DomHelper;
31610 if(!this.el && config && config.autoCreate){
31611 if(typeof config.autoCreate == "object"){
31612 if(!config.autoCreate.id){
31613 config.autoCreate.id = el;
31615 this.el = dh.append(document.body,
31616 config.autoCreate, true);
31618 this.el = dh.append(document.body,
31619 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31623 el.setDisplayed(true);
31624 el.hide = this.hideAction;
31626 el.addClass("x-dlg");
31628 Roo.apply(this, config);
31630 this.proxy = el.createProxy("x-dlg-proxy");
31631 this.proxy.hide = this.hideAction;
31632 this.proxy.setOpacity(.5);
31636 el.setWidth(config.width);
31639 el.setHeight(config.height);
31641 this.size = el.getSize();
31642 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31643 this.xy = [config.x,config.y];
31645 this.xy = el.getCenterXY(true);
31647 /** The header element @type Roo.Element */
31648 this.header = el.child("> .x-dlg-hd");
31649 /** The body element @type Roo.Element */
31650 this.body = el.child("> .x-dlg-bd");
31651 /** The footer element @type Roo.Element */
31652 this.footer = el.child("> .x-dlg-ft");
31655 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31658 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31661 this.header.unselectable();
31663 this.header.update(this.title);
31665 // this element allows the dialog to be focused for keyboard event
31666 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31667 this.focusEl.swallowEvent("click", true);
31669 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31671 // wrap the body and footer for special rendering
31672 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31674 this.bwrap.dom.appendChild(this.footer.dom);
31677 this.bg = this.el.createChild({
31678 tag: "div", cls:"x-dlg-bg",
31679 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31681 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31684 if(this.autoScroll !== false && !this.autoTabs){
31685 this.body.setStyle("overflow", "auto");
31688 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31690 if(this.closable !== false){
31691 this.el.addClass("x-dlg-closable");
31692 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31693 this.close.on("click", this.closeClick, this);
31694 this.close.addClassOnOver("x-dlg-close-over");
31696 if(this.collapsible !== false){
31697 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31698 this.collapseBtn.on("click", this.collapseClick, this);
31699 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31700 this.header.on("dblclick", this.collapseClick, this);
31702 if(this.resizable !== false){
31703 this.el.addClass("x-dlg-resizable");
31704 this.resizer = new Roo.Resizable(el, {
31705 minWidth: this.minWidth || 80,
31706 minHeight:this.minHeight || 80,
31707 handles: this.resizeHandles || "all",
31710 this.resizer.on("beforeresize", this.beforeResize, this);
31711 this.resizer.on("resize", this.onResize, this);
31713 if(this.draggable !== false){
31714 el.addClass("x-dlg-draggable");
31715 if (!this.proxyDrag) {
31716 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
31719 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
31721 dd.setHandleElId(this.header.id);
31722 dd.endDrag = this.endMove.createDelegate(this);
31723 dd.startDrag = this.startMove.createDelegate(this);
31724 dd.onDrag = this.onDrag.createDelegate(this);
31729 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
31730 this.mask.enableDisplayMode("block");
31732 this.el.addClass("x-dlg-modal");
31735 this.shadow = new Roo.Shadow({
31736 mode : typeof this.shadow == "string" ? this.shadow : "sides",
31737 offset : this.shadowOffset
31740 this.shadowOffset = 0;
31742 if(Roo.useShims && this.shim !== false){
31743 this.shim = this.el.createShim();
31744 this.shim.hide = this.hideAction;
31752 if (this.buttons) {
31753 var bts= this.buttons;
31755 Roo.each(bts, function(b) {
31764 * Fires when a key is pressed
31765 * @param {Roo.BasicDialog} this
31766 * @param {Roo.EventObject} e
31771 * Fires when this dialog is moved by the user.
31772 * @param {Roo.BasicDialog} this
31773 * @param {Number} x The new page X
31774 * @param {Number} y The new page Y
31779 * Fires when this dialog is resized by the user.
31780 * @param {Roo.BasicDialog} this
31781 * @param {Number} width The new width
31782 * @param {Number} height The new height
31786 * @event beforehide
31787 * Fires before this dialog is hidden.
31788 * @param {Roo.BasicDialog} this
31790 "beforehide" : true,
31793 * Fires when this dialog is hidden.
31794 * @param {Roo.BasicDialog} this
31798 * @event beforeshow
31799 * Fires before this dialog is shown.
31800 * @param {Roo.BasicDialog} this
31802 "beforeshow" : true,
31805 * Fires when this dialog is shown.
31806 * @param {Roo.BasicDialog} this
31810 el.on("keydown", this.onKeyDown, this);
31811 el.on("mousedown", this.toFront, this);
31812 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
31814 Roo.DialogManager.register(this);
31815 Roo.BasicDialog.superclass.constructor.call(this);
31818 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
31819 shadowOffset: Roo.isIE ? 6 : 5,
31822 minButtonWidth: 75,
31823 defaultButton: null,
31824 buttonAlign: "right",
31829 * Sets the dialog title text
31830 * @param {String} text The title text to display
31831 * @return {Roo.BasicDialog} this
31833 setTitle : function(text){
31834 this.header.update(text);
31839 closeClick : function(){
31844 collapseClick : function(){
31845 this[this.collapsed ? "expand" : "collapse"]();
31849 * Collapses the dialog to its minimized state (only the title bar is visible).
31850 * Equivalent to the user clicking the collapse dialog button.
31852 collapse : function(){
31853 if(!this.collapsed){
31854 this.collapsed = true;
31855 this.el.addClass("x-dlg-collapsed");
31856 this.restoreHeight = this.el.getHeight();
31857 this.resizeTo(this.el.getWidth(), this.header.getHeight());
31862 * Expands a collapsed dialog back to its normal state. Equivalent to the user
31863 * clicking the expand dialog button.
31865 expand : function(){
31866 if(this.collapsed){
31867 this.collapsed = false;
31868 this.el.removeClass("x-dlg-collapsed");
31869 this.resizeTo(this.el.getWidth(), this.restoreHeight);
31874 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
31875 * @return {Roo.TabPanel} The tabs component
31877 initTabs : function(){
31878 var tabs = this.getTabs();
31879 while(tabs.getTab(0)){
31882 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
31884 tabs.addTab(Roo.id(dom), dom.title);
31892 beforeResize : function(){
31893 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
31897 onResize : function(){
31898 this.refreshSize();
31899 this.syncBodyHeight();
31900 this.adjustAssets();
31902 this.fireEvent("resize", this, this.size.width, this.size.height);
31906 onKeyDown : function(e){
31907 if(this.isVisible()){
31908 this.fireEvent("keydown", this, e);
31913 * Resizes the dialog.
31914 * @param {Number} width
31915 * @param {Number} height
31916 * @return {Roo.BasicDialog} this
31918 resizeTo : function(width, height){
31919 this.el.setSize(width, height);
31920 this.size = {width: width, height: height};
31921 this.syncBodyHeight();
31922 if(this.fixedcenter){
31925 if(this.isVisible()){
31926 this.constrainXY();
31927 this.adjustAssets();
31929 this.fireEvent("resize", this, width, height);
31935 * Resizes the dialog to fit the specified content size.
31936 * @param {Number} width
31937 * @param {Number} height
31938 * @return {Roo.BasicDialog} this
31940 setContentSize : function(w, h){
31941 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
31942 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
31943 //if(!this.el.isBorderBox()){
31944 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
31945 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
31948 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
31949 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
31951 this.resizeTo(w, h);
31956 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
31957 * executed in response to a particular key being pressed while the dialog is active.
31958 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
31959 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
31960 * @param {Function} fn The function to call
31961 * @param {Object} scope (optional) The scope of the function
31962 * @return {Roo.BasicDialog} this
31964 addKeyListener : function(key, fn, scope){
31965 var keyCode, shift, ctrl, alt;
31966 if(typeof key == "object" && !(key instanceof Array)){
31967 keyCode = key["key"];
31968 shift = key["shift"];
31969 ctrl = key["ctrl"];
31974 var handler = function(dlg, e){
31975 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
31976 var k = e.getKey();
31977 if(keyCode instanceof Array){
31978 for(var i = 0, len = keyCode.length; i < len; i++){
31979 if(keyCode[i] == k){
31980 fn.call(scope || window, dlg, k, e);
31986 fn.call(scope || window, dlg, k, e);
31991 this.on("keydown", handler);
31996 * Returns the TabPanel component (creates it if it doesn't exist).
31997 * Note: If you wish to simply check for the existence of tabs without creating them,
31998 * check for a null 'tabs' property.
31999 * @return {Roo.TabPanel} The tabs component
32001 getTabs : function(){
32003 this.el.addClass("x-dlg-auto-tabs");
32004 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32005 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32011 * Adds a button to the footer section of the dialog.
32012 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32013 * object or a valid Roo.DomHelper element config
32014 * @param {Function} handler The function called when the button is clicked
32015 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32016 * @return {Roo.Button} The new button
32018 addButton : function(config, handler, scope){
32019 var dh = Roo.DomHelper;
32021 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32023 if(!this.btnContainer){
32024 var tb = this.footer.createChild({
32026 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32027 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32029 this.btnContainer = tb.firstChild.firstChild.firstChild;
32034 minWidth: this.minButtonWidth,
32037 if(typeof config == "string"){
32038 bconfig.text = config;
32041 bconfig.dhconfig = config;
32043 Roo.apply(bconfig, config);
32047 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32048 bconfig.position = Math.max(0, bconfig.position);
32049 fc = this.btnContainer.childNodes[bconfig.position];
32052 var btn = new Roo.Button(
32054 this.btnContainer.insertBefore(document.createElement("td"),fc)
32055 : this.btnContainer.appendChild(document.createElement("td")),
32056 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32059 this.syncBodyHeight();
32062 * Array of all the buttons that have been added to this dialog via addButton
32067 this.buttons.push(btn);
32072 * Sets the default button to be focused when the dialog is displayed.
32073 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32074 * @return {Roo.BasicDialog} this
32076 setDefaultButton : function(btn){
32077 this.defaultButton = btn;
32082 getHeaderFooterHeight : function(safe){
32085 height += this.header.getHeight();
32088 var fm = this.footer.getMargins();
32089 height += (this.footer.getHeight()+fm.top+fm.bottom);
32091 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32092 height += this.centerBg.getPadding("tb");
32097 syncBodyHeight : function()
32099 var bd = this.body, // the text
32100 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32102 var height = this.size.height - this.getHeaderFooterHeight(false);
32103 bd.setHeight(height-bd.getMargins("tb"));
32104 var hh = this.header.getHeight();
32105 var h = this.size.height-hh;
32108 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32109 bw.setHeight(h-cb.getPadding("tb"));
32111 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32112 bd.setWidth(bw.getWidth(true));
32114 this.tabs.syncHeight();
32116 this.tabs.el.repaint();
32122 * Restores the previous state of the dialog if Roo.state is configured.
32123 * @return {Roo.BasicDialog} this
32125 restoreState : function(){
32126 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32127 if(box && box.width){
32128 this.xy = [box.x, box.y];
32129 this.resizeTo(box.width, box.height);
32135 beforeShow : function(){
32137 if(this.fixedcenter){
32138 this.xy = this.el.getCenterXY(true);
32141 Roo.get(document.body).addClass("x-body-masked");
32142 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32145 this.constrainXY();
32149 animShow : function(){
32150 var b = Roo.get(this.animateTarget).getBox();
32151 this.proxy.setSize(b.width, b.height);
32152 this.proxy.setLocation(b.x, b.y);
32154 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32155 true, .35, this.showEl.createDelegate(this));
32159 * Shows the dialog.
32160 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32161 * @return {Roo.BasicDialog} this
32163 show : function(animateTarget){
32164 if (this.fireEvent("beforeshow", this) === false){
32167 if(this.syncHeightBeforeShow){
32168 this.syncBodyHeight();
32169 }else if(this.firstShow){
32170 this.firstShow = false;
32171 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32173 this.animateTarget = animateTarget || this.animateTarget;
32174 if(!this.el.isVisible()){
32176 if(this.animateTarget && Roo.get(this.animateTarget)){
32186 showEl : function(){
32188 this.el.setXY(this.xy);
32190 this.adjustAssets(true);
32193 // IE peekaboo bug - fix found by Dave Fenwick
32197 this.fireEvent("show", this);
32201 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32202 * dialog itself will receive focus.
32204 focus : function(){
32205 if(this.defaultButton){
32206 this.defaultButton.focus();
32208 this.focusEl.focus();
32213 constrainXY : function(){
32214 if(this.constraintoviewport !== false){
32215 if(!this.viewSize){
32216 if(this.container){
32217 var s = this.container.getSize();
32218 this.viewSize = [s.width, s.height];
32220 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32223 var s = Roo.get(this.container||document).getScroll();
32225 var x = this.xy[0], y = this.xy[1];
32226 var w = this.size.width, h = this.size.height;
32227 var vw = this.viewSize[0], vh = this.viewSize[1];
32228 // only move it if it needs it
32230 // first validate right/bottom
32231 if(x + w > vw+s.left){
32235 if(y + h > vh+s.top){
32239 // then make sure top/left isn't negative
32251 if(this.isVisible()){
32252 this.el.setLocation(x, y);
32253 this.adjustAssets();
32260 onDrag : function(){
32261 if(!this.proxyDrag){
32262 this.xy = this.el.getXY();
32263 this.adjustAssets();
32268 adjustAssets : function(doShow){
32269 var x = this.xy[0], y = this.xy[1];
32270 var w = this.size.width, h = this.size.height;
32271 if(doShow === true){
32273 this.shadow.show(this.el);
32279 if(this.shadow && this.shadow.isVisible()){
32280 this.shadow.show(this.el);
32282 if(this.shim && this.shim.isVisible()){
32283 this.shim.setBounds(x, y, w, h);
32288 adjustViewport : function(w, h){
32290 w = Roo.lib.Dom.getViewWidth();
32291 h = Roo.lib.Dom.getViewHeight();
32294 this.viewSize = [w, h];
32295 if(this.modal && this.mask.isVisible()){
32296 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32297 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32299 if(this.isVisible()){
32300 this.constrainXY();
32305 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32306 * shadow, proxy, mask, etc.) Also removes all event listeners.
32307 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32309 destroy : function(removeEl){
32310 if(this.isVisible()){
32311 this.animateTarget = null;
32314 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32316 this.tabs.destroy(removeEl);
32329 for(var i = 0, len = this.buttons.length; i < len; i++){
32330 this.buttons[i].destroy();
32333 this.el.removeAllListeners();
32334 if(removeEl === true){
32335 this.el.update("");
32338 Roo.DialogManager.unregister(this);
32342 startMove : function(){
32343 if(this.proxyDrag){
32346 if(this.constraintoviewport !== false){
32347 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32352 endMove : function(){
32353 if(!this.proxyDrag){
32354 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32356 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32359 this.refreshSize();
32360 this.adjustAssets();
32362 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32366 * Brings this dialog to the front of any other visible dialogs
32367 * @return {Roo.BasicDialog} this
32369 toFront : function(){
32370 Roo.DialogManager.bringToFront(this);
32375 * Sends this dialog to the back (under) of any other visible dialogs
32376 * @return {Roo.BasicDialog} this
32378 toBack : function(){
32379 Roo.DialogManager.sendToBack(this);
32384 * Centers this dialog in the viewport
32385 * @return {Roo.BasicDialog} this
32387 center : function(){
32388 var xy = this.el.getCenterXY(true);
32389 this.moveTo(xy[0], xy[1]);
32394 * Moves the dialog's top-left corner to the specified point
32395 * @param {Number} x
32396 * @param {Number} y
32397 * @return {Roo.BasicDialog} this
32399 moveTo : function(x, y){
32401 if(this.isVisible()){
32402 this.el.setXY(this.xy);
32403 this.adjustAssets();
32409 * Aligns the dialog to the specified element
32410 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32411 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32412 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32413 * @return {Roo.BasicDialog} this
32415 alignTo : function(element, position, offsets){
32416 this.xy = this.el.getAlignToXY(element, position, offsets);
32417 if(this.isVisible()){
32418 this.el.setXY(this.xy);
32419 this.adjustAssets();
32425 * Anchors an element to another element and realigns it when the window is resized.
32426 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32427 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32428 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32429 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32430 * is a number, it is used as the buffer delay (defaults to 50ms).
32431 * @return {Roo.BasicDialog} this
32433 anchorTo : function(el, alignment, offsets, monitorScroll){
32434 var action = function(){
32435 this.alignTo(el, alignment, offsets);
32437 Roo.EventManager.onWindowResize(action, this);
32438 var tm = typeof monitorScroll;
32439 if(tm != 'undefined'){
32440 Roo.EventManager.on(window, 'scroll', action, this,
32441 {buffer: tm == 'number' ? monitorScroll : 50});
32448 * Returns true if the dialog is visible
32449 * @return {Boolean}
32451 isVisible : function(){
32452 return this.el.isVisible();
32456 animHide : function(callback){
32457 var b = Roo.get(this.animateTarget).getBox();
32459 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32461 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32462 this.hideEl.createDelegate(this, [callback]));
32466 * Hides the dialog.
32467 * @param {Function} callback (optional) Function to call when the dialog is hidden
32468 * @return {Roo.BasicDialog} this
32470 hide : function(callback){
32471 if (this.fireEvent("beforehide", this) === false){
32475 this.shadow.hide();
32480 // sometimes animateTarget seems to get set.. causing problems...
32481 // this just double checks..
32482 if(this.animateTarget && Roo.get(this.animateTarget)) {
32483 this.animHide(callback);
32486 this.hideEl(callback);
32492 hideEl : function(callback){
32496 Roo.get(document.body).removeClass("x-body-masked");
32498 this.fireEvent("hide", this);
32499 if(typeof callback == "function"){
32505 hideAction : function(){
32506 this.setLeft("-10000px");
32507 this.setTop("-10000px");
32508 this.setStyle("visibility", "hidden");
32512 refreshSize : function(){
32513 this.size = this.el.getSize();
32514 this.xy = this.el.getXY();
32515 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32519 // z-index is managed by the DialogManager and may be overwritten at any time
32520 setZIndex : function(index){
32522 this.mask.setStyle("z-index", index);
32525 this.shim.setStyle("z-index", ++index);
32528 this.shadow.setZIndex(++index);
32530 this.el.setStyle("z-index", ++index);
32532 this.proxy.setStyle("z-index", ++index);
32535 this.resizer.proxy.setStyle("z-index", ++index);
32538 this.lastZIndex = index;
32542 * Returns the element for this dialog
32543 * @return {Roo.Element} The underlying dialog Element
32545 getEl : function(){
32551 * @class Roo.DialogManager
32552 * Provides global access to BasicDialogs that have been created and
32553 * support for z-indexing (layering) multiple open dialogs.
32555 Roo.DialogManager = function(){
32557 var accessList = [];
32561 var sortDialogs = function(d1, d2){
32562 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32566 var orderDialogs = function(){
32567 accessList.sort(sortDialogs);
32568 var seed = Roo.DialogManager.zseed;
32569 for(var i = 0, len = accessList.length; i < len; i++){
32570 var dlg = accessList[i];
32572 dlg.setZIndex(seed + (i*10));
32579 * The starting z-index for BasicDialogs (defaults to 9000)
32580 * @type Number The z-index value
32585 register : function(dlg){
32586 list[dlg.id] = dlg;
32587 accessList.push(dlg);
32591 unregister : function(dlg){
32592 delete list[dlg.id];
32595 if(!accessList.indexOf){
32596 for( i = 0, len = accessList.length; i < len; i++){
32597 if(accessList[i] == dlg){
32598 accessList.splice(i, 1);
32603 i = accessList.indexOf(dlg);
32605 accessList.splice(i, 1);
32611 * Gets a registered dialog by id
32612 * @param {String/Object} id The id of the dialog or a dialog
32613 * @return {Roo.BasicDialog} this
32615 get : function(id){
32616 return typeof id == "object" ? id : list[id];
32620 * Brings the specified dialog to the front
32621 * @param {String/Object} dlg The id of the dialog or a dialog
32622 * @return {Roo.BasicDialog} this
32624 bringToFront : function(dlg){
32625 dlg = this.get(dlg);
32628 dlg._lastAccess = new Date().getTime();
32635 * Sends the specified dialog to the back
32636 * @param {String/Object} dlg The id of the dialog or a dialog
32637 * @return {Roo.BasicDialog} this
32639 sendToBack : function(dlg){
32640 dlg = this.get(dlg);
32641 dlg._lastAccess = -(new Date().getTime());
32647 * Hides all dialogs
32649 hideAll : function(){
32650 for(var id in list){
32651 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32660 * @class Roo.LayoutDialog
32661 * @extends Roo.BasicDialog
32662 * Dialog which provides adjustments for working with a layout in a Dialog.
32663 * Add your necessary layout config options to the dialog's config.<br>
32664 * Example usage (including a nested layout):
32667 dialog = new Roo.LayoutDialog("download-dlg", {
32676 // layout config merges with the dialog config
32678 tabPosition: "top",
32679 alwaysShowTabs: true
32682 dialog.addKeyListener(27, dialog.hide, dialog);
32683 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32684 dialog.addButton("Build It!", this.getDownload, this);
32686 // we can even add nested layouts
32687 var innerLayout = new Roo.BorderLayout("dl-inner", {
32697 innerLayout.beginUpdate();
32698 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32699 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32700 innerLayout.endUpdate(true);
32702 var layout = dialog.getLayout();
32703 layout.beginUpdate();
32704 layout.add("center", new Roo.ContentPanel("standard-panel",
32705 {title: "Download the Source", fitToFrame:true}));
32706 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32707 {title: "Build your own roo.js"}));
32708 layout.getRegion("center").showPanel(sp);
32709 layout.endUpdate();
32713 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32714 * @param {Object} config configuration options
32716 Roo.LayoutDialog = function(el, cfg){
32719 if (typeof(cfg) == 'undefined') {
32720 config = Roo.apply({}, el);
32721 // not sure why we use documentElement here.. - it should always be body.
32722 // IE7 borks horribly if we use documentElement.
32723 // webkit also does not like documentElement - it creates a body element...
32724 el = Roo.get( document.body || document.documentElement ).createChild();
32725 //config.autoCreate = true;
32729 config.autoTabs = false;
32730 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
32731 this.body.setStyle({overflow:"hidden", position:"relative"});
32732 this.layout = new Roo.BorderLayout(this.body.dom, config);
32733 this.layout.monitorWindowResize = false;
32734 this.el.addClass("x-dlg-auto-layout");
32735 // fix case when center region overwrites center function
32736 this.center = Roo.BasicDialog.prototype.center;
32737 this.on("show", this.layout.layout, this.layout, true);
32738 if (config.items) {
32739 var xitems = config.items;
32740 delete config.items;
32741 Roo.each(xitems, this.addxtype, this);
32746 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
32748 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
32751 endUpdate : function(){
32752 this.layout.endUpdate();
32756 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
32759 beginUpdate : function(){
32760 this.layout.beginUpdate();
32764 * Get the BorderLayout for this dialog
32765 * @return {Roo.BorderLayout}
32767 getLayout : function(){
32768 return this.layout;
32771 showEl : function(){
32772 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
32774 this.layout.layout();
32779 // Use the syncHeightBeforeShow config option to control this automatically
32780 syncBodyHeight : function(){
32781 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
32782 if(this.layout){this.layout.layout();}
32786 * Add an xtype element (actually adds to the layout.)
32787 * @return {Object} xdata xtype object data.
32790 addxtype : function(c) {
32791 return this.layout.addxtype(c);
32795 * Ext JS Library 1.1.1
32796 * Copyright(c) 2006-2007, Ext JS, LLC.
32798 * Originally Released Under LGPL - original licence link has changed is not relivant.
32801 * <script type="text/javascript">
32805 * @class Roo.MessageBox
32806 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
32810 Roo.Msg.alert('Status', 'Changes saved successfully.');
32812 // Prompt for user data:
32813 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
32815 // process text value...
32819 // Show a dialog using config options:
32821 title:'Save Changes?',
32822 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
32823 buttons: Roo.Msg.YESNOCANCEL,
32830 Roo.MessageBox = function(){
32831 var dlg, opt, mask, waitTimer;
32832 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
32833 var buttons, activeTextEl, bwidth;
32836 var handleButton = function(button){
32838 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
32842 var handleHide = function(){
32843 if(opt && opt.cls){
32844 dlg.el.removeClass(opt.cls);
32847 Roo.TaskMgr.stop(waitTimer);
32853 var updateButtons = function(b){
32856 buttons["ok"].hide();
32857 buttons["cancel"].hide();
32858 buttons["yes"].hide();
32859 buttons["no"].hide();
32860 dlg.footer.dom.style.display = 'none';
32863 dlg.footer.dom.style.display = '';
32864 for(var k in buttons){
32865 if(typeof buttons[k] != "function"){
32868 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
32869 width += buttons[k].el.getWidth()+15;
32879 var handleEsc = function(d, k, e){
32880 if(opt && opt.closable !== false){
32890 * Returns a reference to the underlying {@link Roo.BasicDialog} element
32891 * @return {Roo.BasicDialog} The BasicDialog element
32893 getDialog : function(){
32895 dlg = new Roo.BasicDialog("x-msg-box", {
32900 constraintoviewport:false,
32902 collapsible : false,
32905 width:400, height:100,
32906 buttonAlign:"center",
32907 closeClick : function(){
32908 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
32909 handleButton("no");
32911 handleButton("cancel");
32915 dlg.on("hide", handleHide);
32917 dlg.addKeyListener(27, handleEsc);
32919 var bt = this.buttonText;
32920 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
32921 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
32922 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
32923 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
32924 bodyEl = dlg.body.createChild({
32926 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>'
32928 msgEl = bodyEl.dom.firstChild;
32929 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
32930 textboxEl.enableDisplayMode();
32931 textboxEl.addKeyListener([10,13], function(){
32932 if(dlg.isVisible() && opt && opt.buttons){
32933 if(opt.buttons.ok){
32934 handleButton("ok");
32935 }else if(opt.buttons.yes){
32936 handleButton("yes");
32940 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
32941 textareaEl.enableDisplayMode();
32942 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
32943 progressEl.enableDisplayMode();
32944 var pf = progressEl.dom.firstChild;
32946 pp = Roo.get(pf.firstChild);
32947 pp.setHeight(pf.offsetHeight);
32955 * Updates the message box body text
32956 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
32957 * the XHTML-compliant non-breaking space character '&#160;')
32958 * @return {Roo.MessageBox} This message box
32960 updateText : function(text){
32961 if(!dlg.isVisible() && !opt.width){
32962 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
32964 msgEl.innerHTML = text || ' ';
32966 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
32967 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
32969 Math.min(opt.width || cw , this.maxWidth),
32970 Math.max(opt.minWidth || this.minWidth, bwidth)
32973 activeTextEl.setWidth(w);
32975 if(dlg.isVisible()){
32976 dlg.fixedcenter = false;
32978 // to big, make it scroll. = But as usual stupid IE does not support
32981 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
32982 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
32983 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
32985 bodyEl.dom.style.height = '';
32986 bodyEl.dom.style.overflowY = '';
32989 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
32991 bodyEl.dom.style.overflowX = '';
32994 dlg.setContentSize(w, bodyEl.getHeight());
32995 if(dlg.isVisible()){
32996 dlg.fixedcenter = true;
33002 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33003 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33004 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33005 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33006 * @return {Roo.MessageBox} This message box
33008 updateProgress : function(value, text){
33010 this.updateText(text);
33012 if (pp) { // weird bug on my firefox - for some reason this is not defined
33013 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33019 * Returns true if the message box is currently displayed
33020 * @return {Boolean} True if the message box is visible, else false
33022 isVisible : function(){
33023 return dlg && dlg.isVisible();
33027 * Hides the message box if it is displayed
33030 if(this.isVisible()){
33036 * Displays a new message box, or reinitializes an existing message box, based on the config options
33037 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33038 * The following config object properties are supported:
33040 Property Type Description
33041 ---------- --------------- ------------------------------------------------------------------------------------
33042 animEl String/Element An id or Element from which the message box should animate as it opens and
33043 closes (defaults to undefined)
33044 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33045 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33046 closable Boolean False to hide the top-right close button (defaults to true). Note that
33047 progress and wait dialogs will ignore this property and always hide the
33048 close button as they can only be closed programmatically.
33049 cls String A custom CSS class to apply to the message box element
33050 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33051 displayed (defaults to 75)
33052 fn Function A callback function to execute after closing the dialog. The arguments to the
33053 function will be btn (the name of the button that was clicked, if applicable,
33054 e.g. "ok"), and text (the value of the active text field, if applicable).
33055 Progress and wait dialogs will ignore this option since they do not respond to
33056 user actions and can only be closed programmatically, so any required function
33057 should be called by the same code after it closes the dialog.
33058 icon String A CSS class that provides a background image to be used as an icon for
33059 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33060 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33061 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33062 modal Boolean False to allow user interaction with the page while the message box is
33063 displayed (defaults to true)
33064 msg String A string that will replace the existing message box body text (defaults
33065 to the XHTML-compliant non-breaking space character ' ')
33066 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33067 progress Boolean True to display a progress bar (defaults to false)
33068 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33069 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33070 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33071 title String The title text
33072 value String The string value to set into the active textbox element if displayed
33073 wait Boolean True to display a progress bar (defaults to false)
33074 width Number The width of the dialog in pixels
33081 msg: 'Please enter your address:',
33083 buttons: Roo.MessageBox.OKCANCEL,
33086 animEl: 'addAddressBtn'
33089 * @param {Object} config Configuration options
33090 * @return {Roo.MessageBox} This message box
33092 show : function(options)
33095 // this causes nightmares if you show one dialog after another
33096 // especially on callbacks..
33098 if(this.isVisible()){
33101 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33102 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33103 Roo.log("New Dialog Message:" + options.msg )
33104 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33105 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33108 var d = this.getDialog();
33110 d.setTitle(opt.title || " ");
33111 d.close.setDisplayed(opt.closable !== false);
33112 activeTextEl = textboxEl;
33113 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33118 textareaEl.setHeight(typeof opt.multiline == "number" ?
33119 opt.multiline : this.defaultTextHeight);
33120 activeTextEl = textareaEl;
33129 progressEl.setDisplayed(opt.progress === true);
33130 this.updateProgress(0);
33131 activeTextEl.dom.value = opt.value || "";
33133 dlg.setDefaultButton(activeTextEl);
33135 var bs = opt.buttons;
33138 db = buttons["ok"];
33139 }else if(bs && bs.yes){
33140 db = buttons["yes"];
33142 dlg.setDefaultButton(db);
33144 bwidth = updateButtons(opt.buttons);
33145 this.updateText(opt.msg);
33147 d.el.addClass(opt.cls);
33149 d.proxyDrag = opt.proxyDrag === true;
33150 d.modal = opt.modal !== false;
33151 d.mask = opt.modal !== false ? mask : false;
33152 if(!d.isVisible()){
33153 // force it to the end of the z-index stack so it gets a cursor in FF
33154 document.body.appendChild(dlg.el.dom);
33155 d.animateTarget = null;
33156 d.show(options.animEl);
33162 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33163 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33164 * and closing the message box when the process is complete.
33165 * @param {String} title The title bar text
33166 * @param {String} msg The message box body text
33167 * @return {Roo.MessageBox} This message box
33169 progress : function(title, msg){
33176 minWidth: this.minProgressWidth,
33183 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33184 * If a callback function is passed it will be called after the user clicks the button, and the
33185 * id of the button that was clicked will be passed as the only parameter to the callback
33186 * (could also be the top-right close button).
33187 * @param {String} title The title bar text
33188 * @param {String} msg The message box body text
33189 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33190 * @param {Object} scope (optional) The scope of the callback function
33191 * @return {Roo.MessageBox} This message box
33193 alert : function(title, msg, fn, scope){
33206 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33207 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33208 * You are responsible for closing the message box when the process is complete.
33209 * @param {String} msg The message box body text
33210 * @param {String} title (optional) The title bar text
33211 * @return {Roo.MessageBox} This message box
33213 wait : function(msg, title){
33224 waitTimer = Roo.TaskMgr.start({
33226 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33234 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33235 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33236 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33237 * @param {String} title The title bar text
33238 * @param {String} msg The message box body text
33239 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33240 * @param {Object} scope (optional) The scope of the callback function
33241 * @return {Roo.MessageBox} This message box
33243 confirm : function(title, msg, fn, scope){
33247 buttons: this.YESNO,
33256 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33257 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33258 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33259 * (could also be the top-right close button) and the text that was entered will be passed as the two
33260 * parameters to the callback.
33261 * @param {String} title The title bar text
33262 * @param {String} msg The message box body text
33263 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33264 * @param {Object} scope (optional) The scope of the callback function
33265 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33266 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33267 * @return {Roo.MessageBox} This message box
33269 prompt : function(title, msg, fn, scope, multiline){
33273 buttons: this.OKCANCEL,
33278 multiline: multiline,
33285 * Button config that displays a single OK button
33290 * Button config that displays Yes and No buttons
33293 YESNO : {yes:true, no:true},
33295 * Button config that displays OK and Cancel buttons
33298 OKCANCEL : {ok:true, cancel:true},
33300 * Button config that displays Yes, No and Cancel buttons
33303 YESNOCANCEL : {yes:true, no:true, cancel:true},
33306 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33309 defaultTextHeight : 75,
33311 * The maximum width in pixels of the message box (defaults to 600)
33316 * The minimum width in pixels of the message box (defaults to 100)
33321 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33322 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33325 minProgressWidth : 250,
33327 * An object containing the default button text strings that can be overriden for localized language support.
33328 * Supported properties are: ok, cancel, yes and no.
33329 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33342 * Shorthand for {@link Roo.MessageBox}
33344 Roo.Msg = Roo.MessageBox;/*
33346 * Ext JS Library 1.1.1
33347 * Copyright(c) 2006-2007, Ext JS, LLC.
33349 * Originally Released Under LGPL - original licence link has changed is not relivant.
33352 * <script type="text/javascript">
33355 * @class Roo.QuickTips
33356 * Provides attractive and customizable tooltips for any element.
33359 Roo.QuickTips = function(){
33360 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33361 var ce, bd, xy, dd;
33362 var visible = false, disabled = true, inited = false;
33363 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33365 var onOver = function(e){
33369 var t = e.getTarget();
33370 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33373 if(ce && t == ce.el){
33374 clearTimeout(hideProc);
33377 if(t && tagEls[t.id]){
33378 tagEls[t.id].el = t;
33379 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33382 var ttp, et = Roo.fly(t);
33383 var ns = cfg.namespace;
33384 if(tm.interceptTitles && t.title){
33387 t.removeAttribute("title");
33388 e.preventDefault();
33390 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33393 showProc = show.defer(tm.showDelay, tm, [{
33396 width: et.getAttributeNS(ns, cfg.width),
33397 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33398 title: et.getAttributeNS(ns, cfg.title),
33399 cls: et.getAttributeNS(ns, cfg.cls)
33404 var onOut = function(e){
33405 clearTimeout(showProc);
33406 var t = e.getTarget();
33407 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33408 hideProc = setTimeout(hide, tm.hideDelay);
33412 var onMove = function(e){
33418 if(tm.trackMouse && ce){
33423 var onDown = function(e){
33424 clearTimeout(showProc);
33425 clearTimeout(hideProc);
33427 if(tm.hideOnClick){
33430 tm.enable.defer(100, tm);
33435 var getPad = function(){
33436 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33439 var show = function(o){
33443 clearTimeout(dismissProc);
33445 if(removeCls){ // in case manually hidden
33446 el.removeClass(removeCls);
33450 el.addClass(ce.cls);
33451 removeCls = ce.cls;
33454 tipTitle.update(ce.title);
33457 tipTitle.update('');
33460 el.dom.style.width = tm.maxWidth+'px';
33461 //tipBody.dom.style.width = '';
33462 tipBodyText.update(o.text);
33463 var p = getPad(), w = ce.width;
33465 var td = tipBodyText.dom;
33466 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33467 if(aw > tm.maxWidth){
33469 }else if(aw < tm.minWidth){
33475 //tipBody.setWidth(w);
33476 el.setWidth(parseInt(w, 10) + p);
33477 if(ce.autoHide === false){
33478 close.setDisplayed(true);
33483 close.setDisplayed(false);
33489 el.avoidY = xy[1]-18;
33494 el.setStyle("visibility", "visible");
33495 el.fadeIn({callback: afterShow});
33501 var afterShow = function(){
33505 if(tm.autoDismiss && ce.autoHide !== false){
33506 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33511 var hide = function(noanim){
33512 clearTimeout(dismissProc);
33513 clearTimeout(hideProc);
33515 if(el.isVisible()){
33517 if(noanim !== true && tm.animate){
33518 el.fadeOut({callback: afterHide});
33525 var afterHide = function(){
33528 el.removeClass(removeCls);
33535 * @cfg {Number} minWidth
33536 * The minimum width of the quick tip (defaults to 40)
33540 * @cfg {Number} maxWidth
33541 * The maximum width of the quick tip (defaults to 300)
33545 * @cfg {Boolean} interceptTitles
33546 * True to automatically use the element's DOM title value if available (defaults to false)
33548 interceptTitles : false,
33550 * @cfg {Boolean} trackMouse
33551 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33553 trackMouse : false,
33555 * @cfg {Boolean} hideOnClick
33556 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33558 hideOnClick : true,
33560 * @cfg {Number} showDelay
33561 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33565 * @cfg {Number} hideDelay
33566 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33570 * @cfg {Boolean} autoHide
33571 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33572 * Used in conjunction with hideDelay.
33577 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33578 * (defaults to true). Used in conjunction with autoDismissDelay.
33580 autoDismiss : true,
33583 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33585 autoDismissDelay : 5000,
33587 * @cfg {Boolean} animate
33588 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33593 * @cfg {String} title
33594 * Title text to display (defaults to ''). This can be any valid HTML markup.
33598 * @cfg {String} text
33599 * Body text to display (defaults to ''). This can be any valid HTML markup.
33603 * @cfg {String} cls
33604 * A CSS class to apply to the base quick tip element (defaults to '').
33608 * @cfg {Number} width
33609 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33610 * minWidth or maxWidth.
33615 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33616 * or display QuickTips in a page.
33619 tm = Roo.QuickTips;
33620 cfg = tm.tagConfig;
33622 if(!Roo.isReady){ // allow calling of init() before onReady
33623 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33626 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33627 el.fxDefaults = {stopFx: true};
33628 // maximum custom styling
33629 //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>');
33630 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>');
33631 tipTitle = el.child('h3');
33632 tipTitle.enableDisplayMode("block");
33633 tipBody = el.child('div.x-tip-bd');
33634 tipBodyText = el.child('div.x-tip-bd-inner');
33635 //bdLeft = el.child('div.x-tip-bd-left');
33636 //bdRight = el.child('div.x-tip-bd-right');
33637 close = el.child('div.x-tip-close');
33638 close.enableDisplayMode("block");
33639 close.on("click", hide);
33640 var d = Roo.get(document);
33641 d.on("mousedown", onDown);
33642 d.on("mouseover", onOver);
33643 d.on("mouseout", onOut);
33644 d.on("mousemove", onMove);
33645 esc = d.addKeyListener(27, hide);
33648 dd = el.initDD("default", null, {
33649 onDrag : function(){
33653 dd.setHandleElId(tipTitle.id);
33662 * Configures a new quick tip instance and assigns it to a target element. The following config options
33665 Property Type Description
33666 ---------- --------------------- ------------------------------------------------------------------------
33667 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33669 * @param {Object} config The config object
33671 register : function(config){
33672 var cs = config instanceof Array ? config : arguments;
33673 for(var i = 0, len = cs.length; i < len; i++) {
33675 var target = c.target;
33677 if(target instanceof Array){
33678 for(var j = 0, jlen = target.length; j < jlen; j++){
33679 tagEls[target[j]] = c;
33682 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33689 * Removes this quick tip from its element and destroys it.
33690 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33692 unregister : function(el){
33693 delete tagEls[Roo.id(el)];
33697 * Enable this quick tip.
33699 enable : function(){
33700 if(inited && disabled){
33702 if(locks.length < 1){
33709 * Disable this quick tip.
33711 disable : function(){
33713 clearTimeout(showProc);
33714 clearTimeout(hideProc);
33715 clearTimeout(dismissProc);
33723 * Returns true if the quick tip is enabled, else false.
33725 isEnabled : function(){
33731 namespace : "roo", // was ext?? this may break..
33732 alt_namespace : "ext",
33733 attribute : "qtip",
33743 // backwards compat
33744 Roo.QuickTips.tips = Roo.QuickTips.register;/*
33746 * Ext JS Library 1.1.1
33747 * Copyright(c) 2006-2007, Ext JS, LLC.
33749 * Originally Released Under LGPL - original licence link has changed is not relivant.
33752 * <script type="text/javascript">
33757 * @class Roo.tree.TreePanel
33758 * @extends Roo.data.Tree
33760 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
33761 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
33762 * @cfg {Boolean} enableDD true to enable drag and drop
33763 * @cfg {Boolean} enableDrag true to enable just drag
33764 * @cfg {Boolean} enableDrop true to enable just drop
33765 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
33766 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
33767 * @cfg {String} ddGroup The DD group this TreePanel belongs to
33768 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
33769 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
33770 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
33771 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
33772 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
33773 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
33774 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
33775 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
33776 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
33777 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
33778 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
33779 * @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>
33780 * @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>
33783 * @param {String/HTMLElement/Element} el The container element
33784 * @param {Object} config
33786 Roo.tree.TreePanel = function(el, config){
33788 var loader = false;
33790 root = config.root;
33791 delete config.root;
33793 if (config.loader) {
33794 loader = config.loader;
33795 delete config.loader;
33798 Roo.apply(this, config);
33799 Roo.tree.TreePanel.superclass.constructor.call(this);
33800 this.el = Roo.get(el);
33801 this.el.addClass('x-tree');
33802 //console.log(root);
33804 this.setRootNode( Roo.factory(root, Roo.tree));
33807 this.loader = Roo.factory(loader, Roo.tree);
33810 * Read-only. The id of the container element becomes this TreePanel's id.
33812 this.id = this.el.id;
33815 * @event beforeload
33816 * Fires before a node is loaded, return false to cancel
33817 * @param {Node} node The node being loaded
33819 "beforeload" : true,
33822 * Fires when a node is loaded
33823 * @param {Node} node The node that was loaded
33827 * @event textchange
33828 * Fires when the text for a node is changed
33829 * @param {Node} node The node
33830 * @param {String} text The new text
33831 * @param {String} oldText The old text
33833 "textchange" : true,
33835 * @event beforeexpand
33836 * Fires before a node is expanded, return false to cancel.
33837 * @param {Node} node The node
33838 * @param {Boolean} deep
33839 * @param {Boolean} anim
33841 "beforeexpand" : true,
33843 * @event beforecollapse
33844 * Fires before a node is collapsed, return false to cancel.
33845 * @param {Node} node The node
33846 * @param {Boolean} deep
33847 * @param {Boolean} anim
33849 "beforecollapse" : true,
33852 * Fires when a node is expanded
33853 * @param {Node} node The node
33857 * @event disabledchange
33858 * Fires when the disabled status of a node changes
33859 * @param {Node} node The node
33860 * @param {Boolean} disabled
33862 "disabledchange" : true,
33865 * Fires when a node is collapsed
33866 * @param {Node} node The node
33870 * @event beforeclick
33871 * Fires before click processing on a node. Return false to cancel the default action.
33872 * @param {Node} node The node
33873 * @param {Roo.EventObject} e The event object
33875 "beforeclick":true,
33877 * @event checkchange
33878 * Fires when a node with a checkbox's checked property changes
33879 * @param {Node} this This node
33880 * @param {Boolean} checked
33882 "checkchange":true,
33885 * Fires when a node is clicked
33886 * @param {Node} node The node
33887 * @param {Roo.EventObject} e The event object
33892 * Fires when a node is double clicked
33893 * @param {Node} node The node
33894 * @param {Roo.EventObject} e The event object
33898 * @event contextmenu
33899 * Fires when a node is right clicked
33900 * @param {Node} node The node
33901 * @param {Roo.EventObject} e The event object
33903 "contextmenu":true,
33905 * @event beforechildrenrendered
33906 * Fires right before the child nodes for a node are rendered
33907 * @param {Node} node The node
33909 "beforechildrenrendered":true,
33912 * Fires when a node starts being dragged
33913 * @param {Roo.tree.TreePanel} this
33914 * @param {Roo.tree.TreeNode} node
33915 * @param {event} e The raw browser event
33917 "startdrag" : true,
33920 * Fires when a drag operation is complete
33921 * @param {Roo.tree.TreePanel} this
33922 * @param {Roo.tree.TreeNode} node
33923 * @param {event} e The raw browser event
33928 * Fires when a dragged node is dropped on a valid DD target
33929 * @param {Roo.tree.TreePanel} this
33930 * @param {Roo.tree.TreeNode} node
33931 * @param {DD} dd The dd it was dropped on
33932 * @param {event} e The raw browser event
33936 * @event beforenodedrop
33937 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
33938 * passed to handlers has the following properties:<br />
33939 * <ul style="padding:5px;padding-left:16px;">
33940 * <li>tree - The TreePanel</li>
33941 * <li>target - The node being targeted for the drop</li>
33942 * <li>data - The drag data from the drag source</li>
33943 * <li>point - The point of the drop - append, above or below</li>
33944 * <li>source - The drag source</li>
33945 * <li>rawEvent - Raw mouse event</li>
33946 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
33947 * to be inserted by setting them on this object.</li>
33948 * <li>cancel - Set this to true to cancel the drop.</li>
33950 * @param {Object} dropEvent
33952 "beforenodedrop" : true,
33955 * Fires after a DD object is dropped on a node in this tree. The dropEvent
33956 * passed to handlers has the following properties:<br />
33957 * <ul style="padding:5px;padding-left:16px;">
33958 * <li>tree - The TreePanel</li>
33959 * <li>target - The node being targeted for the drop</li>
33960 * <li>data - The drag data from the drag source</li>
33961 * <li>point - The point of the drop - append, above or below</li>
33962 * <li>source - The drag source</li>
33963 * <li>rawEvent - Raw mouse event</li>
33964 * <li>dropNode - Dropped node(s).</li>
33966 * @param {Object} dropEvent
33970 * @event nodedragover
33971 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
33972 * passed to handlers has the following properties:<br />
33973 * <ul style="padding:5px;padding-left:16px;">
33974 * <li>tree - The TreePanel</li>
33975 * <li>target - The node being targeted for the drop</li>
33976 * <li>data - The drag data from the drag source</li>
33977 * <li>point - The point of the drop - append, above or below</li>
33978 * <li>source - The drag source</li>
33979 * <li>rawEvent - Raw mouse event</li>
33980 * <li>dropNode - Drop node(s) provided by the source.</li>
33981 * <li>cancel - Set this to true to signal drop not allowed.</li>
33983 * @param {Object} dragOverEvent
33985 "nodedragover" : true
33988 if(this.singleExpand){
33989 this.on("beforeexpand", this.restrictExpand, this);
33992 this.editor.tree = this;
33993 this.editor = Roo.factory(this.editor, Roo.tree);
33996 if (this.selModel) {
33997 this.selModel = Roo.factory(this.selModel, Roo.tree);
34001 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34002 rootVisible : true,
34003 animate: Roo.enableFx,
34006 hlDrop : Roo.enableFx,
34010 rendererTip: false,
34012 restrictExpand : function(node){
34013 var p = node.parentNode;
34015 if(p.expandedChild && p.expandedChild.parentNode == p){
34016 p.expandedChild.collapse();
34018 p.expandedChild = node;
34022 // private override
34023 setRootNode : function(node){
34024 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34025 if(!this.rootVisible){
34026 node.ui = new Roo.tree.RootTreeNodeUI(node);
34032 * Returns the container element for this TreePanel
34034 getEl : function(){
34039 * Returns the default TreeLoader for this TreePanel
34041 getLoader : function(){
34042 return this.loader;
34048 expandAll : function(){
34049 this.root.expand(true);
34053 * Collapse all nodes
34055 collapseAll : function(){
34056 this.root.collapse(true);
34060 * Returns the selection model used by this TreePanel
34062 getSelectionModel : function(){
34063 if(!this.selModel){
34064 this.selModel = new Roo.tree.DefaultSelectionModel();
34066 return this.selModel;
34070 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34071 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34072 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34075 getChecked : function(a, startNode){
34076 startNode = startNode || this.root;
34078 var f = function(){
34079 if(this.attributes.checked){
34080 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34083 startNode.cascade(f);
34088 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34089 * @param {String} path
34090 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34091 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34092 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34094 expandPath : function(path, attr, callback){
34095 attr = attr || "id";
34096 var keys = path.split(this.pathSeparator);
34097 var curNode = this.root;
34098 if(curNode.attributes[attr] != keys[1]){ // invalid root
34100 callback(false, null);
34105 var f = function(){
34106 if(++index == keys.length){
34108 callback(true, curNode);
34112 var c = curNode.findChild(attr, keys[index]);
34115 callback(false, curNode);
34120 c.expand(false, false, f);
34122 curNode.expand(false, false, f);
34126 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34127 * @param {String} path
34128 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34129 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34130 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34132 selectPath : function(path, attr, callback){
34133 attr = attr || "id";
34134 var keys = path.split(this.pathSeparator);
34135 var v = keys.pop();
34136 if(keys.length > 0){
34137 var f = function(success, node){
34138 if(success && node){
34139 var n = node.findChild(attr, v);
34145 }else if(callback){
34146 callback(false, n);
34150 callback(false, n);
34154 this.expandPath(keys.join(this.pathSeparator), attr, f);
34156 this.root.select();
34158 callback(true, this.root);
34163 getTreeEl : function(){
34168 * Trigger rendering of this TreePanel
34170 render : function(){
34171 if (this.innerCt) {
34172 return this; // stop it rendering more than once!!
34175 this.innerCt = this.el.createChild({tag:"ul",
34176 cls:"x-tree-root-ct " +
34177 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34179 if(this.containerScroll){
34180 Roo.dd.ScrollManager.register(this.el);
34182 if((this.enableDD || this.enableDrop) && !this.dropZone){
34184 * The dropZone used by this tree if drop is enabled
34185 * @type Roo.tree.TreeDropZone
34187 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34188 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34191 if((this.enableDD || this.enableDrag) && !this.dragZone){
34193 * The dragZone used by this tree if drag is enabled
34194 * @type Roo.tree.TreeDragZone
34196 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34197 ddGroup: this.ddGroup || "TreeDD",
34198 scroll: this.ddScroll
34201 this.getSelectionModel().init(this);
34203 Roo.log("ROOT not set in tree");
34206 this.root.render();
34207 if(!this.rootVisible){
34208 this.root.renderChildren();
34214 * Ext JS Library 1.1.1
34215 * Copyright(c) 2006-2007, Ext JS, LLC.
34217 * Originally Released Under LGPL - original licence link has changed is not relivant.
34220 * <script type="text/javascript">
34225 * @class Roo.tree.DefaultSelectionModel
34226 * @extends Roo.util.Observable
34227 * The default single selection for a TreePanel.
34228 * @param {Object} cfg Configuration
34230 Roo.tree.DefaultSelectionModel = function(cfg){
34231 this.selNode = null;
34237 * @event selectionchange
34238 * Fires when the selected node changes
34239 * @param {DefaultSelectionModel} this
34240 * @param {TreeNode} node the new selection
34242 "selectionchange" : true,
34245 * @event beforeselect
34246 * Fires before the selected node changes, return false to cancel the change
34247 * @param {DefaultSelectionModel} this
34248 * @param {TreeNode} node the new selection
34249 * @param {TreeNode} node the old selection
34251 "beforeselect" : true
34254 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34257 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34258 init : function(tree){
34260 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34261 tree.on("click", this.onNodeClick, this);
34264 onNodeClick : function(node, e){
34265 if (e.ctrlKey && this.selNode == node) {
34266 this.unselect(node);
34274 * @param {TreeNode} node The node to select
34275 * @return {TreeNode} The selected node
34277 select : function(node){
34278 var last = this.selNode;
34279 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34281 last.ui.onSelectedChange(false);
34283 this.selNode = node;
34284 node.ui.onSelectedChange(true);
34285 this.fireEvent("selectionchange", this, node, last);
34292 * @param {TreeNode} node The node to unselect
34294 unselect : function(node){
34295 if(this.selNode == node){
34296 this.clearSelections();
34301 * Clear all selections
34303 clearSelections : function(){
34304 var n = this.selNode;
34306 n.ui.onSelectedChange(false);
34307 this.selNode = null;
34308 this.fireEvent("selectionchange", this, null);
34314 * Get the selected node
34315 * @return {TreeNode} The selected node
34317 getSelectedNode : function(){
34318 return this.selNode;
34322 * Returns true if the node is selected
34323 * @param {TreeNode} node The node to check
34324 * @return {Boolean}
34326 isSelected : function(node){
34327 return this.selNode == node;
34331 * Selects the node above the selected node in the tree, intelligently walking the nodes
34332 * @return TreeNode The new selection
34334 selectPrevious : function(){
34335 var s = this.selNode || this.lastSelNode;
34339 var ps = s.previousSibling;
34341 if(!ps.isExpanded() || ps.childNodes.length < 1){
34342 return this.select(ps);
34344 var lc = ps.lastChild;
34345 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34348 return this.select(lc);
34350 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34351 return this.select(s.parentNode);
34357 * Selects the node above the selected node in the tree, intelligently walking the nodes
34358 * @return TreeNode The new selection
34360 selectNext : function(){
34361 var s = this.selNode || this.lastSelNode;
34365 if(s.firstChild && s.isExpanded()){
34366 return this.select(s.firstChild);
34367 }else if(s.nextSibling){
34368 return this.select(s.nextSibling);
34369 }else if(s.parentNode){
34371 s.parentNode.bubble(function(){
34372 if(this.nextSibling){
34373 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34382 onKeyDown : function(e){
34383 var s = this.selNode || this.lastSelNode;
34384 // undesirable, but required
34389 var k = e.getKey();
34397 this.selectPrevious();
34400 e.preventDefault();
34401 if(s.hasChildNodes()){
34402 if(!s.isExpanded()){
34404 }else if(s.firstChild){
34405 this.select(s.firstChild, e);
34410 e.preventDefault();
34411 if(s.hasChildNodes() && s.isExpanded()){
34413 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34414 this.select(s.parentNode, e);
34422 * @class Roo.tree.MultiSelectionModel
34423 * @extends Roo.util.Observable
34424 * Multi selection for a TreePanel.
34425 * @param {Object} cfg Configuration
34427 Roo.tree.MultiSelectionModel = function(){
34428 this.selNodes = [];
34432 * @event selectionchange
34433 * Fires when the selected nodes change
34434 * @param {MultiSelectionModel} this
34435 * @param {Array} nodes Array of the selected nodes
34437 "selectionchange" : true
34439 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34443 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34444 init : function(tree){
34446 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34447 tree.on("click", this.onNodeClick, this);
34450 onNodeClick : function(node, e){
34451 this.select(node, e, e.ctrlKey);
34456 * @param {TreeNode} node The node to select
34457 * @param {EventObject} e (optional) An event associated with the selection
34458 * @param {Boolean} keepExisting True to retain existing selections
34459 * @return {TreeNode} The selected node
34461 select : function(node, e, keepExisting){
34462 if(keepExisting !== true){
34463 this.clearSelections(true);
34465 if(this.isSelected(node)){
34466 this.lastSelNode = node;
34469 this.selNodes.push(node);
34470 this.selMap[node.id] = node;
34471 this.lastSelNode = node;
34472 node.ui.onSelectedChange(true);
34473 this.fireEvent("selectionchange", this, this.selNodes);
34479 * @param {TreeNode} node The node to unselect
34481 unselect : function(node){
34482 if(this.selMap[node.id]){
34483 node.ui.onSelectedChange(false);
34484 var sn = this.selNodes;
34487 index = sn.indexOf(node);
34489 for(var i = 0, len = sn.length; i < len; i++){
34497 this.selNodes.splice(index, 1);
34499 delete this.selMap[node.id];
34500 this.fireEvent("selectionchange", this, this.selNodes);
34505 * Clear all selections
34507 clearSelections : function(suppressEvent){
34508 var sn = this.selNodes;
34510 for(var i = 0, len = sn.length; i < len; i++){
34511 sn[i].ui.onSelectedChange(false);
34513 this.selNodes = [];
34515 if(suppressEvent !== true){
34516 this.fireEvent("selectionchange", this, this.selNodes);
34522 * Returns true if the node is selected
34523 * @param {TreeNode} node The node to check
34524 * @return {Boolean}
34526 isSelected : function(node){
34527 return this.selMap[node.id] ? true : false;
34531 * Returns an array of the selected nodes
34534 getSelectedNodes : function(){
34535 return this.selNodes;
34538 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34540 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34542 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34545 * Ext JS Library 1.1.1
34546 * Copyright(c) 2006-2007, Ext JS, LLC.
34548 * Originally Released Under LGPL - original licence link has changed is not relivant.
34551 * <script type="text/javascript">
34555 * @class Roo.tree.TreeNode
34556 * @extends Roo.data.Node
34557 * @cfg {String} text The text for this node
34558 * @cfg {Boolean} expanded true to start the node expanded
34559 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34560 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34561 * @cfg {Boolean} disabled true to start the node disabled
34562 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34563 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34564 * @cfg {String} cls A css class to be added to the node
34565 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34566 * @cfg {String} href URL of the link used for the node (defaults to #)
34567 * @cfg {String} hrefTarget target frame for the link
34568 * @cfg {String} qtip An Ext QuickTip for the node
34569 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34570 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34571 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34572 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34573 * (defaults to undefined with no checkbox rendered)
34575 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34577 Roo.tree.TreeNode = function(attributes){
34578 attributes = attributes || {};
34579 if(typeof attributes == "string"){
34580 attributes = {text: attributes};
34582 this.childrenRendered = false;
34583 this.rendered = false;
34584 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34585 this.expanded = attributes.expanded === true;
34586 this.isTarget = attributes.isTarget !== false;
34587 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34588 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34591 * Read-only. The text for this node. To change it use setText().
34594 this.text = attributes.text;
34596 * True if this node is disabled.
34599 this.disabled = attributes.disabled === true;
34603 * @event textchange
34604 * Fires when the text for this node is changed
34605 * @param {Node} this This node
34606 * @param {String} text The new text
34607 * @param {String} oldText The old text
34609 "textchange" : true,
34611 * @event beforeexpand
34612 * Fires before this node is expanded, return false to cancel.
34613 * @param {Node} this This node
34614 * @param {Boolean} deep
34615 * @param {Boolean} anim
34617 "beforeexpand" : true,
34619 * @event beforecollapse
34620 * Fires before this node is collapsed, return false to cancel.
34621 * @param {Node} this This node
34622 * @param {Boolean} deep
34623 * @param {Boolean} anim
34625 "beforecollapse" : true,
34628 * Fires when this node is expanded
34629 * @param {Node} this This node
34633 * @event disabledchange
34634 * Fires when the disabled status of this node changes
34635 * @param {Node} this This node
34636 * @param {Boolean} disabled
34638 "disabledchange" : true,
34641 * Fires when this node is collapsed
34642 * @param {Node} this This node
34646 * @event beforeclick
34647 * Fires before click processing. Return false to cancel the default action.
34648 * @param {Node} this This node
34649 * @param {Roo.EventObject} e The event object
34651 "beforeclick":true,
34653 * @event checkchange
34654 * Fires when a node with a checkbox's checked property changes
34655 * @param {Node} this This node
34656 * @param {Boolean} checked
34658 "checkchange":true,
34661 * Fires when this node is clicked
34662 * @param {Node} this This node
34663 * @param {Roo.EventObject} e The event object
34668 * Fires when this node is double clicked
34669 * @param {Node} this This node
34670 * @param {Roo.EventObject} e The event object
34674 * @event contextmenu
34675 * Fires when this node is right clicked
34676 * @param {Node} this This node
34677 * @param {Roo.EventObject} e The event object
34679 "contextmenu":true,
34681 * @event beforechildrenrendered
34682 * Fires right before the child nodes for this node are rendered
34683 * @param {Node} this This node
34685 "beforechildrenrendered":true
34688 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34691 * Read-only. The UI for this node
34694 this.ui = new uiClass(this);
34696 // finally support items[]
34697 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34702 Roo.each(this.attributes.items, function(c) {
34703 this.appendChild(Roo.factory(c,Roo.Tree));
34705 delete this.attributes.items;
34710 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34711 preventHScroll: true,
34713 * Returns true if this node is expanded
34714 * @return {Boolean}
34716 isExpanded : function(){
34717 return this.expanded;
34721 * Returns the UI object for this node
34722 * @return {TreeNodeUI}
34724 getUI : function(){
34728 // private override
34729 setFirstChild : function(node){
34730 var of = this.firstChild;
34731 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
34732 if(this.childrenRendered && of && node != of){
34733 of.renderIndent(true, true);
34736 this.renderIndent(true, true);
34740 // private override
34741 setLastChild : function(node){
34742 var ol = this.lastChild;
34743 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
34744 if(this.childrenRendered && ol && node != ol){
34745 ol.renderIndent(true, true);
34748 this.renderIndent(true, true);
34752 // these methods are overridden to provide lazy rendering support
34753 // private override
34754 appendChild : function()
34756 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
34757 if(node && this.childrenRendered){
34760 this.ui.updateExpandIcon();
34764 // private override
34765 removeChild : function(node){
34766 this.ownerTree.getSelectionModel().unselect(node);
34767 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
34768 // if it's been rendered remove dom node
34769 if(this.childrenRendered){
34772 if(this.childNodes.length < 1){
34773 this.collapse(false, false);
34775 this.ui.updateExpandIcon();
34777 if(!this.firstChild) {
34778 this.childrenRendered = false;
34783 // private override
34784 insertBefore : function(node, refNode){
34785 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
34786 if(newNode && refNode && this.childrenRendered){
34789 this.ui.updateExpandIcon();
34794 * Sets the text for this node
34795 * @param {String} text
34797 setText : function(text){
34798 var oldText = this.text;
34800 this.attributes.text = text;
34801 if(this.rendered){ // event without subscribing
34802 this.ui.onTextChange(this, text, oldText);
34804 this.fireEvent("textchange", this, text, oldText);
34808 * Triggers selection of this node
34810 select : function(){
34811 this.getOwnerTree().getSelectionModel().select(this);
34815 * Triggers deselection of this node
34817 unselect : function(){
34818 this.getOwnerTree().getSelectionModel().unselect(this);
34822 * Returns true if this node is selected
34823 * @return {Boolean}
34825 isSelected : function(){
34826 return this.getOwnerTree().getSelectionModel().isSelected(this);
34830 * Expand this node.
34831 * @param {Boolean} deep (optional) True to expand all children as well
34832 * @param {Boolean} anim (optional) false to cancel the default animation
34833 * @param {Function} callback (optional) A callback to be called when
34834 * expanding this node completes (does not wait for deep expand to complete).
34835 * Called with 1 parameter, this node.
34837 expand : function(deep, anim, callback){
34838 if(!this.expanded){
34839 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
34842 if(!this.childrenRendered){
34843 this.renderChildren();
34845 this.expanded = true;
34846 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
34847 this.ui.animExpand(function(){
34848 this.fireEvent("expand", this);
34849 if(typeof callback == "function"){
34853 this.expandChildNodes(true);
34855 }.createDelegate(this));
34859 this.fireEvent("expand", this);
34860 if(typeof callback == "function"){
34865 if(typeof callback == "function"){
34870 this.expandChildNodes(true);
34874 isHiddenRoot : function(){
34875 return this.isRoot && !this.getOwnerTree().rootVisible;
34879 * Collapse this node.
34880 * @param {Boolean} deep (optional) True to collapse all children as well
34881 * @param {Boolean} anim (optional) false to cancel the default animation
34883 collapse : function(deep, anim){
34884 if(this.expanded && !this.isHiddenRoot()){
34885 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
34888 this.expanded = false;
34889 if((this.getOwnerTree().animate && anim !== false) || anim){
34890 this.ui.animCollapse(function(){
34891 this.fireEvent("collapse", this);
34893 this.collapseChildNodes(true);
34895 }.createDelegate(this));
34898 this.ui.collapse();
34899 this.fireEvent("collapse", this);
34903 var cs = this.childNodes;
34904 for(var i = 0, len = cs.length; i < len; i++) {
34905 cs[i].collapse(true, false);
34911 delayedExpand : function(delay){
34912 if(!this.expandProcId){
34913 this.expandProcId = this.expand.defer(delay, this);
34918 cancelExpand : function(){
34919 if(this.expandProcId){
34920 clearTimeout(this.expandProcId);
34922 this.expandProcId = false;
34926 * Toggles expanded/collapsed state of the node
34928 toggle : function(){
34937 * Ensures all parent nodes are expanded
34939 ensureVisible : function(callback){
34940 var tree = this.getOwnerTree();
34941 tree.expandPath(this.parentNode.getPath(), false, function(){
34942 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
34943 Roo.callback(callback);
34944 }.createDelegate(this));
34948 * Expand all child nodes
34949 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
34951 expandChildNodes : function(deep){
34952 var cs = this.childNodes;
34953 for(var i = 0, len = cs.length; i < len; i++) {
34954 cs[i].expand(deep);
34959 * Collapse all child nodes
34960 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
34962 collapseChildNodes : function(deep){
34963 var cs = this.childNodes;
34964 for(var i = 0, len = cs.length; i < len; i++) {
34965 cs[i].collapse(deep);
34970 * Disables this node
34972 disable : function(){
34973 this.disabled = true;
34975 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
34976 this.ui.onDisableChange(this, true);
34978 this.fireEvent("disabledchange", this, true);
34982 * Enables this node
34984 enable : function(){
34985 this.disabled = false;
34986 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
34987 this.ui.onDisableChange(this, false);
34989 this.fireEvent("disabledchange", this, false);
34993 renderChildren : function(suppressEvent){
34994 if(suppressEvent !== false){
34995 this.fireEvent("beforechildrenrendered", this);
34997 var cs = this.childNodes;
34998 for(var i = 0, len = cs.length; i < len; i++){
34999 cs[i].render(true);
35001 this.childrenRendered = true;
35005 sort : function(fn, scope){
35006 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35007 if(this.childrenRendered){
35008 var cs = this.childNodes;
35009 for(var i = 0, len = cs.length; i < len; i++){
35010 cs[i].render(true);
35016 render : function(bulkRender){
35017 this.ui.render(bulkRender);
35018 if(!this.rendered){
35019 this.rendered = true;
35021 this.expanded = false;
35022 this.expand(false, false);
35028 renderIndent : function(deep, refresh){
35030 this.ui.childIndent = null;
35032 this.ui.renderIndent();
35033 if(deep === true && this.childrenRendered){
35034 var cs = this.childNodes;
35035 for(var i = 0, len = cs.length; i < len; i++){
35036 cs[i].renderIndent(true, refresh);
35042 * Ext JS Library 1.1.1
35043 * Copyright(c) 2006-2007, Ext JS, LLC.
35045 * Originally Released Under LGPL - original licence link has changed is not relivant.
35048 * <script type="text/javascript">
35052 * @class Roo.tree.AsyncTreeNode
35053 * @extends Roo.tree.TreeNode
35054 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35056 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35058 Roo.tree.AsyncTreeNode = function(config){
35059 this.loaded = false;
35060 this.loading = false;
35061 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35063 * @event beforeload
35064 * Fires before this node is loaded, return false to cancel
35065 * @param {Node} this This node
35067 this.addEvents({'beforeload':true, 'load': true});
35070 * Fires when this node is loaded
35071 * @param {Node} this This node
35074 * The loader used by this node (defaults to using the tree's defined loader)
35079 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35080 expand : function(deep, anim, callback){
35081 if(this.loading){ // if an async load is already running, waiting til it's done
35083 var f = function(){
35084 if(!this.loading){ // done loading
35085 clearInterval(timer);
35086 this.expand(deep, anim, callback);
35088 }.createDelegate(this);
35089 timer = setInterval(f, 200);
35093 if(this.fireEvent("beforeload", this) === false){
35096 this.loading = true;
35097 this.ui.beforeLoad(this);
35098 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35100 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35104 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35108 * Returns true if this node is currently loading
35109 * @return {Boolean}
35111 isLoading : function(){
35112 return this.loading;
35115 loadComplete : function(deep, anim, callback){
35116 this.loading = false;
35117 this.loaded = true;
35118 this.ui.afterLoad(this);
35119 this.fireEvent("load", this);
35120 this.expand(deep, anim, callback);
35124 * Returns true if this node has been loaded
35125 * @return {Boolean}
35127 isLoaded : function(){
35128 return this.loaded;
35131 hasChildNodes : function(){
35132 if(!this.isLeaf() && !this.loaded){
35135 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35140 * Trigger a reload for this node
35141 * @param {Function} callback
35143 reload : function(callback){
35144 this.collapse(false, false);
35145 while(this.firstChild){
35146 this.removeChild(this.firstChild);
35148 this.childrenRendered = false;
35149 this.loaded = false;
35150 if(this.isHiddenRoot()){
35151 this.expanded = false;
35153 this.expand(false, false, callback);
35157 * Ext JS Library 1.1.1
35158 * Copyright(c) 2006-2007, Ext JS, LLC.
35160 * Originally Released Under LGPL - original licence link has changed is not relivant.
35163 * <script type="text/javascript">
35167 * @class Roo.tree.TreeNodeUI
35169 * @param {Object} node The node to render
35170 * The TreeNode UI implementation is separate from the
35171 * tree implementation. Unless you are customizing the tree UI,
35172 * you should never have to use this directly.
35174 Roo.tree.TreeNodeUI = function(node){
35176 this.rendered = false;
35177 this.animating = false;
35178 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35181 Roo.tree.TreeNodeUI.prototype = {
35182 removeChild : function(node){
35184 this.ctNode.removeChild(node.ui.getEl());
35188 beforeLoad : function(){
35189 this.addClass("x-tree-node-loading");
35192 afterLoad : function(){
35193 this.removeClass("x-tree-node-loading");
35196 onTextChange : function(node, text, oldText){
35198 this.textNode.innerHTML = text;
35202 onDisableChange : function(node, state){
35203 this.disabled = state;
35205 this.addClass("x-tree-node-disabled");
35207 this.removeClass("x-tree-node-disabled");
35211 onSelectedChange : function(state){
35214 this.addClass("x-tree-selected");
35217 this.removeClass("x-tree-selected");
35221 onMove : function(tree, node, oldParent, newParent, index, refNode){
35222 this.childIndent = null;
35224 var targetNode = newParent.ui.getContainer();
35225 if(!targetNode){//target not rendered
35226 this.holder = document.createElement("div");
35227 this.holder.appendChild(this.wrap);
35230 var insertBefore = refNode ? refNode.ui.getEl() : null;
35232 targetNode.insertBefore(this.wrap, insertBefore);
35234 targetNode.appendChild(this.wrap);
35236 this.node.renderIndent(true);
35240 addClass : function(cls){
35242 Roo.fly(this.elNode).addClass(cls);
35246 removeClass : function(cls){
35248 Roo.fly(this.elNode).removeClass(cls);
35252 remove : function(){
35254 this.holder = document.createElement("div");
35255 this.holder.appendChild(this.wrap);
35259 fireEvent : function(){
35260 return this.node.fireEvent.apply(this.node, arguments);
35263 initEvents : function(){
35264 this.node.on("move", this.onMove, this);
35265 var E = Roo.EventManager;
35266 var a = this.anchor;
35268 var el = Roo.fly(a, '_treeui');
35270 if(Roo.isOpera){ // opera render bug ignores the CSS
35271 el.setStyle("text-decoration", "none");
35274 el.on("click", this.onClick, this);
35275 el.on("dblclick", this.onDblClick, this);
35278 Roo.EventManager.on(this.checkbox,
35279 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35282 el.on("contextmenu", this.onContextMenu, this);
35284 var icon = Roo.fly(this.iconNode);
35285 icon.on("click", this.onClick, this);
35286 icon.on("dblclick", this.onDblClick, this);
35287 icon.on("contextmenu", this.onContextMenu, this);
35288 E.on(this.ecNode, "click", this.ecClick, this, true);
35290 if(this.node.disabled){
35291 this.addClass("x-tree-node-disabled");
35293 if(this.node.hidden){
35294 this.addClass("x-tree-node-disabled");
35296 var ot = this.node.getOwnerTree();
35297 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35298 if(dd && (!this.node.isRoot || ot.rootVisible)){
35299 Roo.dd.Registry.register(this.elNode, {
35301 handles: this.getDDHandles(),
35307 getDDHandles : function(){
35308 return [this.iconNode, this.textNode];
35313 this.wrap.style.display = "none";
35319 this.wrap.style.display = "";
35323 onContextMenu : function(e){
35324 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35325 e.preventDefault();
35327 this.fireEvent("contextmenu", this.node, e);
35331 onClick : function(e){
35336 if(this.fireEvent("beforeclick", this.node, e) !== false){
35337 if(!this.disabled && this.node.attributes.href){
35338 this.fireEvent("click", this.node, e);
35341 e.preventDefault();
35346 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35347 this.node.toggle();
35350 this.fireEvent("click", this.node, e);
35356 onDblClick : function(e){
35357 e.preventDefault();
35362 this.toggleCheck();
35364 if(!this.animating && this.node.hasChildNodes()){
35365 this.node.toggle();
35367 this.fireEvent("dblclick", this.node, e);
35370 onCheckChange : function(){
35371 var checked = this.checkbox.checked;
35372 this.node.attributes.checked = checked;
35373 this.fireEvent('checkchange', this.node, checked);
35376 ecClick : function(e){
35377 if(!this.animating && this.node.hasChildNodes()){
35378 this.node.toggle();
35382 startDrop : function(){
35383 this.dropping = true;
35386 // delayed drop so the click event doesn't get fired on a drop
35387 endDrop : function(){
35388 setTimeout(function(){
35389 this.dropping = false;
35390 }.createDelegate(this), 50);
35393 expand : function(){
35394 this.updateExpandIcon();
35395 this.ctNode.style.display = "";
35398 focus : function(){
35399 if(!this.node.preventHScroll){
35400 try{this.anchor.focus();
35402 }else if(!Roo.isIE){
35404 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35405 var l = noscroll.scrollLeft;
35406 this.anchor.focus();
35407 noscroll.scrollLeft = l;
35412 toggleCheck : function(value){
35413 var cb = this.checkbox;
35415 cb.checked = (value === undefined ? !cb.checked : value);
35421 this.anchor.blur();
35425 animExpand : function(callback){
35426 var ct = Roo.get(this.ctNode);
35428 if(!this.node.hasChildNodes()){
35429 this.updateExpandIcon();
35430 this.ctNode.style.display = "";
35431 Roo.callback(callback);
35434 this.animating = true;
35435 this.updateExpandIcon();
35438 callback : function(){
35439 this.animating = false;
35440 Roo.callback(callback);
35443 duration: this.node.ownerTree.duration || .25
35447 highlight : function(){
35448 var tree = this.node.getOwnerTree();
35449 Roo.fly(this.wrap).highlight(
35450 tree.hlColor || "C3DAF9",
35451 {endColor: tree.hlBaseColor}
35455 collapse : function(){
35456 this.updateExpandIcon();
35457 this.ctNode.style.display = "none";
35460 animCollapse : function(callback){
35461 var ct = Roo.get(this.ctNode);
35462 ct.enableDisplayMode('block');
35465 this.animating = true;
35466 this.updateExpandIcon();
35469 callback : function(){
35470 this.animating = false;
35471 Roo.callback(callback);
35474 duration: this.node.ownerTree.duration || .25
35478 getContainer : function(){
35479 return this.ctNode;
35482 getEl : function(){
35486 appendDDGhost : function(ghostNode){
35487 ghostNode.appendChild(this.elNode.cloneNode(true));
35490 getDDRepairXY : function(){
35491 return Roo.lib.Dom.getXY(this.iconNode);
35494 onRender : function(){
35498 render : function(bulkRender){
35499 var n = this.node, a = n.attributes;
35500 var targetNode = n.parentNode ?
35501 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35503 if(!this.rendered){
35504 this.rendered = true;
35506 this.renderElements(n, a, targetNode, bulkRender);
35509 if(this.textNode.setAttributeNS){
35510 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35512 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35515 this.textNode.setAttribute("ext:qtip", a.qtip);
35517 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35520 }else if(a.qtipCfg){
35521 a.qtipCfg.target = Roo.id(this.textNode);
35522 Roo.QuickTips.register(a.qtipCfg);
35525 if(!this.node.expanded){
35526 this.updateExpandIcon();
35529 if(bulkRender === true) {
35530 targetNode.appendChild(this.wrap);
35535 renderElements : function(n, a, targetNode, bulkRender)
35537 // add some indent caching, this helps performance when rendering a large tree
35538 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35539 var t = n.getOwnerTree();
35540 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35541 if (typeof(n.attributes.html) != 'undefined') {
35542 txt = n.attributes.html;
35544 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35545 var cb = typeof a.checked == 'boolean';
35546 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35547 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35548 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35549 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35550 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35551 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35552 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35553 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35554 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35555 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35558 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35559 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35560 n.nextSibling.ui.getEl(), buf.join(""));
35562 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35565 this.elNode = this.wrap.childNodes[0];
35566 this.ctNode = this.wrap.childNodes[1];
35567 var cs = this.elNode.childNodes;
35568 this.indentNode = cs[0];
35569 this.ecNode = cs[1];
35570 this.iconNode = cs[2];
35573 this.checkbox = cs[3];
35576 this.anchor = cs[index];
35577 this.textNode = cs[index].firstChild;
35580 getAnchor : function(){
35581 return this.anchor;
35584 getTextEl : function(){
35585 return this.textNode;
35588 getIconEl : function(){
35589 return this.iconNode;
35592 isChecked : function(){
35593 return this.checkbox ? this.checkbox.checked : false;
35596 updateExpandIcon : function(){
35598 var n = this.node, c1, c2;
35599 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35600 var hasChild = n.hasChildNodes();
35604 c1 = "x-tree-node-collapsed";
35605 c2 = "x-tree-node-expanded";
35608 c1 = "x-tree-node-expanded";
35609 c2 = "x-tree-node-collapsed";
35612 this.removeClass("x-tree-node-leaf");
35613 this.wasLeaf = false;
35615 if(this.c1 != c1 || this.c2 != c2){
35616 Roo.fly(this.elNode).replaceClass(c1, c2);
35617 this.c1 = c1; this.c2 = c2;
35620 // this changes non-leafs into leafs if they have no children.
35621 // it's not very rational behaviour..
35623 if(!this.wasLeaf && this.node.leaf){
35624 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35627 this.wasLeaf = true;
35630 var ecc = "x-tree-ec-icon "+cls;
35631 if(this.ecc != ecc){
35632 this.ecNode.className = ecc;
35638 getChildIndent : function(){
35639 if(!this.childIndent){
35643 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35645 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35647 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35652 this.childIndent = buf.join("");
35654 return this.childIndent;
35657 renderIndent : function(){
35660 var p = this.node.parentNode;
35662 indent = p.ui.getChildIndent();
35664 if(this.indentMarkup != indent){ // don't rerender if not required
35665 this.indentNode.innerHTML = indent;
35666 this.indentMarkup = indent;
35668 this.updateExpandIcon();
35673 Roo.tree.RootTreeNodeUI = function(){
35674 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35676 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35677 render : function(){
35678 if(!this.rendered){
35679 var targetNode = this.node.ownerTree.innerCt.dom;
35680 this.node.expanded = true;
35681 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35682 this.wrap = this.ctNode = targetNode.firstChild;
35685 collapse : function(){
35687 expand : function(){
35691 * Ext JS Library 1.1.1
35692 * Copyright(c) 2006-2007, Ext JS, LLC.
35694 * Originally Released Under LGPL - original licence link has changed is not relivant.
35697 * <script type="text/javascript">
35700 * @class Roo.tree.TreeLoader
35701 * @extends Roo.util.Observable
35702 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35703 * nodes from a specified URL. The response must be a javascript Array definition
35704 * who's elements are node definition objects. eg:
35709 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35710 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
35717 * The old style respose with just an array is still supported, but not recommended.
35720 * A server request is sent, and child nodes are loaded only when a node is expanded.
35721 * The loading node's id is passed to the server under the parameter name "node" to
35722 * enable the server to produce the correct child nodes.
35724 * To pass extra parameters, an event handler may be attached to the "beforeload"
35725 * event, and the parameters specified in the TreeLoader's baseParams property:
35727 myTreeLoader.on("beforeload", function(treeLoader, node) {
35728 this.baseParams.category = node.attributes.category;
35731 * This would pass an HTTP parameter called "category" to the server containing
35732 * the value of the Node's "category" attribute.
35734 * Creates a new Treeloader.
35735 * @param {Object} config A config object containing config properties.
35737 Roo.tree.TreeLoader = function(config){
35738 this.baseParams = {};
35739 this.requestMethod = "POST";
35740 Roo.apply(this, config);
35745 * @event beforeload
35746 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
35747 * @param {Object} This TreeLoader object.
35748 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35749 * @param {Object} callback The callback function specified in the {@link #load} call.
35754 * Fires when the node has been successfuly loaded.
35755 * @param {Object} This TreeLoader object.
35756 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35757 * @param {Object} response The response object containing the data from the server.
35761 * @event loadexception
35762 * Fires if the network request failed.
35763 * @param {Object} This TreeLoader object.
35764 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35765 * @param {Object} response The response object containing the data from the server.
35767 loadexception : true,
35770 * Fires before a node is created, enabling you to return custom Node types
35771 * @param {Object} This TreeLoader object.
35772 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
35777 Roo.tree.TreeLoader.superclass.constructor.call(this);
35780 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
35782 * @cfg {String} dataUrl The URL from which to request a Json string which
35783 * specifies an array of node definition object representing the child nodes
35787 * @cfg {String} requestMethod either GET or POST
35788 * defaults to POST (due to BC)
35792 * @cfg {Object} baseParams (optional) An object containing properties which
35793 * specify HTTP parameters to be passed to each request for child nodes.
35796 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
35797 * created by this loader. If the attributes sent by the server have an attribute in this object,
35798 * they take priority.
35801 * @cfg {Object} uiProviders (optional) An object containing properties which
35803 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
35804 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
35805 * <i>uiProvider</i> attribute of a returned child node is a string rather
35806 * than a reference to a TreeNodeUI implementation, this that string value
35807 * is used as a property name in the uiProviders object. You can define the provider named
35808 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
35813 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
35814 * child nodes before loading.
35816 clearOnLoad : true,
35819 * @cfg {String} root (optional) Default to false. Use this to read data from an object
35820 * property on loading, rather than expecting an array. (eg. more compatible to a standard
35821 * Grid query { data : [ .....] }
35826 * @cfg {String} queryParam (optional)
35827 * Name of the query as it will be passed on the querystring (defaults to 'node')
35828 * eg. the request will be ?node=[id]
35835 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
35836 * This is called automatically when a node is expanded, but may be used to reload
35837 * a node (or append new children if the {@link #clearOnLoad} option is false.)
35838 * @param {Roo.tree.TreeNode} node
35839 * @param {Function} callback
35841 load : function(node, callback){
35842 if(this.clearOnLoad){
35843 while(node.firstChild){
35844 node.removeChild(node.firstChild);
35847 if(node.attributes.children){ // preloaded json children
35848 var cs = node.attributes.children;
35849 for(var i = 0, len = cs.length; i < len; i++){
35850 node.appendChild(this.createNode(cs[i]));
35852 if(typeof callback == "function"){
35855 }else if(this.dataUrl){
35856 this.requestData(node, callback);
35860 getParams: function(node){
35861 var buf = [], bp = this.baseParams;
35862 for(var key in bp){
35863 if(typeof bp[key] != "function"){
35864 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
35867 var n = this.queryParam === false ? 'node' : this.queryParam;
35868 buf.push(n + "=", encodeURIComponent(node.id));
35869 return buf.join("");
35872 requestData : function(node, callback){
35873 if(this.fireEvent("beforeload", this, node, callback) !== false){
35874 this.transId = Roo.Ajax.request({
35875 method:this.requestMethod,
35876 url: this.dataUrl||this.url,
35877 success: this.handleResponse,
35878 failure: this.handleFailure,
35880 argument: {callback: callback, node: node},
35881 params: this.getParams(node)
35884 // if the load is cancelled, make sure we notify
35885 // the node that we are done
35886 if(typeof callback == "function"){
35892 isLoading : function(){
35893 return this.transId ? true : false;
35896 abort : function(){
35897 if(this.isLoading()){
35898 Roo.Ajax.abort(this.transId);
35903 createNode : function(attr)
35905 // apply baseAttrs, nice idea Corey!
35906 if(this.baseAttrs){
35907 Roo.applyIf(attr, this.baseAttrs);
35909 if(this.applyLoader !== false){
35910 attr.loader = this;
35912 // uiProvider = depreciated..
35914 if(typeof(attr.uiProvider) == 'string'){
35915 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
35916 /** eval:var:attr */ eval(attr.uiProvider);
35918 if(typeof(this.uiProviders['default']) != 'undefined') {
35919 attr.uiProvider = this.uiProviders['default'];
35922 this.fireEvent('create', this, attr);
35924 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
35926 new Roo.tree.TreeNode(attr) :
35927 new Roo.tree.AsyncTreeNode(attr));
35930 processResponse : function(response, node, callback)
35932 var json = response.responseText;
35935 var o = Roo.decode(json);
35937 if (this.root === false && typeof(o.success) != undefined) {
35938 this.root = 'data'; // the default behaviour for list like data..
35941 if (this.root !== false && !o.success) {
35942 // it's a failure condition.
35943 var a = response.argument;
35944 this.fireEvent("loadexception", this, a.node, response);
35945 Roo.log("Load failed - should have a handler really");
35951 if (this.root !== false) {
35955 for(var i = 0, len = o.length; i < len; i++){
35956 var n = this.createNode(o[i]);
35958 node.appendChild(n);
35961 if(typeof callback == "function"){
35962 callback(this, node);
35965 this.handleFailure(response);
35969 handleResponse : function(response){
35970 this.transId = false;
35971 var a = response.argument;
35972 this.processResponse(response, a.node, a.callback);
35973 this.fireEvent("load", this, a.node, response);
35976 handleFailure : function(response)
35978 // should handle failure better..
35979 this.transId = false;
35980 var a = response.argument;
35981 this.fireEvent("loadexception", this, a.node, response);
35982 if(typeof a.callback == "function"){
35983 a.callback(this, a.node);
35988 * Ext JS Library 1.1.1
35989 * Copyright(c) 2006-2007, Ext JS, LLC.
35991 * Originally Released Under LGPL - original licence link has changed is not relivant.
35994 * <script type="text/javascript">
35998 * @class Roo.tree.TreeFilter
35999 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36000 * @param {TreePanel} tree
36001 * @param {Object} config (optional)
36003 Roo.tree.TreeFilter = function(tree, config){
36005 this.filtered = {};
36006 Roo.apply(this, config);
36009 Roo.tree.TreeFilter.prototype = {
36016 * Filter the data by a specific attribute.
36017 * @param {String/RegExp} value Either string that the attribute value
36018 * should start with or a RegExp to test against the attribute
36019 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36020 * @param {TreeNode} startNode (optional) The node to start the filter at.
36022 filter : function(value, attr, startNode){
36023 attr = attr || "text";
36025 if(typeof value == "string"){
36026 var vlen = value.length;
36027 // auto clear empty filter
36028 if(vlen == 0 && this.clearBlank){
36032 value = value.toLowerCase();
36034 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36036 }else if(value.exec){ // regex?
36038 return value.test(n.attributes[attr]);
36041 throw 'Illegal filter type, must be string or regex';
36043 this.filterBy(f, null, startNode);
36047 * Filter by a function. The passed function will be called with each
36048 * node in the tree (or from the startNode). If the function returns true, the node is kept
36049 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36050 * @param {Function} fn The filter function
36051 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36053 filterBy : function(fn, scope, startNode){
36054 startNode = startNode || this.tree.root;
36055 if(this.autoClear){
36058 var af = this.filtered, rv = this.reverse;
36059 var f = function(n){
36060 if(n == startNode){
36066 var m = fn.call(scope || n, n);
36074 startNode.cascade(f);
36077 if(typeof id != "function"){
36079 if(n && n.parentNode){
36080 n.parentNode.removeChild(n);
36088 * Clears the current filter. Note: with the "remove" option
36089 * set a filter cannot be cleared.
36091 clear : function(){
36093 var af = this.filtered;
36095 if(typeof id != "function"){
36102 this.filtered = {};
36107 * Ext JS Library 1.1.1
36108 * Copyright(c) 2006-2007, Ext JS, LLC.
36110 * Originally Released Under LGPL - original licence link has changed is not relivant.
36113 * <script type="text/javascript">
36118 * @class Roo.tree.TreeSorter
36119 * Provides sorting of nodes in a TreePanel
36121 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36122 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36123 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36124 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36125 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36126 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36128 * @param {TreePanel} tree
36129 * @param {Object} config
36131 Roo.tree.TreeSorter = function(tree, config){
36132 Roo.apply(this, config);
36133 tree.on("beforechildrenrendered", this.doSort, this);
36134 tree.on("append", this.updateSort, this);
36135 tree.on("insert", this.updateSort, this);
36137 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36138 var p = this.property || "text";
36139 var sortType = this.sortType;
36140 var fs = this.folderSort;
36141 var cs = this.caseSensitive === true;
36142 var leafAttr = this.leafAttr || 'leaf';
36144 this.sortFn = function(n1, n2){
36146 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36149 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36153 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36154 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36156 return dsc ? +1 : -1;
36158 return dsc ? -1 : +1;
36165 Roo.tree.TreeSorter.prototype = {
36166 doSort : function(node){
36167 node.sort(this.sortFn);
36170 compareNodes : function(n1, n2){
36171 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36174 updateSort : function(tree, node){
36175 if(node.childrenRendered){
36176 this.doSort.defer(1, this, [node]);
36181 * Ext JS Library 1.1.1
36182 * Copyright(c) 2006-2007, Ext JS, LLC.
36184 * Originally Released Under LGPL - original licence link has changed is not relivant.
36187 * <script type="text/javascript">
36190 if(Roo.dd.DropZone){
36192 Roo.tree.TreeDropZone = function(tree, config){
36193 this.allowParentInsert = false;
36194 this.allowContainerDrop = false;
36195 this.appendOnly = false;
36196 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36198 this.lastInsertClass = "x-tree-no-status";
36199 this.dragOverData = {};
36202 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36203 ddGroup : "TreeDD",
36206 expandDelay : 1000,
36208 expandNode : function(node){
36209 if(node.hasChildNodes() && !node.isExpanded()){
36210 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36214 queueExpand : function(node){
36215 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36218 cancelExpand : function(){
36219 if(this.expandProcId){
36220 clearTimeout(this.expandProcId);
36221 this.expandProcId = false;
36225 isValidDropPoint : function(n, pt, dd, e, data){
36226 if(!n || !data){ return false; }
36227 var targetNode = n.node;
36228 var dropNode = data.node;
36229 // default drop rules
36230 if(!(targetNode && targetNode.isTarget && pt)){
36233 if(pt == "append" && targetNode.allowChildren === false){
36236 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36239 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36242 // reuse the object
36243 var overEvent = this.dragOverData;
36244 overEvent.tree = this.tree;
36245 overEvent.target = targetNode;
36246 overEvent.data = data;
36247 overEvent.point = pt;
36248 overEvent.source = dd;
36249 overEvent.rawEvent = e;
36250 overEvent.dropNode = dropNode;
36251 overEvent.cancel = false;
36252 var result = this.tree.fireEvent("nodedragover", overEvent);
36253 return overEvent.cancel === false && result !== false;
36256 getDropPoint : function(e, n, dd)
36260 return tn.allowChildren !== false ? "append" : false; // always append for root
36262 var dragEl = n.ddel;
36263 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36264 var y = Roo.lib.Event.getPageY(e);
36265 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36267 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36268 var noAppend = tn.allowChildren === false;
36269 if(this.appendOnly || tn.parentNode.allowChildren === false){
36270 return noAppend ? false : "append";
36272 var noBelow = false;
36273 if(!this.allowParentInsert){
36274 noBelow = tn.hasChildNodes() && tn.isExpanded();
36276 var q = (b - t) / (noAppend ? 2 : 3);
36277 if(y >= t && y < (t + q)){
36279 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36286 onNodeEnter : function(n, dd, e, data)
36288 this.cancelExpand();
36291 onNodeOver : function(n, dd, e, data)
36294 var pt = this.getDropPoint(e, n, dd);
36297 // auto node expand check
36298 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36299 this.queueExpand(node);
36300 }else if(pt != "append"){
36301 this.cancelExpand();
36304 // set the insert point style on the target node
36305 var returnCls = this.dropNotAllowed;
36306 if(this.isValidDropPoint(n, pt, dd, e, data)){
36311 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36312 cls = "x-tree-drag-insert-above";
36313 }else if(pt == "below"){
36314 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36315 cls = "x-tree-drag-insert-below";
36317 returnCls = "x-tree-drop-ok-append";
36318 cls = "x-tree-drag-append";
36320 if(this.lastInsertClass != cls){
36321 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36322 this.lastInsertClass = cls;
36329 onNodeOut : function(n, dd, e, data){
36331 this.cancelExpand();
36332 this.removeDropIndicators(n);
36335 onNodeDrop : function(n, dd, e, data){
36336 var point = this.getDropPoint(e, n, dd);
36337 var targetNode = n.node;
36338 targetNode.ui.startDrop();
36339 if(!this.isValidDropPoint(n, point, dd, e, data)){
36340 targetNode.ui.endDrop();
36343 // first try to find the drop node
36344 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36347 target: targetNode,
36352 dropNode: dropNode,
36355 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36356 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36357 targetNode.ui.endDrop();
36360 // allow target changing
36361 targetNode = dropEvent.target;
36362 if(point == "append" && !targetNode.isExpanded()){
36363 targetNode.expand(false, null, function(){
36364 this.completeDrop(dropEvent);
36365 }.createDelegate(this));
36367 this.completeDrop(dropEvent);
36372 completeDrop : function(de){
36373 var ns = de.dropNode, p = de.point, t = de.target;
36374 if(!(ns instanceof Array)){
36378 for(var i = 0, len = ns.length; i < len; i++){
36381 t.parentNode.insertBefore(n, t);
36382 }else if(p == "below"){
36383 t.parentNode.insertBefore(n, t.nextSibling);
36389 if(this.tree.hlDrop){
36393 this.tree.fireEvent("nodedrop", de);
36396 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36397 if(this.tree.hlDrop){
36398 dropNode.ui.focus();
36399 dropNode.ui.highlight();
36401 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36404 getTree : function(){
36408 removeDropIndicators : function(n){
36411 Roo.fly(el).removeClass([
36412 "x-tree-drag-insert-above",
36413 "x-tree-drag-insert-below",
36414 "x-tree-drag-append"]);
36415 this.lastInsertClass = "_noclass";
36419 beforeDragDrop : function(target, e, id){
36420 this.cancelExpand();
36424 afterRepair : function(data){
36425 if(data && Roo.enableFx){
36426 data.node.ui.highlight();
36436 * Ext JS Library 1.1.1
36437 * Copyright(c) 2006-2007, Ext JS, LLC.
36439 * Originally Released Under LGPL - original licence link has changed is not relivant.
36442 * <script type="text/javascript">
36446 if(Roo.dd.DragZone){
36447 Roo.tree.TreeDragZone = function(tree, config){
36448 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36452 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36453 ddGroup : "TreeDD",
36455 onBeforeDrag : function(data, e){
36457 return n && n.draggable && !n.disabled;
36461 onInitDrag : function(e){
36462 var data = this.dragData;
36463 this.tree.getSelectionModel().select(data.node);
36464 this.proxy.update("");
36465 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36466 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36469 getRepairXY : function(e, data){
36470 return data.node.ui.getDDRepairXY();
36473 onEndDrag : function(data, e){
36474 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36479 onValidDrop : function(dd, e, id){
36480 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36484 beforeInvalidDrop : function(e, id){
36485 // this scrolls the original position back into view
36486 var sm = this.tree.getSelectionModel();
36487 sm.clearSelections();
36488 sm.select(this.dragData.node);
36493 * Ext JS Library 1.1.1
36494 * Copyright(c) 2006-2007, Ext JS, LLC.
36496 * Originally Released Under LGPL - original licence link has changed is not relivant.
36499 * <script type="text/javascript">
36502 * @class Roo.tree.TreeEditor
36503 * @extends Roo.Editor
36504 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36505 * as the editor field.
36507 * @param {Object} config (used to be the tree panel.)
36508 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36510 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36511 * @cfg {Roo.form.TextField|Object} field The field configuration
36515 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36518 if (oldconfig) { // old style..
36519 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36522 tree = config.tree;
36523 config.field = config.field || {};
36524 config.field.xtype = 'TextField';
36525 field = Roo.factory(config.field, Roo.form);
36527 config = config || {};
36532 * @event beforenodeedit
36533 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36534 * false from the handler of this event.
36535 * @param {Editor} this
36536 * @param {Roo.tree.Node} node
36538 "beforenodeedit" : true
36542 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36546 tree.on('beforeclick', this.beforeNodeClick, this);
36547 tree.getTreeEl().on('mousedown', this.hide, this);
36548 this.on('complete', this.updateNode, this);
36549 this.on('beforestartedit', this.fitToTree, this);
36550 this.on('startedit', this.bindScroll, this, {delay:10});
36551 this.on('specialkey', this.onSpecialKey, this);
36554 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36556 * @cfg {String} alignment
36557 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36563 * @cfg {Boolean} hideEl
36564 * True to hide the bound element while the editor is displayed (defaults to false)
36568 * @cfg {String} cls
36569 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36571 cls: "x-small-editor x-tree-editor",
36573 * @cfg {Boolean} shim
36574 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36580 * @cfg {Number} maxWidth
36581 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36582 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36583 * scroll and client offsets into account prior to each edit.
36590 fitToTree : function(ed, el){
36591 var td = this.tree.getTreeEl().dom, nd = el.dom;
36592 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36593 td.scrollLeft = nd.offsetLeft;
36597 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36598 this.setSize(w, '');
36600 return this.fireEvent('beforenodeedit', this, this.editNode);
36605 triggerEdit : function(node){
36606 this.completeEdit();
36607 this.editNode = node;
36608 this.startEdit(node.ui.textNode, node.text);
36612 bindScroll : function(){
36613 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36617 beforeNodeClick : function(node, e){
36618 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36619 this.lastClick = new Date();
36620 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36622 this.triggerEdit(node);
36629 updateNode : function(ed, value){
36630 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36631 this.editNode.setText(value);
36635 onHide : function(){
36636 Roo.tree.TreeEditor.superclass.onHide.call(this);
36638 this.editNode.ui.focus();
36643 onSpecialKey : function(field, e){
36644 var k = e.getKey();
36648 }else if(k == e.ENTER && !e.hasModifier()){
36650 this.completeEdit();
36653 });//<Script type="text/javascript">
36656 * Ext JS Library 1.1.1
36657 * Copyright(c) 2006-2007, Ext JS, LLC.
36659 * Originally Released Under LGPL - original licence link has changed is not relivant.
36662 * <script type="text/javascript">
36666 * Not documented??? - probably should be...
36669 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36670 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36672 renderElements : function(n, a, targetNode, bulkRender){
36673 //consel.log("renderElements?");
36674 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36676 var t = n.getOwnerTree();
36677 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36679 var cols = t.columns;
36680 var bw = t.borderWidth;
36682 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36683 var cb = typeof a.checked == "boolean";
36684 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36685 var colcls = 'x-t-' + tid + '-c0';
36687 '<li class="x-tree-node">',
36690 '<div class="x-tree-node-el ', a.cls,'">',
36692 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36695 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36696 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36697 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36698 (a.icon ? ' x-tree-node-inline-icon' : ''),
36699 (a.iconCls ? ' '+a.iconCls : ''),
36700 '" unselectable="on" />',
36701 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36702 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36704 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36705 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36706 '<span unselectable="on" qtip="' + tx + '">',
36710 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36711 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36713 for(var i = 1, len = cols.length; i < len; i++){
36715 colcls = 'x-t-' + tid + '-c' +i;
36716 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36717 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
36718 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
36724 '<div class="x-clear"></div></div>',
36725 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36728 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36729 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36730 n.nextSibling.ui.getEl(), buf.join(""));
36732 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36734 var el = this.wrap.firstChild;
36736 this.elNode = el.firstChild;
36737 this.ranchor = el.childNodes[1];
36738 this.ctNode = this.wrap.childNodes[1];
36739 var cs = el.firstChild.childNodes;
36740 this.indentNode = cs[0];
36741 this.ecNode = cs[1];
36742 this.iconNode = cs[2];
36745 this.checkbox = cs[3];
36748 this.anchor = cs[index];
36750 this.textNode = cs[index].firstChild;
36752 //el.on("click", this.onClick, this);
36753 //el.on("dblclick", this.onDblClick, this);
36756 // console.log(this);
36758 initEvents : function(){
36759 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
36762 var a = this.ranchor;
36764 var el = Roo.get(a);
36766 if(Roo.isOpera){ // opera render bug ignores the CSS
36767 el.setStyle("text-decoration", "none");
36770 el.on("click", this.onClick, this);
36771 el.on("dblclick", this.onDblClick, this);
36772 el.on("contextmenu", this.onContextMenu, this);
36776 /*onSelectedChange : function(state){
36779 this.addClass("x-tree-selected");
36782 this.removeClass("x-tree-selected");
36785 addClass : function(cls){
36787 Roo.fly(this.elRow).addClass(cls);
36793 removeClass : function(cls){
36795 Roo.fly(this.elRow).removeClass(cls);
36801 });//<Script type="text/javascript">
36805 * Ext JS Library 1.1.1
36806 * Copyright(c) 2006-2007, Ext JS, LLC.
36808 * Originally Released Under LGPL - original licence link has changed is not relivant.
36811 * <script type="text/javascript">
36816 * @class Roo.tree.ColumnTree
36817 * @extends Roo.data.TreePanel
36818 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
36819 * @cfg {int} borderWidth compined right/left border allowance
36821 * @param {String/HTMLElement/Element} el The container element
36822 * @param {Object} config
36824 Roo.tree.ColumnTree = function(el, config)
36826 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
36830 * Fire this event on a container when it resizes
36831 * @param {int} w Width
36832 * @param {int} h Height
36836 this.on('resize', this.onResize, this);
36839 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
36843 borderWidth: Roo.isBorderBox ? 0 : 2,
36846 render : function(){
36847 // add the header.....
36849 Roo.tree.ColumnTree.superclass.render.apply(this);
36851 this.el.addClass('x-column-tree');
36853 this.headers = this.el.createChild(
36854 {cls:'x-tree-headers'},this.innerCt.dom);
36856 var cols = this.columns, c;
36857 var totalWidth = 0;
36859 var len = cols.length;
36860 for(var i = 0; i < len; i++){
36862 totalWidth += c.width;
36863 this.headEls.push(this.headers.createChild({
36864 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
36866 cls:'x-tree-hd-text',
36869 style:'width:'+(c.width-this.borderWidth)+'px;'
36872 this.headers.createChild({cls:'x-clear'});
36873 // prevent floats from wrapping when clipped
36874 this.headers.setWidth(totalWidth);
36875 //this.innerCt.setWidth(totalWidth);
36876 this.innerCt.setStyle({ overflow: 'auto' });
36877 this.onResize(this.width, this.height);
36881 onResize : function(w,h)
36886 this.innerCt.setWidth(this.width);
36887 this.innerCt.setHeight(this.height-20);
36890 var cols = this.columns, c;
36891 var totalWidth = 0;
36893 var len = cols.length;
36894 for(var i = 0; i < len; i++){
36896 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
36897 // it's the expander..
36898 expEl = this.headEls[i];
36901 totalWidth += c.width;
36905 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
36907 this.headers.setWidth(w-20);
36916 * Ext JS Library 1.1.1
36917 * Copyright(c) 2006-2007, Ext JS, LLC.
36919 * Originally Released Under LGPL - original licence link has changed is not relivant.
36922 * <script type="text/javascript">
36926 * @class Roo.menu.Menu
36927 * @extends Roo.util.Observable
36928 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
36929 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
36931 * Creates a new Menu
36932 * @param {Object} config Configuration options
36934 Roo.menu.Menu = function(config){
36935 Roo.apply(this, config);
36936 this.id = this.id || Roo.id();
36939 * @event beforeshow
36940 * Fires before this menu is displayed
36941 * @param {Roo.menu.Menu} this
36945 * @event beforehide
36946 * Fires before this menu is hidden
36947 * @param {Roo.menu.Menu} this
36952 * Fires after this menu is displayed
36953 * @param {Roo.menu.Menu} this
36958 * Fires after this menu is hidden
36959 * @param {Roo.menu.Menu} this
36964 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
36965 * @param {Roo.menu.Menu} this
36966 * @param {Roo.menu.Item} menuItem The menu item that was clicked
36967 * @param {Roo.EventObject} e
36972 * Fires when the mouse is hovering over this menu
36973 * @param {Roo.menu.Menu} this
36974 * @param {Roo.EventObject} e
36975 * @param {Roo.menu.Item} menuItem The menu item that was clicked
36980 * Fires when the mouse exits this menu
36981 * @param {Roo.menu.Menu} this
36982 * @param {Roo.EventObject} e
36983 * @param {Roo.menu.Item} menuItem The menu item that was clicked
36988 * Fires when a menu item contained in this menu is clicked
36989 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
36990 * @param {Roo.EventObject} e
36994 if (this.registerMenu) {
36995 Roo.menu.MenuMgr.register(this);
36998 var mis = this.items;
36999 this.items = new Roo.util.MixedCollection();
37001 this.add.apply(this, mis);
37005 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37007 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37011 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37012 * for bottom-right shadow (defaults to "sides")
37016 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37017 * this menu (defaults to "tl-tr?")
37019 subMenuAlign : "tl-tr?",
37021 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37022 * relative to its element of origin (defaults to "tl-bl?")
37024 defaultAlign : "tl-bl?",
37026 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37028 allowOtherMenus : false,
37030 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37032 registerMenu : true,
37037 render : function(){
37041 var el = this.el = new Roo.Layer({
37043 shadow:this.shadow,
37045 parentEl: this.parentEl || document.body,
37049 this.keyNav = new Roo.menu.MenuNav(this);
37052 el.addClass("x-menu-plain");
37055 el.addClass(this.cls);
37057 // generic focus element
37058 this.focusEl = el.createChild({
37059 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37061 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37062 //disabling touch- as it's causing issues ..
37063 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37064 ul.on('click' , this.onClick, this);
37067 ul.on("mouseover", this.onMouseOver, this);
37068 ul.on("mouseout", this.onMouseOut, this);
37069 this.items.each(function(item){
37074 var li = document.createElement("li");
37075 li.className = "x-menu-list-item";
37076 ul.dom.appendChild(li);
37077 item.render(li, this);
37084 autoWidth : function(){
37085 var el = this.el, ul = this.ul;
37089 var w = this.width;
37092 }else if(Roo.isIE){
37093 el.setWidth(this.minWidth);
37094 var t = el.dom.offsetWidth; // force recalc
37095 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37100 delayAutoWidth : function(){
37103 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37105 this.awTask.delay(20);
37110 findTargetItem : function(e){
37111 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37112 if(t && t.menuItemId){
37113 return this.items.get(t.menuItemId);
37118 onClick : function(e){
37119 Roo.log("menu.onClick");
37120 var t = this.findTargetItem(e);
37125 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37126 if(t == this.activeItem && t.shouldDeactivate(e)){
37127 this.activeItem.deactivate();
37128 delete this.activeItem;
37132 this.setActiveItem(t, true);
37140 this.fireEvent("click", this, t, e);
37144 setActiveItem : function(item, autoExpand){
37145 if(item != this.activeItem){
37146 if(this.activeItem){
37147 this.activeItem.deactivate();
37149 this.activeItem = item;
37150 item.activate(autoExpand);
37151 }else if(autoExpand){
37157 tryActivate : function(start, step){
37158 var items = this.items;
37159 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37160 var item = items.get(i);
37161 if(!item.disabled && item.canActivate){
37162 this.setActiveItem(item, false);
37170 onMouseOver : function(e){
37172 if(t = this.findTargetItem(e)){
37173 if(t.canActivate && !t.disabled){
37174 this.setActiveItem(t, true);
37177 this.fireEvent("mouseover", this, e, t);
37181 onMouseOut : function(e){
37183 if(t = this.findTargetItem(e)){
37184 if(t == this.activeItem && t.shouldDeactivate(e)){
37185 this.activeItem.deactivate();
37186 delete this.activeItem;
37189 this.fireEvent("mouseout", this, e, t);
37193 * Read-only. Returns true if the menu is currently displayed, else false.
37196 isVisible : function(){
37197 return this.el && !this.hidden;
37201 * Displays this menu relative to another element
37202 * @param {String/HTMLElement/Roo.Element} element The element to align to
37203 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37204 * the element (defaults to this.defaultAlign)
37205 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37207 show : function(el, pos, parentMenu){
37208 this.parentMenu = parentMenu;
37212 this.fireEvent("beforeshow", this);
37213 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37217 * Displays this menu at a specific xy position
37218 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37219 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37221 showAt : function(xy, parentMenu, /* private: */_e){
37222 this.parentMenu = parentMenu;
37227 this.fireEvent("beforeshow", this);
37228 xy = this.el.adjustForConstraints(xy);
37232 this.hidden = false;
37234 this.fireEvent("show", this);
37237 focus : function(){
37239 this.doFocus.defer(50, this);
37243 doFocus : function(){
37245 this.focusEl.focus();
37250 * Hides this menu and optionally all parent menus
37251 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37253 hide : function(deep){
37254 if(this.el && this.isVisible()){
37255 this.fireEvent("beforehide", this);
37256 if(this.activeItem){
37257 this.activeItem.deactivate();
37258 this.activeItem = null;
37261 this.hidden = true;
37262 this.fireEvent("hide", this);
37264 if(deep === true && this.parentMenu){
37265 this.parentMenu.hide(true);
37270 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37271 * Any of the following are valid:
37273 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37274 * <li>An HTMLElement object which will be converted to a menu item</li>
37275 * <li>A menu item config object that will be created as a new menu item</li>
37276 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37277 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37282 var menu = new Roo.menu.Menu();
37284 // Create a menu item to add by reference
37285 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37287 // Add a bunch of items at once using different methods.
37288 // Only the last item added will be returned.
37289 var item = menu.add(
37290 menuItem, // add existing item by ref
37291 'Dynamic Item', // new TextItem
37292 '-', // new separator
37293 { text: 'Config Item' } // new item by config
37296 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37297 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37300 var a = arguments, l = a.length, item;
37301 for(var i = 0; i < l; i++){
37303 if ((typeof(el) == "object") && el.xtype && el.xns) {
37304 el = Roo.factory(el, Roo.menu);
37307 if(el.render){ // some kind of Item
37308 item = this.addItem(el);
37309 }else if(typeof el == "string"){ // string
37310 if(el == "separator" || el == "-"){
37311 item = this.addSeparator();
37313 item = this.addText(el);
37315 }else if(el.tagName || el.el){ // element
37316 item = this.addElement(el);
37317 }else if(typeof el == "object"){ // must be menu item config?
37318 item = this.addMenuItem(el);
37325 * Returns this menu's underlying {@link Roo.Element} object
37326 * @return {Roo.Element} The element
37328 getEl : function(){
37336 * Adds a separator bar to the menu
37337 * @return {Roo.menu.Item} The menu item that was added
37339 addSeparator : function(){
37340 return this.addItem(new Roo.menu.Separator());
37344 * Adds an {@link Roo.Element} object to the menu
37345 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37346 * @return {Roo.menu.Item} The menu item that was added
37348 addElement : function(el){
37349 return this.addItem(new Roo.menu.BaseItem(el));
37353 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37354 * @param {Roo.menu.Item} item The menu item to add
37355 * @return {Roo.menu.Item} The menu item that was added
37357 addItem : function(item){
37358 this.items.add(item);
37360 var li = document.createElement("li");
37361 li.className = "x-menu-list-item";
37362 this.ul.dom.appendChild(li);
37363 item.render(li, this);
37364 this.delayAutoWidth();
37370 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37371 * @param {Object} config A MenuItem config object
37372 * @return {Roo.menu.Item} The menu item that was added
37374 addMenuItem : function(config){
37375 if(!(config instanceof Roo.menu.Item)){
37376 if(typeof config.checked == "boolean"){ // must be check menu item config?
37377 config = new Roo.menu.CheckItem(config);
37379 config = new Roo.menu.Item(config);
37382 return this.addItem(config);
37386 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37387 * @param {String} text The text to display in the menu item
37388 * @return {Roo.menu.Item} The menu item that was added
37390 addText : function(text){
37391 return this.addItem(new Roo.menu.TextItem({ text : text }));
37395 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37396 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37397 * @param {Roo.menu.Item} item The menu item to add
37398 * @return {Roo.menu.Item} The menu item that was added
37400 insert : function(index, item){
37401 this.items.insert(index, item);
37403 var li = document.createElement("li");
37404 li.className = "x-menu-list-item";
37405 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37406 item.render(li, this);
37407 this.delayAutoWidth();
37413 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37414 * @param {Roo.menu.Item} item The menu item to remove
37416 remove : function(item){
37417 this.items.removeKey(item.id);
37422 * Removes and destroys all items in the menu
37424 removeAll : function(){
37426 while(f = this.items.first()){
37432 // MenuNav is a private utility class used internally by the Menu
37433 Roo.menu.MenuNav = function(menu){
37434 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37435 this.scope = this.menu = menu;
37438 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37439 doRelay : function(e, h){
37440 var k = e.getKey();
37441 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37442 this.menu.tryActivate(0, 1);
37445 return h.call(this.scope || this, e, this.menu);
37448 up : function(e, m){
37449 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37450 m.tryActivate(m.items.length-1, -1);
37454 down : function(e, m){
37455 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37456 m.tryActivate(0, 1);
37460 right : function(e, m){
37462 m.activeItem.expandMenu(true);
37466 left : function(e, m){
37468 if(m.parentMenu && m.parentMenu.activeItem){
37469 m.parentMenu.activeItem.activate();
37473 enter : function(e, m){
37475 e.stopPropagation();
37476 m.activeItem.onClick(e);
37477 m.fireEvent("click", this, m.activeItem);
37483 * Ext JS Library 1.1.1
37484 * Copyright(c) 2006-2007, Ext JS, LLC.
37486 * Originally Released Under LGPL - original licence link has changed is not relivant.
37489 * <script type="text/javascript">
37493 * @class Roo.menu.MenuMgr
37494 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37497 Roo.menu.MenuMgr = function(){
37498 var menus, active, groups = {}, attached = false, lastShow = new Date();
37500 // private - called when first menu is created
37503 active = new Roo.util.MixedCollection();
37504 Roo.get(document).addKeyListener(27, function(){
37505 if(active.length > 0){
37512 function hideAll(){
37513 if(active && active.length > 0){
37514 var c = active.clone();
37515 c.each(function(m){
37522 function onHide(m){
37524 if(active.length < 1){
37525 Roo.get(document).un("mousedown", onMouseDown);
37531 function onShow(m){
37532 var last = active.last();
37533 lastShow = new Date();
37536 Roo.get(document).on("mousedown", onMouseDown);
37540 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37541 m.parentMenu.activeChild = m;
37542 }else if(last && last.isVisible()){
37543 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37548 function onBeforeHide(m){
37550 m.activeChild.hide();
37552 if(m.autoHideTimer){
37553 clearTimeout(m.autoHideTimer);
37554 delete m.autoHideTimer;
37559 function onBeforeShow(m){
37560 var pm = m.parentMenu;
37561 if(!pm && !m.allowOtherMenus){
37563 }else if(pm && pm.activeChild && active != m){
37564 pm.activeChild.hide();
37569 function onMouseDown(e){
37570 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37576 function onBeforeCheck(mi, state){
37578 var g = groups[mi.group];
37579 for(var i = 0, l = g.length; i < l; i++){
37581 g[i].setChecked(false);
37590 * Hides all menus that are currently visible
37592 hideAll : function(){
37597 register : function(menu){
37601 menus[menu.id] = menu;
37602 menu.on("beforehide", onBeforeHide);
37603 menu.on("hide", onHide);
37604 menu.on("beforeshow", onBeforeShow);
37605 menu.on("show", onShow);
37606 var g = menu.group;
37607 if(g && menu.events["checkchange"]){
37611 groups[g].push(menu);
37612 menu.on("checkchange", onCheck);
37617 * Returns a {@link Roo.menu.Menu} object
37618 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37619 * be used to generate and return a new Menu instance.
37621 get : function(menu){
37622 if(typeof menu == "string"){ // menu id
37623 return menus[menu];
37624 }else if(menu.events){ // menu instance
37626 }else if(typeof menu.length == 'number'){ // array of menu items?
37627 return new Roo.menu.Menu({items:menu});
37628 }else{ // otherwise, must be a config
37629 return new Roo.menu.Menu(menu);
37634 unregister : function(menu){
37635 delete menus[menu.id];
37636 menu.un("beforehide", onBeforeHide);
37637 menu.un("hide", onHide);
37638 menu.un("beforeshow", onBeforeShow);
37639 menu.un("show", onShow);
37640 var g = menu.group;
37641 if(g && menu.events["checkchange"]){
37642 groups[g].remove(menu);
37643 menu.un("checkchange", onCheck);
37648 registerCheckable : function(menuItem){
37649 var g = menuItem.group;
37654 groups[g].push(menuItem);
37655 menuItem.on("beforecheckchange", onBeforeCheck);
37660 unregisterCheckable : function(menuItem){
37661 var g = menuItem.group;
37663 groups[g].remove(menuItem);
37664 menuItem.un("beforecheckchange", onBeforeCheck);
37670 * Ext JS Library 1.1.1
37671 * Copyright(c) 2006-2007, Ext JS, LLC.
37673 * Originally Released Under LGPL - original licence link has changed is not relivant.
37676 * <script type="text/javascript">
37681 * @class Roo.menu.BaseItem
37682 * @extends Roo.Component
37683 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37684 * management and base configuration options shared by all menu components.
37686 * Creates a new BaseItem
37687 * @param {Object} config Configuration options
37689 Roo.menu.BaseItem = function(config){
37690 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37695 * Fires when this item is clicked
37696 * @param {Roo.menu.BaseItem} this
37697 * @param {Roo.EventObject} e
37702 * Fires when this item is activated
37703 * @param {Roo.menu.BaseItem} this
37707 * @event deactivate
37708 * Fires when this item is deactivated
37709 * @param {Roo.menu.BaseItem} this
37715 this.on("click", this.handler, this.scope, true);
37719 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
37721 * @cfg {Function} handler
37722 * A function that will handle the click event of this menu item (defaults to undefined)
37725 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
37727 canActivate : false,
37730 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
37735 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
37737 activeClass : "x-menu-item-active",
37739 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
37741 hideOnClick : true,
37743 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
37748 ctype: "Roo.menu.BaseItem",
37751 actionMode : "container",
37754 render : function(container, parentMenu){
37755 this.parentMenu = parentMenu;
37756 Roo.menu.BaseItem.superclass.render.call(this, container);
37757 this.container.menuItemId = this.id;
37761 onRender : function(container, position){
37762 this.el = Roo.get(this.el);
37763 container.dom.appendChild(this.el.dom);
37767 onClick : function(e){
37768 if(!this.disabled && this.fireEvent("click", this, e) !== false
37769 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
37770 this.handleClick(e);
37777 activate : function(){
37781 var li = this.container;
37782 li.addClass(this.activeClass);
37783 this.region = li.getRegion().adjust(2, 2, -2, -2);
37784 this.fireEvent("activate", this);
37789 deactivate : function(){
37790 this.container.removeClass(this.activeClass);
37791 this.fireEvent("deactivate", this);
37795 shouldDeactivate : function(e){
37796 return !this.region || !this.region.contains(e.getPoint());
37800 handleClick : function(e){
37801 if(this.hideOnClick){
37802 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
37807 expandMenu : function(autoActivate){
37812 hideMenu : function(){
37817 * Ext JS Library 1.1.1
37818 * Copyright(c) 2006-2007, Ext JS, LLC.
37820 * Originally Released Under LGPL - original licence link has changed is not relivant.
37823 * <script type="text/javascript">
37827 * @class Roo.menu.Adapter
37828 * @extends Roo.menu.BaseItem
37829 * 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.
37830 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
37832 * Creates a new Adapter
37833 * @param {Object} config Configuration options
37835 Roo.menu.Adapter = function(component, config){
37836 Roo.menu.Adapter.superclass.constructor.call(this, config);
37837 this.component = component;
37839 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
37841 canActivate : true,
37844 onRender : function(container, position){
37845 this.component.render(container);
37846 this.el = this.component.getEl();
37850 activate : function(){
37854 this.component.focus();
37855 this.fireEvent("activate", this);
37860 deactivate : function(){
37861 this.fireEvent("deactivate", this);
37865 disable : function(){
37866 this.component.disable();
37867 Roo.menu.Adapter.superclass.disable.call(this);
37871 enable : function(){
37872 this.component.enable();
37873 Roo.menu.Adapter.superclass.enable.call(this);
37877 * Ext JS Library 1.1.1
37878 * Copyright(c) 2006-2007, Ext JS, LLC.
37880 * Originally Released Under LGPL - original licence link has changed is not relivant.
37883 * <script type="text/javascript">
37887 * @class Roo.menu.TextItem
37888 * @extends Roo.menu.BaseItem
37889 * Adds a static text string to a menu, usually used as either a heading or group separator.
37890 * Note: old style constructor with text is still supported.
37893 * Creates a new TextItem
37894 * @param {Object} cfg Configuration
37896 Roo.menu.TextItem = function(cfg){
37897 if (typeof(cfg) == 'string') {
37900 Roo.apply(this,cfg);
37903 Roo.menu.TextItem.superclass.constructor.call(this);
37906 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
37908 * @cfg {Boolean} text Text to show on item.
37913 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
37915 hideOnClick : false,
37917 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
37919 itemCls : "x-menu-text",
37922 onRender : function(){
37923 var s = document.createElement("span");
37924 s.className = this.itemCls;
37925 s.innerHTML = this.text;
37927 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
37931 * Ext JS Library 1.1.1
37932 * Copyright(c) 2006-2007, Ext JS, LLC.
37934 * Originally Released Under LGPL - original licence link has changed is not relivant.
37937 * <script type="text/javascript">
37941 * @class Roo.menu.Separator
37942 * @extends Roo.menu.BaseItem
37943 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
37944 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
37946 * @param {Object} config Configuration options
37948 Roo.menu.Separator = function(config){
37949 Roo.menu.Separator.superclass.constructor.call(this, config);
37952 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
37954 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
37956 itemCls : "x-menu-sep",
37958 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
37960 hideOnClick : false,
37963 onRender : function(li){
37964 var s = document.createElement("span");
37965 s.className = this.itemCls;
37966 s.innerHTML = " ";
37968 li.addClass("x-menu-sep-li");
37969 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
37973 * Ext JS Library 1.1.1
37974 * Copyright(c) 2006-2007, Ext JS, LLC.
37976 * Originally Released Under LGPL - original licence link has changed is not relivant.
37979 * <script type="text/javascript">
37982 * @class Roo.menu.Item
37983 * @extends Roo.menu.BaseItem
37984 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
37985 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
37986 * activation and click handling.
37988 * Creates a new Item
37989 * @param {Object} config Configuration options
37991 Roo.menu.Item = function(config){
37992 Roo.menu.Item.superclass.constructor.call(this, config);
37994 this.menu = Roo.menu.MenuMgr.get(this.menu);
37997 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38000 * @cfg {String} text
38001 * The text to show on the menu item.
38005 * @cfg {String} HTML to render in menu
38006 * The text to show on the menu item (HTML version).
38010 * @cfg {String} icon
38011 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38015 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38017 itemCls : "x-menu-item",
38019 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38021 canActivate : true,
38023 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38026 // doc'd in BaseItem
38030 ctype: "Roo.menu.Item",
38033 onRender : function(container, position){
38034 var el = document.createElement("a");
38035 el.hideFocus = true;
38036 el.unselectable = "on";
38037 el.href = this.href || "#";
38038 if(this.hrefTarget){
38039 el.target = this.hrefTarget;
38041 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38043 var html = this.html.length ? this.html : String.format('{0}',this.text);
38045 el.innerHTML = String.format(
38046 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38047 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38049 Roo.menu.Item.superclass.onRender.call(this, container, position);
38053 * Sets the text to display in this menu item
38054 * @param {String} text The text to display
38055 * @param {Boolean} isHTML true to indicate text is pure html.
38057 setText : function(text, isHTML){
38065 var html = this.html.length ? this.html : String.format('{0}',this.text);
38067 this.el.update(String.format(
38068 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38069 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38070 this.parentMenu.autoWidth();
38075 handleClick : function(e){
38076 if(!this.href){ // if no link defined, stop the event automatically
38079 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38083 activate : function(autoExpand){
38084 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38094 shouldDeactivate : function(e){
38095 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38096 if(this.menu && this.menu.isVisible()){
38097 return !this.menu.getEl().getRegion().contains(e.getPoint());
38105 deactivate : function(){
38106 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38111 expandMenu : function(autoActivate){
38112 if(!this.disabled && this.menu){
38113 clearTimeout(this.hideTimer);
38114 delete this.hideTimer;
38115 if(!this.menu.isVisible() && !this.showTimer){
38116 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38117 }else if (this.menu.isVisible() && autoActivate){
38118 this.menu.tryActivate(0, 1);
38124 deferExpand : function(autoActivate){
38125 delete this.showTimer;
38126 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38128 this.menu.tryActivate(0, 1);
38133 hideMenu : function(){
38134 clearTimeout(this.showTimer);
38135 delete this.showTimer;
38136 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38137 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38142 deferHide : function(){
38143 delete this.hideTimer;
38148 * Ext JS Library 1.1.1
38149 * Copyright(c) 2006-2007, Ext JS, LLC.
38151 * Originally Released Under LGPL - original licence link has changed is not relivant.
38154 * <script type="text/javascript">
38158 * @class Roo.menu.CheckItem
38159 * @extends Roo.menu.Item
38160 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38162 * Creates a new CheckItem
38163 * @param {Object} config Configuration options
38165 Roo.menu.CheckItem = function(config){
38166 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38169 * @event beforecheckchange
38170 * Fires before the checked value is set, providing an opportunity to cancel if needed
38171 * @param {Roo.menu.CheckItem} this
38172 * @param {Boolean} checked The new checked value that will be set
38174 "beforecheckchange" : true,
38176 * @event checkchange
38177 * Fires after the checked value has been set
38178 * @param {Roo.menu.CheckItem} this
38179 * @param {Boolean} checked The checked value that was set
38181 "checkchange" : true
38183 if(this.checkHandler){
38184 this.on('checkchange', this.checkHandler, this.scope);
38187 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38189 * @cfg {String} group
38190 * All check items with the same group name will automatically be grouped into a single-select
38191 * radio button group (defaults to '')
38194 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38196 itemCls : "x-menu-item x-menu-check-item",
38198 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38200 groupClass : "x-menu-group-item",
38203 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38204 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38205 * initialized with checked = true will be rendered as checked.
38210 ctype: "Roo.menu.CheckItem",
38213 onRender : function(c){
38214 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38216 this.el.addClass(this.groupClass);
38218 Roo.menu.MenuMgr.registerCheckable(this);
38220 this.checked = false;
38221 this.setChecked(true, true);
38226 destroy : function(){
38228 Roo.menu.MenuMgr.unregisterCheckable(this);
38230 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38234 * Set the checked state of this item
38235 * @param {Boolean} checked The new checked value
38236 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38238 setChecked : function(state, suppressEvent){
38239 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38240 if(this.container){
38241 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38243 this.checked = state;
38244 if(suppressEvent !== true){
38245 this.fireEvent("checkchange", this, state);
38251 handleClick : function(e){
38252 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38253 this.setChecked(!this.checked);
38255 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38259 * Ext JS Library 1.1.1
38260 * Copyright(c) 2006-2007, Ext JS, LLC.
38262 * Originally Released Under LGPL - original licence link has changed is not relivant.
38265 * <script type="text/javascript">
38269 * @class Roo.menu.DateItem
38270 * @extends Roo.menu.Adapter
38271 * A menu item that wraps the {@link Roo.DatPicker} component.
38273 * Creates a new DateItem
38274 * @param {Object} config Configuration options
38276 Roo.menu.DateItem = function(config){
38277 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38278 /** The Roo.DatePicker object @type Roo.DatePicker */
38279 this.picker = this.component;
38280 this.addEvents({select: true});
38282 this.picker.on("render", function(picker){
38283 picker.getEl().swallowEvent("click");
38284 picker.container.addClass("x-menu-date-item");
38287 this.picker.on("select", this.onSelect, this);
38290 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38292 onSelect : function(picker, date){
38293 this.fireEvent("select", this, date, picker);
38294 Roo.menu.DateItem.superclass.handleClick.call(this);
38298 * Ext JS Library 1.1.1
38299 * Copyright(c) 2006-2007, Ext JS, LLC.
38301 * Originally Released Under LGPL - original licence link has changed is not relivant.
38304 * <script type="text/javascript">
38308 * @class Roo.menu.ColorItem
38309 * @extends Roo.menu.Adapter
38310 * A menu item that wraps the {@link Roo.ColorPalette} component.
38312 * Creates a new ColorItem
38313 * @param {Object} config Configuration options
38315 Roo.menu.ColorItem = function(config){
38316 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38317 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38318 this.palette = this.component;
38319 this.relayEvents(this.palette, ["select"]);
38320 if(this.selectHandler){
38321 this.on('select', this.selectHandler, this.scope);
38324 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38326 * Ext JS Library 1.1.1
38327 * Copyright(c) 2006-2007, Ext JS, LLC.
38329 * Originally Released Under LGPL - original licence link has changed is not relivant.
38332 * <script type="text/javascript">
38337 * @class Roo.menu.DateMenu
38338 * @extends Roo.menu.Menu
38339 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38341 * Creates a new DateMenu
38342 * @param {Object} config Configuration options
38344 Roo.menu.DateMenu = function(config){
38345 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38347 var di = new Roo.menu.DateItem(config);
38350 * The {@link Roo.DatePicker} instance for this DateMenu
38353 this.picker = di.picker;
38356 * @param {DatePicker} picker
38357 * @param {Date} date
38359 this.relayEvents(di, ["select"]);
38360 this.on('beforeshow', function(){
38362 this.picker.hideMonthPicker(false);
38366 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38370 * Ext JS Library 1.1.1
38371 * Copyright(c) 2006-2007, Ext JS, LLC.
38373 * Originally Released Under LGPL - original licence link has changed is not relivant.
38376 * <script type="text/javascript">
38381 * @class Roo.menu.ColorMenu
38382 * @extends Roo.menu.Menu
38383 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38385 * Creates a new ColorMenu
38386 * @param {Object} config Configuration options
38388 Roo.menu.ColorMenu = function(config){
38389 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38391 var ci = new Roo.menu.ColorItem(config);
38394 * The {@link Roo.ColorPalette} instance for this ColorMenu
38395 * @type ColorPalette
38397 this.palette = ci.palette;
38400 * @param {ColorPalette} palette
38401 * @param {String} color
38403 this.relayEvents(ci, ["select"]);
38405 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38407 * Ext JS Library 1.1.1
38408 * Copyright(c) 2006-2007, Ext JS, LLC.
38410 * Originally Released Under LGPL - original licence link has changed is not relivant.
38413 * <script type="text/javascript">
38417 * @class Roo.form.Field
38418 * @extends Roo.BoxComponent
38419 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38421 * Creates a new Field
38422 * @param {Object} config Configuration options
38424 Roo.form.Field = function(config){
38425 Roo.form.Field.superclass.constructor.call(this, config);
38428 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38430 * @cfg {String} fieldLabel Label to use when rendering a form.
38433 * @cfg {String} qtip Mouse over tip
38437 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38439 invalidClass : "x-form-invalid",
38441 * @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")
38443 invalidText : "The value in this field is invalid",
38445 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38447 focusClass : "x-form-focus",
38449 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38450 automatic validation (defaults to "keyup").
38452 validationEvent : "keyup",
38454 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38456 validateOnBlur : true,
38458 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38460 validationDelay : 250,
38462 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38463 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38465 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38467 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38469 fieldClass : "x-form-field",
38471 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38474 ----------- ----------------------------------------------------------------------
38475 qtip Display a quick tip when the user hovers over the field
38476 title Display a default browser title attribute popup
38477 under Add a block div beneath the field containing the error text
38478 side Add an error icon to the right of the field with a popup on hover
38479 [element id] Add the error text directly to the innerHTML of the specified element
38482 msgTarget : 'qtip',
38484 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38489 * @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.
38494 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38499 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38501 inputType : undefined,
38504 * @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).
38506 tabIndex : undefined,
38509 isFormField : true,
38514 * @property {Roo.Element} fieldEl
38515 * Element Containing the rendered Field (with label etc.)
38518 * @cfg {Mixed} value A value to initialize this field with.
38523 * @cfg {String} name The field's HTML name attribute.
38526 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38529 loadedValue : false,
38533 initComponent : function(){
38534 Roo.form.Field.superclass.initComponent.call(this);
38538 * Fires when this field receives input focus.
38539 * @param {Roo.form.Field} this
38544 * Fires when this field loses input focus.
38545 * @param {Roo.form.Field} this
38549 * @event specialkey
38550 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38551 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38552 * @param {Roo.form.Field} this
38553 * @param {Roo.EventObject} e The event object
38558 * Fires just before the field blurs if the field value has changed.
38559 * @param {Roo.form.Field} this
38560 * @param {Mixed} newValue The new value
38561 * @param {Mixed} oldValue The original value
38566 * Fires after the field has been marked as invalid.
38567 * @param {Roo.form.Field} this
38568 * @param {String} msg The validation message
38573 * Fires after the field has been validated with no errors.
38574 * @param {Roo.form.Field} this
38579 * Fires after the key up
38580 * @param {Roo.form.Field} this
38581 * @param {Roo.EventObject} e The event Object
38588 * Returns the name attribute of the field if available
38589 * @return {String} name The field name
38591 getName: function(){
38592 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38596 onRender : function(ct, position){
38597 Roo.form.Field.superclass.onRender.call(this, ct, position);
38599 var cfg = this.getAutoCreate();
38601 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38603 if (!cfg.name.length) {
38606 if(this.inputType){
38607 cfg.type = this.inputType;
38609 this.el = ct.createChild(cfg, position);
38611 var type = this.el.dom.type;
38613 if(type == 'password'){
38616 this.el.addClass('x-form-'+type);
38619 this.el.dom.readOnly = true;
38621 if(this.tabIndex !== undefined){
38622 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38625 this.el.addClass([this.fieldClass, this.cls]);
38630 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38631 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38632 * @return {Roo.form.Field} this
38634 applyTo : function(target){
38635 this.allowDomMove = false;
38636 this.el = Roo.get(target);
38637 this.render(this.el.dom.parentNode);
38642 initValue : function(){
38643 if(this.value !== undefined){
38644 this.setValue(this.value);
38645 }else if(this.el.dom.value.length > 0){
38646 this.setValue(this.el.dom.value);
38651 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38652 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38654 isDirty : function() {
38655 if(this.disabled) {
38658 return String(this.getValue()) !== String(this.originalValue);
38662 * stores the current value in loadedValue
38664 resetHasChanged : function()
38666 this.loadedValue = String(this.getValue());
38669 * checks the current value against the 'loaded' value.
38670 * Note - will return false if 'resetHasChanged' has not been called first.
38672 hasChanged : function()
38674 if(this.disabled || this.readOnly) {
38677 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38683 afterRender : function(){
38684 Roo.form.Field.superclass.afterRender.call(this);
38689 fireKey : function(e){
38690 //Roo.log('field ' + e.getKey());
38691 if(e.isNavKeyPress()){
38692 this.fireEvent("specialkey", this, e);
38697 * Resets the current field value to the originally loaded value and clears any validation messages
38699 reset : function(){
38700 this.setValue(this.resetValue);
38701 this.clearInvalid();
38705 initEvents : function(){
38706 // safari killled keypress - so keydown is now used..
38707 this.el.on("keydown" , this.fireKey, this);
38708 this.el.on("focus", this.onFocus, this);
38709 this.el.on("blur", this.onBlur, this);
38710 this.el.relayEvent('keyup', this);
38712 // reference to original value for reset
38713 this.originalValue = this.getValue();
38714 this.resetValue = this.getValue();
38718 onFocus : function(){
38719 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38720 this.el.addClass(this.focusClass);
38722 if(!this.hasFocus){
38723 this.hasFocus = true;
38724 this.startValue = this.getValue();
38725 this.fireEvent("focus", this);
38729 beforeBlur : Roo.emptyFn,
38732 onBlur : function(){
38734 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38735 this.el.removeClass(this.focusClass);
38737 this.hasFocus = false;
38738 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
38741 var v = this.getValue();
38742 if(String(v) !== String(this.startValue)){
38743 this.fireEvent('change', this, v, this.startValue);
38745 this.fireEvent("blur", this);
38749 * Returns whether or not the field value is currently valid
38750 * @param {Boolean} preventMark True to disable marking the field invalid
38751 * @return {Boolean} True if the value is valid, else false
38753 isValid : function(preventMark){
38757 var restore = this.preventMark;
38758 this.preventMark = preventMark === true;
38759 var v = this.validateValue(this.processValue(this.getRawValue()));
38760 this.preventMark = restore;
38765 * Validates the field value
38766 * @return {Boolean} True if the value is valid, else false
38768 validate : function(){
38769 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
38770 this.clearInvalid();
38776 processValue : function(value){
38781 // Subclasses should provide the validation implementation by overriding this
38782 validateValue : function(value){
38787 * Mark this field as invalid
38788 * @param {String} msg The validation message
38790 markInvalid : function(msg){
38791 if(!this.rendered || this.preventMark){ // not rendered
38795 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38797 obj.el.addClass(this.invalidClass);
38798 msg = msg || this.invalidText;
38799 switch(this.msgTarget){
38801 obj.el.dom.qtip = msg;
38802 obj.el.dom.qclass = 'x-form-invalid-tip';
38803 if(Roo.QuickTips){ // fix for floating editors interacting with DND
38804 Roo.QuickTips.enable();
38808 this.el.dom.title = msg;
38812 var elp = this.el.findParent('.x-form-element', 5, true);
38813 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
38814 this.errorEl.setWidth(elp.getWidth(true)-20);
38816 this.errorEl.update(msg);
38817 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
38820 if(!this.errorIcon){
38821 var elp = this.el.findParent('.x-form-element', 5, true);
38822 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
38824 this.alignErrorIcon();
38825 this.errorIcon.dom.qtip = msg;
38826 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
38827 this.errorIcon.show();
38828 this.on('resize', this.alignErrorIcon, this);
38831 var t = Roo.getDom(this.msgTarget);
38833 t.style.display = this.msgDisplay;
38836 this.fireEvent('invalid', this, msg);
38840 alignErrorIcon : function(){
38841 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
38845 * Clear any invalid styles/messages for this field
38847 clearInvalid : function(){
38848 if(!this.rendered || this.preventMark){ // not rendered
38851 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38853 obj.el.removeClass(this.invalidClass);
38854 switch(this.msgTarget){
38856 obj.el.dom.qtip = '';
38859 this.el.dom.title = '';
38863 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
38867 if(this.errorIcon){
38868 this.errorIcon.dom.qtip = '';
38869 this.errorIcon.hide();
38870 this.un('resize', this.alignErrorIcon, this);
38874 var t = Roo.getDom(this.msgTarget);
38876 t.style.display = 'none';
38879 this.fireEvent('valid', this);
38883 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
38884 * @return {Mixed} value The field value
38886 getRawValue : function(){
38887 var v = this.el.getValue();
38893 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
38894 * @return {Mixed} value The field value
38896 getValue : function(){
38897 var v = this.el.getValue();
38903 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
38904 * @param {Mixed} value The value to set
38906 setRawValue : function(v){
38907 return this.el.dom.value = (v === null || v === undefined ? '' : v);
38911 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
38912 * @param {Mixed} value The value to set
38914 setValue : function(v){
38917 this.el.dom.value = (v === null || v === undefined ? '' : v);
38922 adjustSize : function(w, h){
38923 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
38924 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
38928 adjustWidth : function(tag, w){
38929 tag = tag.toLowerCase();
38930 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
38931 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
38932 if(tag == 'input'){
38935 if(tag == 'textarea'){
38938 }else if(Roo.isOpera){
38939 if(tag == 'input'){
38942 if(tag == 'textarea'){
38952 // anything other than normal should be considered experimental
38953 Roo.form.Field.msgFx = {
38955 show: function(msgEl, f){
38956 msgEl.setDisplayed('block');
38959 hide : function(msgEl, f){
38960 msgEl.setDisplayed(false).update('');
38965 show: function(msgEl, f){
38966 msgEl.slideIn('t', {stopFx:true});
38969 hide : function(msgEl, f){
38970 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
38975 show: function(msgEl, f){
38976 msgEl.fixDisplay();
38977 msgEl.alignTo(f.el, 'tl-tr');
38978 msgEl.slideIn('l', {stopFx:true});
38981 hide : function(msgEl, f){
38982 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
38987 * Ext JS Library 1.1.1
38988 * Copyright(c) 2006-2007, Ext JS, LLC.
38990 * Originally Released Under LGPL - original licence link has changed is not relivant.
38993 * <script type="text/javascript">
38998 * @class Roo.form.TextField
38999 * @extends Roo.form.Field
39000 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39001 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39003 * Creates a new TextField
39004 * @param {Object} config Configuration options
39006 Roo.form.TextField = function(config){
39007 Roo.form.TextField.superclass.constructor.call(this, config);
39011 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39012 * according to the default logic, but this event provides a hook for the developer to apply additional
39013 * logic at runtime to resize the field if needed.
39014 * @param {Roo.form.Field} this This text field
39015 * @param {Number} width The new field width
39021 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39023 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39027 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39031 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39035 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39039 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39043 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39045 disableKeyFilter : false,
39047 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39051 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39055 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39057 maxLength : Number.MAX_VALUE,
39059 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39061 minLengthText : "The minimum length for this field is {0}",
39063 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39065 maxLengthText : "The maximum length for this field is {0}",
39067 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39069 selectOnFocus : false,
39071 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39073 blankText : "This field is required",
39075 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39076 * If available, this function will be called only after the basic validators all return true, and will be passed the
39077 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39081 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39082 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39083 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39087 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39091 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39097 initEvents : function()
39099 if (this.emptyText) {
39100 this.el.attr('placeholder', this.emptyText);
39103 Roo.form.TextField.superclass.initEvents.call(this);
39104 if(this.validationEvent == 'keyup'){
39105 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39106 this.el.on('keyup', this.filterValidation, this);
39108 else if(this.validationEvent !== false){
39109 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39112 if(this.selectOnFocus){
39113 this.on("focus", this.preFocus, this);
39116 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39117 this.el.on("keypress", this.filterKeys, this);
39120 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39121 this.el.on("click", this.autoSize, this);
39123 if(this.el.is('input[type=password]') && Roo.isSafari){
39124 this.el.on('keydown', this.SafariOnKeyDown, this);
39128 processValue : function(value){
39129 if(this.stripCharsRe){
39130 var newValue = value.replace(this.stripCharsRe, '');
39131 if(newValue !== value){
39132 this.setRawValue(newValue);
39139 filterValidation : function(e){
39140 if(!e.isNavKeyPress()){
39141 this.validationTask.delay(this.validationDelay);
39146 onKeyUp : function(e){
39147 if(!e.isNavKeyPress()){
39153 * Resets the current field value to the originally-loaded value and clears any validation messages.
39156 reset : function(){
39157 Roo.form.TextField.superclass.reset.call(this);
39163 preFocus : function(){
39165 if(this.selectOnFocus){
39166 this.el.dom.select();
39172 filterKeys : function(e){
39173 var k = e.getKey();
39174 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39177 var c = e.getCharCode(), cc = String.fromCharCode(c);
39178 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39181 if(!this.maskRe.test(cc)){
39186 setValue : function(v){
39188 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39194 * Validates a value according to the field's validation rules and marks the field as invalid
39195 * if the validation fails
39196 * @param {Mixed} value The value to validate
39197 * @return {Boolean} True if the value is valid, else false
39199 validateValue : function(value){
39200 if(value.length < 1) { // if it's blank
39201 if(this.allowBlank){
39202 this.clearInvalid();
39205 this.markInvalid(this.blankText);
39209 if(value.length < this.minLength){
39210 this.markInvalid(String.format(this.minLengthText, this.minLength));
39213 if(value.length > this.maxLength){
39214 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39218 var vt = Roo.form.VTypes;
39219 if(!vt[this.vtype](value, this)){
39220 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39224 if(typeof this.validator == "function"){
39225 var msg = this.validator(value);
39227 this.markInvalid(msg);
39231 if(this.regex && !this.regex.test(value)){
39232 this.markInvalid(this.regexText);
39239 * Selects text in this field
39240 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39241 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39243 selectText : function(start, end){
39244 var v = this.getRawValue();
39246 start = start === undefined ? 0 : start;
39247 end = end === undefined ? v.length : end;
39248 var d = this.el.dom;
39249 if(d.setSelectionRange){
39250 d.setSelectionRange(start, end);
39251 }else if(d.createTextRange){
39252 var range = d.createTextRange();
39253 range.moveStart("character", start);
39254 range.moveEnd("character", v.length-end);
39261 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39262 * This only takes effect if grow = true, and fires the autosize event.
39264 autoSize : function(){
39265 if(!this.grow || !this.rendered){
39269 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39272 var v = el.dom.value;
39273 var d = document.createElement('div');
39274 d.appendChild(document.createTextNode(v));
39278 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39279 this.el.setWidth(w);
39280 this.fireEvent("autosize", this, w);
39284 SafariOnKeyDown : function(event)
39286 // this is a workaround for a password hang bug on chrome/ webkit.
39288 var isSelectAll = false;
39290 if(this.el.dom.selectionEnd > 0){
39291 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39293 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39294 event.preventDefault();
39299 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39301 event.preventDefault();
39302 // this is very hacky as keydown always get's upper case.
39304 var cc = String.fromCharCode(event.getCharCode());
39307 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39315 * Ext JS Library 1.1.1
39316 * Copyright(c) 2006-2007, Ext JS, LLC.
39318 * Originally Released Under LGPL - original licence link has changed is not relivant.
39321 * <script type="text/javascript">
39325 * @class Roo.form.Hidden
39326 * @extends Roo.form.TextField
39327 * Simple Hidden element used on forms
39329 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39332 * Creates a new Hidden form element.
39333 * @param {Object} config Configuration options
39338 // easy hidden field...
39339 Roo.form.Hidden = function(config){
39340 Roo.form.Hidden.superclass.constructor.call(this, config);
39343 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39345 inputType: 'hidden',
39348 labelSeparator: '',
39350 itemCls : 'x-form-item-display-none'
39358 * Ext JS Library 1.1.1
39359 * Copyright(c) 2006-2007, Ext JS, LLC.
39361 * Originally Released Under LGPL - original licence link has changed is not relivant.
39364 * <script type="text/javascript">
39368 * @class Roo.form.TriggerField
39369 * @extends Roo.form.TextField
39370 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39371 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39372 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39373 * for which you can provide a custom implementation. For example:
39375 var trigger = new Roo.form.TriggerField();
39376 trigger.onTriggerClick = myTriggerFn;
39377 trigger.applyTo('my-field');
39380 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39381 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39382 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39383 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39385 * Create a new TriggerField.
39386 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39387 * to the base TextField)
39389 Roo.form.TriggerField = function(config){
39390 this.mimicing = false;
39391 Roo.form.TriggerField.superclass.constructor.call(this, config);
39394 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39396 * @cfg {String} triggerClass A CSS class to apply to the trigger
39399 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39400 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39402 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39404 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39408 /** @cfg {Boolean} grow @hide */
39409 /** @cfg {Number} growMin @hide */
39410 /** @cfg {Number} growMax @hide */
39416 autoSize: Roo.emptyFn,
39420 deferHeight : true,
39423 actionMode : 'wrap',
39425 onResize : function(w, h){
39426 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39427 if(typeof w == 'number'){
39428 var x = w - this.trigger.getWidth();
39429 this.el.setWidth(this.adjustWidth('input', x));
39430 this.trigger.setStyle('left', x+'px');
39435 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39438 getResizeEl : function(){
39443 getPositionEl : function(){
39448 alignErrorIcon : function(){
39449 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39453 onRender : function(ct, position){
39454 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39455 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39456 this.trigger = this.wrap.createChild(this.triggerConfig ||
39457 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39458 if(this.hideTrigger){
39459 this.trigger.setDisplayed(false);
39461 this.initTrigger();
39463 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39468 initTrigger : function(){
39469 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39470 this.trigger.addClassOnOver('x-form-trigger-over');
39471 this.trigger.addClassOnClick('x-form-trigger-click');
39475 onDestroy : function(){
39477 this.trigger.removeAllListeners();
39478 this.trigger.remove();
39481 this.wrap.remove();
39483 Roo.form.TriggerField.superclass.onDestroy.call(this);
39487 onFocus : function(){
39488 Roo.form.TriggerField.superclass.onFocus.call(this);
39489 if(!this.mimicing){
39490 this.wrap.addClass('x-trigger-wrap-focus');
39491 this.mimicing = true;
39492 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39493 if(this.monitorTab){
39494 this.el.on("keydown", this.checkTab, this);
39500 checkTab : function(e){
39501 if(e.getKey() == e.TAB){
39502 this.triggerBlur();
39507 onBlur : function(){
39512 mimicBlur : function(e, t){
39513 if(!this.wrap.contains(t) && this.validateBlur()){
39514 this.triggerBlur();
39519 triggerBlur : function(){
39520 this.mimicing = false;
39521 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39522 if(this.monitorTab){
39523 this.el.un("keydown", this.checkTab, this);
39525 this.wrap.removeClass('x-trigger-wrap-focus');
39526 Roo.form.TriggerField.superclass.onBlur.call(this);
39530 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39531 validateBlur : function(e, t){
39536 onDisable : function(){
39537 Roo.form.TriggerField.superclass.onDisable.call(this);
39539 this.wrap.addClass('x-item-disabled');
39544 onEnable : function(){
39545 Roo.form.TriggerField.superclass.onEnable.call(this);
39547 this.wrap.removeClass('x-item-disabled');
39552 onShow : function(){
39553 var ae = this.getActionEl();
39556 ae.dom.style.display = '';
39557 ae.dom.style.visibility = 'visible';
39563 onHide : function(){
39564 var ae = this.getActionEl();
39565 ae.dom.style.display = 'none';
39569 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39570 * by an implementing function.
39572 * @param {EventObject} e
39574 onTriggerClick : Roo.emptyFn
39577 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39578 // to be extended by an implementing class. For an example of implementing this class, see the custom
39579 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39580 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39581 initComponent : function(){
39582 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39584 this.triggerConfig = {
39585 tag:'span', cls:'x-form-twin-triggers', cn:[
39586 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39587 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39591 getTrigger : function(index){
39592 return this.triggers[index];
39595 initTrigger : function(){
39596 var ts = this.trigger.select('.x-form-trigger', true);
39597 this.wrap.setStyle('overflow', 'hidden');
39598 var triggerField = this;
39599 ts.each(function(t, all, index){
39600 t.hide = function(){
39601 var w = triggerField.wrap.getWidth();
39602 this.dom.style.display = 'none';
39603 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39605 t.show = function(){
39606 var w = triggerField.wrap.getWidth();
39607 this.dom.style.display = '';
39608 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39610 var triggerIndex = 'Trigger'+(index+1);
39612 if(this['hide'+triggerIndex]){
39613 t.dom.style.display = 'none';
39615 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39616 t.addClassOnOver('x-form-trigger-over');
39617 t.addClassOnClick('x-form-trigger-click');
39619 this.triggers = ts.elements;
39622 onTrigger1Click : Roo.emptyFn,
39623 onTrigger2Click : Roo.emptyFn
39626 * Ext JS Library 1.1.1
39627 * Copyright(c) 2006-2007, Ext JS, LLC.
39629 * Originally Released Under LGPL - original licence link has changed is not relivant.
39632 * <script type="text/javascript">
39636 * @class Roo.form.TextArea
39637 * @extends Roo.form.TextField
39638 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39639 * support for auto-sizing.
39641 * Creates a new TextArea
39642 * @param {Object} config Configuration options
39644 Roo.form.TextArea = function(config){
39645 Roo.form.TextArea.superclass.constructor.call(this, config);
39646 // these are provided exchanges for backwards compat
39647 // minHeight/maxHeight were replaced by growMin/growMax to be
39648 // compatible with TextField growing config values
39649 if(this.minHeight !== undefined){
39650 this.growMin = this.minHeight;
39652 if(this.maxHeight !== undefined){
39653 this.growMax = this.maxHeight;
39657 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39659 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39663 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39667 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39668 * in the field (equivalent to setting overflow: hidden, defaults to false)
39670 preventScrollbars: false,
39672 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39673 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39677 onRender : function(ct, position){
39679 this.defaultAutoCreate = {
39681 style:"width:300px;height:60px;",
39682 autocomplete: "new-password"
39685 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39687 this.textSizeEl = Roo.DomHelper.append(document.body, {
39688 tag: "pre", cls: "x-form-grow-sizer"
39690 if(this.preventScrollbars){
39691 this.el.setStyle("overflow", "hidden");
39693 this.el.setHeight(this.growMin);
39697 onDestroy : function(){
39698 if(this.textSizeEl){
39699 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39701 Roo.form.TextArea.superclass.onDestroy.call(this);
39705 onKeyUp : function(e){
39706 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39712 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39713 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39715 autoSize : function(){
39716 if(!this.grow || !this.textSizeEl){
39720 var v = el.dom.value;
39721 var ts = this.textSizeEl;
39724 ts.appendChild(document.createTextNode(v));
39727 Roo.fly(ts).setWidth(this.el.getWidth());
39729 v = "  ";
39732 v = v.replace(/\n/g, '<p> </p>');
39734 v += " \n ";
39737 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
39738 if(h != this.lastHeight){
39739 this.lastHeight = h;
39740 this.el.setHeight(h);
39741 this.fireEvent("autosize", this, h);
39746 * Ext JS Library 1.1.1
39747 * Copyright(c) 2006-2007, Ext JS, LLC.
39749 * Originally Released Under LGPL - original licence link has changed is not relivant.
39752 * <script type="text/javascript">
39757 * @class Roo.form.NumberField
39758 * @extends Roo.form.TextField
39759 * Numeric text field that provides automatic keystroke filtering and numeric validation.
39761 * Creates a new NumberField
39762 * @param {Object} config Configuration options
39764 Roo.form.NumberField = function(config){
39765 Roo.form.NumberField.superclass.constructor.call(this, config);
39768 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
39770 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
39772 fieldClass: "x-form-field x-form-num-field",
39774 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39776 allowDecimals : true,
39778 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39780 decimalSeparator : ".",
39782 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39784 decimalPrecision : 2,
39786 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39788 allowNegative : true,
39790 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39792 minValue : Number.NEGATIVE_INFINITY,
39794 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39796 maxValue : Number.MAX_VALUE,
39798 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39800 minText : "The minimum value for this field is {0}",
39802 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39804 maxText : "The maximum value for this field is {0}",
39806 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39807 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39809 nanText : "{0} is not a valid number",
39812 initEvents : function(){
39813 Roo.form.NumberField.superclass.initEvents.call(this);
39814 var allowed = "0123456789";
39815 if(this.allowDecimals){
39816 allowed += this.decimalSeparator;
39818 if(this.allowNegative){
39821 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
39822 var keyPress = function(e){
39823 var k = e.getKey();
39824 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39827 var c = e.getCharCode();
39828 if(allowed.indexOf(String.fromCharCode(c)) === -1){
39832 this.el.on("keypress", keyPress, this);
39836 validateValue : function(value){
39837 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
39840 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39843 var num = this.parseValue(value);
39845 this.markInvalid(String.format(this.nanText, value));
39848 if(num < this.minValue){
39849 this.markInvalid(String.format(this.minText, this.minValue));
39852 if(num > this.maxValue){
39853 this.markInvalid(String.format(this.maxText, this.maxValue));
39859 getValue : function(){
39860 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
39864 parseValue : function(value){
39865 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
39866 return isNaN(value) ? '' : value;
39870 fixPrecision : function(value){
39871 var nan = isNaN(value);
39872 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
39873 return nan ? '' : value;
39875 return parseFloat(value).toFixed(this.decimalPrecision);
39878 setValue : function(v){
39879 v = this.fixPrecision(v);
39880 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
39884 decimalPrecisionFcn : function(v){
39885 return Math.floor(v);
39888 beforeBlur : function(){
39889 var v = this.parseValue(this.getRawValue());
39896 * Ext JS Library 1.1.1
39897 * Copyright(c) 2006-2007, Ext JS, LLC.
39899 * Originally Released Under LGPL - original licence link has changed is not relivant.
39902 * <script type="text/javascript">
39906 * @class Roo.form.DateField
39907 * @extends Roo.form.TriggerField
39908 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
39910 * Create a new DateField
39911 * @param {Object} config
39913 Roo.form.DateField = function(config){
39914 Roo.form.DateField.superclass.constructor.call(this, config);
39920 * Fires when a date is selected
39921 * @param {Roo.form.DateField} combo This combo box
39922 * @param {Date} date The date selected
39929 if(typeof this.minValue == "string") {
39930 this.minValue = this.parseDate(this.minValue);
39932 if(typeof this.maxValue == "string") {
39933 this.maxValue = this.parseDate(this.maxValue);
39935 this.ddMatch = null;
39936 if(this.disabledDates){
39937 var dd = this.disabledDates;
39939 for(var i = 0; i < dd.length; i++){
39941 if(i != dd.length-1) {
39945 this.ddMatch = new RegExp(re + ")");
39949 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
39951 * @cfg {String} format
39952 * The default date format string which can be overriden for localization support. The format must be
39953 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
39957 * @cfg {String} altFormats
39958 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
39959 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
39961 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
39963 * @cfg {Array} disabledDays
39964 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
39966 disabledDays : null,
39968 * @cfg {String} disabledDaysText
39969 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
39971 disabledDaysText : "Disabled",
39973 * @cfg {Array} disabledDates
39974 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
39975 * expression so they are very powerful. Some examples:
39977 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
39978 * <li>["03/08", "09/16"] would disable those days for every year</li>
39979 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
39980 * <li>["03/../2006"] would disable every day in March 2006</li>
39981 * <li>["^03"] would disable every day in every March</li>
39983 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
39984 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
39986 disabledDates : null,
39988 * @cfg {String} disabledDatesText
39989 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
39991 disabledDatesText : "Disabled",
39993 * @cfg {Date/String} minValue
39994 * The minimum allowed date. Can be either a Javascript date object or a string date in a
39995 * valid format (defaults to null).
39999 * @cfg {Date/String} maxValue
40000 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40001 * valid format (defaults to null).
40005 * @cfg {String} minText
40006 * The error text to display when the date in the cell is before minValue (defaults to
40007 * 'The date in this field must be after {minValue}').
40009 minText : "The date in this field must be equal to or after {0}",
40011 * @cfg {String} maxText
40012 * The error text to display when the date in the cell is after maxValue (defaults to
40013 * 'The date in this field must be before {maxValue}').
40015 maxText : "The date in this field must be equal to or before {0}",
40017 * @cfg {String} invalidText
40018 * The error text to display when the date in the field is invalid (defaults to
40019 * '{value} is not a valid date - it must be in the format {format}').
40021 invalidText : "{0} is not a valid date - it must be in the format {1}",
40023 * @cfg {String} triggerClass
40024 * An additional CSS class used to style the trigger button. The trigger will always get the
40025 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40026 * which displays a calendar icon).
40028 triggerClass : 'x-form-date-trigger',
40032 * @cfg {Boolean} useIso
40033 * if enabled, then the date field will use a hidden field to store the
40034 * real value as iso formated date. default (false)
40038 * @cfg {String/Object} autoCreate
40039 * A DomHelper element spec, or true for a default element spec (defaults to
40040 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40043 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40046 hiddenField: false,
40048 onRender : function(ct, position)
40050 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40052 //this.el.dom.removeAttribute('name');
40053 Roo.log("Changing name?");
40054 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40055 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40057 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40058 // prevent input submission
40059 this.hiddenName = this.name;
40066 validateValue : function(value)
40068 value = this.formatDate(value);
40069 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40070 Roo.log('super failed');
40073 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40076 var svalue = value;
40077 value = this.parseDate(value);
40079 Roo.log('parse date failed' + svalue);
40080 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40083 var time = value.getTime();
40084 if(this.minValue && time < this.minValue.getTime()){
40085 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40088 if(this.maxValue && time > this.maxValue.getTime()){
40089 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40092 if(this.disabledDays){
40093 var day = value.getDay();
40094 for(var i = 0; i < this.disabledDays.length; i++) {
40095 if(day === this.disabledDays[i]){
40096 this.markInvalid(this.disabledDaysText);
40101 var fvalue = this.formatDate(value);
40102 if(this.ddMatch && this.ddMatch.test(fvalue)){
40103 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40110 // Provides logic to override the default TriggerField.validateBlur which just returns true
40111 validateBlur : function(){
40112 return !this.menu || !this.menu.isVisible();
40115 getName: function()
40117 // returns hidden if it's set..
40118 if (!this.rendered) {return ''};
40119 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40124 * Returns the current date value of the date field.
40125 * @return {Date} The date value
40127 getValue : function(){
40129 return this.hiddenField ?
40130 this.hiddenField.value :
40131 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40135 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40136 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40137 * (the default format used is "m/d/y").
40140 //All of these calls set the same date value (May 4, 2006)
40142 //Pass a date object:
40143 var dt = new Date('5/4/06');
40144 dateField.setValue(dt);
40146 //Pass a date string (default format):
40147 dateField.setValue('5/4/06');
40149 //Pass a date string (custom format):
40150 dateField.format = 'Y-m-d';
40151 dateField.setValue('2006-5-4');
40153 * @param {String/Date} date The date or valid date string
40155 setValue : function(date){
40156 if (this.hiddenField) {
40157 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40159 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40160 // make sure the value field is always stored as a date..
40161 this.value = this.parseDate(date);
40167 parseDate : function(value){
40168 if(!value || value instanceof Date){
40171 var v = Date.parseDate(value, this.format);
40172 if (!v && this.useIso) {
40173 v = Date.parseDate(value, 'Y-m-d');
40175 if(!v && this.altFormats){
40176 if(!this.altFormatsArray){
40177 this.altFormatsArray = this.altFormats.split("|");
40179 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40180 v = Date.parseDate(value, this.altFormatsArray[i]);
40187 formatDate : function(date, fmt){
40188 return (!date || !(date instanceof Date)) ?
40189 date : date.dateFormat(fmt || this.format);
40194 select: function(m, d){
40197 this.fireEvent('select', this, d);
40199 show : function(){ // retain focus styling
40203 this.focus.defer(10, this);
40204 var ml = this.menuListeners;
40205 this.menu.un("select", ml.select, this);
40206 this.menu.un("show", ml.show, this);
40207 this.menu.un("hide", ml.hide, this);
40212 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40213 onTriggerClick : function(){
40217 if(this.menu == null){
40218 this.menu = new Roo.menu.DateMenu();
40220 Roo.apply(this.menu.picker, {
40221 showClear: this.allowBlank,
40222 minDate : this.minValue,
40223 maxDate : this.maxValue,
40224 disabledDatesRE : this.ddMatch,
40225 disabledDatesText : this.disabledDatesText,
40226 disabledDays : this.disabledDays,
40227 disabledDaysText : this.disabledDaysText,
40228 format : this.useIso ? 'Y-m-d' : this.format,
40229 minText : String.format(this.minText, this.formatDate(this.minValue)),
40230 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40232 this.menu.on(Roo.apply({}, this.menuListeners, {
40235 this.menu.picker.setValue(this.getValue() || new Date());
40236 this.menu.show(this.el, "tl-bl?");
40239 beforeBlur : function(){
40240 var v = this.parseDate(this.getRawValue());
40250 isDirty : function() {
40251 if(this.disabled) {
40255 if(typeof(this.startValue) === 'undefined'){
40259 return String(this.getValue()) !== String(this.startValue);
40264 * Ext JS Library 1.1.1
40265 * Copyright(c) 2006-2007, Ext JS, LLC.
40267 * Originally Released Under LGPL - original licence link has changed is not relivant.
40270 * <script type="text/javascript">
40274 * @class Roo.form.MonthField
40275 * @extends Roo.form.TriggerField
40276 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40278 * Create a new MonthField
40279 * @param {Object} config
40281 Roo.form.MonthField = function(config){
40283 Roo.form.MonthField.superclass.constructor.call(this, config);
40289 * Fires when a date is selected
40290 * @param {Roo.form.MonthFieeld} combo This combo box
40291 * @param {Date} date The date selected
40298 if(typeof this.minValue == "string") {
40299 this.minValue = this.parseDate(this.minValue);
40301 if(typeof this.maxValue == "string") {
40302 this.maxValue = this.parseDate(this.maxValue);
40304 this.ddMatch = null;
40305 if(this.disabledDates){
40306 var dd = this.disabledDates;
40308 for(var i = 0; i < dd.length; i++){
40310 if(i != dd.length-1) {
40314 this.ddMatch = new RegExp(re + ")");
40318 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40320 * @cfg {String} format
40321 * The default date format string which can be overriden for localization support. The format must be
40322 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40326 * @cfg {String} altFormats
40327 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40328 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40330 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40332 * @cfg {Array} disabledDays
40333 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40335 disabledDays : [0,1,2,3,4,5,6],
40337 * @cfg {String} disabledDaysText
40338 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40340 disabledDaysText : "Disabled",
40342 * @cfg {Array} disabledDates
40343 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40344 * expression so they are very powerful. Some examples:
40346 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40347 * <li>["03/08", "09/16"] would disable those days for every year</li>
40348 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40349 * <li>["03/../2006"] would disable every day in March 2006</li>
40350 * <li>["^03"] would disable every day in every March</li>
40352 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40353 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40355 disabledDates : null,
40357 * @cfg {String} disabledDatesText
40358 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40360 disabledDatesText : "Disabled",
40362 * @cfg {Date/String} minValue
40363 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40364 * valid format (defaults to null).
40368 * @cfg {Date/String} maxValue
40369 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40370 * valid format (defaults to null).
40374 * @cfg {String} minText
40375 * The error text to display when the date in the cell is before minValue (defaults to
40376 * 'The date in this field must be after {minValue}').
40378 minText : "The date in this field must be equal to or after {0}",
40380 * @cfg {String} maxTextf
40381 * The error text to display when the date in the cell is after maxValue (defaults to
40382 * 'The date in this field must be before {maxValue}').
40384 maxText : "The date in this field must be equal to or before {0}",
40386 * @cfg {String} invalidText
40387 * The error text to display when the date in the field is invalid (defaults to
40388 * '{value} is not a valid date - it must be in the format {format}').
40390 invalidText : "{0} is not a valid date - it must be in the format {1}",
40392 * @cfg {String} triggerClass
40393 * An additional CSS class used to style the trigger button. The trigger will always get the
40394 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40395 * which displays a calendar icon).
40397 triggerClass : 'x-form-date-trigger',
40401 * @cfg {Boolean} useIso
40402 * if enabled, then the date field will use a hidden field to store the
40403 * real value as iso formated date. default (true)
40407 * @cfg {String/Object} autoCreate
40408 * A DomHelper element spec, or true for a default element spec (defaults to
40409 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40412 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40415 hiddenField: false,
40417 hideMonthPicker : false,
40419 onRender : function(ct, position)
40421 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40423 this.el.dom.removeAttribute('name');
40424 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40426 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40427 // prevent input submission
40428 this.hiddenName = this.name;
40435 validateValue : function(value)
40437 value = this.formatDate(value);
40438 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40441 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40444 var svalue = value;
40445 value = this.parseDate(value);
40447 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40450 var time = value.getTime();
40451 if(this.minValue && time < this.minValue.getTime()){
40452 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40455 if(this.maxValue && time > this.maxValue.getTime()){
40456 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40459 /*if(this.disabledDays){
40460 var day = value.getDay();
40461 for(var i = 0; i < this.disabledDays.length; i++) {
40462 if(day === this.disabledDays[i]){
40463 this.markInvalid(this.disabledDaysText);
40469 var fvalue = this.formatDate(value);
40470 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40471 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40479 // Provides logic to override the default TriggerField.validateBlur which just returns true
40480 validateBlur : function(){
40481 return !this.menu || !this.menu.isVisible();
40485 * Returns the current date value of the date field.
40486 * @return {Date} The date value
40488 getValue : function(){
40492 return this.hiddenField ?
40493 this.hiddenField.value :
40494 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40498 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40499 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40500 * (the default format used is "m/d/y").
40503 //All of these calls set the same date value (May 4, 2006)
40505 //Pass a date object:
40506 var dt = new Date('5/4/06');
40507 monthField.setValue(dt);
40509 //Pass a date string (default format):
40510 monthField.setValue('5/4/06');
40512 //Pass a date string (custom format):
40513 monthField.format = 'Y-m-d';
40514 monthField.setValue('2006-5-4');
40516 * @param {String/Date} date The date or valid date string
40518 setValue : function(date){
40519 Roo.log('month setValue' + date);
40520 // can only be first of month..
40522 var val = this.parseDate(date);
40524 if (this.hiddenField) {
40525 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40527 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40528 this.value = this.parseDate(date);
40532 parseDate : function(value){
40533 if(!value || value instanceof Date){
40534 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40537 var v = Date.parseDate(value, this.format);
40538 if (!v && this.useIso) {
40539 v = Date.parseDate(value, 'Y-m-d');
40543 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40547 if(!v && this.altFormats){
40548 if(!this.altFormatsArray){
40549 this.altFormatsArray = this.altFormats.split("|");
40551 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40552 v = Date.parseDate(value, this.altFormatsArray[i]);
40559 formatDate : function(date, fmt){
40560 return (!date || !(date instanceof Date)) ?
40561 date : date.dateFormat(fmt || this.format);
40566 select: function(m, d){
40568 this.fireEvent('select', this, d);
40570 show : function(){ // retain focus styling
40574 this.focus.defer(10, this);
40575 var ml = this.menuListeners;
40576 this.menu.un("select", ml.select, this);
40577 this.menu.un("show", ml.show, this);
40578 this.menu.un("hide", ml.hide, this);
40582 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40583 onTriggerClick : function(){
40587 if(this.menu == null){
40588 this.menu = new Roo.menu.DateMenu();
40592 Roo.apply(this.menu.picker, {
40594 showClear: this.allowBlank,
40595 minDate : this.minValue,
40596 maxDate : this.maxValue,
40597 disabledDatesRE : this.ddMatch,
40598 disabledDatesText : this.disabledDatesText,
40600 format : this.useIso ? 'Y-m-d' : this.format,
40601 minText : String.format(this.minText, this.formatDate(this.minValue)),
40602 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40605 this.menu.on(Roo.apply({}, this.menuListeners, {
40613 // hide month picker get's called when we called by 'before hide';
40615 var ignorehide = true;
40616 p.hideMonthPicker = function(disableAnim){
40620 if(this.monthPicker){
40621 Roo.log("hideMonthPicker called");
40622 if(disableAnim === true){
40623 this.monthPicker.hide();
40625 this.monthPicker.slideOut('t', {duration:.2});
40626 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40627 p.fireEvent("select", this, this.value);
40633 Roo.log('picker set value');
40634 Roo.log(this.getValue());
40635 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40636 m.show(this.el, 'tl-bl?');
40637 ignorehide = false;
40638 // this will trigger hideMonthPicker..
40641 // hidden the day picker
40642 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40648 p.showMonthPicker.defer(100, p);
40654 beforeBlur : function(){
40655 var v = this.parseDate(this.getRawValue());
40661 /** @cfg {Boolean} grow @hide */
40662 /** @cfg {Number} growMin @hide */
40663 /** @cfg {Number} growMax @hide */
40670 * Ext JS Library 1.1.1
40671 * Copyright(c) 2006-2007, Ext JS, LLC.
40673 * Originally Released Under LGPL - original licence link has changed is not relivant.
40676 * <script type="text/javascript">
40681 * @class Roo.form.ComboBox
40682 * @extends Roo.form.TriggerField
40683 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40685 * Create a new ComboBox.
40686 * @param {Object} config Configuration options
40688 Roo.form.ComboBox = function(config){
40689 Roo.form.ComboBox.superclass.constructor.call(this, config);
40693 * Fires when the dropdown list is expanded
40694 * @param {Roo.form.ComboBox} combo This combo box
40699 * Fires when the dropdown list is collapsed
40700 * @param {Roo.form.ComboBox} combo This combo box
40704 * @event beforeselect
40705 * Fires before a list item is selected. Return false to cancel the selection.
40706 * @param {Roo.form.ComboBox} combo This combo box
40707 * @param {Roo.data.Record} record The data record returned from the underlying store
40708 * @param {Number} index The index of the selected item in the dropdown list
40710 'beforeselect' : true,
40713 * Fires when a list item is selected
40714 * @param {Roo.form.ComboBox} combo This combo box
40715 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
40716 * @param {Number} index The index of the selected item in the dropdown list
40720 * @event beforequery
40721 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
40722 * The event object passed has these properties:
40723 * @param {Roo.form.ComboBox} combo This combo box
40724 * @param {String} query The query
40725 * @param {Boolean} forceAll true to force "all" query
40726 * @param {Boolean} cancel true to cancel the query
40727 * @param {Object} e The query event object
40729 'beforequery': true,
40732 * Fires when the 'add' icon is pressed (add a listener to enable add button)
40733 * @param {Roo.form.ComboBox} combo This combo box
40738 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
40739 * @param {Roo.form.ComboBox} combo This combo box
40740 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
40746 if(this.transform){
40747 this.allowDomMove = false;
40748 var s = Roo.getDom(this.transform);
40749 if(!this.hiddenName){
40750 this.hiddenName = s.name;
40753 this.mode = 'local';
40754 var d = [], opts = s.options;
40755 for(var i = 0, len = opts.length;i < len; i++){
40757 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
40759 this.value = value;
40761 d.push([value, o.text]);
40763 this.store = new Roo.data.SimpleStore({
40765 fields: ['value', 'text'],
40768 this.valueField = 'value';
40769 this.displayField = 'text';
40771 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
40772 if(!this.lazyRender){
40773 this.target = true;
40774 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
40775 s.parentNode.removeChild(s); // remove it
40776 this.render(this.el.parentNode);
40778 s.parentNode.removeChild(s); // remove it
40783 this.store = Roo.factory(this.store, Roo.data);
40786 this.selectedIndex = -1;
40787 if(this.mode == 'local'){
40788 if(config.queryDelay === undefined){
40789 this.queryDelay = 10;
40791 if(config.minChars === undefined){
40797 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
40799 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
40802 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
40803 * rendering into an Roo.Editor, defaults to false)
40806 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
40807 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
40810 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
40813 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
40814 * the dropdown list (defaults to undefined, with no header element)
40818 * @cfg {String/Roo.Template} tpl The template to use to render the output
40822 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
40824 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
40826 listWidth: undefined,
40828 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
40829 * mode = 'remote' or 'text' if mode = 'local')
40831 displayField: undefined,
40833 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
40834 * mode = 'remote' or 'value' if mode = 'local').
40835 * Note: use of a valueField requires the user make a selection
40836 * in order for a value to be mapped.
40838 valueField: undefined,
40842 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
40843 * field's data value (defaults to the underlying DOM element's name)
40845 hiddenName: undefined,
40847 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
40851 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
40853 selectedClass: 'x-combo-selected',
40855 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40856 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
40857 * which displays a downward arrow icon).
40859 triggerClass : 'x-form-arrow-trigger',
40861 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
40865 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
40866 * anchor positions (defaults to 'tl-bl')
40868 listAlign: 'tl-bl?',
40870 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
40874 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
40875 * query specified by the allQuery config option (defaults to 'query')
40877 triggerAction: 'query',
40879 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
40880 * (defaults to 4, does not apply if editable = false)
40884 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
40885 * delay (typeAheadDelay) if it matches a known value (defaults to false)
40889 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
40890 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
40894 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
40895 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
40899 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
40900 * when editable = true (defaults to false)
40902 selectOnFocus:false,
40904 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
40906 queryParam: 'query',
40908 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
40909 * when mode = 'remote' (defaults to 'Loading...')
40911 loadingText: 'Loading...',
40913 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
40917 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
40921 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
40922 * traditional select (defaults to true)
40926 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
40930 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
40934 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
40935 * listWidth has a higher value)
40939 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
40940 * allow the user to set arbitrary text into the field (defaults to false)
40942 forceSelection:false,
40944 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
40945 * if typeAhead = true (defaults to 250)
40947 typeAheadDelay : 250,
40949 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
40950 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
40952 valueNotFoundText : undefined,
40954 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
40956 blockFocus : false,
40959 * @cfg {Boolean} disableClear Disable showing of clear button.
40961 disableClear : false,
40963 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
40965 alwaysQuery : false,
40971 // element that contains real text value.. (when hidden is used..)
40974 onRender : function(ct, position){
40975 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
40976 if(this.hiddenName){
40977 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
40979 this.hiddenField.value =
40980 this.hiddenValue !== undefined ? this.hiddenValue :
40981 this.value !== undefined ? this.value : '';
40983 // prevent input submission
40984 this.el.dom.removeAttribute('name');
40989 this.el.dom.setAttribute('autocomplete', 'off');
40992 var cls = 'x-combo-list';
40994 this.list = new Roo.Layer({
40995 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
40998 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
40999 this.list.setWidth(lw);
41000 this.list.swallowEvent('mousewheel');
41001 this.assetHeight = 0;
41004 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41005 this.assetHeight += this.header.getHeight();
41008 this.innerList = this.list.createChild({cls:cls+'-inner'});
41009 this.innerList.on('mouseover', this.onViewOver, this);
41010 this.innerList.on('mousemove', this.onViewMove, this);
41011 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41013 if(this.allowBlank && !this.pageSize && !this.disableClear){
41014 this.footer = this.list.createChild({cls:cls+'-ft'});
41015 this.pageTb = new Roo.Toolbar(this.footer);
41019 this.footer = this.list.createChild({cls:cls+'-ft'});
41020 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41021 {pageSize: this.pageSize});
41025 if (this.pageTb && this.allowBlank && !this.disableClear) {
41027 this.pageTb.add(new Roo.Toolbar.Fill(), {
41028 cls: 'x-btn-icon x-btn-clear',
41030 handler: function()
41033 _this.clearValue();
41034 _this.onSelect(false, -1);
41039 this.assetHeight += this.footer.getHeight();
41044 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41047 this.view = new Roo.View(this.innerList, this.tpl, {
41048 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41051 this.view.on('click', this.onViewClick, this);
41053 this.store.on('beforeload', this.onBeforeLoad, this);
41054 this.store.on('load', this.onLoad, this);
41055 this.store.on('loadexception', this.onLoadException, this);
41057 if(this.resizable){
41058 this.resizer = new Roo.Resizable(this.list, {
41059 pinned:true, handles:'se'
41061 this.resizer.on('resize', function(r, w, h){
41062 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41063 this.listWidth = w;
41064 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41065 this.restrictHeight();
41067 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41069 if(!this.editable){
41070 this.editable = true;
41071 this.setEditable(false);
41075 if (typeof(this.events.add.listeners) != 'undefined') {
41077 this.addicon = this.wrap.createChild(
41078 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41080 this.addicon.on('click', function(e) {
41081 this.fireEvent('add', this);
41084 if (typeof(this.events.edit.listeners) != 'undefined') {
41086 this.editicon = this.wrap.createChild(
41087 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41088 if (this.addicon) {
41089 this.editicon.setStyle('margin-left', '40px');
41091 this.editicon.on('click', function(e) {
41093 // we fire even if inothing is selected..
41094 this.fireEvent('edit', this, this.lastData );
41104 initEvents : function(){
41105 Roo.form.ComboBox.superclass.initEvents.call(this);
41107 this.keyNav = new Roo.KeyNav(this.el, {
41108 "up" : function(e){
41109 this.inKeyMode = true;
41113 "down" : function(e){
41114 if(!this.isExpanded()){
41115 this.onTriggerClick();
41117 this.inKeyMode = true;
41122 "enter" : function(e){
41123 this.onViewClick();
41127 "esc" : function(e){
41131 "tab" : function(e){
41132 this.onViewClick(false);
41133 this.fireEvent("specialkey", this, e);
41139 doRelay : function(foo, bar, hname){
41140 if(hname == 'down' || this.scope.isExpanded()){
41141 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41148 this.queryDelay = Math.max(this.queryDelay || 10,
41149 this.mode == 'local' ? 10 : 250);
41150 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41151 if(this.typeAhead){
41152 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41154 if(this.editable !== false){
41155 this.el.on("keyup", this.onKeyUp, this);
41157 if(this.forceSelection){
41158 this.on('blur', this.doForce, this);
41162 onDestroy : function(){
41164 this.view.setStore(null);
41165 this.view.el.removeAllListeners();
41166 this.view.el.remove();
41167 this.view.purgeListeners();
41170 this.list.destroy();
41173 this.store.un('beforeload', this.onBeforeLoad, this);
41174 this.store.un('load', this.onLoad, this);
41175 this.store.un('loadexception', this.onLoadException, this);
41177 Roo.form.ComboBox.superclass.onDestroy.call(this);
41181 fireKey : function(e){
41182 if(e.isNavKeyPress() && !this.list.isVisible()){
41183 this.fireEvent("specialkey", this, e);
41188 onResize: function(w, h){
41189 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41191 if(typeof w != 'number'){
41192 // we do not handle it!?!?
41195 var tw = this.trigger.getWidth();
41196 tw += this.addicon ? this.addicon.getWidth() : 0;
41197 tw += this.editicon ? this.editicon.getWidth() : 0;
41199 this.el.setWidth( this.adjustWidth('input', x));
41201 this.trigger.setStyle('left', x+'px');
41203 if(this.list && this.listWidth === undefined){
41204 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41205 this.list.setWidth(lw);
41206 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41214 * Allow or prevent the user from directly editing the field text. If false is passed,
41215 * the user will only be able to select from the items defined in the dropdown list. This method
41216 * is the runtime equivalent of setting the 'editable' config option at config time.
41217 * @param {Boolean} value True to allow the user to directly edit the field text
41219 setEditable : function(value){
41220 if(value == this.editable){
41223 this.editable = value;
41225 this.el.dom.setAttribute('readOnly', true);
41226 this.el.on('mousedown', this.onTriggerClick, this);
41227 this.el.addClass('x-combo-noedit');
41229 this.el.dom.setAttribute('readOnly', false);
41230 this.el.un('mousedown', this.onTriggerClick, this);
41231 this.el.removeClass('x-combo-noedit');
41236 onBeforeLoad : function(){
41237 if(!this.hasFocus){
41240 this.innerList.update(this.loadingText ?
41241 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41242 this.restrictHeight();
41243 this.selectedIndex = -1;
41247 onLoad : function(){
41248 if(!this.hasFocus){
41251 if(this.store.getCount() > 0){
41253 this.restrictHeight();
41254 if(this.lastQuery == this.allQuery){
41256 this.el.dom.select();
41258 if(!this.selectByValue(this.value, true)){
41259 this.select(0, true);
41263 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41264 this.taTask.delay(this.typeAheadDelay);
41268 this.onEmptyResults();
41273 onLoadException : function()
41276 Roo.log(this.store.reader.jsonData);
41277 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41278 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41284 onTypeAhead : function(){
41285 if(this.store.getCount() > 0){
41286 var r = this.store.getAt(0);
41287 var newValue = r.data[this.displayField];
41288 var len = newValue.length;
41289 var selStart = this.getRawValue().length;
41290 if(selStart != len){
41291 this.setRawValue(newValue);
41292 this.selectText(selStart, newValue.length);
41298 onSelect : function(record, index){
41299 if(this.fireEvent('beforeselect', this, record, index) !== false){
41300 this.setFromData(index > -1 ? record.data : false);
41302 this.fireEvent('select', this, record, index);
41307 * Returns the currently selected field value or empty string if no value is set.
41308 * @return {String} value The selected value
41310 getValue : function(){
41311 if(this.valueField){
41312 return typeof this.value != 'undefined' ? this.value : '';
41314 return Roo.form.ComboBox.superclass.getValue.call(this);
41318 * Clears any text/value currently set in the field
41320 clearValue : function(){
41321 if(this.hiddenField){
41322 this.hiddenField.value = '';
41325 this.setRawValue('');
41326 this.lastSelectionText = '';
41331 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41332 * will be displayed in the field. If the value does not match the data value of an existing item,
41333 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41334 * Otherwise the field will be blank (although the value will still be set).
41335 * @param {String} value The value to match
41337 setValue : function(v){
41339 if(this.valueField){
41340 var r = this.findRecord(this.valueField, v);
41342 text = r.data[this.displayField];
41343 }else if(this.valueNotFoundText !== undefined){
41344 text = this.valueNotFoundText;
41347 this.lastSelectionText = text;
41348 if(this.hiddenField){
41349 this.hiddenField.value = v;
41351 Roo.form.ComboBox.superclass.setValue.call(this, text);
41355 * @property {Object} the last set data for the element
41360 * Sets the value of the field based on a object which is related to the record format for the store.
41361 * @param {Object} value the value to set as. or false on reset?
41363 setFromData : function(o){
41364 var dv = ''; // display value
41365 var vv = ''; // value value..
41367 if (this.displayField) {
41368 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41370 // this is an error condition!!!
41371 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41374 if(this.valueField){
41375 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41377 if(this.hiddenField){
41378 this.hiddenField.value = vv;
41380 this.lastSelectionText = dv;
41381 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41385 // no hidden field.. - we store the value in 'value', but still display
41386 // display field!!!!
41387 this.lastSelectionText = dv;
41388 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41394 reset : function(){
41395 // overridden so that last data is reset..
41396 this.setValue(this.resetValue);
41397 this.clearInvalid();
41398 this.lastData = false;
41400 this.view.clearSelections();
41404 findRecord : function(prop, value){
41406 if(this.store.getCount() > 0){
41407 this.store.each(function(r){
41408 if(r.data[prop] == value){
41418 getName: function()
41420 // returns hidden if it's set..
41421 if (!this.rendered) {return ''};
41422 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41426 onViewMove : function(e, t){
41427 this.inKeyMode = false;
41431 onViewOver : function(e, t){
41432 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41435 var item = this.view.findItemFromChild(t);
41437 var index = this.view.indexOf(item);
41438 this.select(index, false);
41443 onViewClick : function(doFocus)
41445 var index = this.view.getSelectedIndexes()[0];
41446 var r = this.store.getAt(index);
41448 this.onSelect(r, index);
41450 if(doFocus !== false && !this.blockFocus){
41456 restrictHeight : function(){
41457 this.innerList.dom.style.height = '';
41458 var inner = this.innerList.dom;
41459 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41460 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41461 this.list.beginUpdate();
41462 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41463 this.list.alignTo(this.el, this.listAlign);
41464 this.list.endUpdate();
41468 onEmptyResults : function(){
41473 * Returns true if the dropdown list is expanded, else false.
41475 isExpanded : function(){
41476 return this.list.isVisible();
41480 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41481 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41482 * @param {String} value The data value of the item to select
41483 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41484 * selected item if it is not currently in view (defaults to true)
41485 * @return {Boolean} True if the value matched an item in the list, else false
41487 selectByValue : function(v, scrollIntoView){
41488 if(v !== undefined && v !== null){
41489 var r = this.findRecord(this.valueField || this.displayField, v);
41491 this.select(this.store.indexOf(r), scrollIntoView);
41499 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41500 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41501 * @param {Number} index The zero-based index of the list item to select
41502 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41503 * selected item if it is not currently in view (defaults to true)
41505 select : function(index, scrollIntoView){
41506 this.selectedIndex = index;
41507 this.view.select(index);
41508 if(scrollIntoView !== false){
41509 var el = this.view.getNode(index);
41511 this.innerList.scrollChildIntoView(el, false);
41517 selectNext : function(){
41518 var ct = this.store.getCount();
41520 if(this.selectedIndex == -1){
41522 }else if(this.selectedIndex < ct-1){
41523 this.select(this.selectedIndex+1);
41529 selectPrev : function(){
41530 var ct = this.store.getCount();
41532 if(this.selectedIndex == -1){
41534 }else if(this.selectedIndex != 0){
41535 this.select(this.selectedIndex-1);
41541 onKeyUp : function(e){
41542 if(this.editable !== false && !e.isSpecialKey()){
41543 this.lastKey = e.getKey();
41544 this.dqTask.delay(this.queryDelay);
41549 validateBlur : function(){
41550 return !this.list || !this.list.isVisible();
41554 initQuery : function(){
41555 this.doQuery(this.getRawValue());
41559 doForce : function(){
41560 if(this.el.dom.value.length > 0){
41561 this.el.dom.value =
41562 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41568 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41569 * query allowing the query action to be canceled if needed.
41570 * @param {String} query The SQL query to execute
41571 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41572 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41573 * saved in the current store (defaults to false)
41575 doQuery : function(q, forceAll){
41576 if(q === undefined || q === null){
41581 forceAll: forceAll,
41585 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41589 forceAll = qe.forceAll;
41590 if(forceAll === true || (q.length >= this.minChars)){
41591 if(this.lastQuery != q || this.alwaysQuery){
41592 this.lastQuery = q;
41593 if(this.mode == 'local'){
41594 this.selectedIndex = -1;
41596 this.store.clearFilter();
41598 this.store.filter(this.displayField, q);
41602 this.store.baseParams[this.queryParam] = q;
41604 params: this.getParams(q)
41609 this.selectedIndex = -1;
41616 getParams : function(q){
41618 //p[this.queryParam] = q;
41621 p.limit = this.pageSize;
41627 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41629 collapse : function(){
41630 if(!this.isExpanded()){
41634 Roo.get(document).un('mousedown', this.collapseIf, this);
41635 Roo.get(document).un('mousewheel', this.collapseIf, this);
41636 if (!this.editable) {
41637 Roo.get(document).un('keydown', this.listKeyPress, this);
41639 this.fireEvent('collapse', this);
41643 collapseIf : function(e){
41644 if(!e.within(this.wrap) && !e.within(this.list)){
41650 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41652 expand : function(){
41653 if(this.isExpanded() || !this.hasFocus){
41656 this.list.alignTo(this.el, this.listAlign);
41658 Roo.get(document).on('mousedown', this.collapseIf, this);
41659 Roo.get(document).on('mousewheel', this.collapseIf, this);
41660 if (!this.editable) {
41661 Roo.get(document).on('keydown', this.listKeyPress, this);
41664 this.fireEvent('expand', this);
41668 // Implements the default empty TriggerField.onTriggerClick function
41669 onTriggerClick : function(){
41673 if(this.isExpanded()){
41675 if (!this.blockFocus) {
41680 this.hasFocus = true;
41681 if(this.triggerAction == 'all') {
41682 this.doQuery(this.allQuery, true);
41684 this.doQuery(this.getRawValue());
41686 if (!this.blockFocus) {
41691 listKeyPress : function(e)
41693 //Roo.log('listkeypress');
41694 // scroll to first matching element based on key pres..
41695 if (e.isSpecialKey()) {
41698 var k = String.fromCharCode(e.getKey()).toUpperCase();
41701 var csel = this.view.getSelectedNodes();
41702 var cselitem = false;
41704 var ix = this.view.indexOf(csel[0]);
41705 cselitem = this.store.getAt(ix);
41706 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41712 this.store.each(function(v) {
41714 // start at existing selection.
41715 if (cselitem.id == v.id) {
41721 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
41722 match = this.store.indexOf(v);
41727 if (match === false) {
41728 return true; // no more action?
41731 this.view.select(match);
41732 var sn = Roo.get(this.view.getSelectedNodes()[0]);
41733 sn.scrollIntoView(sn.dom.parentNode, false);
41737 * @cfg {Boolean} grow
41741 * @cfg {Number} growMin
41745 * @cfg {Number} growMax
41753 * Copyright(c) 2010-2012, Roo J Solutions Limited
41760 * @class Roo.form.ComboBoxArray
41761 * @extends Roo.form.TextField
41762 * A facebook style adder... for lists of email / people / countries etc...
41763 * pick multiple items from a combo box, and shows each one.
41765 * Fred [x] Brian [x] [Pick another |v]
41768 * For this to work: it needs various extra information
41769 * - normal combo problay has
41771 * + displayField, valueField
41773 * For our purpose...
41776 * If we change from 'extends' to wrapping...
41783 * Create a new ComboBoxArray.
41784 * @param {Object} config Configuration options
41788 Roo.form.ComboBoxArray = function(config)
41792 * @event beforeremove
41793 * Fires before remove the value from the list
41794 * @param {Roo.form.ComboBoxArray} _self This combo box array
41795 * @param {Roo.form.ComboBoxArray.Item} item removed item
41797 'beforeremove' : true,
41800 * Fires when remove the value from the list
41801 * @param {Roo.form.ComboBoxArray} _self This combo box array
41802 * @param {Roo.form.ComboBoxArray.Item} item removed item
41809 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
41811 this.items = new Roo.util.MixedCollection(false);
41813 // construct the child combo...
41823 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
41826 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
41831 // behavies liek a hiddne field
41832 inputType: 'hidden',
41834 * @cfg {Number} width The width of the box that displays the selected element
41841 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
41845 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
41847 hiddenName : false,
41850 // private the array of items that are displayed..
41852 // private - the hidden field el.
41854 // private - the filed el..
41857 //validateValue : function() { return true; }, // all values are ok!
41858 //onAddClick: function() { },
41860 onRender : function(ct, position)
41863 // create the standard hidden element
41864 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
41867 // give fake names to child combo;
41868 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
41869 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
41871 this.combo = Roo.factory(this.combo, Roo.form);
41872 this.combo.onRender(ct, position);
41873 if (typeof(this.combo.width) != 'undefined') {
41874 this.combo.onResize(this.combo.width,0);
41877 this.combo.initEvents();
41879 // assigned so form know we need to do this..
41880 this.store = this.combo.store;
41881 this.valueField = this.combo.valueField;
41882 this.displayField = this.combo.displayField ;
41885 this.combo.wrap.addClass('x-cbarray-grp');
41887 var cbwrap = this.combo.wrap.createChild(
41888 {tag: 'div', cls: 'x-cbarray-cb'},
41893 this.hiddenEl = this.combo.wrap.createChild({
41894 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
41896 this.el = this.combo.wrap.createChild({
41897 tag: 'input', type:'hidden' , name: this.name, value : ''
41899 // this.el.dom.removeAttribute("name");
41902 this.outerWrap = this.combo.wrap;
41903 this.wrap = cbwrap;
41905 this.outerWrap.setWidth(this.width);
41906 this.outerWrap.dom.removeChild(this.el.dom);
41908 this.wrap.dom.appendChild(this.el.dom);
41909 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
41910 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
41912 this.combo.trigger.setStyle('position','relative');
41913 this.combo.trigger.setStyle('left', '0px');
41914 this.combo.trigger.setStyle('top', '2px');
41916 this.combo.el.setStyle('vertical-align', 'text-bottom');
41918 //this.trigger.setStyle('vertical-align', 'top');
41920 // this should use the code from combo really... on('add' ....)
41924 this.adder = this.outerWrap.createChild(
41925 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
41927 this.adder.on('click', function(e) {
41928 _t.fireEvent('adderclick', this, e);
41932 //this.adder.on('click', this.onAddClick, _t);
41935 this.combo.on('select', function(cb, rec, ix) {
41936 this.addItem(rec.data);
41939 cb.el.dom.value = '';
41940 //cb.lastData = rec.data;
41949 getName: function()
41951 // returns hidden if it's set..
41952 if (!this.rendered) {return ''};
41953 return this.hiddenName ? this.hiddenName : this.name;
41958 onResize: function(w, h){
41961 // not sure if this is needed..
41962 //this.combo.onResize(w,h);
41964 if(typeof w != 'number'){
41965 // we do not handle it!?!?
41968 var tw = this.combo.trigger.getWidth();
41969 tw += this.addicon ? this.addicon.getWidth() : 0;
41970 tw += this.editicon ? this.editicon.getWidth() : 0;
41972 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
41974 this.combo.trigger.setStyle('left', '0px');
41976 if(this.list && this.listWidth === undefined){
41977 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
41978 this.list.setWidth(lw);
41979 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41986 addItem: function(rec)
41988 var valueField = this.combo.valueField;
41989 var displayField = this.combo.displayField;
41990 if (this.items.indexOfKey(rec[valueField]) > -1) {
41991 //console.log("GOT " + rec.data.id);
41995 var x = new Roo.form.ComboBoxArray.Item({
41996 //id : rec[this.idField],
41998 displayField : displayField ,
41999 tipField : displayField ,
42003 this.items.add(rec[valueField],x);
42004 // add it before the element..
42005 this.updateHiddenEl();
42006 x.render(this.outerWrap, this.wrap.dom);
42007 // add the image handler..
42010 updateHiddenEl : function()
42013 if (!this.hiddenEl) {
42017 var idField = this.combo.valueField;
42019 this.items.each(function(f) {
42020 ar.push(f.data[idField]);
42023 this.hiddenEl.dom.value = ar.join(',');
42029 this.items.clear();
42031 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42035 this.el.dom.value = '';
42036 if (this.hiddenEl) {
42037 this.hiddenEl.dom.value = '';
42041 getValue: function()
42043 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42045 setValue: function(v) // not a valid action - must use addItems..
42052 if (this.store.isLocal && (typeof(v) == 'string')) {
42053 // then we can use the store to find the values..
42054 // comma seperated at present.. this needs to allow JSON based encoding..
42055 this.hiddenEl.value = v;
42057 Roo.each(v.split(','), function(k) {
42058 Roo.log("CHECK " + this.valueField + ',' + k);
42059 var li = this.store.query(this.valueField, k);
42064 add[this.valueField] = k;
42065 add[this.displayField] = li.item(0).data[this.displayField];
42071 if (typeof(v) == 'object' ) {
42072 // then let's assume it's an array of objects..
42073 Roo.each(v, function(l) {
42081 setFromData: function(v)
42083 // this recieves an object, if setValues is called.
42085 this.el.dom.value = v[this.displayField];
42086 this.hiddenEl.dom.value = v[this.valueField];
42087 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42090 var kv = v[this.valueField];
42091 var dv = v[this.displayField];
42092 kv = typeof(kv) != 'string' ? '' : kv;
42093 dv = typeof(dv) != 'string' ? '' : dv;
42096 var keys = kv.split(',');
42097 var display = dv.split(',');
42098 for (var i = 0 ; i < keys.length; i++) {
42101 add[this.valueField] = keys[i];
42102 add[this.displayField] = display[i];
42110 * Validates the combox array value
42111 * @return {Boolean} True if the value is valid, else false
42113 validate : function(){
42114 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42115 this.clearInvalid();
42121 validateValue : function(value){
42122 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42130 isDirty : function() {
42131 if(this.disabled) {
42136 var d = Roo.decode(String(this.originalValue));
42138 return String(this.getValue()) !== String(this.originalValue);
42141 var originalValue = [];
42143 for (var i = 0; i < d.length; i++){
42144 originalValue.push(d[i][this.valueField]);
42147 return String(this.getValue()) !== String(originalValue.join(','));
42156 * @class Roo.form.ComboBoxArray.Item
42157 * @extends Roo.BoxComponent
42158 * A selected item in the list
42159 * Fred [x] Brian [x] [Pick another |v]
42162 * Create a new item.
42163 * @param {Object} config Configuration options
42166 Roo.form.ComboBoxArray.Item = function(config) {
42167 config.id = Roo.id();
42168 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42171 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42174 displayField : false,
42178 defaultAutoCreate : {
42180 cls: 'x-cbarray-item',
42187 src : Roo.BLANK_IMAGE_URL ,
42195 onRender : function(ct, position)
42197 Roo.form.Field.superclass.onRender.call(this, ct, position);
42200 var cfg = this.getAutoCreate();
42201 this.el = ct.createChild(cfg, position);
42204 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42206 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42207 this.cb.renderer(this.data) :
42208 String.format('{0}',this.data[this.displayField]);
42211 this.el.child('div').dom.setAttribute('qtip',
42212 String.format('{0}',this.data[this.tipField])
42215 this.el.child('img').on('click', this.remove, this);
42219 remove : function()
42221 if(this.cb.disabled){
42225 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42226 this.cb.items.remove(this);
42227 this.el.child('img').un('click', this.remove, this);
42229 this.cb.updateHiddenEl();
42231 this.cb.fireEvent('remove', this.cb, this);
42237 * Ext JS Library 1.1.1
42238 * Copyright(c) 2006-2007, Ext JS, LLC.
42240 * Originally Released Under LGPL - original licence link has changed is not relivant.
42243 * <script type="text/javascript">
42246 * @class Roo.form.Checkbox
42247 * @extends Roo.form.Field
42248 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42250 * Creates a new Checkbox
42251 * @param {Object} config Configuration options
42253 Roo.form.Checkbox = function(config){
42254 Roo.form.Checkbox.superclass.constructor.call(this, config);
42258 * Fires when the checkbox is checked or unchecked.
42259 * @param {Roo.form.Checkbox} this This checkbox
42260 * @param {Boolean} checked The new checked value
42266 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42268 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42270 focusClass : undefined,
42272 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42274 fieldClass: "x-form-field",
42276 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42280 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42281 * {tag: "input", type: "checkbox", autocomplete: "off"})
42283 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42285 * @cfg {String} boxLabel The text that appears beside the checkbox
42289 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42293 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42295 valueOff: '0', // value when not checked..
42297 actionMode : 'viewEl',
42300 itemCls : 'x-menu-check-item x-form-item',
42301 groupClass : 'x-menu-group-item',
42302 inputType : 'hidden',
42305 inSetChecked: false, // check that we are not calling self...
42307 inputElement: false, // real input element?
42308 basedOn: false, // ????
42310 isFormField: true, // not sure where this is needed!!!!
42312 onResize : function(){
42313 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42314 if(!this.boxLabel){
42315 this.el.alignTo(this.wrap, 'c-c');
42319 initEvents : function(){
42320 Roo.form.Checkbox.superclass.initEvents.call(this);
42321 this.el.on("click", this.onClick, this);
42322 this.el.on("change", this.onClick, this);
42326 getResizeEl : function(){
42330 getPositionEl : function(){
42335 onRender : function(ct, position){
42336 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42338 if(this.inputValue !== undefined){
42339 this.el.dom.value = this.inputValue;
42342 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42343 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42344 var viewEl = this.wrap.createChild({
42345 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42346 this.viewEl = viewEl;
42347 this.wrap.on('click', this.onClick, this);
42349 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42350 this.el.on('propertychange', this.setFromHidden, this); //ie
42355 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42356 // viewEl.on('click', this.onClick, this);
42358 //if(this.checked){
42359 this.setChecked(this.checked);
42361 //this.checked = this.el.dom;
42367 initValue : Roo.emptyFn,
42370 * Returns the checked state of the checkbox.
42371 * @return {Boolean} True if checked, else false
42373 getValue : function(){
42375 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42377 return this.valueOff;
42382 onClick : function(){
42383 if (this.disabled) {
42386 this.setChecked(!this.checked);
42388 //if(this.el.dom.checked != this.checked){
42389 // this.setValue(this.el.dom.checked);
42394 * Sets the checked state of the checkbox.
42395 * On is always based on a string comparison between inputValue and the param.
42396 * @param {Boolean/String} value - the value to set
42397 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42399 setValue : function(v,suppressEvent){
42402 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42403 //if(this.el && this.el.dom){
42404 // this.el.dom.checked = this.checked;
42405 // this.el.dom.defaultChecked = this.checked;
42407 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42408 //this.fireEvent("check", this, this.checked);
42411 setChecked : function(state,suppressEvent)
42413 if (this.inSetChecked) {
42414 this.checked = state;
42420 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42422 this.checked = state;
42423 if(suppressEvent !== true){
42424 this.fireEvent('check', this, state);
42426 this.inSetChecked = true;
42427 this.el.dom.value = state ? this.inputValue : this.valueOff;
42428 this.inSetChecked = false;
42431 // handle setting of hidden value by some other method!!?!?
42432 setFromHidden: function()
42437 //console.log("SET FROM HIDDEN");
42438 //alert('setFrom hidden');
42439 this.setValue(this.el.dom.value);
42442 onDestroy : function()
42445 Roo.get(this.viewEl).remove();
42448 Roo.form.Checkbox.superclass.onDestroy.call(this);
42451 setBoxLabel : function(str)
42453 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42458 * Ext JS Library 1.1.1
42459 * Copyright(c) 2006-2007, Ext JS, LLC.
42461 * Originally Released Under LGPL - original licence link has changed is not relivant.
42464 * <script type="text/javascript">
42468 * @class Roo.form.Radio
42469 * @extends Roo.form.Checkbox
42470 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42471 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42473 * Creates a new Radio
42474 * @param {Object} config Configuration options
42476 Roo.form.Radio = function(){
42477 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42479 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42480 inputType: 'radio',
42483 * If this radio is part of a group, it will return the selected value
42486 getGroupValue : function(){
42487 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42491 onRender : function(ct, position){
42492 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42494 if(this.inputValue !== undefined){
42495 this.el.dom.value = this.inputValue;
42498 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42499 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42500 //var viewEl = this.wrap.createChild({
42501 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42502 //this.viewEl = viewEl;
42503 //this.wrap.on('click', this.onClick, this);
42505 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42506 //this.el.on('propertychange', this.setFromHidden, this); //ie
42511 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42512 // viewEl.on('click', this.onClick, this);
42515 this.el.dom.checked = 'checked' ;
42521 });//<script type="text/javascript">
42524 * Based Ext JS Library 1.1.1
42525 * Copyright(c) 2006-2007, Ext JS, LLC.
42531 * @class Roo.HtmlEditorCore
42532 * @extends Roo.Component
42533 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42535 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42538 Roo.HtmlEditorCore = function(config){
42541 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42546 * @event initialize
42547 * Fires when the editor is fully initialized (including the iframe)
42548 * @param {Roo.HtmlEditorCore} this
42553 * Fires when the editor is first receives the focus. Any insertion must wait
42554 * until after this event.
42555 * @param {Roo.HtmlEditorCore} this
42559 * @event beforesync
42560 * Fires before the textarea is updated with content from the editor iframe. Return false
42561 * to cancel the sync.
42562 * @param {Roo.HtmlEditorCore} this
42563 * @param {String} html
42567 * @event beforepush
42568 * Fires before the iframe editor is updated with content from the textarea. Return false
42569 * to cancel the push.
42570 * @param {Roo.HtmlEditorCore} this
42571 * @param {String} html
42576 * Fires when the textarea is updated with content from the editor iframe.
42577 * @param {Roo.HtmlEditorCore} this
42578 * @param {String} html
42583 * Fires when the iframe editor is updated with content from the textarea.
42584 * @param {Roo.HtmlEditorCore} this
42585 * @param {String} html
42590 * @event editorevent
42591 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42592 * @param {Roo.HtmlEditorCore} this
42598 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42600 // defaults : white / black...
42601 this.applyBlacklists();
42608 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42612 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42618 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42623 * @cfg {Number} height (in pixels)
42627 * @cfg {Number} width (in pixels)
42632 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42635 stylesheets: false,
42640 // private properties
42641 validationEvent : false,
42643 initialized : false,
42645 sourceEditMode : false,
42646 onFocus : Roo.emptyFn,
42648 hideMode:'offsets',
42652 // blacklist + whitelisted elements..
42659 * Protected method that will not generally be called directly. It
42660 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42661 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42663 getDocMarkup : function(){
42667 // inherit styels from page...??
42668 if (this.stylesheets === false) {
42670 Roo.get(document.head).select('style').each(function(node) {
42671 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42674 Roo.get(document.head).select('link').each(function(node) {
42675 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42678 } else if (!this.stylesheets.length) {
42680 st = '<style type="text/css">' +
42681 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42687 st += '<style type="text/css">' +
42688 'IMG { cursor: pointer } ' +
42692 return '<html><head>' + st +
42693 //<style type="text/css">' +
42694 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42696 ' </head><body class="roo-htmleditor-body"></body></html>';
42700 onRender : function(ct, position)
42703 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42704 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42707 this.el.dom.style.border = '0 none';
42708 this.el.dom.setAttribute('tabIndex', -1);
42709 this.el.addClass('x-hidden hide');
42713 if(Roo.isIE){ // fix IE 1px bogus margin
42714 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42718 this.frameId = Roo.id();
42722 var iframe = this.owner.wrap.createChild({
42724 cls: 'form-control', // bootstrap..
42726 name: this.frameId,
42727 frameBorder : 'no',
42728 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42733 this.iframe = iframe.dom;
42735 this.assignDocWin();
42737 this.doc.designMode = 'on';
42740 this.doc.write(this.getDocMarkup());
42744 var task = { // must defer to wait for browser to be ready
42746 //console.log("run task?" + this.doc.readyState);
42747 this.assignDocWin();
42748 if(this.doc.body || this.doc.readyState == 'complete'){
42750 this.doc.designMode="on";
42754 Roo.TaskMgr.stop(task);
42755 this.initEditor.defer(10, this);
42762 Roo.TaskMgr.start(task);
42767 onResize : function(w, h)
42769 Roo.log('resize: ' +w + ',' + h );
42770 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
42774 if(typeof w == 'number'){
42776 this.iframe.style.width = w + 'px';
42778 if(typeof h == 'number'){
42780 this.iframe.style.height = h + 'px';
42782 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
42789 * Toggles the editor between standard and source edit mode.
42790 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42792 toggleSourceEdit : function(sourceEditMode){
42794 this.sourceEditMode = sourceEditMode === true;
42796 if(this.sourceEditMode){
42798 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
42801 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
42802 //this.iframe.className = '';
42805 //this.setSize(this.owner.wrap.getSize());
42806 //this.fireEvent('editmodechange', this, this.sourceEditMode);
42813 * Protected method that will not generally be called directly. If you need/want
42814 * custom HTML cleanup, this is the method you should override.
42815 * @param {String} html The HTML to be cleaned
42816 * return {String} The cleaned HTML
42818 cleanHtml : function(html){
42819 html = String(html);
42820 if(html.length > 5){
42821 if(Roo.isSafari){ // strip safari nonsense
42822 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
42825 if(html == ' '){
42832 * HTML Editor -> Textarea
42833 * Protected method that will not generally be called directly. Syncs the contents
42834 * of the editor iframe with the textarea.
42836 syncValue : function(){
42837 if(this.initialized){
42838 var bd = (this.doc.body || this.doc.documentElement);
42839 //this.cleanUpPaste(); -- this is done else where and causes havoc..
42840 var html = bd.innerHTML;
42842 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
42843 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
42845 html = '<div style="'+m[0]+'">' + html + '</div>';
42848 html = this.cleanHtml(html);
42849 // fix up the special chars.. normaly like back quotes in word...
42850 // however we do not want to do this with chinese..
42851 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
42852 var cc = b.charCodeAt();
42854 (cc >= 0x4E00 && cc < 0xA000 ) ||
42855 (cc >= 0x3400 && cc < 0x4E00 ) ||
42856 (cc >= 0xf900 && cc < 0xfb00 )
42862 if(this.owner.fireEvent('beforesync', this, html) !== false){
42863 this.el.dom.value = html;
42864 this.owner.fireEvent('sync', this, html);
42870 * Protected method that will not generally be called directly. Pushes the value of the textarea
42871 * into the iframe editor.
42873 pushValue : function(){
42874 if(this.initialized){
42875 var v = this.el.dom.value.trim();
42877 // if(v.length < 1){
42881 if(this.owner.fireEvent('beforepush', this, v) !== false){
42882 var d = (this.doc.body || this.doc.documentElement);
42884 this.cleanUpPaste();
42885 this.el.dom.value = d.innerHTML;
42886 this.owner.fireEvent('push', this, v);
42892 deferFocus : function(){
42893 this.focus.defer(10, this);
42897 focus : function(){
42898 if(this.win && !this.sourceEditMode){
42905 assignDocWin: function()
42907 var iframe = this.iframe;
42910 this.doc = iframe.contentWindow.document;
42911 this.win = iframe.contentWindow;
42913 // if (!Roo.get(this.frameId)) {
42916 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
42917 // this.win = Roo.get(this.frameId).dom.contentWindow;
42919 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
42923 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
42924 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
42929 initEditor : function(){
42930 //console.log("INIT EDITOR");
42931 this.assignDocWin();
42935 this.doc.designMode="on";
42937 this.doc.write(this.getDocMarkup());
42940 var dbody = (this.doc.body || this.doc.documentElement);
42941 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
42942 // this copies styles from the containing element into thsi one..
42943 // not sure why we need all of this..
42944 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
42946 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
42947 //ss['background-attachment'] = 'fixed'; // w3c
42948 dbody.bgProperties = 'fixed'; // ie
42949 //Roo.DomHelper.applyStyles(dbody, ss);
42950 Roo.EventManager.on(this.doc, {
42951 //'mousedown': this.onEditorEvent,
42952 'mouseup': this.onEditorEvent,
42953 'dblclick': this.onEditorEvent,
42954 'click': this.onEditorEvent,
42955 'keyup': this.onEditorEvent,
42960 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
42962 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
42963 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
42965 this.initialized = true;
42967 this.owner.fireEvent('initialize', this);
42972 onDestroy : function(){
42978 //for (var i =0; i < this.toolbars.length;i++) {
42979 // // fixme - ask toolbars for heights?
42980 // this.toolbars[i].onDestroy();
42983 //this.wrap.dom.innerHTML = '';
42984 //this.wrap.remove();
42989 onFirstFocus : function(){
42991 this.assignDocWin();
42994 this.activated = true;
42997 if(Roo.isGecko){ // prevent silly gecko errors
42999 var s = this.win.getSelection();
43000 if(!s.focusNode || s.focusNode.nodeType != 3){
43001 var r = s.getRangeAt(0);
43002 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43007 this.execCmd('useCSS', true);
43008 this.execCmd('styleWithCSS', false);
43011 this.owner.fireEvent('activate', this);
43015 adjustFont: function(btn){
43016 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43017 //if(Roo.isSafari){ // safari
43020 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43021 if(Roo.isSafari){ // safari
43022 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43023 v = (v < 10) ? 10 : v;
43024 v = (v > 48) ? 48 : v;
43025 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43030 v = Math.max(1, v+adjust);
43032 this.execCmd('FontSize', v );
43035 onEditorEvent : function(e)
43037 this.owner.fireEvent('editorevent', this, e);
43038 // this.updateToolbar();
43039 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43042 insertTag : function(tg)
43044 // could be a bit smarter... -> wrap the current selected tRoo..
43045 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43047 range = this.createRange(this.getSelection());
43048 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43049 wrappingNode.appendChild(range.extractContents());
43050 range.insertNode(wrappingNode);
43057 this.execCmd("formatblock", tg);
43061 insertText : function(txt)
43065 var range = this.createRange();
43066 range.deleteContents();
43067 //alert(Sender.getAttribute('label'));
43069 range.insertNode(this.doc.createTextNode(txt));
43075 * Executes a Midas editor command on the editor document and performs necessary focus and
43076 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43077 * @param {String} cmd The Midas command
43078 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43080 relayCmd : function(cmd, value){
43082 this.execCmd(cmd, value);
43083 this.owner.fireEvent('editorevent', this);
43084 //this.updateToolbar();
43085 this.owner.deferFocus();
43089 * Executes a Midas editor command directly on the editor document.
43090 * For visual commands, you should use {@link #relayCmd} instead.
43091 * <b>This should only be called after the editor is initialized.</b>
43092 * @param {String} cmd The Midas command
43093 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43095 execCmd : function(cmd, value){
43096 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43103 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43105 * @param {String} text | dom node..
43107 insertAtCursor : function(text)
43112 if(!this.activated){
43118 var r = this.doc.selection.createRange();
43129 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43133 // from jquery ui (MIT licenced)
43135 var win = this.win;
43137 if (win.getSelection && win.getSelection().getRangeAt) {
43138 range = win.getSelection().getRangeAt(0);
43139 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43140 range.insertNode(node);
43141 } else if (win.document.selection && win.document.selection.createRange) {
43142 // no firefox support
43143 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43144 win.document.selection.createRange().pasteHTML(txt);
43146 // no firefox support
43147 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43148 this.execCmd('InsertHTML', txt);
43157 mozKeyPress : function(e){
43159 var c = e.getCharCode(), cmd;
43162 c = String.fromCharCode(c).toLowerCase();
43176 this.cleanUpPaste.defer(100, this);
43184 e.preventDefault();
43192 fixKeys : function(){ // load time branching for fastest keydown performance
43194 return function(e){
43195 var k = e.getKey(), r;
43198 r = this.doc.selection.createRange();
43201 r.pasteHTML('    ');
43208 r = this.doc.selection.createRange();
43210 var target = r.parentElement();
43211 if(!target || target.tagName.toLowerCase() != 'li'){
43213 r.pasteHTML('<br />');
43219 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43220 this.cleanUpPaste.defer(100, this);
43226 }else if(Roo.isOpera){
43227 return function(e){
43228 var k = e.getKey();
43232 this.execCmd('InsertHTML','    ');
43235 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43236 this.cleanUpPaste.defer(100, this);
43241 }else if(Roo.isSafari){
43242 return function(e){
43243 var k = e.getKey();
43247 this.execCmd('InsertText','\t');
43251 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43252 this.cleanUpPaste.defer(100, this);
43260 getAllAncestors: function()
43262 var p = this.getSelectedNode();
43265 a.push(p); // push blank onto stack..
43266 p = this.getParentElement();
43270 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43274 a.push(this.doc.body);
43278 lastSelNode : false,
43281 getSelection : function()
43283 this.assignDocWin();
43284 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43287 getSelectedNode: function()
43289 // this may only work on Gecko!!!
43291 // should we cache this!!!!
43296 var range = this.createRange(this.getSelection()).cloneRange();
43299 var parent = range.parentElement();
43301 var testRange = range.duplicate();
43302 testRange.moveToElementText(parent);
43303 if (testRange.inRange(range)) {
43306 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43309 parent = parent.parentElement;
43314 // is ancestor a text element.
43315 var ac = range.commonAncestorContainer;
43316 if (ac.nodeType == 3) {
43317 ac = ac.parentNode;
43320 var ar = ac.childNodes;
43323 var other_nodes = [];
43324 var has_other_nodes = false;
43325 for (var i=0;i<ar.length;i++) {
43326 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43329 // fullly contained node.
43331 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43336 // probably selected..
43337 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43338 other_nodes.push(ar[i]);
43342 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43347 has_other_nodes = true;
43349 if (!nodes.length && other_nodes.length) {
43350 nodes= other_nodes;
43352 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43358 createRange: function(sel)
43360 // this has strange effects when using with
43361 // top toolbar - not sure if it's a great idea.
43362 //this.editor.contentWindow.focus();
43363 if (typeof sel != "undefined") {
43365 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43367 return this.doc.createRange();
43370 return this.doc.createRange();
43373 getParentElement: function()
43376 this.assignDocWin();
43377 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43379 var range = this.createRange(sel);
43382 var p = range.commonAncestorContainer;
43383 while (p.nodeType == 3) { // text node
43394 * Range intersection.. the hard stuff...
43398 * [ -- selected range --- ]
43402 * if end is before start or hits it. fail.
43403 * if start is after end or hits it fail.
43405 * if either hits (but other is outside. - then it's not
43411 // @see http://www.thismuchiknow.co.uk/?p=64.
43412 rangeIntersectsNode : function(range, node)
43414 var nodeRange = node.ownerDocument.createRange();
43416 nodeRange.selectNode(node);
43418 nodeRange.selectNodeContents(node);
43421 var rangeStartRange = range.cloneRange();
43422 rangeStartRange.collapse(true);
43424 var rangeEndRange = range.cloneRange();
43425 rangeEndRange.collapse(false);
43427 var nodeStartRange = nodeRange.cloneRange();
43428 nodeStartRange.collapse(true);
43430 var nodeEndRange = nodeRange.cloneRange();
43431 nodeEndRange.collapse(false);
43433 return rangeStartRange.compareBoundaryPoints(
43434 Range.START_TO_START, nodeEndRange) == -1 &&
43435 rangeEndRange.compareBoundaryPoints(
43436 Range.START_TO_START, nodeStartRange) == 1;
43440 rangeCompareNode : function(range, node)
43442 var nodeRange = node.ownerDocument.createRange();
43444 nodeRange.selectNode(node);
43446 nodeRange.selectNodeContents(node);
43450 range.collapse(true);
43452 nodeRange.collapse(true);
43454 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43455 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43457 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43459 var nodeIsBefore = ss == 1;
43460 var nodeIsAfter = ee == -1;
43462 if (nodeIsBefore && nodeIsAfter) {
43465 if (!nodeIsBefore && nodeIsAfter) {
43466 return 1; //right trailed.
43469 if (nodeIsBefore && !nodeIsAfter) {
43470 return 2; // left trailed.
43476 // private? - in a new class?
43477 cleanUpPaste : function()
43479 // cleans up the whole document..
43480 Roo.log('cleanuppaste');
43482 this.cleanUpChildren(this.doc.body);
43483 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43484 if (clean != this.doc.body.innerHTML) {
43485 this.doc.body.innerHTML = clean;
43490 cleanWordChars : function(input) {// change the chars to hex code
43491 var he = Roo.HtmlEditorCore;
43493 var output = input;
43494 Roo.each(he.swapCodes, function(sw) {
43495 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43497 output = output.replace(swapper, sw[1]);
43504 cleanUpChildren : function (n)
43506 if (!n.childNodes.length) {
43509 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43510 this.cleanUpChild(n.childNodes[i]);
43517 cleanUpChild : function (node)
43520 //console.log(node);
43521 if (node.nodeName == "#text") {
43522 // clean up silly Windows -- stuff?
43525 if (node.nodeName == "#comment") {
43526 node.parentNode.removeChild(node);
43527 // clean up silly Windows -- stuff?
43530 var lcname = node.tagName.toLowerCase();
43531 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43532 // whitelist of tags..
43534 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43536 node.parentNode.removeChild(node);
43541 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43543 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43544 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43546 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43547 // remove_keep_children = true;
43550 if (remove_keep_children) {
43551 this.cleanUpChildren(node);
43552 // inserts everything just before this node...
43553 while (node.childNodes.length) {
43554 var cn = node.childNodes[0];
43555 node.removeChild(cn);
43556 node.parentNode.insertBefore(cn, node);
43558 node.parentNode.removeChild(node);
43562 if (!node.attributes || !node.attributes.length) {
43563 this.cleanUpChildren(node);
43567 function cleanAttr(n,v)
43570 if (v.match(/^\./) || v.match(/^\//)) {
43573 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
43576 if (v.match(/^#/)) {
43579 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43580 node.removeAttribute(n);
43584 var cwhite = this.cwhite;
43585 var cblack = this.cblack;
43587 function cleanStyle(n,v)
43589 if (v.match(/expression/)) { //XSS?? should we even bother..
43590 node.removeAttribute(n);
43594 var parts = v.split(/;/);
43597 Roo.each(parts, function(p) {
43598 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43602 var l = p.split(':').shift().replace(/\s+/g,'');
43603 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43605 if ( cwhite.length && cblack.indexOf(l) > -1) {
43606 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43607 //node.removeAttribute(n);
43611 // only allow 'c whitelisted system attributes'
43612 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43613 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43614 //node.removeAttribute(n);
43624 if (clean.length) {
43625 node.setAttribute(n, clean.join(';'));
43627 node.removeAttribute(n);
43633 for (var i = node.attributes.length-1; i > -1 ; i--) {
43634 var a = node.attributes[i];
43637 if (a.name.toLowerCase().substr(0,2)=='on') {
43638 node.removeAttribute(a.name);
43641 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43642 node.removeAttribute(a.name);
43645 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43646 cleanAttr(a.name,a.value); // fixme..
43649 if (a.name == 'style') {
43650 cleanStyle(a.name,a.value);
43653 /// clean up MS crap..
43654 // tecnically this should be a list of valid class'es..
43657 if (a.name == 'class') {
43658 if (a.value.match(/^Mso/)) {
43659 node.className = '';
43662 if (a.value.match(/body/)) {
43663 node.className = '';
43674 this.cleanUpChildren(node);
43680 * Clean up MS wordisms...
43682 cleanWord : function(node)
43687 this.cleanWord(this.doc.body);
43690 if (node.nodeName == "#text") {
43691 // clean up silly Windows -- stuff?
43694 if (node.nodeName == "#comment") {
43695 node.parentNode.removeChild(node);
43696 // clean up silly Windows -- stuff?
43700 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43701 node.parentNode.removeChild(node);
43705 // remove - but keep children..
43706 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43707 while (node.childNodes.length) {
43708 var cn = node.childNodes[0];
43709 node.removeChild(cn);
43710 node.parentNode.insertBefore(cn, node);
43712 node.parentNode.removeChild(node);
43713 this.iterateChildren(node, this.cleanWord);
43717 if (node.className.length) {
43719 var cn = node.className.split(/\W+/);
43721 Roo.each(cn, function(cls) {
43722 if (cls.match(/Mso[a-zA-Z]+/)) {
43727 node.className = cna.length ? cna.join(' ') : '';
43729 node.removeAttribute("class");
43733 if (node.hasAttribute("lang")) {
43734 node.removeAttribute("lang");
43737 if (node.hasAttribute("style")) {
43739 var styles = node.getAttribute("style").split(";");
43741 Roo.each(styles, function(s) {
43742 if (!s.match(/:/)) {
43745 var kv = s.split(":");
43746 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
43749 // what ever is left... we allow.
43752 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43753 if (!nstyle.length) {
43754 node.removeAttribute('style');
43757 this.iterateChildren(node, this.cleanWord);
43763 * iterateChildren of a Node, calling fn each time, using this as the scole..
43764 * @param {DomNode} node node to iterate children of.
43765 * @param {Function} fn method of this class to call on each item.
43767 iterateChildren : function(node, fn)
43769 if (!node.childNodes.length) {
43772 for (var i = node.childNodes.length-1; i > -1 ; i--) {
43773 fn.call(this, node.childNodes[i])
43779 * cleanTableWidths.
43781 * Quite often pasting from word etc.. results in tables with column and widths.
43782 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
43785 cleanTableWidths : function(node)
43790 this.cleanTableWidths(this.doc.body);
43795 if (node.nodeName == "#text" || node.nodeName == "#comment") {
43798 Roo.log(node.tagName);
43799 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
43800 this.iterateChildren(node, this.cleanTableWidths);
43803 if (node.hasAttribute('width')) {
43804 node.removeAttribute('width');
43808 if (node.hasAttribute("style")) {
43811 var styles = node.getAttribute("style").split(";");
43813 Roo.each(styles, function(s) {
43814 if (!s.match(/:/)) {
43817 var kv = s.split(":");
43818 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
43821 // what ever is left... we allow.
43824 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43825 if (!nstyle.length) {
43826 node.removeAttribute('style');
43830 this.iterateChildren(node, this.cleanTableWidths);
43838 domToHTML : function(currentElement, depth, nopadtext) {
43840 depth = depth || 0;
43841 nopadtext = nopadtext || false;
43843 if (!currentElement) {
43844 return this.domToHTML(this.doc.body);
43847 //Roo.log(currentElement);
43849 var allText = false;
43850 var nodeName = currentElement.nodeName;
43851 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
43853 if (nodeName == '#text') {
43855 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
43860 if (nodeName != 'BODY') {
43863 // Prints the node tagName, such as <A>, <IMG>, etc
43866 for(i = 0; i < currentElement.attributes.length;i++) {
43868 var aname = currentElement.attributes.item(i).name;
43869 if (!currentElement.attributes.item(i).value.length) {
43872 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
43875 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
43884 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
43887 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
43892 // Traverse the tree
43894 var currentElementChild = currentElement.childNodes.item(i);
43895 var allText = true;
43896 var innerHTML = '';
43898 while (currentElementChild) {
43899 // Formatting code (indent the tree so it looks nice on the screen)
43900 var nopad = nopadtext;
43901 if (lastnode == 'SPAN') {
43905 if (currentElementChild.nodeName == '#text') {
43906 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
43907 toadd = nopadtext ? toadd : toadd.trim();
43908 if (!nopad && toadd.length > 80) {
43909 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
43911 innerHTML += toadd;
43914 currentElementChild = currentElement.childNodes.item(i);
43920 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
43922 // Recursively traverse the tree structure of the child node
43923 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
43924 lastnode = currentElementChild.nodeName;
43926 currentElementChild=currentElement.childNodes.item(i);
43932 // The remaining code is mostly for formatting the tree
43933 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
43938 ret+= "</"+tagName+">";
43944 applyBlacklists : function()
43946 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
43947 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
43951 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
43952 if (b.indexOf(tag) > -1) {
43955 this.white.push(tag);
43959 Roo.each(w, function(tag) {
43960 if (b.indexOf(tag) > -1) {
43963 if (this.white.indexOf(tag) > -1) {
43966 this.white.push(tag);
43971 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
43972 if (w.indexOf(tag) > -1) {
43975 this.black.push(tag);
43979 Roo.each(b, function(tag) {
43980 if (w.indexOf(tag) > -1) {
43983 if (this.black.indexOf(tag) > -1) {
43986 this.black.push(tag);
43991 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
43992 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
43996 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
43997 if (b.indexOf(tag) > -1) {
44000 this.cwhite.push(tag);
44004 Roo.each(w, function(tag) {
44005 if (b.indexOf(tag) > -1) {
44008 if (this.cwhite.indexOf(tag) > -1) {
44011 this.cwhite.push(tag);
44016 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44017 if (w.indexOf(tag) > -1) {
44020 this.cblack.push(tag);
44024 Roo.each(b, function(tag) {
44025 if (w.indexOf(tag) > -1) {
44028 if (this.cblack.indexOf(tag) > -1) {
44031 this.cblack.push(tag);
44036 setStylesheets : function(stylesheets)
44038 if(typeof(stylesheets) == 'string'){
44039 Roo.get(this.iframe.contentDocument.head).createChild({
44041 rel : 'stylesheet',
44050 Roo.each(stylesheets, function(s) {
44055 Roo.get(_this.iframe.contentDocument.head).createChild({
44057 rel : 'stylesheet',
44066 removeStylesheets : function()
44070 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44075 // hide stuff that is not compatible
44089 * @event specialkey
44093 * @cfg {String} fieldClass @hide
44096 * @cfg {String} focusClass @hide
44099 * @cfg {String} autoCreate @hide
44102 * @cfg {String} inputType @hide
44105 * @cfg {String} invalidClass @hide
44108 * @cfg {String} invalidText @hide
44111 * @cfg {String} msgFx @hide
44114 * @cfg {String} validateOnBlur @hide
44118 Roo.HtmlEditorCore.white = [
44119 'area', 'br', 'img', 'input', 'hr', 'wbr',
44121 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44122 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44123 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44124 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44125 'table', 'ul', 'xmp',
44127 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44130 'dir', 'menu', 'ol', 'ul', 'dl',
44136 Roo.HtmlEditorCore.black = [
44137 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44139 'base', 'basefont', 'bgsound', 'blink', 'body',
44140 'frame', 'frameset', 'head', 'html', 'ilayer',
44141 'iframe', 'layer', 'link', 'meta', 'object',
44142 'script', 'style' ,'title', 'xml' // clean later..
44144 Roo.HtmlEditorCore.clean = [
44145 'script', 'style', 'title', 'xml'
44147 Roo.HtmlEditorCore.remove = [
44152 Roo.HtmlEditorCore.ablack = [
44156 Roo.HtmlEditorCore.aclean = [
44157 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44161 Roo.HtmlEditorCore.pwhite= [
44162 'http', 'https', 'mailto'
44165 // white listed style attributes.
44166 Roo.HtmlEditorCore.cwhite= [
44167 // 'text-align', /// default is to allow most things..
44173 // black listed style attributes.
44174 Roo.HtmlEditorCore.cblack= [
44175 // 'font-size' -- this can be set by the project
44179 Roo.HtmlEditorCore.swapCodes =[
44190 //<script type="text/javascript">
44193 * Ext JS Library 1.1.1
44194 * Copyright(c) 2006-2007, Ext JS, LLC.
44200 Roo.form.HtmlEditor = function(config){
44204 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44206 if (!this.toolbars) {
44207 this.toolbars = [];
44209 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44215 * @class Roo.form.HtmlEditor
44216 * @extends Roo.form.Field
44217 * Provides a lightweight HTML Editor component.
44219 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44221 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44222 * supported by this editor.</b><br/><br/>
44223 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44224 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44226 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44228 * @cfg {Boolean} clearUp
44232 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44237 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44242 * @cfg {Number} height (in pixels)
44246 * @cfg {Number} width (in pixels)
44251 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44254 stylesheets: false,
44258 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44263 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44269 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44274 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44282 // private properties
44283 validationEvent : false,
44285 initialized : false,
44288 onFocus : Roo.emptyFn,
44290 hideMode:'offsets',
44292 actionMode : 'container', // defaults to hiding it...
44294 defaultAutoCreate : { // modified by initCompnoent..
44296 style:"width:500px;height:300px;",
44297 autocomplete: "new-password"
44301 initComponent : function(){
44304 * @event initialize
44305 * Fires when the editor is fully initialized (including the iframe)
44306 * @param {HtmlEditor} this
44311 * Fires when the editor is first receives the focus. Any insertion must wait
44312 * until after this event.
44313 * @param {HtmlEditor} this
44317 * @event beforesync
44318 * Fires before the textarea is updated with content from the editor iframe. Return false
44319 * to cancel the sync.
44320 * @param {HtmlEditor} this
44321 * @param {String} html
44325 * @event beforepush
44326 * Fires before the iframe editor is updated with content from the textarea. Return false
44327 * to cancel the push.
44328 * @param {HtmlEditor} this
44329 * @param {String} html
44334 * Fires when the textarea is updated with content from the editor iframe.
44335 * @param {HtmlEditor} this
44336 * @param {String} html
44341 * Fires when the iframe editor is updated with content from the textarea.
44342 * @param {HtmlEditor} this
44343 * @param {String} html
44347 * @event editmodechange
44348 * Fires when the editor switches edit modes
44349 * @param {HtmlEditor} this
44350 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44352 editmodechange: true,
44354 * @event editorevent
44355 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44356 * @param {HtmlEditor} this
44360 * @event firstfocus
44361 * Fires when on first focus - needed by toolbars..
44362 * @param {HtmlEditor} this
44367 * Auto save the htmlEditor value as a file into Events
44368 * @param {HtmlEditor} this
44372 * @event savedpreview
44373 * preview the saved version of htmlEditor
44374 * @param {HtmlEditor} this
44376 savedpreview: true,
44379 * @event stylesheetsclick
44380 * Fires when press the Sytlesheets button
44381 * @param {Roo.HtmlEditorCore} this
44383 stylesheetsclick: true
44385 this.defaultAutoCreate = {
44387 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44388 autocomplete: "new-password"
44393 * Protected method that will not generally be called directly. It
44394 * is called when the editor creates its toolbar. Override this method if you need to
44395 * add custom toolbar buttons.
44396 * @param {HtmlEditor} editor
44398 createToolbar : function(editor){
44399 Roo.log("create toolbars");
44400 if (!editor.toolbars || !editor.toolbars.length) {
44401 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44404 for (var i =0 ; i < editor.toolbars.length;i++) {
44405 editor.toolbars[i] = Roo.factory(
44406 typeof(editor.toolbars[i]) == 'string' ?
44407 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44408 Roo.form.HtmlEditor);
44409 editor.toolbars[i].init(editor);
44417 onRender : function(ct, position)
44420 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44422 this.wrap = this.el.wrap({
44423 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44426 this.editorcore.onRender(ct, position);
44428 if (this.resizable) {
44429 this.resizeEl = new Roo.Resizable(this.wrap, {
44433 minHeight : this.height,
44434 height: this.height,
44435 handles : this.resizable,
44438 resize : function(r, w, h) {
44439 _t.onResize(w,h); // -something
44445 this.createToolbar(this);
44449 this.setSize(this.wrap.getSize());
44451 if (this.resizeEl) {
44452 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44453 // should trigger onReize..
44456 this.keyNav = new Roo.KeyNav(this.el, {
44458 "tab" : function(e){
44459 e.preventDefault();
44461 var value = this.getValue();
44463 var start = this.el.dom.selectionStart;
44464 var end = this.el.dom.selectionEnd;
44468 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44469 this.el.dom.setSelectionRange(end + 1, end + 1);
44473 var f = value.substring(0, start).split("\t");
44475 if(f.pop().length != 0){
44479 this.setValue(f.join("\t") + value.substring(end));
44480 this.el.dom.setSelectionRange(start - 1, start - 1);
44484 "home" : function(e){
44485 e.preventDefault();
44487 var curr = this.el.dom.selectionStart;
44488 var lines = this.getValue().split("\n");
44495 this.el.dom.setSelectionRange(0, 0);
44501 for (var i = 0; i < lines.length;i++) {
44502 pos += lines[i].length;
44512 pos -= lines[i].length;
44518 this.el.dom.setSelectionRange(pos, pos);
44522 this.el.dom.selectionStart = pos;
44523 this.el.dom.selectionEnd = curr;
44526 "end" : function(e){
44527 e.preventDefault();
44529 var curr = this.el.dom.selectionStart;
44530 var lines = this.getValue().split("\n");
44537 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44543 for (var i = 0; i < lines.length;i++) {
44545 pos += lines[i].length;
44559 this.el.dom.setSelectionRange(pos, pos);
44563 this.el.dom.selectionStart = curr;
44564 this.el.dom.selectionEnd = pos;
44569 doRelay : function(foo, bar, hname){
44570 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44576 // if(this.autosave && this.w){
44577 // this.autoSaveFn = setInterval(this.autosave, 1000);
44582 onResize : function(w, h)
44584 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44589 if(typeof w == 'number'){
44590 var aw = w - this.wrap.getFrameWidth('lr');
44591 this.el.setWidth(this.adjustWidth('textarea', aw));
44594 if(typeof h == 'number'){
44596 for (var i =0; i < this.toolbars.length;i++) {
44597 // fixme - ask toolbars for heights?
44598 tbh += this.toolbars[i].tb.el.getHeight();
44599 if (this.toolbars[i].footer) {
44600 tbh += this.toolbars[i].footer.el.getHeight();
44607 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44608 ah -= 5; // knock a few pixes off for look..
44610 this.el.setHeight(this.adjustWidth('textarea', ah));
44614 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44615 this.editorcore.onResize(ew,eh);
44620 * Toggles the editor between standard and source edit mode.
44621 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44623 toggleSourceEdit : function(sourceEditMode)
44625 this.editorcore.toggleSourceEdit(sourceEditMode);
44627 if(this.editorcore.sourceEditMode){
44628 Roo.log('editor - showing textarea');
44631 // Roo.log(this.syncValue());
44632 this.editorcore.syncValue();
44633 this.el.removeClass('x-hidden');
44634 this.el.dom.removeAttribute('tabIndex');
44637 for (var i = 0; i < this.toolbars.length; i++) {
44638 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44639 this.toolbars[i].tb.hide();
44640 this.toolbars[i].footer.hide();
44645 Roo.log('editor - hiding textarea');
44647 // Roo.log(this.pushValue());
44648 this.editorcore.pushValue();
44650 this.el.addClass('x-hidden');
44651 this.el.dom.setAttribute('tabIndex', -1);
44653 for (var i = 0; i < this.toolbars.length; i++) {
44654 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44655 this.toolbars[i].tb.show();
44656 this.toolbars[i].footer.show();
44660 //this.deferFocus();
44663 this.setSize(this.wrap.getSize());
44664 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44666 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44669 // private (for BoxComponent)
44670 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44672 // private (for BoxComponent)
44673 getResizeEl : function(){
44677 // private (for BoxComponent)
44678 getPositionEl : function(){
44683 initEvents : function(){
44684 this.originalValue = this.getValue();
44688 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44691 markInvalid : Roo.emptyFn,
44693 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44696 clearInvalid : Roo.emptyFn,
44698 setValue : function(v){
44699 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44700 this.editorcore.pushValue();
44705 deferFocus : function(){
44706 this.focus.defer(10, this);
44710 focus : function(){
44711 this.editorcore.focus();
44717 onDestroy : function(){
44723 for (var i =0; i < this.toolbars.length;i++) {
44724 // fixme - ask toolbars for heights?
44725 this.toolbars[i].onDestroy();
44728 this.wrap.dom.innerHTML = '';
44729 this.wrap.remove();
44734 onFirstFocus : function(){
44735 //Roo.log("onFirstFocus");
44736 this.editorcore.onFirstFocus();
44737 for (var i =0; i < this.toolbars.length;i++) {
44738 this.toolbars[i].onFirstFocus();
44744 syncValue : function()
44746 this.editorcore.syncValue();
44749 pushValue : function()
44751 this.editorcore.pushValue();
44754 setStylesheets : function(stylesheets)
44756 this.editorcore.setStylesheets(stylesheets);
44759 removeStylesheets : function()
44761 this.editorcore.removeStylesheets();
44765 // hide stuff that is not compatible
44779 * @event specialkey
44783 * @cfg {String} fieldClass @hide
44786 * @cfg {String} focusClass @hide
44789 * @cfg {String} autoCreate @hide
44792 * @cfg {String} inputType @hide
44795 * @cfg {String} invalidClass @hide
44798 * @cfg {String} invalidText @hide
44801 * @cfg {String} msgFx @hide
44804 * @cfg {String} validateOnBlur @hide
44808 // <script type="text/javascript">
44811 * Ext JS Library 1.1.1
44812 * Copyright(c) 2006-2007, Ext JS, LLC.
44818 * @class Roo.form.HtmlEditorToolbar1
44823 new Roo.form.HtmlEditor({
44826 new Roo.form.HtmlEditorToolbar1({
44827 disable : { fonts: 1 , format: 1, ..., ... , ...],
44833 * @cfg {Object} disable List of elements to disable..
44834 * @cfg {Array} btns List of additional buttons.
44838 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
44841 Roo.form.HtmlEditor.ToolbarStandard = function(config)
44844 Roo.apply(this, config);
44846 // default disabled, based on 'good practice'..
44847 this.disable = this.disable || {};
44848 Roo.applyIf(this.disable, {
44851 specialElements : true
44855 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44856 // dont call parent... till later.
44859 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
44866 editorcore : false,
44868 * @cfg {Object} disable List of toolbar elements to disable
44875 * @cfg {String} createLinkText The default text for the create link prompt
44877 createLinkText : 'Please enter the URL for the link:',
44879 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
44881 defaultLinkValue : 'http:/'+'/',
44885 * @cfg {Array} fontFamilies An array of available font families
44903 // "á" , ?? a acute?
44908 "°" // , // degrees
44910 // "é" , // e ecute
44911 // "ú" , // u ecute?
44914 specialElements : [
44916 text: "Insert Table",
44919 ihtml : '<table><tr><td>Cell</td></tr></table>'
44923 text: "Insert Image",
44926 ihtml : '<img src="about:blank"/>'
44935 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
44936 "input:submit", "input:button", "select", "textarea", "label" ],
44939 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
44941 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
44949 * @cfg {String} defaultFont default font to use.
44951 defaultFont: 'tahoma',
44953 fontSelect : false,
44956 formatCombo : false,
44958 init : function(editor)
44960 this.editor = editor;
44961 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44962 var editorcore = this.editorcore;
44966 var fid = editorcore.frameId;
44968 function btn(id, toggle, handler){
44969 var xid = fid + '-'+ id ;
44973 cls : 'x-btn-icon x-edit-'+id,
44974 enableToggle:toggle !== false,
44975 scope: _t, // was editor...
44976 handler:handler||_t.relayBtnCmd,
44977 clickEvent:'mousedown',
44978 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44985 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
44987 // stop form submits
44988 tb.el.on('click', function(e){
44989 e.preventDefault(); // what does this do?
44992 if(!this.disable.font) { // && !Roo.isSafari){
44993 /* why no safari for fonts
44994 editor.fontSelect = tb.el.createChild({
44997 cls:'x-font-select',
44998 html: this.createFontOptions()
45001 editor.fontSelect.on('change', function(){
45002 var font = editor.fontSelect.dom.value;
45003 editor.relayCmd('fontname', font);
45004 editor.deferFocus();
45008 editor.fontSelect.dom,
45014 if(!this.disable.formats){
45015 this.formatCombo = new Roo.form.ComboBox({
45016 store: new Roo.data.SimpleStore({
45019 data : this.formats // from states.js
45023 //autoCreate : {tag: "div", size: "20"},
45024 displayField:'tag',
45028 triggerAction: 'all',
45029 emptyText:'Add tag',
45030 selectOnFocus:true,
45033 'select': function(c, r, i) {
45034 editorcore.insertTag(r.get('tag'));
45040 tb.addField(this.formatCombo);
45044 if(!this.disable.format){
45049 btn('strikethrough')
45052 if(!this.disable.fontSize){
45057 btn('increasefontsize', false, editorcore.adjustFont),
45058 btn('decreasefontsize', false, editorcore.adjustFont)
45063 if(!this.disable.colors){
45066 id:editorcore.frameId +'-forecolor',
45067 cls:'x-btn-icon x-edit-forecolor',
45068 clickEvent:'mousedown',
45069 tooltip: this.buttonTips['forecolor'] || undefined,
45071 menu : new Roo.menu.ColorMenu({
45072 allowReselect: true,
45073 focus: Roo.emptyFn,
45076 selectHandler: function(cp, color){
45077 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45078 editor.deferFocus();
45081 clickEvent:'mousedown'
45084 id:editorcore.frameId +'backcolor',
45085 cls:'x-btn-icon x-edit-backcolor',
45086 clickEvent:'mousedown',
45087 tooltip: this.buttonTips['backcolor'] || undefined,
45089 menu : new Roo.menu.ColorMenu({
45090 focus: Roo.emptyFn,
45093 allowReselect: true,
45094 selectHandler: function(cp, color){
45096 editorcore.execCmd('useCSS', false);
45097 editorcore.execCmd('hilitecolor', color);
45098 editorcore.execCmd('useCSS', true);
45099 editor.deferFocus();
45101 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45102 Roo.isSafari || Roo.isIE ? '#'+color : color);
45103 editor.deferFocus();
45107 clickEvent:'mousedown'
45112 // now add all the items...
45115 if(!this.disable.alignments){
45118 btn('justifyleft'),
45119 btn('justifycenter'),
45120 btn('justifyright')
45124 //if(!Roo.isSafari){
45125 if(!this.disable.links){
45128 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45132 if(!this.disable.lists){
45135 btn('insertorderedlist'),
45136 btn('insertunorderedlist')
45139 if(!this.disable.sourceEdit){
45142 btn('sourceedit', true, function(btn){
45143 this.toggleSourceEdit(btn.pressed);
45150 // special menu.. - needs to be tidied up..
45151 if (!this.disable.special) {
45154 cls: 'x-edit-none',
45160 for (var i =0; i < this.specialChars.length; i++) {
45161 smenu.menu.items.push({
45163 html: this.specialChars[i],
45164 handler: function(a,b) {
45165 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45166 //editor.insertAtCursor(a.html);
45180 if (!this.disable.cleanStyles) {
45182 cls: 'x-btn-icon x-btn-clear',
45188 for (var i =0; i < this.cleanStyles.length; i++) {
45189 cmenu.menu.items.push({
45190 actiontype : this.cleanStyles[i],
45191 html: 'Remove ' + this.cleanStyles[i],
45192 handler: function(a,b) {
45195 var c = Roo.get(editorcore.doc.body);
45196 c.select('[style]').each(function(s) {
45197 s.dom.style.removeProperty(a.actiontype);
45199 editorcore.syncValue();
45204 cmenu.menu.items.push({
45205 actiontype : 'tablewidths',
45206 html: 'Remove Table Widths',
45207 handler: function(a,b) {
45208 editorcore.cleanTableWidths();
45209 editorcore.syncValue();
45213 cmenu.menu.items.push({
45214 actiontype : 'word',
45215 html: 'Remove MS Word Formating',
45216 handler: function(a,b) {
45217 editorcore.cleanWord();
45218 editorcore.syncValue();
45223 cmenu.menu.items.push({
45224 actiontype : 'all',
45225 html: 'Remove All Styles',
45226 handler: function(a,b) {
45228 var c = Roo.get(editorcore.doc.body);
45229 c.select('[style]').each(function(s) {
45230 s.dom.removeAttribute('style');
45232 editorcore.syncValue();
45237 cmenu.menu.items.push({
45238 actiontype : 'all',
45239 html: 'Remove All CSS Classes',
45240 handler: function(a,b) {
45242 var c = Roo.get(editorcore.doc.body);
45243 c.select('[class]').each(function(s) {
45244 s.dom.className = '';
45246 editorcore.syncValue();
45251 cmenu.menu.items.push({
45252 actiontype : 'tidy',
45253 html: 'Tidy HTML Source',
45254 handler: function(a,b) {
45255 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45256 editorcore.syncValue();
45265 if (!this.disable.specialElements) {
45268 cls: 'x-edit-none',
45273 for (var i =0; i < this.specialElements.length; i++) {
45274 semenu.menu.items.push(
45276 handler: function(a,b) {
45277 editor.insertAtCursor(this.ihtml);
45279 }, this.specialElements[i])
45291 for(var i =0; i< this.btns.length;i++) {
45292 var b = Roo.factory(this.btns[i],Roo.form);
45293 b.cls = 'x-edit-none';
45295 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45296 b.cls += ' x-init-enable';
45299 b.scope = editorcore;
45307 // disable everything...
45309 this.tb.items.each(function(item){
45312 item.id != editorcore.frameId+ '-sourceedit' &&
45313 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45319 this.rendered = true;
45321 // the all the btns;
45322 editor.on('editorevent', this.updateToolbar, this);
45323 // other toolbars need to implement this..
45324 //editor.on('editmodechange', this.updateToolbar, this);
45328 relayBtnCmd : function(btn) {
45329 this.editorcore.relayCmd(btn.cmd);
45331 // private used internally
45332 createLink : function(){
45333 Roo.log("create link?");
45334 var url = prompt(this.createLinkText, this.defaultLinkValue);
45335 if(url && url != 'http:/'+'/'){
45336 this.editorcore.relayCmd('createlink', url);
45342 * Protected method that will not generally be called directly. It triggers
45343 * a toolbar update by reading the markup state of the current selection in the editor.
45345 updateToolbar: function(){
45347 if(!this.editorcore.activated){
45348 this.editor.onFirstFocus();
45352 var btns = this.tb.items.map,
45353 doc = this.editorcore.doc,
45354 frameId = this.editorcore.frameId;
45356 if(!this.disable.font && !Roo.isSafari){
45358 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45359 if(name != this.fontSelect.dom.value){
45360 this.fontSelect.dom.value = name;
45364 if(!this.disable.format){
45365 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45366 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45367 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45368 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45370 if(!this.disable.alignments){
45371 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45372 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45373 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45375 if(!Roo.isSafari && !this.disable.lists){
45376 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45377 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45380 var ans = this.editorcore.getAllAncestors();
45381 if (this.formatCombo) {
45384 var store = this.formatCombo.store;
45385 this.formatCombo.setValue("");
45386 for (var i =0; i < ans.length;i++) {
45387 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45389 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45397 // hides menus... - so this cant be on a menu...
45398 Roo.menu.MenuMgr.hideAll();
45400 //this.editorsyncValue();
45404 createFontOptions : function(){
45405 var buf = [], fs = this.fontFamilies, ff, lc;
45409 for(var i = 0, len = fs.length; i< len; i++){
45411 lc = ff.toLowerCase();
45413 '<option value="',lc,'" style="font-family:',ff,';"',
45414 (this.defaultFont == lc ? ' selected="true">' : '>'),
45419 return buf.join('');
45422 toggleSourceEdit : function(sourceEditMode){
45424 Roo.log("toolbar toogle");
45425 if(sourceEditMode === undefined){
45426 sourceEditMode = !this.sourceEditMode;
45428 this.sourceEditMode = sourceEditMode === true;
45429 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45430 // just toggle the button?
45431 if(btn.pressed !== this.sourceEditMode){
45432 btn.toggle(this.sourceEditMode);
45436 if(sourceEditMode){
45437 Roo.log("disabling buttons");
45438 this.tb.items.each(function(item){
45439 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45445 Roo.log("enabling buttons");
45446 if(this.editorcore.initialized){
45447 this.tb.items.each(function(item){
45453 Roo.log("calling toggole on editor");
45454 // tell the editor that it's been pressed..
45455 this.editor.toggleSourceEdit(sourceEditMode);
45459 * Object collection of toolbar tooltips for the buttons in the editor. The key
45460 * is the command id associated with that button and the value is a valid QuickTips object.
45465 title: 'Bold (Ctrl+B)',
45466 text: 'Make the selected text bold.',
45467 cls: 'x-html-editor-tip'
45470 title: 'Italic (Ctrl+I)',
45471 text: 'Make the selected text italic.',
45472 cls: 'x-html-editor-tip'
45480 title: 'Bold (Ctrl+B)',
45481 text: 'Make the selected text bold.',
45482 cls: 'x-html-editor-tip'
45485 title: 'Italic (Ctrl+I)',
45486 text: 'Make the selected text italic.',
45487 cls: 'x-html-editor-tip'
45490 title: 'Underline (Ctrl+U)',
45491 text: 'Underline the selected text.',
45492 cls: 'x-html-editor-tip'
45495 title: 'Strikethrough',
45496 text: 'Strikethrough the selected text.',
45497 cls: 'x-html-editor-tip'
45499 increasefontsize : {
45500 title: 'Grow Text',
45501 text: 'Increase the font size.',
45502 cls: 'x-html-editor-tip'
45504 decreasefontsize : {
45505 title: 'Shrink Text',
45506 text: 'Decrease the font size.',
45507 cls: 'x-html-editor-tip'
45510 title: 'Text Highlight Color',
45511 text: 'Change the background color of the selected text.',
45512 cls: 'x-html-editor-tip'
45515 title: 'Font Color',
45516 text: 'Change the color of the selected text.',
45517 cls: 'x-html-editor-tip'
45520 title: 'Align Text Left',
45521 text: 'Align text to the left.',
45522 cls: 'x-html-editor-tip'
45525 title: 'Center Text',
45526 text: 'Center text in the editor.',
45527 cls: 'x-html-editor-tip'
45530 title: 'Align Text Right',
45531 text: 'Align text to the right.',
45532 cls: 'x-html-editor-tip'
45534 insertunorderedlist : {
45535 title: 'Bullet List',
45536 text: 'Start a bulleted list.',
45537 cls: 'x-html-editor-tip'
45539 insertorderedlist : {
45540 title: 'Numbered List',
45541 text: 'Start a numbered list.',
45542 cls: 'x-html-editor-tip'
45545 title: 'Hyperlink',
45546 text: 'Make the selected text a hyperlink.',
45547 cls: 'x-html-editor-tip'
45550 title: 'Source Edit',
45551 text: 'Switch to source editing mode.',
45552 cls: 'x-html-editor-tip'
45556 onDestroy : function(){
45559 this.tb.items.each(function(item){
45561 item.menu.removeAll();
45563 item.menu.el.destroy();
45571 onFirstFocus: function() {
45572 this.tb.items.each(function(item){
45581 // <script type="text/javascript">
45584 * Ext JS Library 1.1.1
45585 * Copyright(c) 2006-2007, Ext JS, LLC.
45592 * @class Roo.form.HtmlEditor.ToolbarContext
45597 new Roo.form.HtmlEditor({
45600 { xtype: 'ToolbarStandard', styles : {} }
45601 { xtype: 'ToolbarContext', disable : {} }
45607 * @config : {Object} disable List of elements to disable.. (not done yet.)
45608 * @config : {Object} styles Map of styles available.
45612 Roo.form.HtmlEditor.ToolbarContext = function(config)
45615 Roo.apply(this, config);
45616 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45617 // dont call parent... till later.
45618 this.styles = this.styles || {};
45623 Roo.form.HtmlEditor.ToolbarContext.types = {
45635 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45701 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45706 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45716 style : 'fontFamily',
45717 displayField: 'display',
45718 optname : 'font-family',
45767 // should we really allow this??
45768 // should this just be
45779 style : 'fontFamily',
45780 displayField: 'display',
45781 optname : 'font-family',
45788 style : 'fontFamily',
45789 displayField: 'display',
45790 optname : 'font-family',
45797 style : 'fontFamily',
45798 displayField: 'display',
45799 optname : 'font-family',
45810 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
45811 Roo.form.HtmlEditor.ToolbarContext.stores = false;
45813 Roo.form.HtmlEditor.ToolbarContext.options = {
45815 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
45816 [ 'Courier New', 'Courier New'],
45817 [ 'Tahoma', 'Tahoma'],
45818 [ 'Times New Roman,serif', 'Times'],
45819 [ 'Verdana','Verdana' ]
45823 // fixme - these need to be configurable..
45826 //Roo.form.HtmlEditor.ToolbarContext.types
45829 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
45836 editorcore : false,
45838 * @cfg {Object} disable List of toolbar elements to disable
45843 * @cfg {Object} styles List of styles
45844 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
45846 * These must be defined in the page, so they get rendered correctly..
45857 init : function(editor)
45859 this.editor = editor;
45860 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45861 var editorcore = this.editorcore;
45863 var fid = editorcore.frameId;
45865 function btn(id, toggle, handler){
45866 var xid = fid + '-'+ id ;
45870 cls : 'x-btn-icon x-edit-'+id,
45871 enableToggle:toggle !== false,
45872 scope: editorcore, // was editor...
45873 handler:handler||editorcore.relayBtnCmd,
45874 clickEvent:'mousedown',
45875 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45879 // create a new element.
45880 var wdiv = editor.wrap.createChild({
45882 }, editor.wrap.dom.firstChild.nextSibling, true);
45884 // can we do this more than once??
45886 // stop form submits
45889 // disable everything...
45890 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
45891 this.toolbars = {};
45893 for (var i in ty) {
45895 this.toolbars[i] = this.buildToolbar(ty[i],i);
45897 this.tb = this.toolbars.BODY;
45899 this.buildFooter();
45900 this.footer.show();
45901 editor.on('hide', function( ) { this.footer.hide() }, this);
45902 editor.on('show', function( ) { this.footer.show() }, this);
45905 this.rendered = true;
45907 // the all the btns;
45908 editor.on('editorevent', this.updateToolbar, this);
45909 // other toolbars need to implement this..
45910 //editor.on('editmodechange', this.updateToolbar, this);
45916 * Protected method that will not generally be called directly. It triggers
45917 * a toolbar update by reading the markup state of the current selection in the editor.
45919 * Note you can force an update by calling on('editorevent', scope, false)
45921 updateToolbar: function(editor,ev,sel){
45924 // capture mouse up - this is handy for selecting images..
45925 // perhaps should go somewhere else...
45926 if(!this.editorcore.activated){
45927 this.editor.onFirstFocus();
45933 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
45934 // selectNode - might want to handle IE?
45936 (ev.type == 'mouseup' || ev.type == 'click' ) &&
45937 ev.target && ev.target.tagName == 'IMG') {
45938 // they have click on an image...
45939 // let's see if we can change the selection...
45942 var nodeRange = sel.ownerDocument.createRange();
45944 nodeRange.selectNode(sel);
45946 nodeRange.selectNodeContents(sel);
45948 //nodeRange.collapse(true);
45949 var s = this.editorcore.win.getSelection();
45950 s.removeAllRanges();
45951 s.addRange(nodeRange);
45955 var updateFooter = sel ? false : true;
45958 var ans = this.editorcore.getAllAncestors();
45961 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
45964 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
45965 sel = sel ? sel : this.editorcore.doc.body;
45966 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
45969 // pick a menu that exists..
45970 var tn = sel.tagName.toUpperCase();
45971 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
45973 tn = sel.tagName.toUpperCase();
45975 var lastSel = this.tb.selectedNode;
45977 this.tb.selectedNode = sel;
45979 // if current menu does not match..
45981 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
45984 ///console.log("show: " + tn);
45985 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
45988 this.tb.items.first().el.innerHTML = tn + ': ';
45991 // update attributes
45992 if (this.tb.fields) {
45993 this.tb.fields.each(function(e) {
45995 e.setValue(sel.style[e.stylename]);
45998 e.setValue(sel.getAttribute(e.attrname));
46002 var hasStyles = false;
46003 for(var i in this.styles) {
46010 var st = this.tb.fields.item(0);
46012 st.store.removeAll();
46015 var cn = sel.className.split(/\s+/);
46018 if (this.styles['*']) {
46020 Roo.each(this.styles['*'], function(v) {
46021 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46024 if (this.styles[tn]) {
46025 Roo.each(this.styles[tn], function(v) {
46026 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46030 st.store.loadData(avs);
46034 // flag our selected Node.
46035 this.tb.selectedNode = sel;
46038 Roo.menu.MenuMgr.hideAll();
46042 if (!updateFooter) {
46043 //this.footDisp.dom.innerHTML = '';
46046 // update the footer
46050 this.footerEls = ans.reverse();
46051 Roo.each(this.footerEls, function(a,i) {
46052 if (!a) { return; }
46053 html += html.length ? ' > ' : '';
46055 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46060 var sz = this.footDisp.up('td').getSize();
46061 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46062 this.footDisp.dom.style.marginLeft = '5px';
46064 this.footDisp.dom.style.overflow = 'hidden';
46066 this.footDisp.dom.innerHTML = html;
46068 //this.editorsyncValue();
46075 onDestroy : function(){
46078 this.tb.items.each(function(item){
46080 item.menu.removeAll();
46082 item.menu.el.destroy();
46090 onFirstFocus: function() {
46091 // need to do this for all the toolbars..
46092 this.tb.items.each(function(item){
46096 buildToolbar: function(tlist, nm)
46098 var editor = this.editor;
46099 var editorcore = this.editorcore;
46100 // create a new element.
46101 var wdiv = editor.wrap.createChild({
46103 }, editor.wrap.dom.firstChild.nextSibling, true);
46106 var tb = new Roo.Toolbar(wdiv);
46109 tb.add(nm+ ": ");
46112 for(var i in this.styles) {
46117 if (styles && styles.length) {
46119 // this needs a multi-select checkbox...
46120 tb.addField( new Roo.form.ComboBox({
46121 store: new Roo.data.SimpleStore({
46123 fields: ['val', 'selected'],
46126 name : '-roo-edit-className',
46127 attrname : 'className',
46128 displayField: 'val',
46132 triggerAction: 'all',
46133 emptyText:'Select Style',
46134 selectOnFocus:true,
46137 'select': function(c, r, i) {
46138 // initial support only for on class per el..
46139 tb.selectedNode.className = r ? r.get('val') : '';
46140 editorcore.syncValue();
46147 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46148 var tbops = tbc.options;
46150 for (var i in tlist) {
46152 var item = tlist[i];
46153 tb.add(item.title + ": ");
46156 //optname == used so you can configure the options available..
46157 var opts = item.opts ? item.opts : false;
46158 if (item.optname) {
46159 opts = tbops[item.optname];
46164 // opts == pulldown..
46165 tb.addField( new Roo.form.ComboBox({
46166 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46168 fields: ['val', 'display'],
46171 name : '-roo-edit-' + i,
46173 stylename : item.style ? item.style : false,
46174 displayField: item.displayField ? item.displayField : 'val',
46175 valueField : 'val',
46177 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46179 triggerAction: 'all',
46180 emptyText:'Select',
46181 selectOnFocus:true,
46182 width: item.width ? item.width : 130,
46184 'select': function(c, r, i) {
46186 tb.selectedNode.style[c.stylename] = r.get('val');
46189 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46198 tb.addField( new Roo.form.TextField({
46201 //allowBlank:false,
46206 tb.addField( new Roo.form.TextField({
46207 name: '-roo-edit-' + i,
46214 'change' : function(f, nv, ov) {
46215 tb.selectedNode.setAttribute(f.attrname, nv);
46216 editorcore.syncValue();
46229 text: 'Stylesheets',
46232 click : function ()
46234 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46242 text: 'Remove Tag',
46245 click : function ()
46248 // undo does not work.
46250 var sn = tb.selectedNode;
46252 var pn = sn.parentNode;
46254 var stn = sn.childNodes[0];
46255 var en = sn.childNodes[sn.childNodes.length - 1 ];
46256 while (sn.childNodes.length) {
46257 var node = sn.childNodes[0];
46258 sn.removeChild(node);
46260 pn.insertBefore(node, sn);
46263 pn.removeChild(sn);
46264 var range = editorcore.createRange();
46266 range.setStart(stn,0);
46267 range.setEnd(en,0); //????
46268 //range.selectNode(sel);
46271 var selection = editorcore.getSelection();
46272 selection.removeAllRanges();
46273 selection.addRange(range);
46277 //_this.updateToolbar(null, null, pn);
46278 _this.updateToolbar(null, null, null);
46279 _this.footDisp.dom.innerHTML = '';
46289 tb.el.on('click', function(e){
46290 e.preventDefault(); // what does this do?
46292 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46295 // dont need to disable them... as they will get hidden
46300 buildFooter : function()
46303 var fel = this.editor.wrap.createChild();
46304 this.footer = new Roo.Toolbar(fel);
46305 // toolbar has scrolly on left / right?
46306 var footDisp= new Roo.Toolbar.Fill();
46312 handler : function() {
46313 _t.footDisp.scrollTo('left',0,true)
46317 this.footer.add( footDisp );
46322 handler : function() {
46324 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46328 var fel = Roo.get(footDisp.el);
46329 fel.addClass('x-editor-context');
46330 this.footDispWrap = fel;
46331 this.footDispWrap.overflow = 'hidden';
46333 this.footDisp = fel.createChild();
46334 this.footDispWrap.on('click', this.onContextClick, this)
46338 onContextClick : function (ev,dom)
46340 ev.preventDefault();
46341 var cn = dom.className;
46343 if (!cn.match(/x-ed-loc-/)) {
46346 var n = cn.split('-').pop();
46347 var ans = this.footerEls;
46351 var range = this.editorcore.createRange();
46353 range.selectNodeContents(sel);
46354 //range.selectNode(sel);
46357 var selection = this.editorcore.getSelection();
46358 selection.removeAllRanges();
46359 selection.addRange(range);
46363 this.updateToolbar(null, null, sel);
46380 * Ext JS Library 1.1.1
46381 * Copyright(c) 2006-2007, Ext JS, LLC.
46383 * Originally Released Under LGPL - original licence link has changed is not relivant.
46386 * <script type="text/javascript">
46390 * @class Roo.form.BasicForm
46391 * @extends Roo.util.Observable
46392 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46394 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46395 * @param {Object} config Configuration options
46397 Roo.form.BasicForm = function(el, config){
46398 this.allItems = [];
46399 this.childForms = [];
46400 Roo.apply(this, config);
46402 * The Roo.form.Field items in this form.
46403 * @type MixedCollection
46407 this.items = new Roo.util.MixedCollection(false, function(o){
46408 return o.id || (o.id = Roo.id());
46412 * @event beforeaction
46413 * Fires before any action is performed. Return false to cancel the action.
46414 * @param {Form} this
46415 * @param {Action} action The action to be performed
46417 beforeaction: true,
46419 * @event actionfailed
46420 * Fires when an action fails.
46421 * @param {Form} this
46422 * @param {Action} action The action that failed
46424 actionfailed : true,
46426 * @event actioncomplete
46427 * Fires when an action is completed.
46428 * @param {Form} this
46429 * @param {Action} action The action that completed
46431 actioncomplete : true
46436 Roo.form.BasicForm.superclass.constructor.call(this);
46439 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46441 * @cfg {String} method
46442 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46445 * @cfg {DataReader} reader
46446 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46447 * This is optional as there is built-in support for processing JSON.
46450 * @cfg {DataReader} errorReader
46451 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46452 * This is completely optional as there is built-in support for processing JSON.
46455 * @cfg {String} url
46456 * The URL to use for form actions if one isn't supplied in the action options.
46459 * @cfg {Boolean} fileUpload
46460 * Set to true if this form is a file upload.
46464 * @cfg {Object} baseParams
46465 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46470 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46475 activeAction : null,
46478 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46479 * or setValues() data instead of when the form was first created.
46481 trackResetOnLoad : false,
46485 * childForms - used for multi-tab forms
46488 childForms : false,
46491 * allItems - full list of fields.
46497 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46498 * element by passing it or its id or mask the form itself by passing in true.
46501 waitMsgTarget : false,
46504 initEl : function(el){
46505 this.el = Roo.get(el);
46506 this.id = this.el.id || Roo.id();
46507 this.el.on('submit', this.onSubmit, this);
46508 this.el.addClass('x-form');
46512 onSubmit : function(e){
46517 * Returns true if client-side validation on the form is successful.
46520 isValid : function(){
46522 this.items.each(function(f){
46531 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46534 isDirty : function(){
46536 this.items.each(function(f){
46546 * Returns true if any fields in this form have changed since their original load. (New version)
46550 hasChanged : function()
46553 this.items.each(function(f){
46554 if(f.hasChanged()){
46563 * Resets all hasChanged to 'false' -
46564 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46565 * So hasChanged storage is only to be used for this purpose
46568 resetHasChanged : function()
46570 this.items.each(function(f){
46571 f.resetHasChanged();
46578 * Performs a predefined action (submit or load) or custom actions you define on this form.
46579 * @param {String} actionName The name of the action type
46580 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46581 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46582 * accept other config options):
46584 Property Type Description
46585 ---------------- --------------- ----------------------------------------------------------------------------------
46586 url String The url for the action (defaults to the form's url)
46587 method String The form method to use (defaults to the form's method, or POST if not defined)
46588 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46589 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46590 validate the form on the client (defaults to false)
46592 * @return {BasicForm} this
46594 doAction : function(action, options){
46595 if(typeof action == 'string'){
46596 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46598 if(this.fireEvent('beforeaction', this, action) !== false){
46599 this.beforeAction(action);
46600 action.run.defer(100, action);
46606 * Shortcut to do a submit action.
46607 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46608 * @return {BasicForm} this
46610 submit : function(options){
46611 this.doAction('submit', options);
46616 * Shortcut to do a load action.
46617 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46618 * @return {BasicForm} this
46620 load : function(options){
46621 this.doAction('load', options);
46626 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46627 * @param {Record} record The record to edit
46628 * @return {BasicForm} this
46630 updateRecord : function(record){
46631 record.beginEdit();
46632 var fs = record.fields;
46633 fs.each(function(f){
46634 var field = this.findField(f.name);
46636 record.set(f.name, field.getValue());
46644 * Loads an Roo.data.Record into this form.
46645 * @param {Record} record The record to load
46646 * @return {BasicForm} this
46648 loadRecord : function(record){
46649 this.setValues(record.data);
46654 beforeAction : function(action){
46655 var o = action.options;
46658 if(this.waitMsgTarget === true){
46659 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46660 }else if(this.waitMsgTarget){
46661 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46662 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46664 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46670 afterAction : function(action, success){
46671 this.activeAction = null;
46672 var o = action.options;
46674 if(this.waitMsgTarget === true){
46676 }else if(this.waitMsgTarget){
46677 this.waitMsgTarget.unmask();
46679 Roo.MessageBox.updateProgress(1);
46680 Roo.MessageBox.hide();
46687 Roo.callback(o.success, o.scope, [this, action]);
46688 this.fireEvent('actioncomplete', this, action);
46692 // failure condition..
46693 // we have a scenario where updates need confirming.
46694 // eg. if a locking scenario exists..
46695 // we look for { errors : { needs_confirm : true }} in the response.
46697 (typeof(action.result) != 'undefined') &&
46698 (typeof(action.result.errors) != 'undefined') &&
46699 (typeof(action.result.errors.needs_confirm) != 'undefined')
46702 Roo.MessageBox.confirm(
46703 "Change requires confirmation",
46704 action.result.errorMsg,
46709 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46719 Roo.callback(o.failure, o.scope, [this, action]);
46720 // show an error message if no failed handler is set..
46721 if (!this.hasListener('actionfailed')) {
46722 Roo.MessageBox.alert("Error",
46723 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46724 action.result.errorMsg :
46725 "Saving Failed, please check your entries or try again"
46729 this.fireEvent('actionfailed', this, action);
46735 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46736 * @param {String} id The value to search for
46739 findField : function(id){
46740 var field = this.items.get(id);
46742 this.items.each(function(f){
46743 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
46749 return field || null;
46753 * Add a secondary form to this one,
46754 * Used to provide tabbed forms. One form is primary, with hidden values
46755 * which mirror the elements from the other forms.
46757 * @param {Roo.form.Form} form to add.
46760 addForm : function(form)
46763 if (this.childForms.indexOf(form) > -1) {
46767 this.childForms.push(form);
46769 Roo.each(form.allItems, function (fe) {
46771 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
46772 if (this.findField(n)) { // already added..
46775 var add = new Roo.form.Hidden({
46778 add.render(this.el);
46785 * Mark fields in this form invalid in bulk.
46786 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
46787 * @return {BasicForm} this
46789 markInvalid : function(errors){
46790 if(errors instanceof Array){
46791 for(var i = 0, len = errors.length; i < len; i++){
46792 var fieldError = errors[i];
46793 var f = this.findField(fieldError.id);
46795 f.markInvalid(fieldError.msg);
46801 if(typeof errors[id] != 'function' && (field = this.findField(id))){
46802 field.markInvalid(errors[id]);
46806 Roo.each(this.childForms || [], function (f) {
46807 f.markInvalid(errors);
46814 * Set values for fields in this form in bulk.
46815 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
46816 * @return {BasicForm} this
46818 setValues : function(values){
46819 if(values instanceof Array){ // array of objects
46820 for(var i = 0, len = values.length; i < len; i++){
46822 var f = this.findField(v.id);
46824 f.setValue(v.value);
46825 if(this.trackResetOnLoad){
46826 f.originalValue = f.getValue();
46830 }else{ // object hash
46833 if(typeof values[id] != 'function' && (field = this.findField(id))){
46835 if (field.setFromData &&
46836 field.valueField &&
46837 field.displayField &&
46838 // combos' with local stores can
46839 // be queried via setValue()
46840 // to set their value..
46841 (field.store && !field.store.isLocal)
46845 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
46846 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
46847 field.setFromData(sd);
46850 field.setValue(values[id]);
46854 if(this.trackResetOnLoad){
46855 field.originalValue = field.getValue();
46860 this.resetHasChanged();
46863 Roo.each(this.childForms || [], function (f) {
46864 f.setValues(values);
46865 f.resetHasChanged();
46872 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
46873 * they are returned as an array.
46874 * @param {Boolean} asString
46877 getValues : function(asString){
46878 if (this.childForms) {
46879 // copy values from the child forms
46880 Roo.each(this.childForms, function (f) {
46881 this.setValues(f.getValues());
46887 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
46888 if(asString === true){
46891 return Roo.urlDecode(fs);
46895 * Returns the fields in this form as an object with key/value pairs.
46896 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
46899 getFieldValues : function(with_hidden)
46901 if (this.childForms) {
46902 // copy values from the child forms
46903 // should this call getFieldValues - probably not as we do not currently copy
46904 // hidden fields when we generate..
46905 Roo.each(this.childForms, function (f) {
46906 this.setValues(f.getValues());
46911 this.items.each(function(f){
46912 if (!f.getName()) {
46915 var v = f.getValue();
46916 if (f.inputType =='radio') {
46917 if (typeof(ret[f.getName()]) == 'undefined') {
46918 ret[f.getName()] = ''; // empty..
46921 if (!f.el.dom.checked) {
46925 v = f.el.dom.value;
46929 // not sure if this supported any more..
46930 if ((typeof(v) == 'object') && f.getRawValue) {
46931 v = f.getRawValue() ; // dates..
46933 // combo boxes where name != hiddenName...
46934 if (f.name != f.getName()) {
46935 ret[f.name] = f.getRawValue();
46937 ret[f.getName()] = v;
46944 * Clears all invalid messages in this form.
46945 * @return {BasicForm} this
46947 clearInvalid : function(){
46948 this.items.each(function(f){
46952 Roo.each(this.childForms || [], function (f) {
46961 * Resets this form.
46962 * @return {BasicForm} this
46964 reset : function(){
46965 this.items.each(function(f){
46969 Roo.each(this.childForms || [], function (f) {
46972 this.resetHasChanged();
46978 * Add Roo.form components to this form.
46979 * @param {Field} field1
46980 * @param {Field} field2 (optional)
46981 * @param {Field} etc (optional)
46982 * @return {BasicForm} this
46985 this.items.addAll(Array.prototype.slice.call(arguments, 0));
46991 * Removes a field from the items collection (does NOT remove its markup).
46992 * @param {Field} field
46993 * @return {BasicForm} this
46995 remove : function(field){
46996 this.items.remove(field);
47001 * Looks at the fields in this form, checks them for an id attribute,
47002 * and calls applyTo on the existing dom element with that id.
47003 * @return {BasicForm} this
47005 render : function(){
47006 this.items.each(function(f){
47007 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47015 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47016 * @param {Object} values
47017 * @return {BasicForm} this
47019 applyToFields : function(o){
47020 this.items.each(function(f){
47027 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47028 * @param {Object} values
47029 * @return {BasicForm} this
47031 applyIfToFields : function(o){
47032 this.items.each(function(f){
47040 Roo.BasicForm = Roo.form.BasicForm;/*
47042 * Ext JS Library 1.1.1
47043 * Copyright(c) 2006-2007, Ext JS, LLC.
47045 * Originally Released Under LGPL - original licence link has changed is not relivant.
47048 * <script type="text/javascript">
47052 * @class Roo.form.Form
47053 * @extends Roo.form.BasicForm
47054 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47056 * @param {Object} config Configuration options
47058 Roo.form.Form = function(config){
47060 if (config.items) {
47061 xitems = config.items;
47062 delete config.items;
47066 Roo.form.Form.superclass.constructor.call(this, null, config);
47067 this.url = this.url || this.action;
47069 this.root = new Roo.form.Layout(Roo.applyIf({
47073 this.active = this.root;
47075 * Array of all the buttons that have been added to this form via {@link addButton}
47079 this.allItems = [];
47082 * @event clientvalidation
47083 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47084 * @param {Form} this
47085 * @param {Boolean} valid true if the form has passed client-side validation
47087 clientvalidation: true,
47090 * Fires when the form is rendered
47091 * @param {Roo.form.Form} form
47096 if (this.progressUrl) {
47097 // push a hidden field onto the list of fields..
47101 name : 'UPLOAD_IDENTIFIER'
47106 Roo.each(xitems, this.addxtype, this);
47112 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47114 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47117 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47120 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47122 buttonAlign:'center',
47125 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47130 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47131 * This property cascades to child containers if not set.
47136 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47137 * fires a looping event with that state. This is required to bind buttons to the valid
47138 * state using the config value formBind:true on the button.
47140 monitorValid : false,
47143 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47148 * @cfg {String} progressUrl - Url to return progress data
47151 progressUrl : false,
47154 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47155 * fields are added and the column is closed. If no fields are passed the column remains open
47156 * until end() is called.
47157 * @param {Object} config The config to pass to the column
47158 * @param {Field} field1 (optional)
47159 * @param {Field} field2 (optional)
47160 * @param {Field} etc (optional)
47161 * @return Column The column container object
47163 column : function(c){
47164 var col = new Roo.form.Column(c);
47166 if(arguments.length > 1){ // duplicate code required because of Opera
47167 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47174 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47175 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47176 * until end() is called.
47177 * @param {Object} config The config to pass to the fieldset
47178 * @param {Field} field1 (optional)
47179 * @param {Field} field2 (optional)
47180 * @param {Field} etc (optional)
47181 * @return FieldSet The fieldset container object
47183 fieldset : function(c){
47184 var fs = new Roo.form.FieldSet(c);
47186 if(arguments.length > 1){ // duplicate code required because of Opera
47187 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47194 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47195 * fields are added and the container is closed. If no fields are passed the container remains open
47196 * until end() is called.
47197 * @param {Object} config The config to pass to the Layout
47198 * @param {Field} field1 (optional)
47199 * @param {Field} field2 (optional)
47200 * @param {Field} etc (optional)
47201 * @return Layout The container object
47203 container : function(c){
47204 var l = new Roo.form.Layout(c);
47206 if(arguments.length > 1){ // duplicate code required because of Opera
47207 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47214 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47215 * @param {Object} container A Roo.form.Layout or subclass of Layout
47216 * @return {Form} this
47218 start : function(c){
47219 // cascade label info
47220 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47221 this.active.stack.push(c);
47222 c.ownerCt = this.active;
47228 * Closes the current open container
47229 * @return {Form} this
47232 if(this.active == this.root){
47235 this.active = this.active.ownerCt;
47240 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47241 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47242 * as the label of the field.
47243 * @param {Field} field1
47244 * @param {Field} field2 (optional)
47245 * @param {Field} etc. (optional)
47246 * @return {Form} this
47249 this.active.stack.push.apply(this.active.stack, arguments);
47250 this.allItems.push.apply(this.allItems,arguments);
47252 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47253 if(a[i].isFormField){
47258 Roo.form.Form.superclass.add.apply(this, r);
47268 * Find any element that has been added to a form, using it's ID or name
47269 * This can include framesets, columns etc. along with regular fields..
47270 * @param {String} id - id or name to find.
47272 * @return {Element} e - or false if nothing found.
47274 findbyId : function(id)
47280 Roo.each(this.allItems, function(f){
47281 if (f.id == id || f.name == id ){
47292 * Render this form into the passed container. This should only be called once!
47293 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47294 * @return {Form} this
47296 render : function(ct)
47302 var o = this.autoCreate || {
47304 method : this.method || 'POST',
47305 id : this.id || Roo.id()
47307 this.initEl(ct.createChild(o));
47309 this.root.render(this.el);
47313 this.items.each(function(f){
47314 f.render('x-form-el-'+f.id);
47317 if(this.buttons.length > 0){
47318 // tables are required to maintain order and for correct IE layout
47319 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47320 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47321 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47323 var tr = tb.getElementsByTagName('tr')[0];
47324 for(var i = 0, len = this.buttons.length; i < len; i++) {
47325 var b = this.buttons[i];
47326 var td = document.createElement('td');
47327 td.className = 'x-form-btn-td';
47328 b.render(tr.appendChild(td));
47331 if(this.monitorValid){ // initialize after render
47332 this.startMonitoring();
47334 this.fireEvent('rendered', this);
47339 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47340 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47341 * object or a valid Roo.DomHelper element config
47342 * @param {Function} handler The function called when the button is clicked
47343 * @param {Object} scope (optional) The scope of the handler function
47344 * @return {Roo.Button}
47346 addButton : function(config, handler, scope){
47350 minWidth: this.minButtonWidth,
47353 if(typeof config == "string"){
47356 Roo.apply(bc, config);
47358 var btn = new Roo.Button(null, bc);
47359 this.buttons.push(btn);
47364 * Adds a series of form elements (using the xtype property as the factory method.
47365 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47366 * @param {Object} config
47369 addxtype : function()
47371 var ar = Array.prototype.slice.call(arguments, 0);
47373 for(var i = 0; i < ar.length; i++) {
47375 continue; // skip -- if this happends something invalid got sent, we
47376 // should ignore it, as basically that interface element will not show up
47377 // and that should be pretty obvious!!
47380 if (Roo.form[ar[i].xtype]) {
47382 var fe = Roo.factory(ar[i], Roo.form);
47388 fe.store.form = this;
47393 this.allItems.push(fe);
47394 if (fe.items && fe.addxtype) {
47395 fe.addxtype.apply(fe, fe.items);
47405 // console.log('adding ' + ar[i].xtype);
47407 if (ar[i].xtype == 'Button') {
47408 //console.log('adding button');
47409 //console.log(ar[i]);
47410 this.addButton(ar[i]);
47411 this.allItems.push(fe);
47415 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47416 alert('end is not supported on xtype any more, use items');
47418 // //console.log('adding end');
47426 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47427 * option "monitorValid"
47429 startMonitoring : function(){
47432 Roo.TaskMgr.start({
47433 run : this.bindHandler,
47434 interval : this.monitorPoll || 200,
47441 * Stops monitoring of the valid state of this form
47443 stopMonitoring : function(){
47444 this.bound = false;
47448 bindHandler : function(){
47450 return false; // stops binding
47453 this.items.each(function(f){
47454 if(!f.isValid(true)){
47459 for(var i = 0, len = this.buttons.length; i < len; i++){
47460 var btn = this.buttons[i];
47461 if(btn.formBind === true && btn.disabled === valid){
47462 btn.setDisabled(!valid);
47465 this.fireEvent('clientvalidation', this, valid);
47479 Roo.Form = Roo.form.Form;
47482 * Ext JS Library 1.1.1
47483 * Copyright(c) 2006-2007, Ext JS, LLC.
47485 * Originally Released Under LGPL - original licence link has changed is not relivant.
47488 * <script type="text/javascript">
47491 // as we use this in bootstrap.
47492 Roo.namespace('Roo.form');
47494 * @class Roo.form.Action
47495 * Internal Class used to handle form actions
47497 * @param {Roo.form.BasicForm} el The form element or its id
47498 * @param {Object} config Configuration options
47503 // define the action interface
47504 Roo.form.Action = function(form, options){
47506 this.options = options || {};
47509 * Client Validation Failed
47512 Roo.form.Action.CLIENT_INVALID = 'client';
47514 * Server Validation Failed
47517 Roo.form.Action.SERVER_INVALID = 'server';
47519 * Connect to Server Failed
47522 Roo.form.Action.CONNECT_FAILURE = 'connect';
47524 * Reading Data from Server Failed
47527 Roo.form.Action.LOAD_FAILURE = 'load';
47529 Roo.form.Action.prototype = {
47531 failureType : undefined,
47532 response : undefined,
47533 result : undefined,
47535 // interface method
47536 run : function(options){
47540 // interface method
47541 success : function(response){
47545 // interface method
47546 handleResponse : function(response){
47550 // default connection failure
47551 failure : function(response){
47553 this.response = response;
47554 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47555 this.form.afterAction(this, false);
47558 processResponse : function(response){
47559 this.response = response;
47560 if(!response.responseText){
47563 this.result = this.handleResponse(response);
47564 return this.result;
47567 // utility functions used internally
47568 getUrl : function(appendParams){
47569 var url = this.options.url || this.form.url || this.form.el.dom.action;
47571 var p = this.getParams();
47573 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47579 getMethod : function(){
47580 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47583 getParams : function(){
47584 var bp = this.form.baseParams;
47585 var p = this.options.params;
47587 if(typeof p == "object"){
47588 p = Roo.urlEncode(Roo.applyIf(p, bp));
47589 }else if(typeof p == 'string' && bp){
47590 p += '&' + Roo.urlEncode(bp);
47593 p = Roo.urlEncode(bp);
47598 createCallback : function(){
47600 success: this.success,
47601 failure: this.failure,
47603 timeout: (this.form.timeout*1000),
47604 upload: this.form.fileUpload ? this.success : undefined
47609 Roo.form.Action.Submit = function(form, options){
47610 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47613 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47616 haveProgress : false,
47617 uploadComplete : false,
47619 // uploadProgress indicator.
47620 uploadProgress : function()
47622 if (!this.form.progressUrl) {
47626 if (!this.haveProgress) {
47627 Roo.MessageBox.progress("Uploading", "Uploading");
47629 if (this.uploadComplete) {
47630 Roo.MessageBox.hide();
47634 this.haveProgress = true;
47636 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47638 var c = new Roo.data.Connection();
47640 url : this.form.progressUrl,
47645 success : function(req){
47646 //console.log(data);
47650 rdata = Roo.decode(req.responseText)
47652 Roo.log("Invalid data from server..");
47656 if (!rdata || !rdata.success) {
47658 Roo.MessageBox.alert(Roo.encode(rdata));
47661 var data = rdata.data;
47663 if (this.uploadComplete) {
47664 Roo.MessageBox.hide();
47669 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47670 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47673 this.uploadProgress.defer(2000,this);
47676 failure: function(data) {
47677 Roo.log('progress url failed ');
47688 // run get Values on the form, so it syncs any secondary forms.
47689 this.form.getValues();
47691 var o = this.options;
47692 var method = this.getMethod();
47693 var isPost = method == 'POST';
47694 if(o.clientValidation === false || this.form.isValid()){
47696 if (this.form.progressUrl) {
47697 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47698 (new Date() * 1) + '' + Math.random());
47703 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47704 form:this.form.el.dom,
47705 url:this.getUrl(!isPost),
47707 params:isPost ? this.getParams() : null,
47708 isUpload: this.form.fileUpload
47711 this.uploadProgress();
47713 }else if (o.clientValidation !== false){ // client validation failed
47714 this.failureType = Roo.form.Action.CLIENT_INVALID;
47715 this.form.afterAction(this, false);
47719 success : function(response)
47721 this.uploadComplete= true;
47722 if (this.haveProgress) {
47723 Roo.MessageBox.hide();
47727 var result = this.processResponse(response);
47728 if(result === true || result.success){
47729 this.form.afterAction(this, true);
47733 this.form.markInvalid(result.errors);
47734 this.failureType = Roo.form.Action.SERVER_INVALID;
47736 this.form.afterAction(this, false);
47738 failure : function(response)
47740 this.uploadComplete= true;
47741 if (this.haveProgress) {
47742 Roo.MessageBox.hide();
47745 this.response = response;
47746 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47747 this.form.afterAction(this, false);
47750 handleResponse : function(response){
47751 if(this.form.errorReader){
47752 var rs = this.form.errorReader.read(response);
47755 for(var i = 0, len = rs.records.length; i < len; i++) {
47756 var r = rs.records[i];
47757 errors[i] = r.data;
47760 if(errors.length < 1){
47764 success : rs.success,
47770 ret = Roo.decode(response.responseText);
47774 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
47784 Roo.form.Action.Load = function(form, options){
47785 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
47786 this.reader = this.form.reader;
47789 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
47794 Roo.Ajax.request(Roo.apply(
47795 this.createCallback(), {
47796 method:this.getMethod(),
47797 url:this.getUrl(false),
47798 params:this.getParams()
47802 success : function(response){
47804 var result = this.processResponse(response);
47805 if(result === true || !result.success || !result.data){
47806 this.failureType = Roo.form.Action.LOAD_FAILURE;
47807 this.form.afterAction(this, false);
47810 this.form.clearInvalid();
47811 this.form.setValues(result.data);
47812 this.form.afterAction(this, true);
47815 handleResponse : function(response){
47816 if(this.form.reader){
47817 var rs = this.form.reader.read(response);
47818 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
47820 success : rs.success,
47824 return Roo.decode(response.responseText);
47828 Roo.form.Action.ACTION_TYPES = {
47829 'load' : Roo.form.Action.Load,
47830 'submit' : Roo.form.Action.Submit
47833 * Ext JS Library 1.1.1
47834 * Copyright(c) 2006-2007, Ext JS, LLC.
47836 * Originally Released Under LGPL - original licence link has changed is not relivant.
47839 * <script type="text/javascript">
47843 * @class Roo.form.Layout
47844 * @extends Roo.Component
47845 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
47847 * @param {Object} config Configuration options
47849 Roo.form.Layout = function(config){
47851 if (config.items) {
47852 xitems = config.items;
47853 delete config.items;
47855 Roo.form.Layout.superclass.constructor.call(this, config);
47857 Roo.each(xitems, this.addxtype, this);
47861 Roo.extend(Roo.form.Layout, Roo.Component, {
47863 * @cfg {String/Object} autoCreate
47864 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
47867 * @cfg {String/Object/Function} style
47868 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
47869 * a function which returns such a specification.
47872 * @cfg {String} labelAlign
47873 * Valid values are "left," "top" and "right" (defaults to "left")
47876 * @cfg {Number} labelWidth
47877 * Fixed width in pixels of all field labels (defaults to undefined)
47880 * @cfg {Boolean} clear
47881 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
47885 * @cfg {String} labelSeparator
47886 * The separator to use after field labels (defaults to ':')
47888 labelSeparator : ':',
47890 * @cfg {Boolean} hideLabels
47891 * True to suppress the display of field labels in this layout (defaults to false)
47893 hideLabels : false,
47896 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
47901 onRender : function(ct, position){
47902 if(this.el){ // from markup
47903 this.el = Roo.get(this.el);
47904 }else { // generate
47905 var cfg = this.getAutoCreate();
47906 this.el = ct.createChild(cfg, position);
47909 this.el.applyStyles(this.style);
47911 if(this.labelAlign){
47912 this.el.addClass('x-form-label-'+this.labelAlign);
47914 if(this.hideLabels){
47915 this.labelStyle = "display:none";
47916 this.elementStyle = "padding-left:0;";
47918 if(typeof this.labelWidth == 'number'){
47919 this.labelStyle = "width:"+this.labelWidth+"px;";
47920 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
47922 if(this.labelAlign == 'top'){
47923 this.labelStyle = "width:auto;";
47924 this.elementStyle = "padding-left:0;";
47927 var stack = this.stack;
47928 var slen = stack.length;
47930 if(!this.fieldTpl){
47931 var t = new Roo.Template(
47932 '<div class="x-form-item {5}">',
47933 '<label for="{0}" style="{2}">{1}{4}</label>',
47934 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
47936 '</div><div class="x-form-clear-left"></div>'
47938 t.disableFormats = true;
47940 Roo.form.Layout.prototype.fieldTpl = t;
47942 for(var i = 0; i < slen; i++) {
47943 if(stack[i].isFormField){
47944 this.renderField(stack[i]);
47946 this.renderComponent(stack[i]);
47951 this.el.createChild({cls:'x-form-clear'});
47956 renderField : function(f){
47957 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
47960 f.labelStyle||this.labelStyle||'', //2
47961 this.elementStyle||'', //3
47962 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
47963 f.itemCls||this.itemCls||'' //5
47964 ], true).getPrevSibling());
47968 renderComponent : function(c){
47969 c.render(c.isLayout ? this.el : this.el.createChild());
47972 * Adds a object form elements (using the xtype property as the factory method.)
47973 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
47974 * @param {Object} config
47976 addxtype : function(o)
47978 // create the lement.
47979 o.form = this.form;
47980 var fe = Roo.factory(o, Roo.form);
47981 this.form.allItems.push(fe);
47982 this.stack.push(fe);
47984 if (fe.isFormField) {
47985 this.form.items.add(fe);
47993 * @class Roo.form.Column
47994 * @extends Roo.form.Layout
47995 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
47997 * @param {Object} config Configuration options
47999 Roo.form.Column = function(config){
48000 Roo.form.Column.superclass.constructor.call(this, config);
48003 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48005 * @cfg {Number/String} width
48006 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48009 * @cfg {String/Object} autoCreate
48010 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48014 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48017 onRender : function(ct, position){
48018 Roo.form.Column.superclass.onRender.call(this, ct, position);
48020 this.el.setWidth(this.width);
48027 * @class Roo.form.Row
48028 * @extends Roo.form.Layout
48029 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48031 * @param {Object} config Configuration options
48035 Roo.form.Row = function(config){
48036 Roo.form.Row.superclass.constructor.call(this, config);
48039 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48041 * @cfg {Number/String} width
48042 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48045 * @cfg {Number/String} height
48046 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48048 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48052 onRender : function(ct, position){
48053 //console.log('row render');
48055 var t = new Roo.Template(
48056 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48057 '<label for="{0}" style="{2}">{1}{4}</label>',
48058 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48062 t.disableFormats = true;
48064 Roo.form.Layout.prototype.rowTpl = t;
48066 this.fieldTpl = this.rowTpl;
48068 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48069 var labelWidth = 100;
48071 if ((this.labelAlign != 'top')) {
48072 if (typeof this.labelWidth == 'number') {
48073 labelWidth = this.labelWidth
48075 this.padWidth = 20 + labelWidth;
48079 Roo.form.Column.superclass.onRender.call(this, ct, position);
48081 this.el.setWidth(this.width);
48084 this.el.setHeight(this.height);
48089 renderField : function(f){
48090 f.fieldEl = this.fieldTpl.append(this.el, [
48091 f.id, f.fieldLabel,
48092 f.labelStyle||this.labelStyle||'',
48093 this.elementStyle||'',
48094 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48095 f.itemCls||this.itemCls||'',
48096 f.width ? f.width + this.padWidth : 160 + this.padWidth
48103 * @class Roo.form.FieldSet
48104 * @extends Roo.form.Layout
48105 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48107 * @param {Object} config Configuration options
48109 Roo.form.FieldSet = function(config){
48110 Roo.form.FieldSet.superclass.constructor.call(this, config);
48113 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48115 * @cfg {String} legend
48116 * The text to display as the legend for the FieldSet (defaults to '')
48119 * @cfg {String/Object} autoCreate
48120 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48124 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48127 onRender : function(ct, position){
48128 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48130 this.setLegend(this.legend);
48135 setLegend : function(text){
48137 this.el.child('legend').update(text);
48142 * Ext JS Library 1.1.1
48143 * Copyright(c) 2006-2007, Ext JS, LLC.
48145 * Originally Released Under LGPL - original licence link has changed is not relivant.
48148 * <script type="text/javascript">
48151 * @class Roo.form.VTypes
48152 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48155 Roo.form.VTypes = function(){
48156 // closure these in so they are only created once.
48157 var alpha = /^[a-zA-Z_]+$/;
48158 var alphanum = /^[a-zA-Z0-9_]+$/;
48159 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48160 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48162 // All these messages and functions are configurable
48165 * The function used to validate email addresses
48166 * @param {String} value The email address
48168 'email' : function(v){
48169 return email.test(v);
48172 * The error text to display when the email validation function returns false
48175 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48177 * The keystroke filter mask to be applied on email input
48180 'emailMask' : /[a-z0-9_\.\-@]/i,
48183 * The function used to validate URLs
48184 * @param {String} value The URL
48186 'url' : function(v){
48187 return url.test(v);
48190 * The error text to display when the url validation function returns false
48193 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48196 * The function used to validate alpha values
48197 * @param {String} value The value
48199 'alpha' : function(v){
48200 return alpha.test(v);
48203 * The error text to display when the alpha validation function returns false
48206 'alphaText' : 'This field should only contain letters and _',
48208 * The keystroke filter mask to be applied on alpha input
48211 'alphaMask' : /[a-z_]/i,
48214 * The function used to validate alphanumeric values
48215 * @param {String} value The value
48217 'alphanum' : function(v){
48218 return alphanum.test(v);
48221 * The error text to display when the alphanumeric validation function returns false
48224 'alphanumText' : 'This field should only contain letters, numbers and _',
48226 * The keystroke filter mask to be applied on alphanumeric input
48229 'alphanumMask' : /[a-z0-9_]/i
48231 }();//<script type="text/javascript">
48234 * @class Roo.form.FCKeditor
48235 * @extends Roo.form.TextArea
48236 * Wrapper around the FCKEditor http://www.fckeditor.net
48238 * Creates a new FCKeditor
48239 * @param {Object} config Configuration options
48241 Roo.form.FCKeditor = function(config){
48242 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48245 * @event editorinit
48246 * Fired when the editor is initialized - you can add extra handlers here..
48247 * @param {FCKeditor} this
48248 * @param {Object} the FCK object.
48255 Roo.form.FCKeditor.editors = { };
48256 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48258 //defaultAutoCreate : {
48259 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48263 * @cfg {Object} fck options - see fck manual for details.
48268 * @cfg {Object} fck toolbar set (Basic or Default)
48270 toolbarSet : 'Basic',
48272 * @cfg {Object} fck BasePath
48274 basePath : '/fckeditor/',
48282 onRender : function(ct, position)
48285 this.defaultAutoCreate = {
48287 style:"width:300px;height:60px;",
48288 autocomplete: "new-password"
48291 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48294 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48295 if(this.preventScrollbars){
48296 this.el.setStyle("overflow", "hidden");
48298 this.el.setHeight(this.growMin);
48301 //console.log('onrender' + this.getId() );
48302 Roo.form.FCKeditor.editors[this.getId()] = this;
48305 this.replaceTextarea() ;
48309 getEditor : function() {
48310 return this.fckEditor;
48313 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48314 * @param {Mixed} value The value to set
48318 setValue : function(value)
48320 //console.log('setValue: ' + value);
48322 if(typeof(value) == 'undefined') { // not sure why this is happending...
48325 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48327 //if(!this.el || !this.getEditor()) {
48328 // this.value = value;
48329 //this.setValue.defer(100,this,[value]);
48333 if(!this.getEditor()) {
48337 this.getEditor().SetData(value);
48344 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48345 * @return {Mixed} value The field value
48347 getValue : function()
48350 if (this.frame && this.frame.dom.style.display == 'none') {
48351 return Roo.form.FCKeditor.superclass.getValue.call(this);
48354 if(!this.el || !this.getEditor()) {
48356 // this.getValue.defer(100,this);
48361 var value=this.getEditor().GetData();
48362 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48363 return Roo.form.FCKeditor.superclass.getValue.call(this);
48369 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48370 * @return {Mixed} value The field value
48372 getRawValue : function()
48374 if (this.frame && this.frame.dom.style.display == 'none') {
48375 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48378 if(!this.el || !this.getEditor()) {
48379 //this.getRawValue.defer(100,this);
48386 var value=this.getEditor().GetData();
48387 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48388 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48392 setSize : function(w,h) {
48396 //if (this.frame && this.frame.dom.style.display == 'none') {
48397 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48400 //if(!this.el || !this.getEditor()) {
48401 // this.setSize.defer(100,this, [w,h]);
48407 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48409 this.frame.dom.setAttribute('width', w);
48410 this.frame.dom.setAttribute('height', h);
48411 this.frame.setSize(w,h);
48415 toggleSourceEdit : function(value) {
48419 this.el.dom.style.display = value ? '' : 'none';
48420 this.frame.dom.style.display = value ? 'none' : '';
48425 focus: function(tag)
48427 if (this.frame.dom.style.display == 'none') {
48428 return Roo.form.FCKeditor.superclass.focus.call(this);
48430 if(!this.el || !this.getEditor()) {
48431 this.focus.defer(100,this, [tag]);
48438 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48439 this.getEditor().Focus();
48441 if (!this.getEditor().Selection.GetSelection()) {
48442 this.focus.defer(100,this, [tag]);
48447 var r = this.getEditor().EditorDocument.createRange();
48448 r.setStart(tgs[0],0);
48449 r.setEnd(tgs[0],0);
48450 this.getEditor().Selection.GetSelection().removeAllRanges();
48451 this.getEditor().Selection.GetSelection().addRange(r);
48452 this.getEditor().Focus();
48459 replaceTextarea : function()
48461 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48464 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48466 // We must check the elements firstly using the Id and then the name.
48467 var oTextarea = document.getElementById( this.getId() );
48469 var colElementsByName = document.getElementsByName( this.getId() ) ;
48471 oTextarea.style.display = 'none' ;
48473 if ( oTextarea.tabIndex ) {
48474 this.TabIndex = oTextarea.tabIndex ;
48477 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48478 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48479 this.frame = Roo.get(this.getId() + '___Frame')
48482 _getConfigHtml : function()
48486 for ( var o in this.fckconfig ) {
48487 sConfig += sConfig.length > 0 ? '&' : '';
48488 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48491 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48495 _getIFrameHtml : function()
48497 var sFile = 'fckeditor.html' ;
48498 /* no idea what this is about..
48501 if ( (/fcksource=true/i).test( window.top.location.search ) )
48502 sFile = 'fckeditor.original.html' ;
48507 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48508 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48511 var html = '<iframe id="' + this.getId() +
48512 '___Frame" src="' + sLink +
48513 '" width="' + this.width +
48514 '" height="' + this.height + '"' +
48515 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48516 ' frameborder="0" scrolling="no"></iframe>' ;
48521 _insertHtmlBefore : function( html, element )
48523 if ( element.insertAdjacentHTML ) {
48525 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48527 var oRange = document.createRange() ;
48528 oRange.setStartBefore( element ) ;
48529 var oFragment = oRange.createContextualFragment( html );
48530 element.parentNode.insertBefore( oFragment, element ) ;
48543 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48545 function FCKeditor_OnComplete(editorInstance){
48546 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48547 f.fckEditor = editorInstance;
48548 //console.log("loaded");
48549 f.fireEvent('editorinit', f, editorInstance);
48569 //<script type="text/javascript">
48571 * @class Roo.form.GridField
48572 * @extends Roo.form.Field
48573 * Embed a grid (or editable grid into a form)
48576 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48578 * xgrid.store = Roo.data.Store
48579 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48580 * xgrid.store.reader = Roo.data.JsonReader
48584 * Creates a new GridField
48585 * @param {Object} config Configuration options
48587 Roo.form.GridField = function(config){
48588 Roo.form.GridField.superclass.constructor.call(this, config);
48592 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48594 * @cfg {Number} width - used to restrict width of grid..
48598 * @cfg {Number} height - used to restrict height of grid..
48602 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48608 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48609 * {tag: "input", type: "checkbox", autocomplete: "off"})
48611 // defaultAutoCreate : { tag: 'div' },
48612 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48614 * @cfg {String} addTitle Text to include for adding a title.
48618 onResize : function(){
48619 Roo.form.Field.superclass.onResize.apply(this, arguments);
48622 initEvents : function(){
48623 // Roo.form.Checkbox.superclass.initEvents.call(this);
48624 // has no events...
48629 getResizeEl : function(){
48633 getPositionEl : function(){
48638 onRender : function(ct, position){
48640 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48641 var style = this.style;
48644 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48645 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48646 this.viewEl = this.wrap.createChild({ tag: 'div' });
48648 this.viewEl.applyStyles(style);
48651 this.viewEl.setWidth(this.width);
48654 this.viewEl.setHeight(this.height);
48656 //if(this.inputValue !== undefined){
48657 //this.setValue(this.value);
48660 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48663 this.grid.render();
48664 this.grid.getDataSource().on('remove', this.refreshValue, this);
48665 this.grid.getDataSource().on('update', this.refreshValue, this);
48666 this.grid.on('afteredit', this.refreshValue, this);
48672 * Sets the value of the item.
48673 * @param {String} either an object or a string..
48675 setValue : function(v){
48677 v = v || []; // empty set..
48678 // this does not seem smart - it really only affects memoryproxy grids..
48679 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48680 var ds = this.grid.getDataSource();
48681 // assumes a json reader..
48683 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48684 ds.loadData( data);
48686 // clear selection so it does not get stale.
48687 if (this.grid.sm) {
48688 this.grid.sm.clearSelections();
48691 Roo.form.GridField.superclass.setValue.call(this, v);
48692 this.refreshValue();
48693 // should load data in the grid really....
48697 refreshValue: function() {
48699 this.grid.getDataSource().each(function(r) {
48702 this.el.dom.value = Roo.encode(val);
48710 * Ext JS Library 1.1.1
48711 * Copyright(c) 2006-2007, Ext JS, LLC.
48713 * Originally Released Under LGPL - original licence link has changed is not relivant.
48716 * <script type="text/javascript">
48719 * @class Roo.form.DisplayField
48720 * @extends Roo.form.Field
48721 * A generic Field to display non-editable data.
48722 * @cfg {Boolean} closable (true|false) default false
48724 * Creates a new Display Field item.
48725 * @param {Object} config Configuration options
48727 Roo.form.DisplayField = function(config){
48728 Roo.form.DisplayField.superclass.constructor.call(this, config);
48733 * Fires after the click the close btn
48734 * @param {Roo.form.DisplayField} this
48740 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
48741 inputType: 'hidden',
48747 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48749 focusClass : undefined,
48751 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48753 fieldClass: 'x-form-field',
48756 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
48758 valueRenderer: undefined,
48762 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48763 * {tag: "input", type: "checkbox", autocomplete: "off"})
48766 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
48770 onResize : function(){
48771 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
48775 initEvents : function(){
48776 // Roo.form.Checkbox.superclass.initEvents.call(this);
48777 // has no events...
48780 this.closeEl.on('click', this.onClose, this);
48786 getResizeEl : function(){
48790 getPositionEl : function(){
48795 onRender : function(ct, position){
48797 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
48798 //if(this.inputValue !== undefined){
48799 this.wrap = this.el.wrap();
48801 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
48804 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
48807 if (this.bodyStyle) {
48808 this.viewEl.applyStyles(this.bodyStyle);
48810 //this.viewEl.setStyle('padding', '2px');
48812 this.setValue(this.value);
48817 initValue : Roo.emptyFn,
48822 onClick : function(){
48827 * Sets the checked state of the checkbox.
48828 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
48830 setValue : function(v){
48832 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
48833 // this might be called before we have a dom element..
48834 if (!this.viewEl) {
48837 this.viewEl.dom.innerHTML = html;
48838 Roo.form.DisplayField.superclass.setValue.call(this, v);
48842 onClose : function(e)
48844 e.preventDefault();
48846 this.fireEvent('close', this);
48855 * @class Roo.form.DayPicker
48856 * @extends Roo.form.Field
48857 * A Day picker show [M] [T] [W] ....
48859 * Creates a new Day Picker
48860 * @param {Object} config Configuration options
48862 Roo.form.DayPicker= function(config){
48863 Roo.form.DayPicker.superclass.constructor.call(this, config);
48867 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
48869 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48871 focusClass : undefined,
48873 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48875 fieldClass: "x-form-field",
48878 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48879 * {tag: "input", type: "checkbox", autocomplete: "off"})
48881 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
48884 actionMode : 'viewEl',
48888 inputType : 'hidden',
48891 inputElement: false, // real input element?
48892 basedOn: false, // ????
48894 isFormField: true, // not sure where this is needed!!!!
48896 onResize : function(){
48897 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
48898 if(!this.boxLabel){
48899 this.el.alignTo(this.wrap, 'c-c');
48903 initEvents : function(){
48904 Roo.form.Checkbox.superclass.initEvents.call(this);
48905 this.el.on("click", this.onClick, this);
48906 this.el.on("change", this.onClick, this);
48910 getResizeEl : function(){
48914 getPositionEl : function(){
48920 onRender : function(ct, position){
48921 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
48923 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
48925 var r1 = '<table><tr>';
48926 var r2 = '<tr class="x-form-daypick-icons">';
48927 for (var i=0; i < 7; i++) {
48928 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
48929 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
48932 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
48933 viewEl.select('img').on('click', this.onClick, this);
48934 this.viewEl = viewEl;
48937 // this will not work on Chrome!!!
48938 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
48939 this.el.on('propertychange', this.setFromHidden, this); //ie
48947 initValue : Roo.emptyFn,
48950 * Returns the checked state of the checkbox.
48951 * @return {Boolean} True if checked, else false
48953 getValue : function(){
48954 return this.el.dom.value;
48959 onClick : function(e){
48960 //this.setChecked(!this.checked);
48961 Roo.get(e.target).toggleClass('x-menu-item-checked');
48962 this.refreshValue();
48963 //if(this.el.dom.checked != this.checked){
48964 // this.setValue(this.el.dom.checked);
48969 refreshValue : function()
48972 this.viewEl.select('img',true).each(function(e,i,n) {
48973 val += e.is(".x-menu-item-checked") ? String(n) : '';
48975 this.setValue(val, true);
48979 * Sets the checked state of the checkbox.
48980 * On is always based on a string comparison between inputValue and the param.
48981 * @param {Boolean/String} value - the value to set
48982 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
48984 setValue : function(v,suppressEvent){
48985 if (!this.el.dom) {
48988 var old = this.el.dom.value ;
48989 this.el.dom.value = v;
48990 if (suppressEvent) {
48994 // update display..
48995 this.viewEl.select('img',true).each(function(e,i,n) {
48997 var on = e.is(".x-menu-item-checked");
48998 var newv = v.indexOf(String(n)) > -1;
49000 e.toggleClass('x-menu-item-checked');
49006 this.fireEvent('change', this, v, old);
49011 // handle setting of hidden value by some other method!!?!?
49012 setFromHidden: function()
49017 //console.log("SET FROM HIDDEN");
49018 //alert('setFrom hidden');
49019 this.setValue(this.el.dom.value);
49022 onDestroy : function()
49025 Roo.get(this.viewEl).remove();
49028 Roo.form.DayPicker.superclass.onDestroy.call(this);
49032 * RooJS Library 1.1.1
49033 * Copyright(c) 2008-2011 Alan Knowles
49040 * @class Roo.form.ComboCheck
49041 * @extends Roo.form.ComboBox
49042 * A combobox for multiple select items.
49044 * FIXME - could do with a reset button..
49047 * Create a new ComboCheck
49048 * @param {Object} config Configuration options
49050 Roo.form.ComboCheck = function(config){
49051 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49052 // should verify some data...
49054 // hiddenName = required..
49055 // displayField = required
49056 // valudField == required
49057 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49059 Roo.each(req, function(e) {
49060 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49061 throw "Roo.form.ComboCheck : missing value for: " + e;
49068 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49073 selectedClass: 'x-menu-item-checked',
49076 onRender : function(ct, position){
49082 var cls = 'x-combo-list';
49085 this.tpl = new Roo.Template({
49086 html : '<div class="'+cls+'-item x-menu-check-item">' +
49087 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49088 '<span>{' + this.displayField + '}</span>' +
49095 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49096 this.view.singleSelect = false;
49097 this.view.multiSelect = true;
49098 this.view.toggleSelect = true;
49099 this.pageTb.add(new Roo.Toolbar.Fill(), {
49102 handler: function()
49109 onViewOver : function(e, t){
49115 onViewClick : function(doFocus,index){
49119 select: function () {
49120 //Roo.log("SELECT CALLED");
49123 selectByValue : function(xv, scrollIntoView){
49124 var ar = this.getValueArray();
49127 Roo.each(ar, function(v) {
49128 if(v === undefined || v === null){
49131 var r = this.findRecord(this.valueField, v);
49133 sels.push(this.store.indexOf(r))
49137 this.view.select(sels);
49143 onSelect : function(record, index){
49144 // Roo.log("onselect Called");
49145 // this is only called by the clear button now..
49146 this.view.clearSelections();
49147 this.setValue('[]');
49148 if (this.value != this.valueBefore) {
49149 this.fireEvent('change', this, this.value, this.valueBefore);
49150 this.valueBefore = this.value;
49153 getValueArray : function()
49158 //Roo.log(this.value);
49159 if (typeof(this.value) == 'undefined') {
49162 var ar = Roo.decode(this.value);
49163 return ar instanceof Array ? ar : []; //?? valid?
49166 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49171 expand : function ()
49174 Roo.form.ComboCheck.superclass.expand.call(this);
49175 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49176 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49181 collapse : function(){
49182 Roo.form.ComboCheck.superclass.collapse.call(this);
49183 var sl = this.view.getSelectedIndexes();
49184 var st = this.store;
49188 Roo.each(sl, function(i) {
49190 nv.push(r.get(this.valueField));
49192 this.setValue(Roo.encode(nv));
49193 if (this.value != this.valueBefore) {
49195 this.fireEvent('change', this, this.value, this.valueBefore);
49196 this.valueBefore = this.value;
49201 setValue : function(v){
49205 var vals = this.getValueArray();
49207 Roo.each(vals, function(k) {
49208 var r = this.findRecord(this.valueField, k);
49210 tv.push(r.data[this.displayField]);
49211 }else if(this.valueNotFoundText !== undefined){
49212 tv.push( this.valueNotFoundText );
49217 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49218 this.hiddenField.value = v;
49224 * Ext JS Library 1.1.1
49225 * Copyright(c) 2006-2007, Ext JS, LLC.
49227 * Originally Released Under LGPL - original licence link has changed is not relivant.
49230 * <script type="text/javascript">
49234 * @class Roo.form.Signature
49235 * @extends Roo.form.Field
49239 * @param {Object} config Configuration options
49242 Roo.form.Signature = function(config){
49243 Roo.form.Signature.superclass.constructor.call(this, config);
49245 this.addEvents({// not in used??
49248 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49249 * @param {Roo.form.Signature} combo This combo box
49254 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49255 * @param {Roo.form.ComboBox} combo This combo box
49256 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49262 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49264 * @cfg {Object} labels Label to use when rendering a form.
49268 * confirm : "Confirm"
49273 confirm : "Confirm"
49276 * @cfg {Number} width The signature panel width (defaults to 300)
49280 * @cfg {Number} height The signature panel height (defaults to 100)
49284 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49286 allowBlank : false,
49289 // {Object} signPanel The signature SVG panel element (defaults to {})
49291 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49292 isMouseDown : false,
49293 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49294 isConfirmed : false,
49295 // {String} signatureTmp SVG mapping string (defaults to empty string)
49299 defaultAutoCreate : { // modified by initCompnoent..
49305 onRender : function(ct, position){
49307 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49309 this.wrap = this.el.wrap({
49310 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49313 this.createToolbar(this);
49314 this.signPanel = this.wrap.createChild({
49316 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49320 this.svgID = Roo.id();
49321 this.svgEl = this.signPanel.createChild({
49322 xmlns : 'http://www.w3.org/2000/svg',
49324 id : this.svgID + "-svg",
49326 height: this.height,
49327 viewBox: '0 0 '+this.width+' '+this.height,
49331 id: this.svgID + "-svg-r",
49333 height: this.height,
49338 id: this.svgID + "-svg-l",
49340 y1: (this.height*0.8), // start set the line in 80% of height
49341 x2: this.width, // end
49342 y2: (this.height*0.8), // end set the line in 80% of height
49344 'stroke-width': "1",
49345 'stroke-dasharray': "3",
49346 'shape-rendering': "crispEdges",
49347 'pointer-events': "none"
49351 id: this.svgID + "-svg-p",
49353 'stroke-width': "3",
49355 'pointer-events': 'none'
49360 this.svgBox = this.svgEl.dom.getScreenCTM();
49362 createSVG : function(){
49363 var svg = this.signPanel;
49364 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49367 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49368 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49369 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49370 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49371 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49372 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49373 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49376 isTouchEvent : function(e){
49377 return e.type.match(/^touch/);
49379 getCoords : function (e) {
49380 var pt = this.svgEl.dom.createSVGPoint();
49383 if (this.isTouchEvent(e)) {
49384 pt.x = e.targetTouches[0].clientX;
49385 pt.y = e.targetTouches[0].clientY;
49387 var a = this.svgEl.dom.getScreenCTM();
49388 var b = a.inverse();
49389 var mx = pt.matrixTransform(b);
49390 return mx.x + ',' + mx.y;
49392 //mouse event headler
49393 down : function (e) {
49394 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49395 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49397 this.isMouseDown = true;
49399 e.preventDefault();
49401 move : function (e) {
49402 if (this.isMouseDown) {
49403 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49404 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49407 e.preventDefault();
49409 up : function (e) {
49410 this.isMouseDown = false;
49411 var sp = this.signatureTmp.split(' ');
49414 if(!sp[sp.length-2].match(/^L/)){
49418 this.signatureTmp = sp.join(" ");
49421 if(this.getValue() != this.signatureTmp){
49422 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49423 this.isConfirmed = false;
49425 e.preventDefault();
49429 * Protected method that will not generally be called directly. It
49430 * is called when the editor creates its toolbar. Override this method if you need to
49431 * add custom toolbar buttons.
49432 * @param {HtmlEditor} editor
49434 createToolbar : function(editor){
49435 function btn(id, toggle, handler){
49436 var xid = fid + '-'+ id ;
49440 cls : 'x-btn-icon x-edit-'+id,
49441 enableToggle:toggle !== false,
49442 scope: editor, // was editor...
49443 handler:handler||editor.relayBtnCmd,
49444 clickEvent:'mousedown',
49445 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49451 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49455 cls : ' x-signature-btn x-signature-'+id,
49456 scope: editor, // was editor...
49457 handler: this.reset,
49458 clickEvent:'mousedown',
49459 text: this.labels.clear
49466 cls : ' x-signature-btn x-signature-'+id,
49467 scope: editor, // was editor...
49468 handler: this.confirmHandler,
49469 clickEvent:'mousedown',
49470 text: this.labels.confirm
49477 * when user is clicked confirm then show this image.....
49479 * @return {String} Image Data URI
49481 getImageDataURI : function(){
49482 var svg = this.svgEl.dom.parentNode.innerHTML;
49483 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49488 * @return {Boolean} this.isConfirmed
49490 getConfirmed : function(){
49491 return this.isConfirmed;
49495 * @return {Number} this.width
49497 getWidth : function(){
49502 * @return {Number} this.height
49504 getHeight : function(){
49505 return this.height;
49508 getSignature : function(){
49509 return this.signatureTmp;
49512 reset : function(){
49513 this.signatureTmp = '';
49514 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49515 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49516 this.isConfirmed = false;
49517 Roo.form.Signature.superclass.reset.call(this);
49519 setSignature : function(s){
49520 this.signatureTmp = s;
49521 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49522 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49524 this.isConfirmed = false;
49525 Roo.form.Signature.superclass.reset.call(this);
49528 // Roo.log(this.signPanel.dom.contentWindow.up())
49531 setConfirmed : function(){
49535 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49538 confirmHandler : function(){
49539 if(!this.getSignature()){
49543 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49544 this.setValue(this.getSignature());
49545 this.isConfirmed = true;
49547 this.fireEvent('confirm', this);
49550 // Subclasses should provide the validation implementation by overriding this
49551 validateValue : function(value){
49552 if(this.allowBlank){
49556 if(this.isConfirmed){
49563 * Ext JS Library 1.1.1
49564 * Copyright(c) 2006-2007, Ext JS, LLC.
49566 * Originally Released Under LGPL - original licence link has changed is not relivant.
49569 * <script type="text/javascript">
49574 * @class Roo.form.ComboBox
49575 * @extends Roo.form.TriggerField
49576 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49578 * Create a new ComboBox.
49579 * @param {Object} config Configuration options
49581 Roo.form.Select = function(config){
49582 Roo.form.Select.superclass.constructor.call(this, config);
49586 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49588 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49591 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49592 * rendering into an Roo.Editor, defaults to false)
49595 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49596 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49599 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49602 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49603 * the dropdown list (defaults to undefined, with no header element)
49607 * @cfg {String/Roo.Template} tpl The template to use to render the output
49611 defaultAutoCreate : {tag: "select" },
49613 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49615 listWidth: undefined,
49617 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49618 * mode = 'remote' or 'text' if mode = 'local')
49620 displayField: undefined,
49622 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49623 * mode = 'remote' or 'value' if mode = 'local').
49624 * Note: use of a valueField requires the user make a selection
49625 * in order for a value to be mapped.
49627 valueField: undefined,
49631 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49632 * field's data value (defaults to the underlying DOM element's name)
49634 hiddenName: undefined,
49636 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49640 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49642 selectedClass: 'x-combo-selected',
49644 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49645 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49646 * which displays a downward arrow icon).
49648 triggerClass : 'x-form-arrow-trigger',
49650 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49654 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49655 * anchor positions (defaults to 'tl-bl')
49657 listAlign: 'tl-bl?',
49659 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49663 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49664 * query specified by the allQuery config option (defaults to 'query')
49666 triggerAction: 'query',
49668 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49669 * (defaults to 4, does not apply if editable = false)
49673 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49674 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49678 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49679 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49683 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49684 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49688 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49689 * when editable = true (defaults to false)
49691 selectOnFocus:false,
49693 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49695 queryParam: 'query',
49697 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49698 * when mode = 'remote' (defaults to 'Loading...')
49700 loadingText: 'Loading...',
49702 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49706 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49710 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49711 * traditional select (defaults to true)
49715 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49719 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49723 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49724 * listWidth has a higher value)
49728 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49729 * allow the user to set arbitrary text into the field (defaults to false)
49731 forceSelection:false,
49733 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49734 * if typeAhead = true (defaults to 250)
49736 typeAheadDelay : 250,
49738 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
49739 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
49741 valueNotFoundText : undefined,
49744 * @cfg {String} defaultValue The value displayed after loading the store.
49749 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
49751 blockFocus : false,
49754 * @cfg {Boolean} disableClear Disable showing of clear button.
49756 disableClear : false,
49758 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
49760 alwaysQuery : false,
49766 // element that contains real text value.. (when hidden is used..)
49769 onRender : function(ct, position){
49770 Roo.form.Field.prototype.onRender.call(this, ct, position);
49773 this.store.on('beforeload', this.onBeforeLoad, this);
49774 this.store.on('load', this.onLoad, this);
49775 this.store.on('loadexception', this.onLoadException, this);
49776 this.store.load({});
49784 initEvents : function(){
49785 //Roo.form.ComboBox.superclass.initEvents.call(this);
49789 onDestroy : function(){
49792 this.store.un('beforeload', this.onBeforeLoad, this);
49793 this.store.un('load', this.onLoad, this);
49794 this.store.un('loadexception', this.onLoadException, this);
49796 //Roo.form.ComboBox.superclass.onDestroy.call(this);
49800 fireKey : function(e){
49801 if(e.isNavKeyPress() && !this.list.isVisible()){
49802 this.fireEvent("specialkey", this, e);
49807 onResize: function(w, h){
49815 * Allow or prevent the user from directly editing the field text. If false is passed,
49816 * the user will only be able to select from the items defined in the dropdown list. This method
49817 * is the runtime equivalent of setting the 'editable' config option at config time.
49818 * @param {Boolean} value True to allow the user to directly edit the field text
49820 setEditable : function(value){
49825 onBeforeLoad : function(){
49827 Roo.log("Select before load");
49830 this.innerList.update(this.loadingText ?
49831 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
49832 //this.restrictHeight();
49833 this.selectedIndex = -1;
49837 onLoad : function(){
49840 var dom = this.el.dom;
49841 dom.innerHTML = '';
49842 var od = dom.ownerDocument;
49844 if (this.emptyText) {
49845 var op = od.createElement('option');
49846 op.setAttribute('value', '');
49847 op.innerHTML = String.format('{0}', this.emptyText);
49848 dom.appendChild(op);
49850 if(this.store.getCount() > 0){
49852 var vf = this.valueField;
49853 var df = this.displayField;
49854 this.store.data.each(function(r) {
49855 // which colmsn to use... testing - cdoe / title..
49856 var op = od.createElement('option');
49857 op.setAttribute('value', r.data[vf]);
49858 op.innerHTML = String.format('{0}', r.data[df]);
49859 dom.appendChild(op);
49861 if (typeof(this.defaultValue != 'undefined')) {
49862 this.setValue(this.defaultValue);
49867 //this.onEmptyResults();
49872 onLoadException : function()
49874 dom.innerHTML = '';
49876 Roo.log("Select on load exception");
49880 Roo.log(this.store.reader.jsonData);
49881 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
49882 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
49888 onTypeAhead : function(){
49893 onSelect : function(record, index){
49894 Roo.log('on select?');
49896 if(this.fireEvent('beforeselect', this, record, index) !== false){
49897 this.setFromData(index > -1 ? record.data : false);
49899 this.fireEvent('select', this, record, index);
49904 * Returns the currently selected field value or empty string if no value is set.
49905 * @return {String} value The selected value
49907 getValue : function(){
49908 var dom = this.el.dom;
49909 this.value = dom.options[dom.selectedIndex].value;
49915 * Clears any text/value currently set in the field
49917 clearValue : function(){
49919 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
49924 * Sets the specified value into the field. If the value finds a match, the corresponding record text
49925 * will be displayed in the field. If the value does not match the data value of an existing item,
49926 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
49927 * Otherwise the field will be blank (although the value will still be set).
49928 * @param {String} value The value to match
49930 setValue : function(v){
49931 var d = this.el.dom;
49932 for (var i =0; i < d.options.length;i++) {
49933 if (v == d.options[i].value) {
49934 d.selectedIndex = i;
49942 * @property {Object} the last set data for the element
49947 * Sets the value of the field based on a object which is related to the record format for the store.
49948 * @param {Object} value the value to set as. or false on reset?
49950 setFromData : function(o){
49951 Roo.log('setfrom data?');
49957 reset : function(){
49961 findRecord : function(prop, value){
49966 if(this.store.getCount() > 0){
49967 this.store.each(function(r){
49968 if(r.data[prop] == value){
49978 getName: function()
49980 // returns hidden if it's set..
49981 if (!this.rendered) {return ''};
49982 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
49990 onEmptyResults : function(){
49991 Roo.log('empty results');
49996 * Returns true if the dropdown list is expanded, else false.
49998 isExpanded : function(){
50003 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50004 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50005 * @param {String} value The data value of the item to select
50006 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50007 * selected item if it is not currently in view (defaults to true)
50008 * @return {Boolean} True if the value matched an item in the list, else false
50010 selectByValue : function(v, scrollIntoView){
50011 Roo.log('select By Value');
50014 if(v !== undefined && v !== null){
50015 var r = this.findRecord(this.valueField || this.displayField, v);
50017 this.select(this.store.indexOf(r), scrollIntoView);
50025 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50026 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50027 * @param {Number} index The zero-based index of the list item to select
50028 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50029 * selected item if it is not currently in view (defaults to true)
50031 select : function(index, scrollIntoView){
50032 Roo.log('select ');
50035 this.selectedIndex = index;
50036 this.view.select(index);
50037 if(scrollIntoView !== false){
50038 var el = this.view.getNode(index);
50040 this.innerList.scrollChildIntoView(el, false);
50048 validateBlur : function(){
50055 initQuery : function(){
50056 this.doQuery(this.getRawValue());
50060 doForce : function(){
50061 if(this.el.dom.value.length > 0){
50062 this.el.dom.value =
50063 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50069 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50070 * query allowing the query action to be canceled if needed.
50071 * @param {String} query The SQL query to execute
50072 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50073 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50074 * saved in the current store (defaults to false)
50076 doQuery : function(q, forceAll){
50078 Roo.log('doQuery?');
50079 if(q === undefined || q === null){
50084 forceAll: forceAll,
50088 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50092 forceAll = qe.forceAll;
50093 if(forceAll === true || (q.length >= this.minChars)){
50094 if(this.lastQuery != q || this.alwaysQuery){
50095 this.lastQuery = q;
50096 if(this.mode == 'local'){
50097 this.selectedIndex = -1;
50099 this.store.clearFilter();
50101 this.store.filter(this.displayField, q);
50105 this.store.baseParams[this.queryParam] = q;
50107 params: this.getParams(q)
50112 this.selectedIndex = -1;
50119 getParams : function(q){
50121 //p[this.queryParam] = q;
50124 p.limit = this.pageSize;
50130 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50132 collapse : function(){
50137 collapseIf : function(e){
50142 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50144 expand : function(){
50152 * @cfg {Boolean} grow
50156 * @cfg {Number} growMin
50160 * @cfg {Number} growMax
50168 setWidth : function()
50172 getResizeEl : function(){
50175 });//<script type="text/javasscript">
50179 * @class Roo.DDView
50180 * A DnD enabled version of Roo.View.
50181 * @param {Element/String} container The Element in which to create the View.
50182 * @param {String} tpl The template string used to create the markup for each element of the View
50183 * @param {Object} config The configuration properties. These include all the config options of
50184 * {@link Roo.View} plus some specific to this class.<br>
50186 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50187 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50189 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50190 .x-view-drag-insert-above {
50191 border-top:1px dotted #3366cc;
50193 .x-view-drag-insert-below {
50194 border-bottom:1px dotted #3366cc;
50200 Roo.DDView = function(container, tpl, config) {
50201 Roo.DDView.superclass.constructor.apply(this, arguments);
50202 this.getEl().setStyle("outline", "0px none");
50203 this.getEl().unselectable();
50204 if (this.dragGroup) {
50205 this.setDraggable(this.dragGroup.split(","));
50207 if (this.dropGroup) {
50208 this.setDroppable(this.dropGroup.split(","));
50210 if (this.deletable) {
50211 this.setDeletable();
50213 this.isDirtyFlag = false;
50219 Roo.extend(Roo.DDView, Roo.View, {
50220 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50221 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50222 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50223 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50227 reset: Roo.emptyFn,
50229 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50231 validate: function() {
50235 destroy: function() {
50236 this.purgeListeners();
50237 this.getEl.removeAllListeners();
50238 this.getEl().remove();
50239 if (this.dragZone) {
50240 if (this.dragZone.destroy) {
50241 this.dragZone.destroy();
50244 if (this.dropZone) {
50245 if (this.dropZone.destroy) {
50246 this.dropZone.destroy();
50251 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50252 getName: function() {
50256 /** Loads the View from a JSON string representing the Records to put into the Store. */
50257 setValue: function(v) {
50259 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50262 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50263 this.store.proxy = new Roo.data.MemoryProxy(data);
50267 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50268 getValue: function() {
50270 this.store.each(function(rec) {
50271 result += rec.id + ',';
50273 return result.substr(0, result.length - 1) + ')';
50276 getIds: function() {
50277 var i = 0, result = new Array(this.store.getCount());
50278 this.store.each(function(rec) {
50279 result[i++] = rec.id;
50284 isDirty: function() {
50285 return this.isDirtyFlag;
50289 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50290 * whole Element becomes the target, and this causes the drop gesture to append.
50292 getTargetFromEvent : function(e) {
50293 var target = e.getTarget();
50294 while ((target !== null) && (target.parentNode != this.el.dom)) {
50295 target = target.parentNode;
50298 target = this.el.dom.lastChild || this.el.dom;
50304 * Create the drag data which consists of an object which has the property "ddel" as
50305 * the drag proxy element.
50307 getDragData : function(e) {
50308 var target = this.findItemFromChild(e.getTarget());
50310 this.handleSelection(e);
50311 var selNodes = this.getSelectedNodes();
50314 copy: this.copy || (this.allowCopy && e.ctrlKey),
50318 var selectedIndices = this.getSelectedIndexes();
50319 for (var i = 0; i < selectedIndices.length; i++) {
50320 dragData.records.push(this.store.getAt(selectedIndices[i]));
50322 if (selNodes.length == 1) {
50323 dragData.ddel = target.cloneNode(true); // the div element
50325 var div = document.createElement('div'); // create the multi element drag "ghost"
50326 div.className = 'multi-proxy';
50327 for (var i = 0, len = selNodes.length; i < len; i++) {
50328 div.appendChild(selNodes[i].cloneNode(true));
50330 dragData.ddel = div;
50332 //console.log(dragData)
50333 //console.log(dragData.ddel.innerHTML)
50336 //console.log('nodragData')
50340 /** Specify to which ddGroup items in this DDView may be dragged. */
50341 setDraggable: function(ddGroup) {
50342 if (ddGroup instanceof Array) {
50343 Roo.each(ddGroup, this.setDraggable, this);
50346 if (this.dragZone) {
50347 this.dragZone.addToGroup(ddGroup);
50349 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50350 containerScroll: true,
50354 // Draggability implies selection. DragZone's mousedown selects the element.
50355 if (!this.multiSelect) { this.singleSelect = true; }
50357 // Wire the DragZone's handlers up to methods in *this*
50358 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50362 /** Specify from which ddGroup this DDView accepts drops. */
50363 setDroppable: function(ddGroup) {
50364 if (ddGroup instanceof Array) {
50365 Roo.each(ddGroup, this.setDroppable, this);
50368 if (this.dropZone) {
50369 this.dropZone.addToGroup(ddGroup);
50371 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50372 containerScroll: true,
50376 // Wire the DropZone's handlers up to methods in *this*
50377 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50378 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50379 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50380 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50381 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50385 /** Decide whether to drop above or below a View node. */
50386 getDropPoint : function(e, n, dd){
50387 if (n == this.el.dom) { return "above"; }
50388 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50389 var c = t + (b - t) / 2;
50390 var y = Roo.lib.Event.getPageY(e);
50398 onNodeEnter : function(n, dd, e, data){
50402 onNodeOver : function(n, dd, e, data){
50403 var pt = this.getDropPoint(e, n, dd);
50404 // set the insert point style on the target node
50405 var dragElClass = this.dropNotAllowed;
50408 if (pt == "above"){
50409 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50410 targetElClass = "x-view-drag-insert-above";
50412 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50413 targetElClass = "x-view-drag-insert-below";
50415 if (this.lastInsertClass != targetElClass){
50416 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50417 this.lastInsertClass = targetElClass;
50420 return dragElClass;
50423 onNodeOut : function(n, dd, e, data){
50424 this.removeDropIndicators(n);
50427 onNodeDrop : function(n, dd, e, data){
50428 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50431 var pt = this.getDropPoint(e, n, dd);
50432 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50433 if (pt == "below") { insertAt++; }
50434 for (var i = 0; i < data.records.length; i++) {
50435 var r = data.records[i];
50436 var dup = this.store.getById(r.id);
50437 if (dup && (dd != this.dragZone)) {
50438 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50441 this.store.insert(insertAt++, r.copy());
50443 data.source.isDirtyFlag = true;
50445 this.store.insert(insertAt++, r);
50447 this.isDirtyFlag = true;
50450 this.dragZone.cachedTarget = null;
50454 removeDropIndicators : function(n){
50456 Roo.fly(n).removeClass([
50457 "x-view-drag-insert-above",
50458 "x-view-drag-insert-below"]);
50459 this.lastInsertClass = "_noclass";
50464 * Utility method. Add a delete option to the DDView's context menu.
50465 * @param {String} imageUrl The URL of the "delete" icon image.
50467 setDeletable: function(imageUrl) {
50468 if (!this.singleSelect && !this.multiSelect) {
50469 this.singleSelect = true;
50471 var c = this.getContextMenu();
50472 this.contextMenu.on("itemclick", function(item) {
50475 this.remove(this.getSelectedIndexes());
50479 this.contextMenu.add({
50486 /** Return the context menu for this DDView. */
50487 getContextMenu: function() {
50488 if (!this.contextMenu) {
50489 // Create the View's context menu
50490 this.contextMenu = new Roo.menu.Menu({
50491 id: this.id + "-contextmenu"
50493 this.el.on("contextmenu", this.showContextMenu, this);
50495 return this.contextMenu;
50498 disableContextMenu: function() {
50499 if (this.contextMenu) {
50500 this.el.un("contextmenu", this.showContextMenu, this);
50504 showContextMenu: function(e, item) {
50505 item = this.findItemFromChild(e.getTarget());
50508 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50509 this.contextMenu.showAt(e.getXY());
50514 * Remove {@link Roo.data.Record}s at the specified indices.
50515 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50517 remove: function(selectedIndices) {
50518 selectedIndices = [].concat(selectedIndices);
50519 for (var i = 0; i < selectedIndices.length; i++) {
50520 var rec = this.store.getAt(selectedIndices[i]);
50521 this.store.remove(rec);
50526 * Double click fires the event, but also, if this is draggable, and there is only one other
50527 * related DropZone, it transfers the selected node.
50529 onDblClick : function(e){
50530 var item = this.findItemFromChild(e.getTarget());
50532 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50535 if (this.dragGroup) {
50536 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50537 while (targets.indexOf(this.dropZone) > -1) {
50538 targets.remove(this.dropZone);
50540 if (targets.length == 1) {
50541 this.dragZone.cachedTarget = null;
50542 var el = Roo.get(targets[0].getEl());
50543 var box = el.getBox(true);
50544 targets[0].onNodeDrop(el.dom, {
50546 xy: [box.x, box.y + box.height - 1]
50547 }, null, this.getDragData(e));
50553 handleSelection: function(e) {
50554 this.dragZone.cachedTarget = null;
50555 var item = this.findItemFromChild(e.getTarget());
50557 this.clearSelections(true);
50560 if (item && (this.multiSelect || this.singleSelect)){
50561 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50562 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50563 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50564 this.unselect(item);
50566 this.select(item, this.multiSelect && e.ctrlKey);
50567 this.lastSelection = item;
50572 onItemClick : function(item, index, e){
50573 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50579 unselect : function(nodeInfo, suppressEvent){
50580 var node = this.getNode(nodeInfo);
50581 if(node && this.isSelected(node)){
50582 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50583 Roo.fly(node).removeClass(this.selectedClass);
50584 this.selections.remove(node);
50585 if(!suppressEvent){
50586 this.fireEvent("selectionchange", this, this.selections);
50594 * Ext JS Library 1.1.1
50595 * Copyright(c) 2006-2007, Ext JS, LLC.
50597 * Originally Released Under LGPL - original licence link has changed is not relivant.
50600 * <script type="text/javascript">
50604 * @class Roo.LayoutManager
50605 * @extends Roo.util.Observable
50606 * Base class for layout managers.
50608 Roo.LayoutManager = function(container, config){
50609 Roo.LayoutManager.superclass.constructor.call(this);
50610 this.el = Roo.get(container);
50611 // ie scrollbar fix
50612 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50613 document.body.scroll = "no";
50614 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50615 this.el.position('relative');
50617 this.id = this.el.id;
50618 this.el.addClass("x-layout-container");
50619 /** false to disable window resize monitoring @type Boolean */
50620 this.monitorWindowResize = true;
50625 * Fires when a layout is performed.
50626 * @param {Roo.LayoutManager} this
50630 * @event regionresized
50631 * Fires when the user resizes a region.
50632 * @param {Roo.LayoutRegion} region The resized region
50633 * @param {Number} newSize The new size (width for east/west, height for north/south)
50635 "regionresized" : true,
50637 * @event regioncollapsed
50638 * Fires when a region is collapsed.
50639 * @param {Roo.LayoutRegion} region The collapsed region
50641 "regioncollapsed" : true,
50643 * @event regionexpanded
50644 * Fires when a region is expanded.
50645 * @param {Roo.LayoutRegion} region The expanded region
50647 "regionexpanded" : true
50649 this.updating = false;
50650 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50653 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50655 * Returns true if this layout is currently being updated
50656 * @return {Boolean}
50658 isUpdating : function(){
50659 return this.updating;
50663 * Suspend the LayoutManager from doing auto-layouts while
50664 * making multiple add or remove calls
50666 beginUpdate : function(){
50667 this.updating = true;
50671 * Restore auto-layouts and optionally disable the manager from performing a layout
50672 * @param {Boolean} noLayout true to disable a layout update
50674 endUpdate : function(noLayout){
50675 this.updating = false;
50681 layout: function(){
50685 onRegionResized : function(region, newSize){
50686 this.fireEvent("regionresized", region, newSize);
50690 onRegionCollapsed : function(region){
50691 this.fireEvent("regioncollapsed", region);
50694 onRegionExpanded : function(region){
50695 this.fireEvent("regionexpanded", region);
50699 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50700 * performs box-model adjustments.
50701 * @return {Object} The size as an object {width: (the width), height: (the height)}
50703 getViewSize : function(){
50705 if(this.el.dom != document.body){
50706 size = this.el.getSize();
50708 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50710 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50711 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50716 * Returns the Element this layout is bound to.
50717 * @return {Roo.Element}
50719 getEl : function(){
50724 * Returns the specified region.
50725 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50726 * @return {Roo.LayoutRegion}
50728 getRegion : function(target){
50729 return this.regions[target.toLowerCase()];
50732 onWindowResize : function(){
50733 if(this.monitorWindowResize){
50739 * Ext JS Library 1.1.1
50740 * Copyright(c) 2006-2007, Ext JS, LLC.
50742 * Originally Released Under LGPL - original licence link has changed is not relivant.
50745 * <script type="text/javascript">
50748 * @class Roo.BorderLayout
50749 * @extends Roo.LayoutManager
50750 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
50751 * please see: <br><br>
50752 * <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>
50753 * <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>
50756 var layout = new Roo.BorderLayout(document.body, {
50790 preferredTabWidth: 150
50795 var CP = Roo.ContentPanel;
50797 layout.beginUpdate();
50798 layout.add("north", new CP("north", "North"));
50799 layout.add("south", new CP("south", {title: "South", closable: true}));
50800 layout.add("west", new CP("west", {title: "West"}));
50801 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
50802 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
50803 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
50804 layout.getRegion("center").showPanel("center1");
50805 layout.endUpdate();
50808 <b>The container the layout is rendered into can be either the body element or any other element.
50809 If it is not the body element, the container needs to either be an absolute positioned element,
50810 or you will need to add "position:relative" to the css of the container. You will also need to specify
50811 the container size if it is not the body element.</b>
50814 * Create a new BorderLayout
50815 * @param {String/HTMLElement/Element} container The container this layout is bound to
50816 * @param {Object} config Configuration options
50818 Roo.BorderLayout = function(container, config){
50819 config = config || {};
50820 Roo.BorderLayout.superclass.constructor.call(this, container, config);
50821 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
50822 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
50823 var target = this.factory.validRegions[i];
50824 if(config[target]){
50825 this.addRegion(target, config[target]);
50830 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
50832 * Creates and adds a new region if it doesn't already exist.
50833 * @param {String} target The target region key (north, south, east, west or center).
50834 * @param {Object} config The regions config object
50835 * @return {BorderLayoutRegion} The new region
50837 addRegion : function(target, config){
50838 if(!this.regions[target]){
50839 var r = this.factory.create(target, this, config);
50840 this.bindRegion(target, r);
50842 return this.regions[target];
50846 bindRegion : function(name, r){
50847 this.regions[name] = r;
50848 r.on("visibilitychange", this.layout, this);
50849 r.on("paneladded", this.layout, this);
50850 r.on("panelremoved", this.layout, this);
50851 r.on("invalidated", this.layout, this);
50852 r.on("resized", this.onRegionResized, this);
50853 r.on("collapsed", this.onRegionCollapsed, this);
50854 r.on("expanded", this.onRegionExpanded, this);
50858 * Performs a layout update.
50860 layout : function(){
50861 if(this.updating) {
50864 var size = this.getViewSize();
50865 var w = size.width;
50866 var h = size.height;
50871 //var x = 0, y = 0;
50873 var rs = this.regions;
50874 var north = rs["north"];
50875 var south = rs["south"];
50876 var west = rs["west"];
50877 var east = rs["east"];
50878 var center = rs["center"];
50879 //if(this.hideOnLayout){ // not supported anymore
50880 //c.el.setStyle("display", "none");
50882 if(north && north.isVisible()){
50883 var b = north.getBox();
50884 var m = north.getMargins();
50885 b.width = w - (m.left+m.right);
50888 centerY = b.height + b.y + m.bottom;
50889 centerH -= centerY;
50890 north.updateBox(this.safeBox(b));
50892 if(south && south.isVisible()){
50893 var b = south.getBox();
50894 var m = south.getMargins();
50895 b.width = w - (m.left+m.right);
50897 var totalHeight = (b.height + m.top + m.bottom);
50898 b.y = h - totalHeight + m.top;
50899 centerH -= totalHeight;
50900 south.updateBox(this.safeBox(b));
50902 if(west && west.isVisible()){
50903 var b = west.getBox();
50904 var m = west.getMargins();
50905 b.height = centerH - (m.top+m.bottom);
50907 b.y = centerY + m.top;
50908 var totalWidth = (b.width + m.left + m.right);
50909 centerX += totalWidth;
50910 centerW -= totalWidth;
50911 west.updateBox(this.safeBox(b));
50913 if(east && east.isVisible()){
50914 var b = east.getBox();
50915 var m = east.getMargins();
50916 b.height = centerH - (m.top+m.bottom);
50917 var totalWidth = (b.width + m.left + m.right);
50918 b.x = w - totalWidth + m.left;
50919 b.y = centerY + m.top;
50920 centerW -= totalWidth;
50921 east.updateBox(this.safeBox(b));
50924 var m = center.getMargins();
50926 x: centerX + m.left,
50927 y: centerY + m.top,
50928 width: centerW - (m.left+m.right),
50929 height: centerH - (m.top+m.bottom)
50931 //if(this.hideOnLayout){
50932 //center.el.setStyle("display", "block");
50934 center.updateBox(this.safeBox(centerBox));
50937 this.fireEvent("layout", this);
50941 safeBox : function(box){
50942 box.width = Math.max(0, box.width);
50943 box.height = Math.max(0, box.height);
50948 * Adds a ContentPanel (or subclass) to this layout.
50949 * @param {String} target The target region key (north, south, east, west or center).
50950 * @param {Roo.ContentPanel} panel The panel to add
50951 * @return {Roo.ContentPanel} The added panel
50953 add : function(target, panel){
50955 target = target.toLowerCase();
50956 return this.regions[target].add(panel);
50960 * Remove a ContentPanel (or subclass) to this layout.
50961 * @param {String} target The target region key (north, south, east, west or center).
50962 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
50963 * @return {Roo.ContentPanel} The removed panel
50965 remove : function(target, panel){
50966 target = target.toLowerCase();
50967 return this.regions[target].remove(panel);
50971 * Searches all regions for a panel with the specified id
50972 * @param {String} panelId
50973 * @return {Roo.ContentPanel} The panel or null if it wasn't found
50975 findPanel : function(panelId){
50976 var rs = this.regions;
50977 for(var target in rs){
50978 if(typeof rs[target] != "function"){
50979 var p = rs[target].getPanel(panelId);
50989 * Searches all regions for a panel with the specified id and activates (shows) it.
50990 * @param {String/ContentPanel} panelId The panels id or the panel itself
50991 * @return {Roo.ContentPanel} The shown panel or null
50993 showPanel : function(panelId) {
50994 var rs = this.regions;
50995 for(var target in rs){
50996 var r = rs[target];
50997 if(typeof r != "function"){
50998 if(r.hasPanel(panelId)){
50999 return r.showPanel(panelId);
51007 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51008 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51010 restoreState : function(provider){
51012 provider = Roo.state.Manager;
51014 var sm = new Roo.LayoutStateManager();
51015 sm.init(this, provider);
51019 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51020 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51021 * a valid ContentPanel config object. Example:
51023 // Create the main layout
51024 var layout = new Roo.BorderLayout('main-ct', {
51035 // Create and add multiple ContentPanels at once via configs
51038 id: 'source-files',
51040 title:'Ext Source Files',
51053 * @param {Object} regions An object containing ContentPanel configs by region name
51055 batchAdd : function(regions){
51056 this.beginUpdate();
51057 for(var rname in regions){
51058 var lr = this.regions[rname];
51060 this.addTypedPanels(lr, regions[rname]);
51067 addTypedPanels : function(lr, ps){
51068 if(typeof ps == 'string'){
51069 lr.add(new Roo.ContentPanel(ps));
51071 else if(ps instanceof Array){
51072 for(var i =0, len = ps.length; i < len; i++){
51073 this.addTypedPanels(lr, ps[i]);
51076 else if(!ps.events){ // raw config?
51078 delete ps.el; // prevent conflict
51079 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51081 else { // panel object assumed!
51086 * Adds a xtype elements to the layout.
51090 xtype : 'ContentPanel',
51097 xtype : 'NestedLayoutPanel',
51103 items : [ ... list of content panels or nested layout panels.. ]
51107 * @param {Object} cfg Xtype definition of item to add.
51109 addxtype : function(cfg)
51111 // basically accepts a pannel...
51112 // can accept a layout region..!?!?
51113 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51115 if (!cfg.xtype.match(/Panel$/)) {
51120 if (typeof(cfg.region) == 'undefined') {
51121 Roo.log("Failed to add Panel, region was not set");
51125 var region = cfg.region;
51131 xitems = cfg.items;
51138 case 'ContentPanel': // ContentPanel (el, cfg)
51139 case 'ScrollPanel': // ContentPanel (el, cfg)
51141 if(cfg.autoCreate) {
51142 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51144 var el = this.el.createChild();
51145 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51148 this.add(region, ret);
51152 case 'TreePanel': // our new panel!
51153 cfg.el = this.el.createChild();
51154 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51155 this.add(region, ret);
51158 case 'NestedLayoutPanel':
51159 // create a new Layout (which is a Border Layout...
51160 var el = this.el.createChild();
51161 var clayout = cfg.layout;
51163 clayout.items = clayout.items || [];
51164 // replace this exitems with the clayout ones..
51165 xitems = clayout.items;
51168 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51169 cfg.background = false;
51171 var layout = new Roo.BorderLayout(el, clayout);
51173 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51174 //console.log('adding nested layout panel ' + cfg.toSource());
51175 this.add(region, ret);
51176 nb = {}; /// find first...
51181 // needs grid and region
51183 //var el = this.getRegion(region).el.createChild();
51184 var el = this.el.createChild();
51185 // create the grid first...
51187 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51189 if (region == 'center' && this.active ) {
51190 cfg.background = false;
51192 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51194 this.add(region, ret);
51195 if (cfg.background) {
51196 ret.on('activate', function(gp) {
51197 if (!gp.grid.rendered) {
51212 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51214 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51215 this.add(region, ret);
51218 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51222 // GridPanel (grid, cfg)
51225 this.beginUpdate();
51229 Roo.each(xitems, function(i) {
51230 region = nb && i.region ? i.region : false;
51232 var add = ret.addxtype(i);
51235 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51236 if (!i.background) {
51237 abn[region] = nb[region] ;
51244 // make the last non-background panel active..
51245 //if (nb) { Roo.log(abn); }
51248 for(var r in abn) {
51249 region = this.getRegion(r);
51251 // tried using nb[r], but it does not work..
51253 region.showPanel(abn[r]);
51264 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51265 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51266 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51267 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51270 var CP = Roo.ContentPanel;
51272 var layout = Roo.BorderLayout.create({
51276 panels: [new CP("north", "North")]
51285 panels: [new CP("west", {title: "West"})]
51294 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51303 panels: [new CP("south", {title: "South", closable: true})]
51310 preferredTabWidth: 150,
51312 new CP("center1", {title: "Close Me", closable: true}),
51313 new CP("center2", {title: "Center Panel", closable: false})
51318 layout.getRegion("center").showPanel("center1");
51323 Roo.BorderLayout.create = function(config, targetEl){
51324 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51325 layout.beginUpdate();
51326 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51327 for(var j = 0, jlen = regions.length; j < jlen; j++){
51328 var lr = regions[j];
51329 if(layout.regions[lr] && config[lr].panels){
51330 var r = layout.regions[lr];
51331 var ps = config[lr].panels;
51332 layout.addTypedPanels(r, ps);
51335 layout.endUpdate();
51340 Roo.BorderLayout.RegionFactory = {
51342 validRegions : ["north","south","east","west","center"],
51345 create : function(target, mgr, config){
51346 target = target.toLowerCase();
51347 if(config.lightweight || config.basic){
51348 return new Roo.BasicLayoutRegion(mgr, config, target);
51352 return new Roo.NorthLayoutRegion(mgr, config);
51354 return new Roo.SouthLayoutRegion(mgr, config);
51356 return new Roo.EastLayoutRegion(mgr, config);
51358 return new Roo.WestLayoutRegion(mgr, config);
51360 return new Roo.CenterLayoutRegion(mgr, config);
51362 throw 'Layout region "'+target+'" not supported.';
51366 * Ext JS Library 1.1.1
51367 * Copyright(c) 2006-2007, Ext JS, LLC.
51369 * Originally Released Under LGPL - original licence link has changed is not relivant.
51372 * <script type="text/javascript">
51376 * @class Roo.BasicLayoutRegion
51377 * @extends Roo.util.Observable
51378 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51379 * and does not have a titlebar, tabs or any other features. All it does is size and position
51380 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51382 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51384 this.position = pos;
51387 * @scope Roo.BasicLayoutRegion
51391 * @event beforeremove
51392 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51393 * @param {Roo.LayoutRegion} this
51394 * @param {Roo.ContentPanel} panel The panel
51395 * @param {Object} e The cancel event object
51397 "beforeremove" : true,
51399 * @event invalidated
51400 * Fires when the layout for this region is changed.
51401 * @param {Roo.LayoutRegion} this
51403 "invalidated" : true,
51405 * @event visibilitychange
51406 * Fires when this region is shown or hidden
51407 * @param {Roo.LayoutRegion} this
51408 * @param {Boolean} visibility true or false
51410 "visibilitychange" : true,
51412 * @event paneladded
51413 * Fires when a panel is added.
51414 * @param {Roo.LayoutRegion} this
51415 * @param {Roo.ContentPanel} panel The panel
51417 "paneladded" : true,
51419 * @event panelremoved
51420 * Fires when a panel is removed.
51421 * @param {Roo.LayoutRegion} this
51422 * @param {Roo.ContentPanel} panel The panel
51424 "panelremoved" : true,
51427 * Fires when this region is collapsed.
51428 * @param {Roo.LayoutRegion} this
51430 "collapsed" : true,
51433 * Fires when this region is expanded.
51434 * @param {Roo.LayoutRegion} this
51439 * Fires when this region is slid into view.
51440 * @param {Roo.LayoutRegion} this
51442 "slideshow" : true,
51445 * Fires when this region slides out of view.
51446 * @param {Roo.LayoutRegion} this
51448 "slidehide" : true,
51450 * @event panelactivated
51451 * Fires when a panel is activated.
51452 * @param {Roo.LayoutRegion} this
51453 * @param {Roo.ContentPanel} panel The activated panel
51455 "panelactivated" : true,
51458 * Fires when the user resizes this region.
51459 * @param {Roo.LayoutRegion} this
51460 * @param {Number} newSize The new size (width for east/west, height for north/south)
51464 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51465 this.panels = new Roo.util.MixedCollection();
51466 this.panels.getKey = this.getPanelId.createDelegate(this);
51468 this.activePanel = null;
51469 // ensure listeners are added...
51471 if (config.listeners || config.events) {
51472 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51473 listeners : config.listeners || {},
51474 events : config.events || {}
51478 if(skipConfig !== true){
51479 this.applyConfig(config);
51483 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51484 getPanelId : function(p){
51488 applyConfig : function(config){
51489 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51490 this.config = config;
51495 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51496 * the width, for horizontal (north, south) the height.
51497 * @param {Number} newSize The new width or height
51499 resizeTo : function(newSize){
51500 var el = this.el ? this.el :
51501 (this.activePanel ? this.activePanel.getEl() : null);
51503 switch(this.position){
51506 el.setWidth(newSize);
51507 this.fireEvent("resized", this, newSize);
51511 el.setHeight(newSize);
51512 this.fireEvent("resized", this, newSize);
51518 getBox : function(){
51519 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51522 getMargins : function(){
51523 return this.margins;
51526 updateBox : function(box){
51528 var el = this.activePanel.getEl();
51529 el.dom.style.left = box.x + "px";
51530 el.dom.style.top = box.y + "px";
51531 this.activePanel.setSize(box.width, box.height);
51535 * Returns the container element for this region.
51536 * @return {Roo.Element}
51538 getEl : function(){
51539 return this.activePanel;
51543 * Returns true if this region is currently visible.
51544 * @return {Boolean}
51546 isVisible : function(){
51547 return this.activePanel ? true : false;
51550 setActivePanel : function(panel){
51551 panel = this.getPanel(panel);
51552 if(this.activePanel && this.activePanel != panel){
51553 this.activePanel.setActiveState(false);
51554 this.activePanel.getEl().setLeftTop(-10000,-10000);
51556 this.activePanel = panel;
51557 panel.setActiveState(true);
51559 panel.setSize(this.box.width, this.box.height);
51561 this.fireEvent("panelactivated", this, panel);
51562 this.fireEvent("invalidated");
51566 * Show the specified panel.
51567 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51568 * @return {Roo.ContentPanel} The shown panel or null
51570 showPanel : function(panel){
51571 if(panel = this.getPanel(panel)){
51572 this.setActivePanel(panel);
51578 * Get the active panel for this region.
51579 * @return {Roo.ContentPanel} The active panel or null
51581 getActivePanel : function(){
51582 return this.activePanel;
51586 * Add the passed ContentPanel(s)
51587 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51588 * @return {Roo.ContentPanel} The panel added (if only one was added)
51590 add : function(panel){
51591 if(arguments.length > 1){
51592 for(var i = 0, len = arguments.length; i < len; i++) {
51593 this.add(arguments[i]);
51597 if(this.hasPanel(panel)){
51598 this.showPanel(panel);
51601 var el = panel.getEl();
51602 if(el.dom.parentNode != this.mgr.el.dom){
51603 this.mgr.el.dom.appendChild(el.dom);
51605 if(panel.setRegion){
51606 panel.setRegion(this);
51608 this.panels.add(panel);
51609 el.setStyle("position", "absolute");
51610 if(!panel.background){
51611 this.setActivePanel(panel);
51612 if(this.config.initialSize && this.panels.getCount()==1){
51613 this.resizeTo(this.config.initialSize);
51616 this.fireEvent("paneladded", this, panel);
51621 * Returns true if the panel is in this region.
51622 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51623 * @return {Boolean}
51625 hasPanel : function(panel){
51626 if(typeof panel == "object"){ // must be panel obj
51627 panel = panel.getId();
51629 return this.getPanel(panel) ? true : false;
51633 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51634 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51635 * @param {Boolean} preservePanel Overrides the config preservePanel option
51636 * @return {Roo.ContentPanel} The panel that was removed
51638 remove : function(panel, preservePanel){
51639 panel = this.getPanel(panel);
51644 this.fireEvent("beforeremove", this, panel, e);
51645 if(e.cancel === true){
51648 var panelId = panel.getId();
51649 this.panels.removeKey(panelId);
51654 * Returns the panel specified or null if it's not in this region.
51655 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51656 * @return {Roo.ContentPanel}
51658 getPanel : function(id){
51659 if(typeof id == "object"){ // must be panel obj
51662 return this.panels.get(id);
51666 * Returns this regions position (north/south/east/west/center).
51669 getPosition: function(){
51670 return this.position;
51674 * Ext JS Library 1.1.1
51675 * Copyright(c) 2006-2007, Ext JS, LLC.
51677 * Originally Released Under LGPL - original licence link has changed is not relivant.
51680 * <script type="text/javascript">
51684 * @class Roo.LayoutRegion
51685 * @extends Roo.BasicLayoutRegion
51686 * This class represents a region in a layout manager.
51687 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51688 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51689 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51690 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51691 * @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})
51692 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51693 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51694 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51695 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51696 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51697 * @cfg {String} title The title for the region (overrides panel titles)
51698 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51699 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51700 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51701 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51702 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51703 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51704 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51705 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51706 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51707 * @cfg {Boolean} showPin True to show a pin button
51708 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51709 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51710 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51711 * @cfg {Number} width For East/West panels
51712 * @cfg {Number} height For North/South panels
51713 * @cfg {Boolean} split To show the splitter
51714 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51716 Roo.LayoutRegion = function(mgr, config, pos){
51717 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51718 var dh = Roo.DomHelper;
51719 /** This region's container element
51720 * @type Roo.Element */
51721 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51722 /** This region's title element
51723 * @type Roo.Element */
51725 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51726 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51727 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51729 this.titleEl.enableDisplayMode();
51730 /** This region's title text element
51731 * @type HTMLElement */
51732 this.titleTextEl = this.titleEl.dom.firstChild;
51733 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
51734 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
51735 this.closeBtn.enableDisplayMode();
51736 this.closeBtn.on("click", this.closeClicked, this);
51737 this.closeBtn.hide();
51739 this.createBody(config);
51740 this.visible = true;
51741 this.collapsed = false;
51743 if(config.hideWhenEmpty){
51745 this.on("paneladded", this.validateVisibility, this);
51746 this.on("panelremoved", this.validateVisibility, this);
51748 this.applyConfig(config);
51751 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
51753 createBody : function(){
51754 /** This region's body element
51755 * @type Roo.Element */
51756 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
51759 applyConfig : function(c){
51760 if(c.collapsible && this.position != "center" && !this.collapsedEl){
51761 var dh = Roo.DomHelper;
51762 if(c.titlebar !== false){
51763 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
51764 this.collapseBtn.on("click", this.collapse, this);
51765 this.collapseBtn.enableDisplayMode();
51767 if(c.showPin === true || this.showPin){
51768 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
51769 this.stickBtn.enableDisplayMode();
51770 this.stickBtn.on("click", this.expand, this);
51771 this.stickBtn.hide();
51774 /** This region's collapsed element
51775 * @type Roo.Element */
51776 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
51777 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
51779 if(c.floatable !== false){
51780 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
51781 this.collapsedEl.on("click", this.collapseClick, this);
51784 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
51785 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
51786 id: "message", unselectable: "on", style:{"float":"left"}});
51787 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
51789 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
51790 this.expandBtn.on("click", this.expand, this);
51792 if(this.collapseBtn){
51793 this.collapseBtn.setVisible(c.collapsible == true);
51795 this.cmargins = c.cmargins || this.cmargins ||
51796 (this.position == "west" || this.position == "east" ?
51797 {top: 0, left: 2, right:2, bottom: 0} :
51798 {top: 2, left: 0, right:0, bottom: 2});
51799 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51800 this.bottomTabs = c.tabPosition != "top";
51801 this.autoScroll = c.autoScroll || false;
51802 if(this.autoScroll){
51803 this.bodyEl.setStyle("overflow", "auto");
51805 this.bodyEl.setStyle("overflow", "hidden");
51807 //if(c.titlebar !== false){
51808 if((!c.titlebar && !c.title) || c.titlebar === false){
51809 this.titleEl.hide();
51811 this.titleEl.show();
51813 this.titleTextEl.innerHTML = c.title;
51817 this.duration = c.duration || .30;
51818 this.slideDuration = c.slideDuration || .45;
51821 this.collapse(true);
51828 * Returns true if this region is currently visible.
51829 * @return {Boolean}
51831 isVisible : function(){
51832 return this.visible;
51836 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
51837 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
51839 setCollapsedTitle : function(title){
51840 title = title || " ";
51841 if(this.collapsedTitleTextEl){
51842 this.collapsedTitleTextEl.innerHTML = title;
51846 getBox : function(){
51848 if(!this.collapsed){
51849 b = this.el.getBox(false, true);
51851 b = this.collapsedEl.getBox(false, true);
51856 getMargins : function(){
51857 return this.collapsed ? this.cmargins : this.margins;
51860 highlight : function(){
51861 this.el.addClass("x-layout-panel-dragover");
51864 unhighlight : function(){
51865 this.el.removeClass("x-layout-panel-dragover");
51868 updateBox : function(box){
51870 if(!this.collapsed){
51871 this.el.dom.style.left = box.x + "px";
51872 this.el.dom.style.top = box.y + "px";
51873 this.updateBody(box.width, box.height);
51875 this.collapsedEl.dom.style.left = box.x + "px";
51876 this.collapsedEl.dom.style.top = box.y + "px";
51877 this.collapsedEl.setSize(box.width, box.height);
51880 this.tabs.autoSizeTabs();
51884 updateBody : function(w, h){
51886 this.el.setWidth(w);
51887 w -= this.el.getBorderWidth("rl");
51888 if(this.config.adjustments){
51889 w += this.config.adjustments[0];
51893 this.el.setHeight(h);
51894 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
51895 h -= this.el.getBorderWidth("tb");
51896 if(this.config.adjustments){
51897 h += this.config.adjustments[1];
51899 this.bodyEl.setHeight(h);
51901 h = this.tabs.syncHeight(h);
51904 if(this.panelSize){
51905 w = w !== null ? w : this.panelSize.width;
51906 h = h !== null ? h : this.panelSize.height;
51908 if(this.activePanel){
51909 var el = this.activePanel.getEl();
51910 w = w !== null ? w : el.getWidth();
51911 h = h !== null ? h : el.getHeight();
51912 this.panelSize = {width: w, height: h};
51913 this.activePanel.setSize(w, h);
51915 if(Roo.isIE && this.tabs){
51916 this.tabs.el.repaint();
51921 * Returns the container element for this region.
51922 * @return {Roo.Element}
51924 getEl : function(){
51929 * Hides this region.
51932 if(!this.collapsed){
51933 this.el.dom.style.left = "-2000px";
51936 this.collapsedEl.dom.style.left = "-2000px";
51937 this.collapsedEl.hide();
51939 this.visible = false;
51940 this.fireEvent("visibilitychange", this, false);
51944 * Shows this region if it was previously hidden.
51947 if(!this.collapsed){
51950 this.collapsedEl.show();
51952 this.visible = true;
51953 this.fireEvent("visibilitychange", this, true);
51956 closeClicked : function(){
51957 if(this.activePanel){
51958 this.remove(this.activePanel);
51962 collapseClick : function(e){
51964 e.stopPropagation();
51967 e.stopPropagation();
51973 * Collapses this region.
51974 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
51976 collapse : function(skipAnim){
51977 if(this.collapsed) {
51980 this.collapsed = true;
51982 this.split.el.hide();
51984 if(this.config.animate && skipAnim !== true){
51985 this.fireEvent("invalidated", this);
51986 this.animateCollapse();
51988 this.el.setLocation(-20000,-20000);
51990 this.collapsedEl.show();
51991 this.fireEvent("collapsed", this);
51992 this.fireEvent("invalidated", this);
51996 animateCollapse : function(){
52001 * Expands this region if it was previously collapsed.
52002 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52003 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52005 expand : function(e, skipAnim){
52007 e.stopPropagation();
52009 if(!this.collapsed || this.el.hasActiveFx()) {
52013 this.afterSlideIn();
52016 this.collapsed = false;
52017 if(this.config.animate && skipAnim !== true){
52018 this.animateExpand();
52022 this.split.el.show();
52024 this.collapsedEl.setLocation(-2000,-2000);
52025 this.collapsedEl.hide();
52026 this.fireEvent("invalidated", this);
52027 this.fireEvent("expanded", this);
52031 animateExpand : function(){
52035 initTabs : function()
52037 this.bodyEl.setStyle("overflow", "hidden");
52038 var ts = new Roo.TabPanel(
52041 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52042 disableTooltips: this.config.disableTabTips,
52043 toolbar : this.config.toolbar
52046 if(this.config.hideTabs){
52047 ts.stripWrap.setDisplayed(false);
52050 ts.resizeTabs = this.config.resizeTabs === true;
52051 ts.minTabWidth = this.config.minTabWidth || 40;
52052 ts.maxTabWidth = this.config.maxTabWidth || 250;
52053 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52054 ts.monitorResize = false;
52055 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52056 ts.bodyEl.addClass('x-layout-tabs-body');
52057 this.panels.each(this.initPanelAsTab, this);
52060 initPanelAsTab : function(panel){
52061 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52062 this.config.closeOnTab && panel.isClosable());
52063 if(panel.tabTip !== undefined){
52064 ti.setTooltip(panel.tabTip);
52066 ti.on("activate", function(){
52067 this.setActivePanel(panel);
52069 if(this.config.closeOnTab){
52070 ti.on("beforeclose", function(t, e){
52072 this.remove(panel);
52078 updatePanelTitle : function(panel, title){
52079 if(this.activePanel == panel){
52080 this.updateTitle(title);
52083 var ti = this.tabs.getTab(panel.getEl().id);
52085 if(panel.tabTip !== undefined){
52086 ti.setTooltip(panel.tabTip);
52091 updateTitle : function(title){
52092 if(this.titleTextEl && !this.config.title){
52093 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52097 setActivePanel : function(panel){
52098 panel = this.getPanel(panel);
52099 if(this.activePanel && this.activePanel != panel){
52100 this.activePanel.setActiveState(false);
52102 this.activePanel = panel;
52103 panel.setActiveState(true);
52104 if(this.panelSize){
52105 panel.setSize(this.panelSize.width, this.panelSize.height);
52108 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52110 this.updateTitle(panel.getTitle());
52112 this.fireEvent("invalidated", this);
52114 this.fireEvent("panelactivated", this, panel);
52118 * Shows the specified panel.
52119 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52120 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52122 showPanel : function(panel)
52124 panel = this.getPanel(panel);
52127 var tab = this.tabs.getTab(panel.getEl().id);
52128 if(tab.isHidden()){
52129 this.tabs.unhideTab(tab.id);
52133 this.setActivePanel(panel);
52140 * Get the active panel for this region.
52141 * @return {Roo.ContentPanel} The active panel or null
52143 getActivePanel : function(){
52144 return this.activePanel;
52147 validateVisibility : function(){
52148 if(this.panels.getCount() < 1){
52149 this.updateTitle(" ");
52150 this.closeBtn.hide();
52153 if(!this.isVisible()){
52160 * Adds the passed ContentPanel(s) to this region.
52161 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52162 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52164 add : function(panel){
52165 if(arguments.length > 1){
52166 for(var i = 0, len = arguments.length; i < len; i++) {
52167 this.add(arguments[i]);
52171 if(this.hasPanel(panel)){
52172 this.showPanel(panel);
52175 panel.setRegion(this);
52176 this.panels.add(panel);
52177 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52178 this.bodyEl.dom.appendChild(panel.getEl().dom);
52179 if(panel.background !== true){
52180 this.setActivePanel(panel);
52182 this.fireEvent("paneladded", this, panel);
52188 this.initPanelAsTab(panel);
52190 if(panel.background !== true){
52191 this.tabs.activate(panel.getEl().id);
52193 this.fireEvent("paneladded", this, panel);
52198 * Hides the tab for the specified panel.
52199 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52201 hidePanel : function(panel){
52202 if(this.tabs && (panel = this.getPanel(panel))){
52203 this.tabs.hideTab(panel.getEl().id);
52208 * Unhides the tab for a previously hidden panel.
52209 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52211 unhidePanel : function(panel){
52212 if(this.tabs && (panel = this.getPanel(panel))){
52213 this.tabs.unhideTab(panel.getEl().id);
52217 clearPanels : function(){
52218 while(this.panels.getCount() > 0){
52219 this.remove(this.panels.first());
52224 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52225 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52226 * @param {Boolean} preservePanel Overrides the config preservePanel option
52227 * @return {Roo.ContentPanel} The panel that was removed
52229 remove : function(panel, preservePanel){
52230 panel = this.getPanel(panel);
52235 this.fireEvent("beforeremove", this, panel, e);
52236 if(e.cancel === true){
52239 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52240 var panelId = panel.getId();
52241 this.panels.removeKey(panelId);
52243 document.body.appendChild(panel.getEl().dom);
52246 this.tabs.removeTab(panel.getEl().id);
52247 }else if (!preservePanel){
52248 this.bodyEl.dom.removeChild(panel.getEl().dom);
52250 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52251 var p = this.panels.first();
52252 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52253 tempEl.appendChild(p.getEl().dom);
52254 this.bodyEl.update("");
52255 this.bodyEl.dom.appendChild(p.getEl().dom);
52257 this.updateTitle(p.getTitle());
52259 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52260 this.setActivePanel(p);
52262 panel.setRegion(null);
52263 if(this.activePanel == panel){
52264 this.activePanel = null;
52266 if(this.config.autoDestroy !== false && preservePanel !== true){
52267 try{panel.destroy();}catch(e){}
52269 this.fireEvent("panelremoved", this, panel);
52274 * Returns the TabPanel component used by this region
52275 * @return {Roo.TabPanel}
52277 getTabs : function(){
52281 createTool : function(parentEl, className){
52282 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52283 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52284 btn.addClassOnOver("x-layout-tools-button-over");
52289 * Ext JS Library 1.1.1
52290 * Copyright(c) 2006-2007, Ext JS, LLC.
52292 * Originally Released Under LGPL - original licence link has changed is not relivant.
52295 * <script type="text/javascript">
52301 * @class Roo.SplitLayoutRegion
52302 * @extends Roo.LayoutRegion
52303 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52305 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52306 this.cursor = cursor;
52307 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52310 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52311 splitTip : "Drag to resize.",
52312 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52313 useSplitTips : false,
52315 applyConfig : function(config){
52316 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52319 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52320 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52321 /** The SplitBar for this region
52322 * @type Roo.SplitBar */
52323 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52324 this.split.on("moved", this.onSplitMove, this);
52325 this.split.useShim = config.useShim === true;
52326 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52327 if(this.useSplitTips){
52328 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52330 if(config.collapsible){
52331 this.split.el.on("dblclick", this.collapse, this);
52334 if(typeof config.minSize != "undefined"){
52335 this.split.minSize = config.minSize;
52337 if(typeof config.maxSize != "undefined"){
52338 this.split.maxSize = config.maxSize;
52340 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52341 this.hideSplitter();
52346 getHMaxSize : function(){
52347 var cmax = this.config.maxSize || 10000;
52348 var center = this.mgr.getRegion("center");
52349 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52352 getVMaxSize : function(){
52353 var cmax = this.config.maxSize || 10000;
52354 var center = this.mgr.getRegion("center");
52355 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52358 onSplitMove : function(split, newSize){
52359 this.fireEvent("resized", this, newSize);
52363 * Returns the {@link Roo.SplitBar} for this region.
52364 * @return {Roo.SplitBar}
52366 getSplitBar : function(){
52371 this.hideSplitter();
52372 Roo.SplitLayoutRegion.superclass.hide.call(this);
52375 hideSplitter : function(){
52377 this.split.el.setLocation(-2000,-2000);
52378 this.split.el.hide();
52384 this.split.el.show();
52386 Roo.SplitLayoutRegion.superclass.show.call(this);
52389 beforeSlide: function(){
52390 if(Roo.isGecko){// firefox overflow auto bug workaround
52391 this.bodyEl.clip();
52393 this.tabs.bodyEl.clip();
52395 if(this.activePanel){
52396 this.activePanel.getEl().clip();
52398 if(this.activePanel.beforeSlide){
52399 this.activePanel.beforeSlide();
52405 afterSlide : function(){
52406 if(Roo.isGecko){// firefox overflow auto bug workaround
52407 this.bodyEl.unclip();
52409 this.tabs.bodyEl.unclip();
52411 if(this.activePanel){
52412 this.activePanel.getEl().unclip();
52413 if(this.activePanel.afterSlide){
52414 this.activePanel.afterSlide();
52420 initAutoHide : function(){
52421 if(this.autoHide !== false){
52422 if(!this.autoHideHd){
52423 var st = new Roo.util.DelayedTask(this.slideIn, this);
52424 this.autoHideHd = {
52425 "mouseout": function(e){
52426 if(!e.within(this.el, true)){
52430 "mouseover" : function(e){
52436 this.el.on(this.autoHideHd);
52440 clearAutoHide : function(){
52441 if(this.autoHide !== false){
52442 this.el.un("mouseout", this.autoHideHd.mouseout);
52443 this.el.un("mouseover", this.autoHideHd.mouseover);
52447 clearMonitor : function(){
52448 Roo.get(document).un("click", this.slideInIf, this);
52451 // these names are backwards but not changed for compat
52452 slideOut : function(){
52453 if(this.isSlid || this.el.hasActiveFx()){
52456 this.isSlid = true;
52457 if(this.collapseBtn){
52458 this.collapseBtn.hide();
52460 this.closeBtnState = this.closeBtn.getStyle('display');
52461 this.closeBtn.hide();
52463 this.stickBtn.show();
52466 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52467 this.beforeSlide();
52468 this.el.setStyle("z-index", 10001);
52469 this.el.slideIn(this.getSlideAnchor(), {
52470 callback: function(){
52472 this.initAutoHide();
52473 Roo.get(document).on("click", this.slideInIf, this);
52474 this.fireEvent("slideshow", this);
52481 afterSlideIn : function(){
52482 this.clearAutoHide();
52483 this.isSlid = false;
52484 this.clearMonitor();
52485 this.el.setStyle("z-index", "");
52486 if(this.collapseBtn){
52487 this.collapseBtn.show();
52489 this.closeBtn.setStyle('display', this.closeBtnState);
52491 this.stickBtn.hide();
52493 this.fireEvent("slidehide", this);
52496 slideIn : function(cb){
52497 if(!this.isSlid || this.el.hasActiveFx()){
52501 this.isSlid = false;
52502 this.beforeSlide();
52503 this.el.slideOut(this.getSlideAnchor(), {
52504 callback: function(){
52505 this.el.setLeftTop(-10000, -10000);
52507 this.afterSlideIn();
52515 slideInIf : function(e){
52516 if(!e.within(this.el)){
52521 animateCollapse : function(){
52522 this.beforeSlide();
52523 this.el.setStyle("z-index", 20000);
52524 var anchor = this.getSlideAnchor();
52525 this.el.slideOut(anchor, {
52526 callback : function(){
52527 this.el.setStyle("z-index", "");
52528 this.collapsedEl.slideIn(anchor, {duration:.3});
52530 this.el.setLocation(-10000,-10000);
52532 this.fireEvent("collapsed", this);
52539 animateExpand : function(){
52540 this.beforeSlide();
52541 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52542 this.el.setStyle("z-index", 20000);
52543 this.collapsedEl.hide({
52546 this.el.slideIn(this.getSlideAnchor(), {
52547 callback : function(){
52548 this.el.setStyle("z-index", "");
52551 this.split.el.show();
52553 this.fireEvent("invalidated", this);
52554 this.fireEvent("expanded", this);
52582 getAnchor : function(){
52583 return this.anchors[this.position];
52586 getCollapseAnchor : function(){
52587 return this.canchors[this.position];
52590 getSlideAnchor : function(){
52591 return this.sanchors[this.position];
52594 getAlignAdj : function(){
52595 var cm = this.cmargins;
52596 switch(this.position){
52612 getExpandAdj : function(){
52613 var c = this.collapsedEl, cm = this.cmargins;
52614 switch(this.position){
52616 return [-(cm.right+c.getWidth()+cm.left), 0];
52619 return [cm.right+c.getWidth()+cm.left, 0];
52622 return [0, -(cm.top+cm.bottom+c.getHeight())];
52625 return [0, cm.top+cm.bottom+c.getHeight()];
52631 * Ext JS Library 1.1.1
52632 * Copyright(c) 2006-2007, Ext JS, LLC.
52634 * Originally Released Under LGPL - original licence link has changed is not relivant.
52637 * <script type="text/javascript">
52640 * These classes are private internal classes
52642 Roo.CenterLayoutRegion = function(mgr, config){
52643 Roo.LayoutRegion.call(this, mgr, config, "center");
52644 this.visible = true;
52645 this.minWidth = config.minWidth || 20;
52646 this.minHeight = config.minHeight || 20;
52649 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52651 // center panel can't be hidden
52655 // center panel can't be hidden
52658 getMinWidth: function(){
52659 return this.minWidth;
52662 getMinHeight: function(){
52663 return this.minHeight;
52668 Roo.NorthLayoutRegion = function(mgr, config){
52669 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52671 this.split.placement = Roo.SplitBar.TOP;
52672 this.split.orientation = Roo.SplitBar.VERTICAL;
52673 this.split.el.addClass("x-layout-split-v");
52675 var size = config.initialSize || config.height;
52676 if(typeof size != "undefined"){
52677 this.el.setHeight(size);
52680 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52681 orientation: Roo.SplitBar.VERTICAL,
52682 getBox : function(){
52683 if(this.collapsed){
52684 return this.collapsedEl.getBox();
52686 var box = this.el.getBox();
52688 box.height += this.split.el.getHeight();
52693 updateBox : function(box){
52694 if(this.split && !this.collapsed){
52695 box.height -= this.split.el.getHeight();
52696 this.split.el.setLeft(box.x);
52697 this.split.el.setTop(box.y+box.height);
52698 this.split.el.setWidth(box.width);
52700 if(this.collapsed){
52701 this.updateBody(box.width, null);
52703 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52707 Roo.SouthLayoutRegion = function(mgr, config){
52708 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52710 this.split.placement = Roo.SplitBar.BOTTOM;
52711 this.split.orientation = Roo.SplitBar.VERTICAL;
52712 this.split.el.addClass("x-layout-split-v");
52714 var size = config.initialSize || config.height;
52715 if(typeof size != "undefined"){
52716 this.el.setHeight(size);
52719 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52720 orientation: Roo.SplitBar.VERTICAL,
52721 getBox : function(){
52722 if(this.collapsed){
52723 return this.collapsedEl.getBox();
52725 var box = this.el.getBox();
52727 var sh = this.split.el.getHeight();
52734 updateBox : function(box){
52735 if(this.split && !this.collapsed){
52736 var sh = this.split.el.getHeight();
52739 this.split.el.setLeft(box.x);
52740 this.split.el.setTop(box.y-sh);
52741 this.split.el.setWidth(box.width);
52743 if(this.collapsed){
52744 this.updateBody(box.width, null);
52746 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52750 Roo.EastLayoutRegion = function(mgr, config){
52751 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
52753 this.split.placement = Roo.SplitBar.RIGHT;
52754 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52755 this.split.el.addClass("x-layout-split-h");
52757 var size = config.initialSize || config.width;
52758 if(typeof size != "undefined"){
52759 this.el.setWidth(size);
52762 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
52763 orientation: Roo.SplitBar.HORIZONTAL,
52764 getBox : function(){
52765 if(this.collapsed){
52766 return this.collapsedEl.getBox();
52768 var box = this.el.getBox();
52770 var sw = this.split.el.getWidth();
52777 updateBox : function(box){
52778 if(this.split && !this.collapsed){
52779 var sw = this.split.el.getWidth();
52781 this.split.el.setLeft(box.x);
52782 this.split.el.setTop(box.y);
52783 this.split.el.setHeight(box.height);
52786 if(this.collapsed){
52787 this.updateBody(null, box.height);
52789 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52793 Roo.WestLayoutRegion = function(mgr, config){
52794 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
52796 this.split.placement = Roo.SplitBar.LEFT;
52797 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52798 this.split.el.addClass("x-layout-split-h");
52800 var size = config.initialSize || config.width;
52801 if(typeof size != "undefined"){
52802 this.el.setWidth(size);
52805 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
52806 orientation: Roo.SplitBar.HORIZONTAL,
52807 getBox : function(){
52808 if(this.collapsed){
52809 return this.collapsedEl.getBox();
52811 var box = this.el.getBox();
52813 box.width += this.split.el.getWidth();
52818 updateBox : function(box){
52819 if(this.split && !this.collapsed){
52820 var sw = this.split.el.getWidth();
52822 this.split.el.setLeft(box.x+box.width);
52823 this.split.el.setTop(box.y);
52824 this.split.el.setHeight(box.height);
52826 if(this.collapsed){
52827 this.updateBody(null, box.height);
52829 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52834 * Ext JS Library 1.1.1
52835 * Copyright(c) 2006-2007, Ext JS, LLC.
52837 * Originally Released Under LGPL - original licence link has changed is not relivant.
52840 * <script type="text/javascript">
52845 * Private internal class for reading and applying state
52847 Roo.LayoutStateManager = function(layout){
52848 // default empty state
52857 Roo.LayoutStateManager.prototype = {
52858 init : function(layout, provider){
52859 this.provider = provider;
52860 var state = provider.get(layout.id+"-layout-state");
52862 var wasUpdating = layout.isUpdating();
52864 layout.beginUpdate();
52866 for(var key in state){
52867 if(typeof state[key] != "function"){
52868 var rstate = state[key];
52869 var r = layout.getRegion(key);
52872 r.resizeTo(rstate.size);
52874 if(rstate.collapsed == true){
52877 r.expand(null, true);
52883 layout.endUpdate();
52885 this.state = state;
52887 this.layout = layout;
52888 layout.on("regionresized", this.onRegionResized, this);
52889 layout.on("regioncollapsed", this.onRegionCollapsed, this);
52890 layout.on("regionexpanded", this.onRegionExpanded, this);
52893 storeState : function(){
52894 this.provider.set(this.layout.id+"-layout-state", this.state);
52897 onRegionResized : function(region, newSize){
52898 this.state[region.getPosition()].size = newSize;
52902 onRegionCollapsed : function(region){
52903 this.state[region.getPosition()].collapsed = true;
52907 onRegionExpanded : function(region){
52908 this.state[region.getPosition()].collapsed = false;
52913 * Ext JS Library 1.1.1
52914 * Copyright(c) 2006-2007, Ext JS, LLC.
52916 * Originally Released Under LGPL - original licence link has changed is not relivant.
52919 * <script type="text/javascript">
52922 * @class Roo.ContentPanel
52923 * @extends Roo.util.Observable
52924 * A basic ContentPanel element.
52925 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
52926 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
52927 * @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
52928 * @cfg {Boolean} closable True if the panel can be closed/removed
52929 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
52930 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
52931 * @cfg {Toolbar} toolbar A toolbar for this panel
52932 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
52933 * @cfg {String} title The title for this panel
52934 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
52935 * @cfg {String} url Calls {@link #setUrl} with this value
52936 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
52937 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
52938 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
52939 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
52942 * Create a new ContentPanel.
52943 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
52944 * @param {String/Object} config A string to set only the title or a config object
52945 * @param {String} content (optional) Set the HTML content for this panel
52946 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
52948 Roo.ContentPanel = function(el, config, content){
52952 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
52956 if (config && config.parentLayout) {
52957 el = config.parentLayout.el.createChild();
52960 if(el.autoCreate){ // xtype is available if this is called from factory
52964 this.el = Roo.get(el);
52965 if(!this.el && config && config.autoCreate){
52966 if(typeof config.autoCreate == "object"){
52967 if(!config.autoCreate.id){
52968 config.autoCreate.id = config.id||el;
52970 this.el = Roo.DomHelper.append(document.body,
52971 config.autoCreate, true);
52973 this.el = Roo.DomHelper.append(document.body,
52974 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
52977 this.closable = false;
52978 this.loaded = false;
52979 this.active = false;
52980 if(typeof config == "string"){
52981 this.title = config;
52983 Roo.apply(this, config);
52986 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
52987 this.wrapEl = this.el.wrap();
52988 this.toolbar.container = this.el.insertSibling(false, 'before');
52989 this.toolbar = new Roo.Toolbar(this.toolbar);
52992 // xtype created footer. - not sure if will work as we normally have to render first..
52993 if (this.footer && !this.footer.el && this.footer.xtype) {
52994 if (!this.wrapEl) {
52995 this.wrapEl = this.el.wrap();
52998 this.footer.container = this.wrapEl.createChild();
53000 this.footer = Roo.factory(this.footer, Roo);
53005 this.resizeEl = Roo.get(this.resizeEl, true);
53007 this.resizeEl = this.el;
53009 // handle view.xtype
53017 * Fires when this panel is activated.
53018 * @param {Roo.ContentPanel} this
53022 * @event deactivate
53023 * Fires when this panel is activated.
53024 * @param {Roo.ContentPanel} this
53026 "deactivate" : true,
53030 * Fires when this panel is resized if fitToFrame is true.
53031 * @param {Roo.ContentPanel} this
53032 * @param {Number} width The width after any component adjustments
53033 * @param {Number} height The height after any component adjustments
53039 * Fires when this tab is created
53040 * @param {Roo.ContentPanel} this
53051 if(this.autoScroll){
53052 this.resizeEl.setStyle("overflow", "auto");
53054 // fix randome scrolling
53055 this.el.on('scroll', function() {
53056 Roo.log('fix random scolling');
53057 this.scrollTo('top',0);
53060 content = content || this.content;
53062 this.setContent(content);
53064 if(config && config.url){
53065 this.setUrl(this.url, this.params, this.loadOnce);
53070 Roo.ContentPanel.superclass.constructor.call(this);
53072 if (this.view && typeof(this.view.xtype) != 'undefined') {
53073 this.view.el = this.el.appendChild(document.createElement("div"));
53074 this.view = Roo.factory(this.view);
53075 this.view.render && this.view.render(false, '');
53079 this.fireEvent('render', this);
53082 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53084 setRegion : function(region){
53085 this.region = region;
53087 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53089 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53094 * Returns the toolbar for this Panel if one was configured.
53095 * @return {Roo.Toolbar}
53097 getToolbar : function(){
53098 return this.toolbar;
53101 setActiveState : function(active){
53102 this.active = active;
53104 this.fireEvent("deactivate", this);
53106 this.fireEvent("activate", this);
53110 * Updates this panel's element
53111 * @param {String} content The new content
53112 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53114 setContent : function(content, loadScripts){
53115 this.el.update(content, loadScripts);
53118 ignoreResize : function(w, h){
53119 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53122 this.lastSize = {width: w, height: h};
53127 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53128 * @return {Roo.UpdateManager} The UpdateManager
53130 getUpdateManager : function(){
53131 return this.el.getUpdateManager();
53134 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53135 * @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:
53138 url: "your-url.php",
53139 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53140 callback: yourFunction,
53141 scope: yourObject, //(optional scope)
53144 text: "Loading...",
53149 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53150 * 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.
53151 * @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}
53152 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53153 * @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.
53154 * @return {Roo.ContentPanel} this
53157 var um = this.el.getUpdateManager();
53158 um.update.apply(um, arguments);
53164 * 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.
53165 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53166 * @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)
53167 * @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)
53168 * @return {Roo.UpdateManager} The UpdateManager
53170 setUrl : function(url, params, loadOnce){
53171 if(this.refreshDelegate){
53172 this.removeListener("activate", this.refreshDelegate);
53174 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53175 this.on("activate", this.refreshDelegate);
53176 return this.el.getUpdateManager();
53179 _handleRefresh : function(url, params, loadOnce){
53180 if(!loadOnce || !this.loaded){
53181 var updater = this.el.getUpdateManager();
53182 updater.update(url, params, this._setLoaded.createDelegate(this));
53186 _setLoaded : function(){
53187 this.loaded = true;
53191 * Returns this panel's id
53194 getId : function(){
53199 * Returns this panel's element - used by regiosn to add.
53200 * @return {Roo.Element}
53202 getEl : function(){
53203 return this.wrapEl || this.el;
53206 adjustForComponents : function(width, height)
53208 //Roo.log('adjustForComponents ');
53209 if(this.resizeEl != this.el){
53210 width -= this.el.getFrameWidth('lr');
53211 height -= this.el.getFrameWidth('tb');
53214 var te = this.toolbar.getEl();
53215 height -= te.getHeight();
53216 te.setWidth(width);
53219 var te = this.footer.getEl();
53220 Roo.log("footer:" + te.getHeight());
53222 height -= te.getHeight();
53223 te.setWidth(width);
53227 if(this.adjustments){
53228 width += this.adjustments[0];
53229 height += this.adjustments[1];
53231 return {"width": width, "height": height};
53234 setSize : function(width, height){
53235 if(this.fitToFrame && !this.ignoreResize(width, height)){
53236 if(this.fitContainer && this.resizeEl != this.el){
53237 this.el.setSize(width, height);
53239 var size = this.adjustForComponents(width, height);
53240 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53241 this.fireEvent('resize', this, size.width, size.height);
53246 * Returns this panel's title
53249 getTitle : function(){
53254 * Set this panel's title
53255 * @param {String} title
53257 setTitle : function(title){
53258 this.title = title;
53260 this.region.updatePanelTitle(this, title);
53265 * Returns true is this panel was configured to be closable
53266 * @return {Boolean}
53268 isClosable : function(){
53269 return this.closable;
53272 beforeSlide : function(){
53274 this.resizeEl.clip();
53277 afterSlide : function(){
53279 this.resizeEl.unclip();
53283 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53284 * Will fail silently if the {@link #setUrl} method has not been called.
53285 * This does not activate the panel, just updates its content.
53287 refresh : function(){
53288 if(this.refreshDelegate){
53289 this.loaded = false;
53290 this.refreshDelegate();
53295 * Destroys this panel
53297 destroy : function(){
53298 this.el.removeAllListeners();
53299 var tempEl = document.createElement("span");
53300 tempEl.appendChild(this.el.dom);
53301 tempEl.innerHTML = "";
53307 * form - if the content panel contains a form - this is a reference to it.
53308 * @type {Roo.form.Form}
53312 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53313 * This contains a reference to it.
53319 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53329 * @param {Object} cfg Xtype definition of item to add.
53332 addxtype : function(cfg) {
53334 if (cfg.xtype.match(/^Form$/)) {
53337 //if (this.footer) {
53338 // el = this.footer.container.insertSibling(false, 'before');
53340 el = this.el.createChild();
53343 this.form = new Roo.form.Form(cfg);
53346 if ( this.form.allItems.length) {
53347 this.form.render(el.dom);
53351 // should only have one of theses..
53352 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53353 // views.. should not be just added - used named prop 'view''
53355 cfg.el = this.el.appendChild(document.createElement("div"));
53358 var ret = new Roo.factory(cfg);
53360 ret.render && ret.render(false, ''); // render blank..
53369 * @class Roo.GridPanel
53370 * @extends Roo.ContentPanel
53372 * Create a new GridPanel.
53373 * @param {Roo.grid.Grid} grid The grid for this panel
53374 * @param {String/Object} config A string to set only the panel's title, or a config object
53376 Roo.GridPanel = function(grid, config){
53379 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53380 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53382 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53384 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53387 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53389 // xtype created footer. - not sure if will work as we normally have to render first..
53390 if (this.footer && !this.footer.el && this.footer.xtype) {
53392 this.footer.container = this.grid.getView().getFooterPanel(true);
53393 this.footer.dataSource = this.grid.dataSource;
53394 this.footer = Roo.factory(this.footer, Roo);
53398 grid.monitorWindowResize = false; // turn off autosizing
53399 grid.autoHeight = false;
53400 grid.autoWidth = false;
53402 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53405 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53406 getId : function(){
53407 return this.grid.id;
53411 * Returns the grid for this panel
53412 * @return {Roo.grid.Grid}
53414 getGrid : function(){
53418 setSize : function(width, height){
53419 if(!this.ignoreResize(width, height)){
53420 var grid = this.grid;
53421 var size = this.adjustForComponents(width, height);
53422 grid.getGridEl().setSize(size.width, size.height);
53427 beforeSlide : function(){
53428 this.grid.getView().scroller.clip();
53431 afterSlide : function(){
53432 this.grid.getView().scroller.unclip();
53435 destroy : function(){
53436 this.grid.destroy();
53438 Roo.GridPanel.superclass.destroy.call(this);
53444 * @class Roo.NestedLayoutPanel
53445 * @extends Roo.ContentPanel
53447 * Create a new NestedLayoutPanel.
53450 * @param {Roo.BorderLayout} layout The layout for this panel
53451 * @param {String/Object} config A string to set only the title or a config object
53453 Roo.NestedLayoutPanel = function(layout, config)
53455 // construct with only one argument..
53456 /* FIXME - implement nicer consturctors
53457 if (layout.layout) {
53459 layout = config.layout;
53460 delete config.layout;
53462 if (layout.xtype && !layout.getEl) {
53463 // then layout needs constructing..
53464 layout = Roo.factory(layout, Roo);
53469 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53471 layout.monitorWindowResize = false; // turn off autosizing
53472 this.layout = layout;
53473 this.layout.getEl().addClass("x-layout-nested-layout");
53480 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53482 setSize : function(width, height){
53483 if(!this.ignoreResize(width, height)){
53484 var size = this.adjustForComponents(width, height);
53485 var el = this.layout.getEl();
53486 el.setSize(size.width, size.height);
53487 var touch = el.dom.offsetWidth;
53488 this.layout.layout();
53489 // ie requires a double layout on the first pass
53490 if(Roo.isIE && !this.initialized){
53491 this.initialized = true;
53492 this.layout.layout();
53497 // activate all subpanels if not currently active..
53499 setActiveState : function(active){
53500 this.active = active;
53502 this.fireEvent("deactivate", this);
53506 this.fireEvent("activate", this);
53507 // not sure if this should happen before or after..
53508 if (!this.layout) {
53509 return; // should not happen..
53512 for (var r in this.layout.regions) {
53513 reg = this.layout.getRegion(r);
53514 if (reg.getActivePanel()) {
53515 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53516 reg.setActivePanel(reg.getActivePanel());
53519 if (!reg.panels.length) {
53522 reg.showPanel(reg.getPanel(0));
53531 * Returns the nested BorderLayout for this panel
53532 * @return {Roo.BorderLayout}
53534 getLayout : function(){
53535 return this.layout;
53539 * Adds a xtype elements to the layout of the nested panel
53543 xtype : 'ContentPanel',
53550 xtype : 'NestedLayoutPanel',
53556 items : [ ... list of content panels or nested layout panels.. ]
53560 * @param {Object} cfg Xtype definition of item to add.
53562 addxtype : function(cfg) {
53563 return this.layout.addxtype(cfg);
53568 Roo.ScrollPanel = function(el, config, content){
53569 config = config || {};
53570 config.fitToFrame = true;
53571 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53573 this.el.dom.style.overflow = "hidden";
53574 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53575 this.el.removeClass("x-layout-inactive-content");
53576 this.el.on("mousewheel", this.onWheel, this);
53578 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53579 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53580 up.unselectable(); down.unselectable();
53581 up.on("click", this.scrollUp, this);
53582 down.on("click", this.scrollDown, this);
53583 up.addClassOnOver("x-scroller-btn-over");
53584 down.addClassOnOver("x-scroller-btn-over");
53585 up.addClassOnClick("x-scroller-btn-click");
53586 down.addClassOnClick("x-scroller-btn-click");
53587 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53589 this.resizeEl = this.el;
53590 this.el = wrap; this.up = up; this.down = down;
53593 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53595 wheelIncrement : 5,
53596 scrollUp : function(){
53597 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53600 scrollDown : function(){
53601 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53604 afterScroll : function(){
53605 var el = this.resizeEl;
53606 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53607 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53608 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53611 setSize : function(){
53612 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53613 this.afterScroll();
53616 onWheel : function(e){
53617 var d = e.getWheelDelta();
53618 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53619 this.afterScroll();
53623 setContent : function(content, loadScripts){
53624 this.resizeEl.update(content, loadScripts);
53638 * @class Roo.TreePanel
53639 * @extends Roo.ContentPanel
53641 * Create a new TreePanel. - defaults to fit/scoll contents.
53642 * @param {String/Object} config A string to set only the panel's title, or a config object
53643 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53645 Roo.TreePanel = function(config){
53646 var el = config.el;
53647 var tree = config.tree;
53648 delete config.tree;
53649 delete config.el; // hopefull!
53651 // wrapper for IE7 strict & safari scroll issue
53653 var treeEl = el.createChild();
53654 config.resizeEl = treeEl;
53658 Roo.TreePanel.superclass.constructor.call(this, el, config);
53661 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53662 //console.log(tree);
53663 this.on('activate', function()
53665 if (this.tree.rendered) {
53668 //console.log('render tree');
53669 this.tree.render();
53671 // this should not be needed.. - it's actually the 'el' that resizes?
53672 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53674 //this.on('resize', function (cp, w, h) {
53675 // this.tree.innerCt.setWidth(w);
53676 // this.tree.innerCt.setHeight(h);
53677 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53684 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53701 * Ext JS Library 1.1.1
53702 * Copyright(c) 2006-2007, Ext JS, LLC.
53704 * Originally Released Under LGPL - original licence link has changed is not relivant.
53707 * <script type="text/javascript">
53712 * @class Roo.ReaderLayout
53713 * @extends Roo.BorderLayout
53714 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53715 * center region containing two nested regions (a top one for a list view and one for item preview below),
53716 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53717 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53718 * expedites the setup of the overall layout and regions for this common application style.
53721 var reader = new Roo.ReaderLayout();
53722 var CP = Roo.ContentPanel; // shortcut for adding
53724 reader.beginUpdate();
53725 reader.add("north", new CP("north", "North"));
53726 reader.add("west", new CP("west", {title: "West"}));
53727 reader.add("east", new CP("east", {title: "East"}));
53729 reader.regions.listView.add(new CP("listView", "List"));
53730 reader.regions.preview.add(new CP("preview", "Preview"));
53731 reader.endUpdate();
53734 * Create a new ReaderLayout
53735 * @param {Object} config Configuration options
53736 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
53737 * document.body if omitted)
53739 Roo.ReaderLayout = function(config, renderTo){
53740 var c = config || {size:{}};
53741 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
53742 north: c.north !== false ? Roo.apply({
53746 }, c.north) : false,
53747 west: c.west !== false ? Roo.apply({
53755 margins:{left:5,right:0,bottom:5,top:5},
53756 cmargins:{left:5,right:5,bottom:5,top:5}
53757 }, c.west) : false,
53758 east: c.east !== false ? Roo.apply({
53766 margins:{left:0,right:5,bottom:5,top:5},
53767 cmargins:{left:5,right:5,bottom:5,top:5}
53768 }, c.east) : false,
53769 center: Roo.apply({
53770 tabPosition: 'top',
53774 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
53778 this.el.addClass('x-reader');
53780 this.beginUpdate();
53782 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
53783 south: c.preview !== false ? Roo.apply({
53790 cmargins:{top:5,left:0, right:0, bottom:0}
53791 }, c.preview) : false,
53792 center: Roo.apply({
53798 this.add('center', new Roo.NestedLayoutPanel(inner,
53799 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
53803 this.regions.preview = inner.getRegion('south');
53804 this.regions.listView = inner.getRegion('center');
53807 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
53809 * Ext JS Library 1.1.1
53810 * Copyright(c) 2006-2007, Ext JS, LLC.
53812 * Originally Released Under LGPL - original licence link has changed is not relivant.
53815 * <script type="text/javascript">
53819 * @class Roo.grid.Grid
53820 * @extends Roo.util.Observable
53821 * This class represents the primary interface of a component based grid control.
53822 * <br><br>Usage:<pre><code>
53823 var grid = new Roo.grid.Grid("my-container-id", {
53826 selModel: mySelectionModel,
53827 autoSizeColumns: true,
53828 monitorWindowResize: false,
53829 trackMouseOver: true
53834 * <b>Common Problems:</b><br/>
53835 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
53836 * element will correct this<br/>
53837 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
53838 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
53839 * are unpredictable.<br/>
53840 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
53841 * grid to calculate dimensions/offsets.<br/>
53843 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53844 * The container MUST have some type of size defined for the grid to fill. The container will be
53845 * automatically set to position relative if it isn't already.
53846 * @param {Object} config A config object that sets properties on this grid.
53848 Roo.grid.Grid = function(container, config){
53849 // initialize the container
53850 this.container = Roo.get(container);
53851 this.container.update("");
53852 this.container.setStyle("overflow", "hidden");
53853 this.container.addClass('x-grid-container');
53855 this.id = this.container.id;
53857 Roo.apply(this, config);
53858 // check and correct shorthanded configs
53860 this.dataSource = this.ds;
53864 this.colModel = this.cm;
53868 this.selModel = this.sm;
53872 if (this.selModel) {
53873 this.selModel = Roo.factory(this.selModel, Roo.grid);
53874 this.sm = this.selModel;
53875 this.sm.xmodule = this.xmodule || false;
53877 if (typeof(this.colModel.config) == 'undefined') {
53878 this.colModel = new Roo.grid.ColumnModel(this.colModel);
53879 this.cm = this.colModel;
53880 this.cm.xmodule = this.xmodule || false;
53882 if (this.dataSource) {
53883 this.dataSource= Roo.factory(this.dataSource, Roo.data);
53884 this.ds = this.dataSource;
53885 this.ds.xmodule = this.xmodule || false;
53892 this.container.setWidth(this.width);
53896 this.container.setHeight(this.height);
53903 * The raw click event for the entire grid.
53904 * @param {Roo.EventObject} e
53909 * The raw dblclick event for the entire grid.
53910 * @param {Roo.EventObject} e
53914 * @event contextmenu
53915 * The raw contextmenu event for the entire grid.
53916 * @param {Roo.EventObject} e
53918 "contextmenu" : true,
53921 * The raw mousedown event for the entire grid.
53922 * @param {Roo.EventObject} e
53924 "mousedown" : true,
53927 * The raw mouseup event for the entire grid.
53928 * @param {Roo.EventObject} e
53933 * The raw mouseover event for the entire grid.
53934 * @param {Roo.EventObject} e
53936 "mouseover" : true,
53939 * The raw mouseout event for the entire grid.
53940 * @param {Roo.EventObject} e
53945 * The raw keypress event for the entire grid.
53946 * @param {Roo.EventObject} e
53951 * The raw keydown event for the entire grid.
53952 * @param {Roo.EventObject} e
53960 * Fires when a cell is clicked
53961 * @param {Grid} this
53962 * @param {Number} rowIndex
53963 * @param {Number} columnIndex
53964 * @param {Roo.EventObject} e
53966 "cellclick" : true,
53968 * @event celldblclick
53969 * Fires when a cell is double clicked
53970 * @param {Grid} this
53971 * @param {Number} rowIndex
53972 * @param {Number} columnIndex
53973 * @param {Roo.EventObject} e
53975 "celldblclick" : true,
53978 * Fires when a row is clicked
53979 * @param {Grid} this
53980 * @param {Number} rowIndex
53981 * @param {Roo.EventObject} e
53985 * @event rowdblclick
53986 * Fires when a row is double clicked
53987 * @param {Grid} this
53988 * @param {Number} rowIndex
53989 * @param {Roo.EventObject} e
53991 "rowdblclick" : true,
53993 * @event headerclick
53994 * Fires when a header is clicked
53995 * @param {Grid} this
53996 * @param {Number} columnIndex
53997 * @param {Roo.EventObject} e
53999 "headerclick" : true,
54001 * @event headerdblclick
54002 * Fires when a header cell is double clicked
54003 * @param {Grid} this
54004 * @param {Number} columnIndex
54005 * @param {Roo.EventObject} e
54007 "headerdblclick" : true,
54009 * @event rowcontextmenu
54010 * Fires when a row is right clicked
54011 * @param {Grid} this
54012 * @param {Number} rowIndex
54013 * @param {Roo.EventObject} e
54015 "rowcontextmenu" : true,
54017 * @event cellcontextmenu
54018 * Fires when a cell is right clicked
54019 * @param {Grid} this
54020 * @param {Number} rowIndex
54021 * @param {Number} cellIndex
54022 * @param {Roo.EventObject} e
54024 "cellcontextmenu" : true,
54026 * @event headercontextmenu
54027 * Fires when a header is right clicked
54028 * @param {Grid} this
54029 * @param {Number} columnIndex
54030 * @param {Roo.EventObject} e
54032 "headercontextmenu" : true,
54034 * @event bodyscroll
54035 * Fires when the body element is scrolled
54036 * @param {Number} scrollLeft
54037 * @param {Number} scrollTop
54039 "bodyscroll" : true,
54041 * @event columnresize
54042 * Fires when the user resizes a column
54043 * @param {Number} columnIndex
54044 * @param {Number} newSize
54046 "columnresize" : true,
54048 * @event columnmove
54049 * Fires when the user moves a column
54050 * @param {Number} oldIndex
54051 * @param {Number} newIndex
54053 "columnmove" : true,
54056 * Fires when row(s) start being dragged
54057 * @param {Grid} this
54058 * @param {Roo.GridDD} dd The drag drop object
54059 * @param {event} e The raw browser event
54061 "startdrag" : true,
54064 * Fires when a drag operation is complete
54065 * @param {Grid} this
54066 * @param {Roo.GridDD} dd The drag drop object
54067 * @param {event} e The raw browser event
54072 * Fires when dragged row(s) are dropped on a valid DD target
54073 * @param {Grid} this
54074 * @param {Roo.GridDD} dd The drag drop object
54075 * @param {String} targetId The target drag drop object
54076 * @param {event} e The raw browser event
54081 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54082 * @param {Grid} this
54083 * @param {Roo.GridDD} dd The drag drop object
54084 * @param {String} targetId The target drag drop object
54085 * @param {event} e The raw browser event
54090 * Fires when the dragged row(s) first cross another DD target while being dragged
54091 * @param {Grid} this
54092 * @param {Roo.GridDD} dd The drag drop object
54093 * @param {String} targetId The target drag drop object
54094 * @param {event} e The raw browser event
54096 "dragenter" : true,
54099 * Fires when the dragged row(s) leave another DD target while being dragged
54100 * @param {Grid} this
54101 * @param {Roo.GridDD} dd The drag drop object
54102 * @param {String} targetId The target drag drop object
54103 * @param {event} e The raw browser event
54108 * Fires when a row is rendered, so you can change add a style to it.
54109 * @param {GridView} gridview The grid view
54110 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54116 * Fires when the grid is rendered
54117 * @param {Grid} grid
54122 Roo.grid.Grid.superclass.constructor.call(this);
54124 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54127 * @cfg {String} ddGroup - drag drop group.
54131 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54133 minColumnWidth : 25,
54136 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54137 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54138 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54140 autoSizeColumns : false,
54143 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54145 autoSizeHeaders : true,
54148 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54150 monitorWindowResize : true,
54153 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54154 * rows measured to get a columns size. Default is 0 (all rows).
54156 maxRowsToMeasure : 0,
54159 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54161 trackMouseOver : true,
54164 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54168 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54170 enableDragDrop : false,
54173 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54175 enableColumnMove : true,
54178 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54180 enableColumnHide : true,
54183 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54185 enableRowHeightSync : false,
54188 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54193 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54195 autoHeight : false,
54198 * @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.
54200 autoExpandColumn : false,
54203 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54206 autoExpandMin : 50,
54209 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54211 autoExpandMax : 1000,
54214 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54219 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54223 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54233 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54234 * of a fixed width. Default is false.
54237 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54240 * Called once after all setup has been completed and the grid is ready to be rendered.
54241 * @return {Roo.grid.Grid} this
54243 render : function()
54245 var c = this.container;
54246 // try to detect autoHeight/width mode
54247 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54248 this.autoHeight = true;
54250 var view = this.getView();
54253 c.on("click", this.onClick, this);
54254 c.on("dblclick", this.onDblClick, this);
54255 c.on("contextmenu", this.onContextMenu, this);
54256 c.on("keydown", this.onKeyDown, this);
54258 c.on("touchstart", this.onTouchStart, this);
54261 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54263 this.getSelectionModel().init(this);
54268 this.loadMask = new Roo.LoadMask(this.container,
54269 Roo.apply({store:this.dataSource}, this.loadMask));
54273 if (this.toolbar && this.toolbar.xtype) {
54274 this.toolbar.container = this.getView().getHeaderPanel(true);
54275 this.toolbar = new Roo.Toolbar(this.toolbar);
54277 if (this.footer && this.footer.xtype) {
54278 this.footer.dataSource = this.getDataSource();
54279 this.footer.container = this.getView().getFooterPanel(true);
54280 this.footer = Roo.factory(this.footer, Roo);
54282 if (this.dropTarget && this.dropTarget.xtype) {
54283 delete this.dropTarget.xtype;
54284 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54288 this.rendered = true;
54289 this.fireEvent('render', this);
54294 * Reconfigures the grid to use a different Store and Column Model.
54295 * The View will be bound to the new objects and refreshed.
54296 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54297 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54299 reconfigure : function(dataSource, colModel){
54301 this.loadMask.destroy();
54302 this.loadMask = new Roo.LoadMask(this.container,
54303 Roo.apply({store:dataSource}, this.loadMask));
54305 this.view.bind(dataSource, colModel);
54306 this.dataSource = dataSource;
54307 this.colModel = colModel;
54308 this.view.refresh(true);
54312 onKeyDown : function(e){
54313 this.fireEvent("keydown", e);
54317 * Destroy this grid.
54318 * @param {Boolean} removeEl True to remove the element
54320 destroy : function(removeEl, keepListeners){
54322 this.loadMask.destroy();
54324 var c = this.container;
54325 c.removeAllListeners();
54326 this.view.destroy();
54327 this.colModel.purgeListeners();
54328 if(!keepListeners){
54329 this.purgeListeners();
54332 if(removeEl === true){
54338 processEvent : function(name, e){
54339 // does this fire select???
54340 //Roo.log('grid:processEvent ' + name);
54342 if (name != 'touchstart' ) {
54343 this.fireEvent(name, e);
54346 var t = e.getTarget();
54348 var header = v.findHeaderIndex(t);
54349 if(header !== false){
54350 var ename = name == 'touchstart' ? 'click' : name;
54352 this.fireEvent("header" + ename, this, header, e);
54354 var row = v.findRowIndex(t);
54355 var cell = v.findCellIndex(t);
54356 if (name == 'touchstart') {
54357 // first touch is always a click.
54358 // hopefull this happens after selection is updated.?
54361 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54362 var cs = this.selModel.getSelectedCell();
54363 if (row == cs[0] && cell == cs[1]){
54367 if (typeof(this.selModel.getSelections) != 'undefined') {
54368 var cs = this.selModel.getSelections();
54369 var ds = this.dataSource;
54370 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54381 this.fireEvent("row" + name, this, row, e);
54382 if(cell !== false){
54383 this.fireEvent("cell" + name, this, row, cell, e);
54390 onClick : function(e){
54391 this.processEvent("click", e);
54394 onTouchStart : function(e){
54395 this.processEvent("touchstart", e);
54399 onContextMenu : function(e, t){
54400 this.processEvent("contextmenu", e);
54404 onDblClick : function(e){
54405 this.processEvent("dblclick", e);
54409 walkCells : function(row, col, step, fn, scope){
54410 var cm = this.colModel, clen = cm.getColumnCount();
54411 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54423 if(fn.call(scope || this, row, col, cm) === true){
54441 if(fn.call(scope || this, row, col, cm) === true){
54453 getSelections : function(){
54454 return this.selModel.getSelections();
54458 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54459 * but if manual update is required this method will initiate it.
54461 autoSize : function(){
54463 this.view.layout();
54464 if(this.view.adjustForScroll){
54465 this.view.adjustForScroll();
54471 * Returns the grid's underlying element.
54472 * @return {Element} The element
54474 getGridEl : function(){
54475 return this.container;
54478 // private for compatibility, overridden by editor grid
54479 stopEditing : function(){},
54482 * Returns the grid's SelectionModel.
54483 * @return {SelectionModel}
54485 getSelectionModel : function(){
54486 if(!this.selModel){
54487 this.selModel = new Roo.grid.RowSelectionModel();
54489 return this.selModel;
54493 * Returns the grid's DataSource.
54494 * @return {DataSource}
54496 getDataSource : function(){
54497 return this.dataSource;
54501 * Returns the grid's ColumnModel.
54502 * @return {ColumnModel}
54504 getColumnModel : function(){
54505 return this.colModel;
54509 * Returns the grid's GridView object.
54510 * @return {GridView}
54512 getView : function(){
54514 this.view = new Roo.grid.GridView(this.viewConfig);
54519 * Called to get grid's drag proxy text, by default returns this.ddText.
54522 getDragDropText : function(){
54523 var count = this.selModel.getCount();
54524 return String.format(this.ddText, count, count == 1 ? '' : 's');
54528 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54529 * %0 is replaced with the number of selected rows.
54532 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54534 * Ext JS Library 1.1.1
54535 * Copyright(c) 2006-2007, Ext JS, LLC.
54537 * Originally Released Under LGPL - original licence link has changed is not relivant.
54540 * <script type="text/javascript">
54543 Roo.grid.AbstractGridView = function(){
54547 "beforerowremoved" : true,
54548 "beforerowsinserted" : true,
54549 "beforerefresh" : true,
54550 "rowremoved" : true,
54551 "rowsinserted" : true,
54552 "rowupdated" : true,
54555 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54558 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54559 rowClass : "x-grid-row",
54560 cellClass : "x-grid-cell",
54561 tdClass : "x-grid-td",
54562 hdClass : "x-grid-hd",
54563 splitClass : "x-grid-hd-split",
54565 init: function(grid){
54567 var cid = this.grid.getGridEl().id;
54568 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54569 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54570 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54571 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54574 getColumnRenderers : function(){
54575 var renderers = [];
54576 var cm = this.grid.colModel;
54577 var colCount = cm.getColumnCount();
54578 for(var i = 0; i < colCount; i++){
54579 renderers[i] = cm.getRenderer(i);
54584 getColumnIds : function(){
54586 var cm = this.grid.colModel;
54587 var colCount = cm.getColumnCount();
54588 for(var i = 0; i < colCount; i++){
54589 ids[i] = cm.getColumnId(i);
54594 getDataIndexes : function(){
54595 if(!this.indexMap){
54596 this.indexMap = this.buildIndexMap();
54598 return this.indexMap.colToData;
54601 getColumnIndexByDataIndex : function(dataIndex){
54602 if(!this.indexMap){
54603 this.indexMap = this.buildIndexMap();
54605 return this.indexMap.dataToCol[dataIndex];
54609 * Set a css style for a column dynamically.
54610 * @param {Number} colIndex The index of the column
54611 * @param {String} name The css property name
54612 * @param {String} value The css value
54614 setCSSStyle : function(colIndex, name, value){
54615 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54616 Roo.util.CSS.updateRule(selector, name, value);
54619 generateRules : function(cm){
54620 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54621 Roo.util.CSS.removeStyleSheet(rulesId);
54622 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54623 var cid = cm.getColumnId(i);
54624 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54625 this.tdSelector, cid, " {\n}\n",
54626 this.hdSelector, cid, " {\n}\n",
54627 this.splitSelector, cid, " {\n}\n");
54629 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54633 * Ext JS Library 1.1.1
54634 * Copyright(c) 2006-2007, Ext JS, LLC.
54636 * Originally Released Under LGPL - original licence link has changed is not relivant.
54639 * <script type="text/javascript">
54643 // This is a support class used internally by the Grid components
54644 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54646 this.view = grid.getView();
54647 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54648 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54650 this.setHandleElId(Roo.id(hd));
54651 this.setOuterHandleElId(Roo.id(hd2));
54653 this.scroll = false;
54655 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54657 getDragData : function(e){
54658 var t = Roo.lib.Event.getTarget(e);
54659 var h = this.view.findHeaderCell(t);
54661 return {ddel: h.firstChild, header:h};
54666 onInitDrag : function(e){
54667 this.view.headersDisabled = true;
54668 var clone = this.dragData.ddel.cloneNode(true);
54669 clone.id = Roo.id();
54670 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54671 this.proxy.update(clone);
54675 afterValidDrop : function(){
54677 setTimeout(function(){
54678 v.headersDisabled = false;
54682 afterInvalidDrop : function(){
54684 setTimeout(function(){
54685 v.headersDisabled = false;
54691 * Ext JS Library 1.1.1
54692 * Copyright(c) 2006-2007, Ext JS, LLC.
54694 * Originally Released Under LGPL - original licence link has changed is not relivant.
54697 * <script type="text/javascript">
54700 // This is a support class used internally by the Grid components
54701 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54703 this.view = grid.getView();
54704 // split the proxies so they don't interfere with mouse events
54705 this.proxyTop = Roo.DomHelper.append(document.body, {
54706 cls:"col-move-top", html:" "
54708 this.proxyBottom = Roo.DomHelper.append(document.body, {
54709 cls:"col-move-bottom", html:" "
54711 this.proxyTop.hide = this.proxyBottom.hide = function(){
54712 this.setLeftTop(-100,-100);
54713 this.setStyle("visibility", "hidden");
54715 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54716 // temporarily disabled
54717 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54718 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54720 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54721 proxyOffsets : [-4, -9],
54722 fly: Roo.Element.fly,
54724 getTargetFromEvent : function(e){
54725 var t = Roo.lib.Event.getTarget(e);
54726 var cindex = this.view.findCellIndex(t);
54727 if(cindex !== false){
54728 return this.view.getHeaderCell(cindex);
54733 nextVisible : function(h){
54734 var v = this.view, cm = this.grid.colModel;
54737 if(!cm.isHidden(v.getCellIndex(h))){
54745 prevVisible : function(h){
54746 var v = this.view, cm = this.grid.colModel;
54749 if(!cm.isHidden(v.getCellIndex(h))){
54757 positionIndicator : function(h, n, e){
54758 var x = Roo.lib.Event.getPageX(e);
54759 var r = Roo.lib.Dom.getRegion(n.firstChild);
54760 var px, pt, py = r.top + this.proxyOffsets[1];
54761 if((r.right - x) <= (r.right-r.left)/2){
54762 px = r.right+this.view.borderWidth;
54768 var oldIndex = this.view.getCellIndex(h);
54769 var newIndex = this.view.getCellIndex(n);
54771 if(this.grid.colModel.isFixed(newIndex)){
54775 var locked = this.grid.colModel.isLocked(newIndex);
54780 if(oldIndex < newIndex){
54783 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
54786 px += this.proxyOffsets[0];
54787 this.proxyTop.setLeftTop(px, py);
54788 this.proxyTop.show();
54789 if(!this.bottomOffset){
54790 this.bottomOffset = this.view.mainHd.getHeight();
54792 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
54793 this.proxyBottom.show();
54797 onNodeEnter : function(n, dd, e, data){
54798 if(data.header != n){
54799 this.positionIndicator(data.header, n, e);
54803 onNodeOver : function(n, dd, e, data){
54804 var result = false;
54805 if(data.header != n){
54806 result = this.positionIndicator(data.header, n, e);
54809 this.proxyTop.hide();
54810 this.proxyBottom.hide();
54812 return result ? this.dropAllowed : this.dropNotAllowed;
54815 onNodeOut : function(n, dd, e, data){
54816 this.proxyTop.hide();
54817 this.proxyBottom.hide();
54820 onNodeDrop : function(n, dd, e, data){
54821 var h = data.header;
54823 var cm = this.grid.colModel;
54824 var x = Roo.lib.Event.getPageX(e);
54825 var r = Roo.lib.Dom.getRegion(n.firstChild);
54826 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
54827 var oldIndex = this.view.getCellIndex(h);
54828 var newIndex = this.view.getCellIndex(n);
54829 var locked = cm.isLocked(newIndex);
54833 if(oldIndex < newIndex){
54836 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
54839 cm.setLocked(oldIndex, locked, true);
54840 cm.moveColumn(oldIndex, newIndex);
54841 this.grid.fireEvent("columnmove", oldIndex, newIndex);
54849 * Ext JS Library 1.1.1
54850 * Copyright(c) 2006-2007, Ext JS, LLC.
54852 * Originally Released Under LGPL - original licence link has changed is not relivant.
54855 * <script type="text/javascript">
54859 * @class Roo.grid.GridView
54860 * @extends Roo.util.Observable
54863 * @param {Object} config
54865 Roo.grid.GridView = function(config){
54866 Roo.grid.GridView.superclass.constructor.call(this);
54869 Roo.apply(this, config);
54872 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
54874 unselectable : 'unselectable="on"',
54875 unselectableCls : 'x-unselectable',
54878 rowClass : "x-grid-row",
54880 cellClass : "x-grid-col",
54882 tdClass : "x-grid-td",
54884 hdClass : "x-grid-hd",
54886 splitClass : "x-grid-split",
54888 sortClasses : ["sort-asc", "sort-desc"],
54890 enableMoveAnim : false,
54894 dh : Roo.DomHelper,
54896 fly : Roo.Element.fly,
54898 css : Roo.util.CSS,
54904 scrollIncrement : 22,
54906 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
54908 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
54910 bind : function(ds, cm){
54912 this.ds.un("load", this.onLoad, this);
54913 this.ds.un("datachanged", this.onDataChange, this);
54914 this.ds.un("add", this.onAdd, this);
54915 this.ds.un("remove", this.onRemove, this);
54916 this.ds.un("update", this.onUpdate, this);
54917 this.ds.un("clear", this.onClear, this);
54920 ds.on("load", this.onLoad, this);
54921 ds.on("datachanged", this.onDataChange, this);
54922 ds.on("add", this.onAdd, this);
54923 ds.on("remove", this.onRemove, this);
54924 ds.on("update", this.onUpdate, this);
54925 ds.on("clear", this.onClear, this);
54930 this.cm.un("widthchange", this.onColWidthChange, this);
54931 this.cm.un("headerchange", this.onHeaderChange, this);
54932 this.cm.un("hiddenchange", this.onHiddenChange, this);
54933 this.cm.un("columnmoved", this.onColumnMove, this);
54934 this.cm.un("columnlockchange", this.onColumnLock, this);
54937 this.generateRules(cm);
54938 cm.on("widthchange", this.onColWidthChange, this);
54939 cm.on("headerchange", this.onHeaderChange, this);
54940 cm.on("hiddenchange", this.onHiddenChange, this);
54941 cm.on("columnmoved", this.onColumnMove, this);
54942 cm.on("columnlockchange", this.onColumnLock, this);
54947 init: function(grid){
54948 Roo.grid.GridView.superclass.init.call(this, grid);
54950 this.bind(grid.dataSource, grid.colModel);
54952 grid.on("headerclick", this.handleHeaderClick, this);
54954 if(grid.trackMouseOver){
54955 grid.on("mouseover", this.onRowOver, this);
54956 grid.on("mouseout", this.onRowOut, this);
54958 grid.cancelTextSelection = function(){};
54959 this.gridId = grid.id;
54961 var tpls = this.templates || {};
54964 tpls.master = new Roo.Template(
54965 '<div class="x-grid" hidefocus="true">',
54966 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
54967 '<div class="x-grid-topbar"></div>',
54968 '<div class="x-grid-scroller"><div></div></div>',
54969 '<div class="x-grid-locked">',
54970 '<div class="x-grid-header">{lockedHeader}</div>',
54971 '<div class="x-grid-body">{lockedBody}</div>',
54973 '<div class="x-grid-viewport">',
54974 '<div class="x-grid-header">{header}</div>',
54975 '<div class="x-grid-body">{body}</div>',
54977 '<div class="x-grid-bottombar"></div>',
54979 '<div class="x-grid-resize-proxy"> </div>',
54982 tpls.master.disableformats = true;
54986 tpls.header = new Roo.Template(
54987 '<table border="0" cellspacing="0" cellpadding="0">',
54988 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
54991 tpls.header.disableformats = true;
54993 tpls.header.compile();
54996 tpls.hcell = new Roo.Template(
54997 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
54998 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55001 tpls.hcell.disableFormats = true;
55003 tpls.hcell.compile();
55006 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55007 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55008 tpls.hsplit.disableFormats = true;
55010 tpls.hsplit.compile();
55013 tpls.body = new Roo.Template(
55014 '<table border="0" cellspacing="0" cellpadding="0">',
55015 "<tbody>{rows}</tbody>",
55018 tpls.body.disableFormats = true;
55020 tpls.body.compile();
55023 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55024 tpls.row.disableFormats = true;
55026 tpls.row.compile();
55029 tpls.cell = new Roo.Template(
55030 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55031 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55032 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55035 tpls.cell.disableFormats = true;
55037 tpls.cell.compile();
55039 this.templates = tpls;
55042 // remap these for backwards compat
55043 onColWidthChange : function(){
55044 this.updateColumns.apply(this, arguments);
55046 onHeaderChange : function(){
55047 this.updateHeaders.apply(this, arguments);
55049 onHiddenChange : function(){
55050 this.handleHiddenChange.apply(this, arguments);
55052 onColumnMove : function(){
55053 this.handleColumnMove.apply(this, arguments);
55055 onColumnLock : function(){
55056 this.handleLockChange.apply(this, arguments);
55059 onDataChange : function(){
55061 this.updateHeaderSortState();
55064 onClear : function(){
55068 onUpdate : function(ds, record){
55069 this.refreshRow(record);
55072 refreshRow : function(record){
55073 var ds = this.ds, index;
55074 if(typeof record == 'number'){
55076 record = ds.getAt(index);
55078 index = ds.indexOf(record);
55080 this.insertRows(ds, index, index, true);
55081 this.onRemove(ds, record, index+1, true);
55082 this.syncRowHeights(index, index);
55084 this.fireEvent("rowupdated", this, index, record);
55087 onAdd : function(ds, records, index){
55088 this.insertRows(ds, index, index + (records.length-1));
55091 onRemove : function(ds, record, index, isUpdate){
55092 if(isUpdate !== true){
55093 this.fireEvent("beforerowremoved", this, index, record);
55095 var bt = this.getBodyTable(), lt = this.getLockedTable();
55096 if(bt.rows[index]){
55097 bt.firstChild.removeChild(bt.rows[index]);
55099 if(lt.rows[index]){
55100 lt.firstChild.removeChild(lt.rows[index]);
55102 if(isUpdate !== true){
55103 this.stripeRows(index);
55104 this.syncRowHeights(index, index);
55106 this.fireEvent("rowremoved", this, index, record);
55110 onLoad : function(){
55111 this.scrollToTop();
55115 * Scrolls the grid to the top
55117 scrollToTop : function(){
55119 this.scroller.dom.scrollTop = 0;
55125 * Gets a panel in the header of the grid that can be used for toolbars etc.
55126 * After modifying the contents of this panel a call to grid.autoSize() may be
55127 * required to register any changes in size.
55128 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55129 * @return Roo.Element
55131 getHeaderPanel : function(doShow){
55133 this.headerPanel.show();
55135 return this.headerPanel;
55139 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55140 * After modifying the contents of this panel a call to grid.autoSize() may be
55141 * required to register any changes in size.
55142 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55143 * @return Roo.Element
55145 getFooterPanel : function(doShow){
55147 this.footerPanel.show();
55149 return this.footerPanel;
55152 initElements : function(){
55153 var E = Roo.Element;
55154 var el = this.grid.getGridEl().dom.firstChild;
55155 var cs = el.childNodes;
55157 this.el = new E(el);
55159 this.focusEl = new E(el.firstChild);
55160 this.focusEl.swallowEvent("click", true);
55162 this.headerPanel = new E(cs[1]);
55163 this.headerPanel.enableDisplayMode("block");
55165 this.scroller = new E(cs[2]);
55166 this.scrollSizer = new E(this.scroller.dom.firstChild);
55168 this.lockedWrap = new E(cs[3]);
55169 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55170 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55172 this.mainWrap = new E(cs[4]);
55173 this.mainHd = new E(this.mainWrap.dom.firstChild);
55174 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55176 this.footerPanel = new E(cs[5]);
55177 this.footerPanel.enableDisplayMode("block");
55179 this.resizeProxy = new E(cs[6]);
55181 this.headerSelector = String.format(
55182 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55183 this.lockedHd.id, this.mainHd.id
55186 this.splitterSelector = String.format(
55187 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55188 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55191 idToCssName : function(s)
55193 return s.replace(/[^a-z0-9]+/ig, '-');
55196 getHeaderCell : function(index){
55197 return Roo.DomQuery.select(this.headerSelector)[index];
55200 getHeaderCellMeasure : function(index){
55201 return this.getHeaderCell(index).firstChild;
55204 getHeaderCellText : function(index){
55205 return this.getHeaderCell(index).firstChild.firstChild;
55208 getLockedTable : function(){
55209 return this.lockedBody.dom.firstChild;
55212 getBodyTable : function(){
55213 return this.mainBody.dom.firstChild;
55216 getLockedRow : function(index){
55217 return this.getLockedTable().rows[index];
55220 getRow : function(index){
55221 return this.getBodyTable().rows[index];
55224 getRowComposite : function(index){
55226 this.rowEl = new Roo.CompositeElementLite();
55228 var els = [], lrow, mrow;
55229 if(lrow = this.getLockedRow(index)){
55232 if(mrow = this.getRow(index)){
55235 this.rowEl.elements = els;
55239 * Gets the 'td' of the cell
55241 * @param {Integer} rowIndex row to select
55242 * @param {Integer} colIndex column to select
55246 getCell : function(rowIndex, colIndex){
55247 var locked = this.cm.getLockedCount();
55249 if(colIndex < locked){
55250 source = this.lockedBody.dom.firstChild;
55252 source = this.mainBody.dom.firstChild;
55253 colIndex -= locked;
55255 return source.rows[rowIndex].childNodes[colIndex];
55258 getCellText : function(rowIndex, colIndex){
55259 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55262 getCellBox : function(cell){
55263 var b = this.fly(cell).getBox();
55264 if(Roo.isOpera){ // opera fails to report the Y
55265 b.y = cell.offsetTop + this.mainBody.getY();
55270 getCellIndex : function(cell){
55271 var id = String(cell.className).match(this.cellRE);
55273 return parseInt(id[1], 10);
55278 findHeaderIndex : function(n){
55279 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55280 return r ? this.getCellIndex(r) : false;
55283 findHeaderCell : function(n){
55284 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55285 return r ? r : false;
55288 findRowIndex : function(n){
55292 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55293 return r ? r.rowIndex : false;
55296 findCellIndex : function(node){
55297 var stop = this.el.dom;
55298 while(node && node != stop){
55299 if(this.findRE.test(node.className)){
55300 return this.getCellIndex(node);
55302 node = node.parentNode;
55307 getColumnId : function(index){
55308 return this.cm.getColumnId(index);
55311 getSplitters : function()
55313 if(this.splitterSelector){
55314 return Roo.DomQuery.select(this.splitterSelector);
55320 getSplitter : function(index){
55321 return this.getSplitters()[index];
55324 onRowOver : function(e, t){
55326 if((row = this.findRowIndex(t)) !== false){
55327 this.getRowComposite(row).addClass("x-grid-row-over");
55331 onRowOut : function(e, t){
55333 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55334 this.getRowComposite(row).removeClass("x-grid-row-over");
55338 renderHeaders : function(){
55340 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55341 var cb = [], lb = [], sb = [], lsb = [], p = {};
55342 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55343 p.cellId = "x-grid-hd-0-" + i;
55344 p.splitId = "x-grid-csplit-0-" + i;
55345 p.id = cm.getColumnId(i);
55346 p.value = cm.getColumnHeader(i) || "";
55347 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55348 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55349 if(!cm.isLocked(i)){
55350 cb[cb.length] = ct.apply(p);
55351 sb[sb.length] = st.apply(p);
55353 lb[lb.length] = ct.apply(p);
55354 lsb[lsb.length] = st.apply(p);
55357 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55358 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55361 updateHeaders : function(){
55362 var html = this.renderHeaders();
55363 this.lockedHd.update(html[0]);
55364 this.mainHd.update(html[1]);
55368 * Focuses the specified row.
55369 * @param {Number} row The row index
55371 focusRow : function(row)
55373 //Roo.log('GridView.focusRow');
55374 var x = this.scroller.dom.scrollLeft;
55375 this.focusCell(row, 0, false);
55376 this.scroller.dom.scrollLeft = x;
55380 * Focuses the specified cell.
55381 * @param {Number} row The row index
55382 * @param {Number} col The column index
55383 * @param {Boolean} hscroll false to disable horizontal scrolling
55385 focusCell : function(row, col, hscroll)
55387 //Roo.log('GridView.focusCell');
55388 var el = this.ensureVisible(row, col, hscroll);
55389 this.focusEl.alignTo(el, "tl-tl");
55391 this.focusEl.focus();
55393 this.focusEl.focus.defer(1, this.focusEl);
55398 * Scrolls the specified cell into view
55399 * @param {Number} row The row index
55400 * @param {Number} col The column index
55401 * @param {Boolean} hscroll false to disable horizontal scrolling
55403 ensureVisible : function(row, col, hscroll)
55405 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55406 //return null; //disable for testing.
55407 if(typeof row != "number"){
55408 row = row.rowIndex;
55410 if(row < 0 && row >= this.ds.getCount()){
55413 col = (col !== undefined ? col : 0);
55414 var cm = this.grid.colModel;
55415 while(cm.isHidden(col)){
55419 var el = this.getCell(row, col);
55423 var c = this.scroller.dom;
55425 var ctop = parseInt(el.offsetTop, 10);
55426 var cleft = parseInt(el.offsetLeft, 10);
55427 var cbot = ctop + el.offsetHeight;
55428 var cright = cleft + el.offsetWidth;
55430 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55431 var stop = parseInt(c.scrollTop, 10);
55432 var sleft = parseInt(c.scrollLeft, 10);
55433 var sbot = stop + ch;
55434 var sright = sleft + c.clientWidth;
55436 Roo.log('GridView.ensureVisible:' +
55438 ' c.clientHeight:' + c.clientHeight +
55439 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55447 c.scrollTop = ctop;
55448 //Roo.log("set scrolltop to ctop DISABLE?");
55449 }else if(cbot > sbot){
55450 //Roo.log("set scrolltop to cbot-ch");
55451 c.scrollTop = cbot-ch;
55454 if(hscroll !== false){
55456 c.scrollLeft = cleft;
55457 }else if(cright > sright){
55458 c.scrollLeft = cright-c.clientWidth;
55465 updateColumns : function(){
55466 this.grid.stopEditing();
55467 var cm = this.grid.colModel, colIds = this.getColumnIds();
55468 //var totalWidth = cm.getTotalWidth();
55470 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55471 //if(cm.isHidden(i)) continue;
55472 var w = cm.getColumnWidth(i);
55473 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55474 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55476 this.updateSplitters();
55479 generateRules : function(cm){
55480 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55481 Roo.util.CSS.removeStyleSheet(rulesId);
55482 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55483 var cid = cm.getColumnId(i);
55485 if(cm.config[i].align){
55486 align = 'text-align:'+cm.config[i].align+';';
55489 if(cm.isHidden(i)){
55490 hidden = 'display:none;';
55492 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55494 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55495 this.hdSelector, cid, " {\n", align, width, "}\n",
55496 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55497 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55499 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55502 updateSplitters : function(){
55503 var cm = this.cm, s = this.getSplitters();
55504 if(s){ // splitters not created yet
55505 var pos = 0, locked = true;
55506 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55507 if(cm.isHidden(i)) {
55510 var w = cm.getColumnWidth(i); // make sure it's a number
55511 if(!cm.isLocked(i) && locked){
55516 s[i].style.left = (pos-this.splitOffset) + "px";
55521 handleHiddenChange : function(colModel, colIndex, hidden){
55523 this.hideColumn(colIndex);
55525 this.unhideColumn(colIndex);
55529 hideColumn : function(colIndex){
55530 var cid = this.getColumnId(colIndex);
55531 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55532 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55534 this.updateHeaders();
55536 this.updateSplitters();
55540 unhideColumn : function(colIndex){
55541 var cid = this.getColumnId(colIndex);
55542 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55543 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55546 this.updateHeaders();
55548 this.updateSplitters();
55552 insertRows : function(dm, firstRow, lastRow, isUpdate){
55553 if(firstRow == 0 && lastRow == dm.getCount()-1){
55557 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55559 var s = this.getScrollState();
55560 var markup = this.renderRows(firstRow, lastRow);
55561 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55562 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55563 this.restoreScroll(s);
55565 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55566 this.syncRowHeights(firstRow, lastRow);
55567 this.stripeRows(firstRow);
55573 bufferRows : function(markup, target, index){
55574 var before = null, trows = target.rows, tbody = target.tBodies[0];
55575 if(index < trows.length){
55576 before = trows[index];
55578 var b = document.createElement("div");
55579 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55580 var rows = b.firstChild.rows;
55581 for(var i = 0, len = rows.length; i < len; i++){
55583 tbody.insertBefore(rows[0], before);
55585 tbody.appendChild(rows[0]);
55592 deleteRows : function(dm, firstRow, lastRow){
55593 if(dm.getRowCount()<1){
55594 this.fireEvent("beforerefresh", this);
55595 this.mainBody.update("");
55596 this.lockedBody.update("");
55597 this.fireEvent("refresh", this);
55599 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55600 var bt = this.getBodyTable();
55601 var tbody = bt.firstChild;
55602 var rows = bt.rows;
55603 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55604 tbody.removeChild(rows[firstRow]);
55606 this.stripeRows(firstRow);
55607 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55611 updateRows : function(dataSource, firstRow, lastRow){
55612 var s = this.getScrollState();
55614 this.restoreScroll(s);
55617 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55621 this.updateHeaderSortState();
55624 getScrollState : function(){
55626 var sb = this.scroller.dom;
55627 return {left: sb.scrollLeft, top: sb.scrollTop};
55630 stripeRows : function(startRow){
55631 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55634 startRow = startRow || 0;
55635 var rows = this.getBodyTable().rows;
55636 var lrows = this.getLockedTable().rows;
55637 var cls = ' x-grid-row-alt ';
55638 for(var i = startRow, len = rows.length; i < len; i++){
55639 var row = rows[i], lrow = lrows[i];
55640 var isAlt = ((i+1) % 2 == 0);
55641 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55642 if(isAlt == hasAlt){
55646 row.className += " x-grid-row-alt";
55648 row.className = row.className.replace("x-grid-row-alt", "");
55651 lrow.className = row.className;
55656 restoreScroll : function(state){
55657 //Roo.log('GridView.restoreScroll');
55658 var sb = this.scroller.dom;
55659 sb.scrollLeft = state.left;
55660 sb.scrollTop = state.top;
55664 syncScroll : function(){
55665 //Roo.log('GridView.syncScroll');
55666 var sb = this.scroller.dom;
55667 var sh = this.mainHd.dom;
55668 var bs = this.mainBody.dom;
55669 var lv = this.lockedBody.dom;
55670 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55671 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55674 handleScroll : function(e){
55676 var sb = this.scroller.dom;
55677 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55681 handleWheel : function(e){
55682 var d = e.getWheelDelta();
55683 this.scroller.dom.scrollTop -= d*22;
55684 // set this here to prevent jumpy scrolling on large tables
55685 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55689 renderRows : function(startRow, endRow){
55690 // pull in all the crap needed to render rows
55691 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55692 var colCount = cm.getColumnCount();
55694 if(ds.getCount() < 1){
55698 // build a map for all the columns
55700 for(var i = 0; i < colCount; i++){
55701 var name = cm.getDataIndex(i);
55703 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55704 renderer : cm.getRenderer(i),
55705 id : cm.getColumnId(i),
55706 locked : cm.isLocked(i),
55707 has_editor : cm.isCellEditable(i)
55711 startRow = startRow || 0;
55712 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55714 // records to render
55715 var rs = ds.getRange(startRow, endRow);
55717 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55720 // As much as I hate to duplicate code, this was branched because FireFox really hates
55721 // [].join("") on strings. The performance difference was substantial enough to
55722 // branch this function
55723 doRender : Roo.isGecko ?
55724 function(cs, rs, ds, startRow, colCount, stripe){
55725 var ts = this.templates, ct = ts.cell, rt = ts.row;
55727 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55729 var hasListener = this.grid.hasListener('rowclass');
55731 for(var j = 0, len = rs.length; j < len; j++){
55732 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
55733 for(var i = 0; i < colCount; i++){
55735 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55737 p.css = p.attr = "";
55738 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55739 if(p.value == undefined || p.value === "") {
55740 p.value = " ";
55743 p.css += ' x-grid-editable-cell';
55745 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
55746 p.css += ' x-grid-dirty-cell';
55748 var markup = ct.apply(p);
55756 if(stripe && ((rowIndex+1) % 2 == 0)){
55757 alt.push("x-grid-row-alt")
55760 alt.push( " x-grid-dirty-row");
55763 if(this.getRowClass){
55764 alt.push(this.getRowClass(r, rowIndex));
55770 rowIndex : rowIndex,
55773 this.grid.fireEvent('rowclass', this, rowcfg);
55774 alt.push(rowcfg.rowClass);
55776 rp.alt = alt.join(" ");
55777 lbuf+= rt.apply(rp);
55779 buf+= rt.apply(rp);
55781 return [lbuf, buf];
55783 function(cs, rs, ds, startRow, colCount, stripe){
55784 var ts = this.templates, ct = ts.cell, rt = ts.row;
55786 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55787 var hasListener = this.grid.hasListener('rowclass');
55790 for(var j = 0, len = rs.length; j < len; j++){
55791 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
55792 for(var i = 0; i < colCount; i++){
55794 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55796 p.css = p.attr = "";
55797 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55798 if(p.value == undefined || p.value === "") {
55799 p.value = " ";
55803 p.css += ' x-grid-editable-cell';
55805 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
55806 p.css += ' x-grid-dirty-cell'
55809 var markup = ct.apply(p);
55811 cb[cb.length] = markup;
55813 lcb[lcb.length] = markup;
55817 if(stripe && ((rowIndex+1) % 2 == 0)){
55818 alt.push( "x-grid-row-alt");
55821 alt.push(" x-grid-dirty-row");
55824 if(this.getRowClass){
55825 alt.push( this.getRowClass(r, rowIndex));
55831 rowIndex : rowIndex,
55834 this.grid.fireEvent('rowclass', this, rowcfg);
55835 alt.push(rowcfg.rowClass);
55838 rp.alt = alt.join(" ");
55839 rp.cells = lcb.join("");
55840 lbuf[lbuf.length] = rt.apply(rp);
55841 rp.cells = cb.join("");
55842 buf[buf.length] = rt.apply(rp);
55844 return [lbuf.join(""), buf.join("")];
55847 renderBody : function(){
55848 var markup = this.renderRows();
55849 var bt = this.templates.body;
55850 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
55854 * Refreshes the grid
55855 * @param {Boolean} headersToo
55857 refresh : function(headersToo){
55858 this.fireEvent("beforerefresh", this);
55859 this.grid.stopEditing();
55860 var result = this.renderBody();
55861 this.lockedBody.update(result[0]);
55862 this.mainBody.update(result[1]);
55863 if(headersToo === true){
55864 this.updateHeaders();
55865 this.updateColumns();
55866 this.updateSplitters();
55867 this.updateHeaderSortState();
55869 this.syncRowHeights();
55871 this.fireEvent("refresh", this);
55874 handleColumnMove : function(cm, oldIndex, newIndex){
55875 this.indexMap = null;
55876 var s = this.getScrollState();
55877 this.refresh(true);
55878 this.restoreScroll(s);
55879 this.afterMove(newIndex);
55882 afterMove : function(colIndex){
55883 if(this.enableMoveAnim && Roo.enableFx){
55884 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
55886 // if multisort - fix sortOrder, and reload..
55887 if (this.grid.dataSource.multiSort) {
55888 // the we can call sort again..
55889 var dm = this.grid.dataSource;
55890 var cm = this.grid.colModel;
55892 for(var i = 0; i < cm.config.length; i++ ) {
55894 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
55895 continue; // dont' bother, it's not in sort list or being set.
55898 so.push(cm.config[i].dataIndex);
55901 dm.load(dm.lastOptions);
55908 updateCell : function(dm, rowIndex, dataIndex){
55909 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
55910 if(typeof colIndex == "undefined"){ // not present in grid
55913 var cm = this.grid.colModel;
55914 var cell = this.getCell(rowIndex, colIndex);
55915 var cellText = this.getCellText(rowIndex, colIndex);
55918 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
55919 id : cm.getColumnId(colIndex),
55920 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
55922 var renderer = cm.getRenderer(colIndex);
55923 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
55924 if(typeof val == "undefined" || val === "") {
55927 cellText.innerHTML = val;
55928 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
55929 this.syncRowHeights(rowIndex, rowIndex);
55932 calcColumnWidth : function(colIndex, maxRowsToMeasure){
55934 if(this.grid.autoSizeHeaders){
55935 var h = this.getHeaderCellMeasure(colIndex);
55936 maxWidth = Math.max(maxWidth, h.scrollWidth);
55939 if(this.cm.isLocked(colIndex)){
55940 tb = this.getLockedTable();
55943 tb = this.getBodyTable();
55944 index = colIndex - this.cm.getLockedCount();
55947 var rows = tb.rows;
55948 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
55949 for(var i = 0; i < stopIndex; i++){
55950 var cell = rows[i].childNodes[index].firstChild;
55951 maxWidth = Math.max(maxWidth, cell.scrollWidth);
55954 return maxWidth + /*margin for error in IE*/ 5;
55957 * Autofit a column to its content.
55958 * @param {Number} colIndex
55959 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
55961 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
55962 if(this.cm.isHidden(colIndex)){
55963 return; // can't calc a hidden column
55966 var cid = this.cm.getColumnId(colIndex);
55967 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
55968 if(this.grid.autoSizeHeaders){
55969 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
55972 var newWidth = this.calcColumnWidth(colIndex);
55973 this.cm.setColumnWidth(colIndex,
55974 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
55975 if(!suppressEvent){
55976 this.grid.fireEvent("columnresize", colIndex, newWidth);
55981 * Autofits all columns to their content and then expands to fit any extra space in the grid
55983 autoSizeColumns : function(){
55984 var cm = this.grid.colModel;
55985 var colCount = cm.getColumnCount();
55986 for(var i = 0; i < colCount; i++){
55987 this.autoSizeColumn(i, true, true);
55989 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
55992 this.updateColumns();
55998 * Autofits all columns to the grid's width proportionate with their current size
55999 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56001 fitColumns : function(reserveScrollSpace){
56002 var cm = this.grid.colModel;
56003 var colCount = cm.getColumnCount();
56007 for (i = 0; i < colCount; i++){
56008 if(!cm.isHidden(i) && !cm.isFixed(i)){
56009 w = cm.getColumnWidth(i);
56015 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56016 if(reserveScrollSpace){
56019 var frac = (avail - cm.getTotalWidth())/width;
56020 while (cols.length){
56023 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56025 this.updateColumns();
56029 onRowSelect : function(rowIndex){
56030 var row = this.getRowComposite(rowIndex);
56031 row.addClass("x-grid-row-selected");
56034 onRowDeselect : function(rowIndex){
56035 var row = this.getRowComposite(rowIndex);
56036 row.removeClass("x-grid-row-selected");
56039 onCellSelect : function(row, col){
56040 var cell = this.getCell(row, col);
56042 Roo.fly(cell).addClass("x-grid-cell-selected");
56046 onCellDeselect : function(row, col){
56047 var cell = this.getCell(row, col);
56049 Roo.fly(cell).removeClass("x-grid-cell-selected");
56053 updateHeaderSortState : function(){
56055 // sort state can be single { field: xxx, direction : yyy}
56056 // or { xxx=>ASC , yyy : DESC ..... }
56059 if (!this.ds.multiSort) {
56060 var state = this.ds.getSortState();
56064 mstate[state.field] = state.direction;
56065 // FIXME... - this is not used here.. but might be elsewhere..
56066 this.sortState = state;
56069 mstate = this.ds.sortToggle;
56071 //remove existing sort classes..
56073 var sc = this.sortClasses;
56074 var hds = this.el.select(this.headerSelector).removeClass(sc);
56076 for(var f in mstate) {
56078 var sortColumn = this.cm.findColumnIndex(f);
56080 if(sortColumn != -1){
56081 var sortDir = mstate[f];
56082 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56091 handleHeaderClick : function(g, index,e){
56093 Roo.log("header click");
56096 // touch events on header are handled by context
56097 this.handleHdCtx(g,index,e);
56102 if(this.headersDisabled){
56105 var dm = g.dataSource, cm = g.colModel;
56106 if(!cm.isSortable(index)){
56111 if (dm.multiSort) {
56112 // update the sortOrder
56114 for(var i = 0; i < cm.config.length; i++ ) {
56116 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56117 continue; // dont' bother, it's not in sort list or being set.
56120 so.push(cm.config[i].dataIndex);
56126 dm.sort(cm.getDataIndex(index));
56130 destroy : function(){
56132 this.colMenu.removeAll();
56133 Roo.menu.MenuMgr.unregister(this.colMenu);
56134 this.colMenu.getEl().remove();
56135 delete this.colMenu;
56138 this.hmenu.removeAll();
56139 Roo.menu.MenuMgr.unregister(this.hmenu);
56140 this.hmenu.getEl().remove();
56143 if(this.grid.enableColumnMove){
56144 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56146 for(var dd in dds){
56147 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56148 var elid = dds[dd].dragElId;
56150 Roo.get(elid).remove();
56151 } else if(dds[dd].config.isTarget){
56152 dds[dd].proxyTop.remove();
56153 dds[dd].proxyBottom.remove();
56156 if(Roo.dd.DDM.locationCache[dd]){
56157 delete Roo.dd.DDM.locationCache[dd];
56160 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56163 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56164 this.bind(null, null);
56165 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56168 handleLockChange : function(){
56169 this.refresh(true);
56172 onDenyColumnLock : function(){
56176 onDenyColumnHide : function(){
56180 handleHdMenuClick : function(item){
56181 var index = this.hdCtxIndex;
56182 var cm = this.cm, ds = this.ds;
56185 ds.sort(cm.getDataIndex(index), "ASC");
56188 ds.sort(cm.getDataIndex(index), "DESC");
56191 var lc = cm.getLockedCount();
56192 if(cm.getColumnCount(true) <= lc+1){
56193 this.onDenyColumnLock();
56197 cm.setLocked(index, true, true);
56198 cm.moveColumn(index, lc);
56199 this.grid.fireEvent("columnmove", index, lc);
56201 cm.setLocked(index, true);
56205 var lc = cm.getLockedCount();
56206 if((lc-1) != index){
56207 cm.setLocked(index, false, true);
56208 cm.moveColumn(index, lc-1);
56209 this.grid.fireEvent("columnmove", index, lc-1);
56211 cm.setLocked(index, false);
56214 case 'wider': // used to expand cols on touch..
56216 var cw = cm.getColumnWidth(index);
56217 cw += (item.id == 'wider' ? 1 : -1) * 50;
56218 cw = Math.max(0, cw);
56219 cw = Math.min(cw,4000);
56220 cm.setColumnWidth(index, cw);
56224 index = cm.getIndexById(item.id.substr(4));
56226 if(item.checked && cm.getColumnCount(true) <= 1){
56227 this.onDenyColumnHide();
56230 cm.setHidden(index, item.checked);
56236 beforeColMenuShow : function(){
56237 var cm = this.cm, colCount = cm.getColumnCount();
56238 this.colMenu.removeAll();
56239 for(var i = 0; i < colCount; i++){
56240 this.colMenu.add(new Roo.menu.CheckItem({
56241 id: "col-"+cm.getColumnId(i),
56242 text: cm.getColumnHeader(i),
56243 checked: !cm.isHidden(i),
56249 handleHdCtx : function(g, index, e){
56251 var hd = this.getHeaderCell(index);
56252 this.hdCtxIndex = index;
56253 var ms = this.hmenu.items, cm = this.cm;
56254 ms.get("asc").setDisabled(!cm.isSortable(index));
56255 ms.get("desc").setDisabled(!cm.isSortable(index));
56256 if(this.grid.enableColLock !== false){
56257 ms.get("lock").setDisabled(cm.isLocked(index));
56258 ms.get("unlock").setDisabled(!cm.isLocked(index));
56260 this.hmenu.show(hd, "tl-bl");
56263 handleHdOver : function(e){
56264 var hd = this.findHeaderCell(e.getTarget());
56265 if(hd && !this.headersDisabled){
56266 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56267 this.fly(hd).addClass("x-grid-hd-over");
56272 handleHdOut : function(e){
56273 var hd = this.findHeaderCell(e.getTarget());
56275 this.fly(hd).removeClass("x-grid-hd-over");
56279 handleSplitDblClick : function(e, t){
56280 var i = this.getCellIndex(t);
56281 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56282 this.autoSizeColumn(i, true);
56287 render : function(){
56290 var colCount = cm.getColumnCount();
56292 if(this.grid.monitorWindowResize === true){
56293 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56295 var header = this.renderHeaders();
56296 var body = this.templates.body.apply({rows:""});
56297 var html = this.templates.master.apply({
56300 lockedHeader: header[0],
56304 //this.updateColumns();
56306 this.grid.getGridEl().dom.innerHTML = html;
56308 this.initElements();
56310 // a kludge to fix the random scolling effect in webkit
56311 this.el.on("scroll", function() {
56312 this.el.dom.scrollTop=0; // hopefully not recursive..
56315 this.scroller.on("scroll", this.handleScroll, this);
56316 this.lockedBody.on("mousewheel", this.handleWheel, this);
56317 this.mainBody.on("mousewheel", this.handleWheel, this);
56319 this.mainHd.on("mouseover", this.handleHdOver, this);
56320 this.mainHd.on("mouseout", this.handleHdOut, this);
56321 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56322 {delegate: "."+this.splitClass});
56324 this.lockedHd.on("mouseover", this.handleHdOver, this);
56325 this.lockedHd.on("mouseout", this.handleHdOut, this);
56326 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56327 {delegate: "."+this.splitClass});
56329 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56330 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56333 this.updateSplitters();
56335 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56336 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56337 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56340 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56341 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56343 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56344 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56346 if(this.grid.enableColLock !== false){
56347 this.hmenu.add('-',
56348 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56349 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56353 this.hmenu.add('-',
56354 {id:"wider", text: this.columnsWiderText},
56355 {id:"narrow", text: this.columnsNarrowText }
56361 if(this.grid.enableColumnHide !== false){
56363 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56364 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56365 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56367 this.hmenu.add('-',
56368 {id:"columns", text: this.columnsText, menu: this.colMenu}
56371 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56373 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56376 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56377 this.dd = new Roo.grid.GridDragZone(this.grid, {
56378 ddGroup : this.grid.ddGroup || 'GridDD'
56384 for(var i = 0; i < colCount; i++){
56385 if(cm.isHidden(i)){
56386 this.hideColumn(i);
56388 if(cm.config[i].align){
56389 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56390 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56394 this.updateHeaderSortState();
56396 this.beforeInitialResize();
56399 // two part rendering gives faster view to the user
56400 this.renderPhase2.defer(1, this);
56403 renderPhase2 : function(){
56404 // render the rows now
56406 if(this.grid.autoSizeColumns){
56407 this.autoSizeColumns();
56411 beforeInitialResize : function(){
56415 onColumnSplitterMoved : function(i, w){
56416 this.userResized = true;
56417 var cm = this.grid.colModel;
56418 cm.setColumnWidth(i, w, true);
56419 var cid = cm.getColumnId(i);
56420 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56421 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56422 this.updateSplitters();
56424 this.grid.fireEvent("columnresize", i, w);
56427 syncRowHeights : function(startIndex, endIndex){
56428 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56429 startIndex = startIndex || 0;
56430 var mrows = this.getBodyTable().rows;
56431 var lrows = this.getLockedTable().rows;
56432 var len = mrows.length-1;
56433 endIndex = Math.min(endIndex || len, len);
56434 for(var i = startIndex; i <= endIndex; i++){
56435 var m = mrows[i], l = lrows[i];
56436 var h = Math.max(m.offsetHeight, l.offsetHeight);
56437 m.style.height = l.style.height = h + "px";
56442 layout : function(initialRender, is2ndPass){
56444 var auto = g.autoHeight;
56445 var scrollOffset = 16;
56446 var c = g.getGridEl(), cm = this.cm,
56447 expandCol = g.autoExpandColumn,
56449 //c.beginMeasure();
56451 if(!c.dom.offsetWidth){ // display:none?
56453 this.lockedWrap.show();
56454 this.mainWrap.show();
56459 var hasLock = this.cm.isLocked(0);
56461 var tbh = this.headerPanel.getHeight();
56462 var bbh = this.footerPanel.getHeight();
56465 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56466 var newHeight = ch + c.getBorderWidth("tb");
56468 newHeight = Math.min(g.maxHeight, newHeight);
56470 c.setHeight(newHeight);
56474 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56477 var s = this.scroller;
56479 var csize = c.getSize(true);
56481 this.el.setSize(csize.width, csize.height);
56483 this.headerPanel.setWidth(csize.width);
56484 this.footerPanel.setWidth(csize.width);
56486 var hdHeight = this.mainHd.getHeight();
56487 var vw = csize.width;
56488 var vh = csize.height - (tbh + bbh);
56492 var bt = this.getBodyTable();
56494 if(cm.getLockedCount() == cm.config.length){
56495 bt = this.getLockedTable();
56498 var ltWidth = hasLock ?
56499 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56501 var scrollHeight = bt.offsetHeight;
56502 var scrollWidth = ltWidth + bt.offsetWidth;
56503 var vscroll = false, hscroll = false;
56505 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56507 var lw = this.lockedWrap, mw = this.mainWrap;
56508 var lb = this.lockedBody, mb = this.mainBody;
56510 setTimeout(function(){
56511 var t = s.dom.offsetTop;
56512 var w = s.dom.clientWidth,
56513 h = s.dom.clientHeight;
56516 lw.setSize(ltWidth, h);
56518 mw.setLeftTop(ltWidth, t);
56519 mw.setSize(w-ltWidth, h);
56521 lb.setHeight(h-hdHeight);
56522 mb.setHeight(h-hdHeight);
56524 if(is2ndPass !== true && !gv.userResized && expandCol){
56525 // high speed resize without full column calculation
56527 var ci = cm.getIndexById(expandCol);
56529 ci = cm.findColumnIndex(expandCol);
56531 ci = Math.max(0, ci); // make sure it's got at least the first col.
56532 var expandId = cm.getColumnId(ci);
56533 var tw = cm.getTotalWidth(false);
56534 var currentWidth = cm.getColumnWidth(ci);
56535 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56536 if(currentWidth != cw){
56537 cm.setColumnWidth(ci, cw, true);
56538 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56539 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56540 gv.updateSplitters();
56541 gv.layout(false, true);
56553 onWindowResize : function(){
56554 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56560 appendFooter : function(parentEl){
56564 sortAscText : "Sort Ascending",
56565 sortDescText : "Sort Descending",
56566 lockText : "Lock Column",
56567 unlockText : "Unlock Column",
56568 columnsText : "Columns",
56570 columnsWiderText : "Wider",
56571 columnsNarrowText : "Thinner"
56575 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56576 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56577 this.proxy.el.addClass('x-grid3-col-dd');
56580 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56581 handleMouseDown : function(e){
56585 callHandleMouseDown : function(e){
56586 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56591 * Ext JS Library 1.1.1
56592 * Copyright(c) 2006-2007, Ext JS, LLC.
56594 * Originally Released Under LGPL - original licence link has changed is not relivant.
56597 * <script type="text/javascript">
56601 // This is a support class used internally by the Grid components
56602 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56604 this.view = grid.getView();
56605 this.proxy = this.view.resizeProxy;
56606 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56607 "gridSplitters" + this.grid.getGridEl().id, {
56608 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56610 this.setHandleElId(Roo.id(hd));
56611 this.setOuterHandleElId(Roo.id(hd2));
56612 this.scroll = false;
56614 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56615 fly: Roo.Element.fly,
56617 b4StartDrag : function(x, y){
56618 this.view.headersDisabled = true;
56619 this.proxy.setHeight(this.view.mainWrap.getHeight());
56620 var w = this.cm.getColumnWidth(this.cellIndex);
56621 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56622 this.resetConstraints();
56623 this.setXConstraint(minw, 1000);
56624 this.setYConstraint(0, 0);
56625 this.minX = x - minw;
56626 this.maxX = x + 1000;
56628 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56632 handleMouseDown : function(e){
56633 ev = Roo.EventObject.setEvent(e);
56634 var t = this.fly(ev.getTarget());
56635 if(t.hasClass("x-grid-split")){
56636 this.cellIndex = this.view.getCellIndex(t.dom);
56637 this.split = t.dom;
56638 this.cm = this.grid.colModel;
56639 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56640 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56645 endDrag : function(e){
56646 this.view.headersDisabled = false;
56647 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56648 var diff = endX - this.startPos;
56649 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56652 autoOffset : function(){
56653 this.setDelta(0,0);
56657 * Ext JS Library 1.1.1
56658 * Copyright(c) 2006-2007, Ext JS, LLC.
56660 * Originally Released Under LGPL - original licence link has changed is not relivant.
56663 * <script type="text/javascript">
56667 // This is a support class used internally by the Grid components
56668 Roo.grid.GridDragZone = function(grid, config){
56669 this.view = grid.getView();
56670 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56671 if(this.view.lockedBody){
56672 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56673 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56675 this.scroll = false;
56677 this.ddel = document.createElement('div');
56678 this.ddel.className = 'x-grid-dd-wrap';
56681 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56682 ddGroup : "GridDD",
56684 getDragData : function(e){
56685 var t = Roo.lib.Event.getTarget(e);
56686 var rowIndex = this.view.findRowIndex(t);
56687 var sm = this.grid.selModel;
56689 //Roo.log(rowIndex);
56691 if (sm.getSelectedCell) {
56692 // cell selection..
56693 if (!sm.getSelectedCell()) {
56696 if (rowIndex != sm.getSelectedCell()[0]) {
56702 if(rowIndex !== false){
56707 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56709 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56712 if (e.hasModifier()){
56713 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56716 Roo.log("getDragData");
56721 rowIndex: rowIndex,
56722 selections:sm.getSelections ? sm.getSelections() : (
56723 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
56730 onInitDrag : function(e){
56731 var data = this.dragData;
56732 this.ddel.innerHTML = this.grid.getDragDropText();
56733 this.proxy.update(this.ddel);
56734 // fire start drag?
56737 afterRepair : function(){
56738 this.dragging = false;
56741 getRepairXY : function(e, data){
56745 onEndDrag : function(data, e){
56749 onValidDrop : function(dd, e, id){
56754 beforeInvalidDrop : function(e, id){
56759 * Ext JS Library 1.1.1
56760 * Copyright(c) 2006-2007, Ext JS, LLC.
56762 * Originally Released Under LGPL - original licence link has changed is not relivant.
56765 * <script type="text/javascript">
56770 * @class Roo.grid.ColumnModel
56771 * @extends Roo.util.Observable
56772 * This is the default implementation of a ColumnModel used by the Grid. It defines
56773 * the columns in the grid.
56776 var colModel = new Roo.grid.ColumnModel([
56777 {header: "Ticker", width: 60, sortable: true, locked: true},
56778 {header: "Company Name", width: 150, sortable: true},
56779 {header: "Market Cap.", width: 100, sortable: true},
56780 {header: "$ Sales", width: 100, sortable: true, renderer: money},
56781 {header: "Employees", width: 100, sortable: true, resizable: false}
56786 * The config options listed for this class are options which may appear in each
56787 * individual column definition.
56788 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
56790 * @param {Object} config An Array of column config objects. See this class's
56791 * config objects for details.
56793 Roo.grid.ColumnModel = function(config){
56795 * The config passed into the constructor
56797 this.config = config;
56800 // if no id, create one
56801 // if the column does not have a dataIndex mapping,
56802 // map it to the order it is in the config
56803 for(var i = 0, len = config.length; i < len; i++){
56805 if(typeof c.dataIndex == "undefined"){
56808 if(typeof c.renderer == "string"){
56809 c.renderer = Roo.util.Format[c.renderer];
56811 if(typeof c.id == "undefined"){
56814 if(c.editor && c.editor.xtype){
56815 c.editor = Roo.factory(c.editor, Roo.grid);
56817 if(c.editor && c.editor.isFormField){
56818 c.editor = new Roo.grid.GridEditor(c.editor);
56820 this.lookup[c.id] = c;
56824 * The width of columns which have no width specified (defaults to 100)
56827 this.defaultWidth = 100;
56830 * Default sortable of columns which have no sortable specified (defaults to false)
56833 this.defaultSortable = false;
56837 * @event widthchange
56838 * Fires when the width of a column changes.
56839 * @param {ColumnModel} this
56840 * @param {Number} columnIndex The column index
56841 * @param {Number} newWidth The new width
56843 "widthchange": true,
56845 * @event headerchange
56846 * Fires when the text of a header changes.
56847 * @param {ColumnModel} this
56848 * @param {Number} columnIndex The column index
56849 * @param {Number} newText The new header text
56851 "headerchange": true,
56853 * @event hiddenchange
56854 * Fires when a column is hidden or "unhidden".
56855 * @param {ColumnModel} this
56856 * @param {Number} columnIndex The column index
56857 * @param {Boolean} hidden true if hidden, false otherwise
56859 "hiddenchange": true,
56861 * @event columnmoved
56862 * Fires when a column is moved.
56863 * @param {ColumnModel} this
56864 * @param {Number} oldIndex
56865 * @param {Number} newIndex
56867 "columnmoved" : true,
56869 * @event columlockchange
56870 * Fires when a column's locked state is changed
56871 * @param {ColumnModel} this
56872 * @param {Number} colIndex
56873 * @param {Boolean} locked true if locked
56875 "columnlockchange" : true
56877 Roo.grid.ColumnModel.superclass.constructor.call(this);
56879 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
56881 * @cfg {String} header The header text to display in the Grid view.
56884 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
56885 * {@link Roo.data.Record} definition from which to draw the column's value. If not
56886 * specified, the column's index is used as an index into the Record's data Array.
56889 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
56890 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
56893 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
56894 * Defaults to the value of the {@link #defaultSortable} property.
56895 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
56898 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
56901 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
56904 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
56907 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
56910 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
56911 * given the cell's data value. See {@link #setRenderer}. If not specified, the
56912 * default renderer uses the raw data value. If an object is returned (bootstrap only)
56913 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
56916 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
56919 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
56922 * @cfg {String} cursor (Optional)
56925 * @cfg {String} tooltip (Optional)
56928 * @cfg {Number} xs (Optional)
56931 * @cfg {Number} sm (Optional)
56934 * @cfg {Number} md (Optional)
56937 * @cfg {Number} lg (Optional)
56940 * Returns the id of the column at the specified index.
56941 * @param {Number} index The column index
56942 * @return {String} the id
56944 getColumnId : function(index){
56945 return this.config[index].id;
56949 * Returns the column for a specified id.
56950 * @param {String} id The column id
56951 * @return {Object} the column
56953 getColumnById : function(id){
56954 return this.lookup[id];
56959 * Returns the column for a specified dataIndex.
56960 * @param {String} dataIndex The column dataIndex
56961 * @return {Object|Boolean} the column or false if not found
56963 getColumnByDataIndex: function(dataIndex){
56964 var index = this.findColumnIndex(dataIndex);
56965 return index > -1 ? this.config[index] : false;
56969 * Returns the index for a specified column id.
56970 * @param {String} id The column id
56971 * @return {Number} the index, or -1 if not found
56973 getIndexById : function(id){
56974 for(var i = 0, len = this.config.length; i < len; i++){
56975 if(this.config[i].id == id){
56983 * Returns the index for a specified column dataIndex.
56984 * @param {String} dataIndex The column dataIndex
56985 * @return {Number} the index, or -1 if not found
56988 findColumnIndex : function(dataIndex){
56989 for(var i = 0, len = this.config.length; i < len; i++){
56990 if(this.config[i].dataIndex == dataIndex){
56998 moveColumn : function(oldIndex, newIndex){
56999 var c = this.config[oldIndex];
57000 this.config.splice(oldIndex, 1);
57001 this.config.splice(newIndex, 0, c);
57002 this.dataMap = null;
57003 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57006 isLocked : function(colIndex){
57007 return this.config[colIndex].locked === true;
57010 setLocked : function(colIndex, value, suppressEvent){
57011 if(this.isLocked(colIndex) == value){
57014 this.config[colIndex].locked = value;
57015 if(!suppressEvent){
57016 this.fireEvent("columnlockchange", this, colIndex, value);
57020 getTotalLockedWidth : function(){
57021 var totalWidth = 0;
57022 for(var i = 0; i < this.config.length; i++){
57023 if(this.isLocked(i) && !this.isHidden(i)){
57024 this.totalWidth += this.getColumnWidth(i);
57030 getLockedCount : function(){
57031 for(var i = 0, len = this.config.length; i < len; i++){
57032 if(!this.isLocked(i)){
57037 return this.config.length;
57041 * Returns the number of columns.
57044 getColumnCount : function(visibleOnly){
57045 if(visibleOnly === true){
57047 for(var i = 0, len = this.config.length; i < len; i++){
57048 if(!this.isHidden(i)){
57054 return this.config.length;
57058 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57059 * @param {Function} fn
57060 * @param {Object} scope (optional)
57061 * @return {Array} result
57063 getColumnsBy : function(fn, scope){
57065 for(var i = 0, len = this.config.length; i < len; i++){
57066 var c = this.config[i];
57067 if(fn.call(scope||this, c, i) === true){
57075 * Returns true if the specified column is sortable.
57076 * @param {Number} col The column index
57077 * @return {Boolean}
57079 isSortable : function(col){
57080 if(typeof this.config[col].sortable == "undefined"){
57081 return this.defaultSortable;
57083 return this.config[col].sortable;
57087 * Returns the rendering (formatting) function defined for the column.
57088 * @param {Number} col The column index.
57089 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57091 getRenderer : function(col){
57092 if(!this.config[col].renderer){
57093 return Roo.grid.ColumnModel.defaultRenderer;
57095 return this.config[col].renderer;
57099 * Sets the rendering (formatting) function for a column.
57100 * @param {Number} col The column index
57101 * @param {Function} fn The function to use to process the cell's raw data
57102 * to return HTML markup for the grid view. The render function is called with
57103 * the following parameters:<ul>
57104 * <li>Data value.</li>
57105 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57106 * <li>css A CSS style string to apply to the table cell.</li>
57107 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57108 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57109 * <li>Row index</li>
57110 * <li>Column index</li>
57111 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57113 setRenderer : function(col, fn){
57114 this.config[col].renderer = fn;
57118 * Returns the width for the specified column.
57119 * @param {Number} col The column index
57122 getColumnWidth : function(col){
57123 return this.config[col].width * 1 || this.defaultWidth;
57127 * Sets the width for a column.
57128 * @param {Number} col The column index
57129 * @param {Number} width The new width
57131 setColumnWidth : function(col, width, suppressEvent){
57132 this.config[col].width = width;
57133 this.totalWidth = null;
57134 if(!suppressEvent){
57135 this.fireEvent("widthchange", this, col, width);
57140 * Returns the total width of all columns.
57141 * @param {Boolean} includeHidden True to include hidden column widths
57144 getTotalWidth : function(includeHidden){
57145 if(!this.totalWidth){
57146 this.totalWidth = 0;
57147 for(var i = 0, len = this.config.length; i < len; i++){
57148 if(includeHidden || !this.isHidden(i)){
57149 this.totalWidth += this.getColumnWidth(i);
57153 return this.totalWidth;
57157 * Returns the header for the specified column.
57158 * @param {Number} col The column index
57161 getColumnHeader : function(col){
57162 return this.config[col].header;
57166 * Sets the header for a column.
57167 * @param {Number} col The column index
57168 * @param {String} header The new header
57170 setColumnHeader : function(col, header){
57171 this.config[col].header = header;
57172 this.fireEvent("headerchange", this, col, header);
57176 * Returns the tooltip for the specified column.
57177 * @param {Number} col The column index
57180 getColumnTooltip : function(col){
57181 return this.config[col].tooltip;
57184 * Sets the tooltip for a column.
57185 * @param {Number} col The column index
57186 * @param {String} tooltip The new tooltip
57188 setColumnTooltip : function(col, tooltip){
57189 this.config[col].tooltip = tooltip;
57193 * Returns the dataIndex for the specified column.
57194 * @param {Number} col The column index
57197 getDataIndex : function(col){
57198 return this.config[col].dataIndex;
57202 * Sets the dataIndex for a column.
57203 * @param {Number} col The column index
57204 * @param {Number} dataIndex The new dataIndex
57206 setDataIndex : function(col, dataIndex){
57207 this.config[col].dataIndex = dataIndex;
57213 * Returns true if the cell is editable.
57214 * @param {Number} colIndex The column index
57215 * @param {Number} rowIndex The row index - this is nto actually used..?
57216 * @return {Boolean}
57218 isCellEditable : function(colIndex, rowIndex){
57219 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57223 * Returns the editor defined for the cell/column.
57224 * return false or null to disable editing.
57225 * @param {Number} colIndex The column index
57226 * @param {Number} rowIndex The row index
57229 getCellEditor : function(colIndex, rowIndex){
57230 return this.config[colIndex].editor;
57234 * Sets if a column is editable.
57235 * @param {Number} col The column index
57236 * @param {Boolean} editable True if the column is editable
57238 setEditable : function(col, editable){
57239 this.config[col].editable = editable;
57244 * Returns true if the column is hidden.
57245 * @param {Number} colIndex The column index
57246 * @return {Boolean}
57248 isHidden : function(colIndex){
57249 return this.config[colIndex].hidden;
57254 * Returns true if the column width cannot be changed
57256 isFixed : function(colIndex){
57257 return this.config[colIndex].fixed;
57261 * Returns true if the column can be resized
57262 * @return {Boolean}
57264 isResizable : function(colIndex){
57265 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57268 * Sets if a column is hidden.
57269 * @param {Number} colIndex The column index
57270 * @param {Boolean} hidden True if the column is hidden
57272 setHidden : function(colIndex, hidden){
57273 this.config[colIndex].hidden = hidden;
57274 this.totalWidth = null;
57275 this.fireEvent("hiddenchange", this, colIndex, hidden);
57279 * Sets the editor for a column.
57280 * @param {Number} col The column index
57281 * @param {Object} editor The editor object
57283 setEditor : function(col, editor){
57284 this.config[col].editor = editor;
57288 Roo.grid.ColumnModel.defaultRenderer = function(value){
57289 if(typeof value == "string" && value.length < 1){
57295 // Alias for backwards compatibility
57296 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57299 * Ext JS Library 1.1.1
57300 * Copyright(c) 2006-2007, Ext JS, LLC.
57302 * Originally Released Under LGPL - original licence link has changed is not relivant.
57305 * <script type="text/javascript">
57309 * @class Roo.grid.AbstractSelectionModel
57310 * @extends Roo.util.Observable
57311 * Abstract base class for grid SelectionModels. It provides the interface that should be
57312 * implemented by descendant classes. This class should not be directly instantiated.
57315 Roo.grid.AbstractSelectionModel = function(){
57316 this.locked = false;
57317 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57320 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57321 /** @ignore Called by the grid automatically. Do not call directly. */
57322 init : function(grid){
57328 * Locks the selections.
57331 this.locked = true;
57335 * Unlocks the selections.
57337 unlock : function(){
57338 this.locked = false;
57342 * Returns true if the selections are locked.
57343 * @return {Boolean}
57345 isLocked : function(){
57346 return this.locked;
57350 * Ext JS Library 1.1.1
57351 * Copyright(c) 2006-2007, Ext JS, LLC.
57353 * Originally Released Under LGPL - original licence link has changed is not relivant.
57356 * <script type="text/javascript">
57359 * @extends Roo.grid.AbstractSelectionModel
57360 * @class Roo.grid.RowSelectionModel
57361 * The default SelectionModel used by {@link Roo.grid.Grid}.
57362 * It supports multiple selections and keyboard selection/navigation.
57364 * @param {Object} config
57366 Roo.grid.RowSelectionModel = function(config){
57367 Roo.apply(this, config);
57368 this.selections = new Roo.util.MixedCollection(false, function(o){
57373 this.lastActive = false;
57377 * @event selectionchange
57378 * Fires when the selection changes
57379 * @param {SelectionModel} this
57381 "selectionchange" : true,
57383 * @event afterselectionchange
57384 * Fires after the selection changes (eg. by key press or clicking)
57385 * @param {SelectionModel} this
57387 "afterselectionchange" : true,
57389 * @event beforerowselect
57390 * Fires when a row is selected being selected, return false to cancel.
57391 * @param {SelectionModel} this
57392 * @param {Number} rowIndex The selected index
57393 * @param {Boolean} keepExisting False if other selections will be cleared
57395 "beforerowselect" : true,
57398 * Fires when a row is selected.
57399 * @param {SelectionModel} this
57400 * @param {Number} rowIndex The selected index
57401 * @param {Roo.data.Record} r The record
57403 "rowselect" : true,
57405 * @event rowdeselect
57406 * Fires when a row is deselected.
57407 * @param {SelectionModel} this
57408 * @param {Number} rowIndex The selected index
57410 "rowdeselect" : true
57412 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57413 this.locked = false;
57416 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57418 * @cfg {Boolean} singleSelect
57419 * True to allow selection of only one row at a time (defaults to false)
57421 singleSelect : false,
57424 initEvents : function(){
57426 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57427 this.grid.on("mousedown", this.handleMouseDown, this);
57428 }else{ // allow click to work like normal
57429 this.grid.on("rowclick", this.handleDragableRowClick, this);
57432 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57433 "up" : function(e){
57435 this.selectPrevious(e.shiftKey);
57436 }else if(this.last !== false && this.lastActive !== false){
57437 var last = this.last;
57438 this.selectRange(this.last, this.lastActive-1);
57439 this.grid.getView().focusRow(this.lastActive);
57440 if(last !== false){
57444 this.selectFirstRow();
57446 this.fireEvent("afterselectionchange", this);
57448 "down" : function(e){
57450 this.selectNext(e.shiftKey);
57451 }else if(this.last !== false && this.lastActive !== false){
57452 var last = this.last;
57453 this.selectRange(this.last, this.lastActive+1);
57454 this.grid.getView().focusRow(this.lastActive);
57455 if(last !== false){
57459 this.selectFirstRow();
57461 this.fireEvent("afterselectionchange", this);
57466 var view = this.grid.view;
57467 view.on("refresh", this.onRefresh, this);
57468 view.on("rowupdated", this.onRowUpdated, this);
57469 view.on("rowremoved", this.onRemove, this);
57473 onRefresh : function(){
57474 var ds = this.grid.dataSource, i, v = this.grid.view;
57475 var s = this.selections;
57476 s.each(function(r){
57477 if((i = ds.indexOfId(r.id)) != -1){
57479 s.add(ds.getAt(i)); // updating the selection relate data
57487 onRemove : function(v, index, r){
57488 this.selections.remove(r);
57492 onRowUpdated : function(v, index, r){
57493 if(this.isSelected(r)){
57494 v.onRowSelect(index);
57500 * @param {Array} records The records to select
57501 * @param {Boolean} keepExisting (optional) True to keep existing selections
57503 selectRecords : function(records, keepExisting){
57505 this.clearSelections();
57507 var ds = this.grid.dataSource;
57508 for(var i = 0, len = records.length; i < len; i++){
57509 this.selectRow(ds.indexOf(records[i]), true);
57514 * Gets the number of selected rows.
57517 getCount : function(){
57518 return this.selections.length;
57522 * Selects the first row in the grid.
57524 selectFirstRow : function(){
57529 * Select the last row.
57530 * @param {Boolean} keepExisting (optional) True to keep existing selections
57532 selectLastRow : function(keepExisting){
57533 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57537 * Selects the row immediately following the last selected row.
57538 * @param {Boolean} keepExisting (optional) True to keep existing selections
57540 selectNext : function(keepExisting){
57541 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57542 this.selectRow(this.last+1, keepExisting);
57543 this.grid.getView().focusRow(this.last);
57548 * Selects the row that precedes the last selected row.
57549 * @param {Boolean} keepExisting (optional) True to keep existing selections
57551 selectPrevious : function(keepExisting){
57553 this.selectRow(this.last-1, keepExisting);
57554 this.grid.getView().focusRow(this.last);
57559 * Returns the selected records
57560 * @return {Array} Array of selected records
57562 getSelections : function(){
57563 return [].concat(this.selections.items);
57567 * Returns the first selected record.
57570 getSelected : function(){
57571 return this.selections.itemAt(0);
57576 * Clears all selections.
57578 clearSelections : function(fast){
57583 var ds = this.grid.dataSource;
57584 var s = this.selections;
57585 s.each(function(r){
57586 this.deselectRow(ds.indexOfId(r.id));
57590 this.selections.clear();
57597 * Selects all rows.
57599 selectAll : function(){
57603 this.selections.clear();
57604 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57605 this.selectRow(i, true);
57610 * Returns True if there is a selection.
57611 * @return {Boolean}
57613 hasSelection : function(){
57614 return this.selections.length > 0;
57618 * Returns True if the specified row is selected.
57619 * @param {Number/Record} record The record or index of the record to check
57620 * @return {Boolean}
57622 isSelected : function(index){
57623 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57624 return (r && this.selections.key(r.id) ? true : false);
57628 * Returns True if the specified record id is selected.
57629 * @param {String} id The id of record to check
57630 * @return {Boolean}
57632 isIdSelected : function(id){
57633 return (this.selections.key(id) ? true : false);
57637 handleMouseDown : function(e, t){
57638 var view = this.grid.getView(), rowIndex;
57639 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57642 if(e.shiftKey && this.last !== false){
57643 var last = this.last;
57644 this.selectRange(last, rowIndex, e.ctrlKey);
57645 this.last = last; // reset the last
57646 view.focusRow(rowIndex);
57648 var isSelected = this.isSelected(rowIndex);
57649 if(e.button !== 0 && isSelected){
57650 view.focusRow(rowIndex);
57651 }else if(e.ctrlKey && isSelected){
57652 this.deselectRow(rowIndex);
57653 }else if(!isSelected){
57654 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57655 view.focusRow(rowIndex);
57658 this.fireEvent("afterselectionchange", this);
57661 handleDragableRowClick : function(grid, rowIndex, e)
57663 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57664 this.selectRow(rowIndex, false);
57665 grid.view.focusRow(rowIndex);
57666 this.fireEvent("afterselectionchange", this);
57671 * Selects multiple rows.
57672 * @param {Array} rows Array of the indexes of the row to select
57673 * @param {Boolean} keepExisting (optional) True to keep existing selections
57675 selectRows : function(rows, keepExisting){
57677 this.clearSelections();
57679 for(var i = 0, len = rows.length; i < len; i++){
57680 this.selectRow(rows[i], true);
57685 * Selects a range of rows. All rows in between startRow and endRow are also selected.
57686 * @param {Number} startRow The index of the first row in the range
57687 * @param {Number} endRow The index of the last row in the range
57688 * @param {Boolean} keepExisting (optional) True to retain existing selections
57690 selectRange : function(startRow, endRow, keepExisting){
57695 this.clearSelections();
57697 if(startRow <= endRow){
57698 for(var i = startRow; i <= endRow; i++){
57699 this.selectRow(i, true);
57702 for(var i = startRow; i >= endRow; i--){
57703 this.selectRow(i, true);
57709 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57710 * @param {Number} startRow The index of the first row in the range
57711 * @param {Number} endRow The index of the last row in the range
57713 deselectRange : function(startRow, endRow, preventViewNotify){
57717 for(var i = startRow; i <= endRow; i++){
57718 this.deselectRow(i, preventViewNotify);
57724 * @param {Number} row The index of the row to select
57725 * @param {Boolean} keepExisting (optional) True to keep existing selections
57727 selectRow : function(index, keepExisting, preventViewNotify){
57728 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
57731 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
57732 if(!keepExisting || this.singleSelect){
57733 this.clearSelections();
57735 var r = this.grid.dataSource.getAt(index);
57736 this.selections.add(r);
57737 this.last = this.lastActive = index;
57738 if(!preventViewNotify){
57739 this.grid.getView().onRowSelect(index);
57741 this.fireEvent("rowselect", this, index, r);
57742 this.fireEvent("selectionchange", this);
57748 * @param {Number} row The index of the row to deselect
57750 deselectRow : function(index, preventViewNotify){
57754 if(this.last == index){
57757 if(this.lastActive == index){
57758 this.lastActive = false;
57760 var r = this.grid.dataSource.getAt(index);
57761 this.selections.remove(r);
57762 if(!preventViewNotify){
57763 this.grid.getView().onRowDeselect(index);
57765 this.fireEvent("rowdeselect", this, index);
57766 this.fireEvent("selectionchange", this);
57770 restoreLast : function(){
57772 this.last = this._last;
57777 acceptsNav : function(row, col, cm){
57778 return !cm.isHidden(col) && cm.isCellEditable(col, row);
57782 onEditorKey : function(field, e){
57783 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
57788 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
57790 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
57792 }else if(k == e.ENTER && !e.ctrlKey){
57796 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
57798 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
57800 }else if(k == e.ESC){
57804 g.startEditing(newCell[0], newCell[1]);
57809 * Ext JS Library 1.1.1
57810 * Copyright(c) 2006-2007, Ext JS, LLC.
57812 * Originally Released Under LGPL - original licence link has changed is not relivant.
57815 * <script type="text/javascript">
57818 * @class Roo.grid.CellSelectionModel
57819 * @extends Roo.grid.AbstractSelectionModel
57820 * This class provides the basic implementation for cell selection in a grid.
57822 * @param {Object} config The object containing the configuration of this model.
57823 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
57825 Roo.grid.CellSelectionModel = function(config){
57826 Roo.apply(this, config);
57828 this.selection = null;
57832 * @event beforerowselect
57833 * Fires before a cell is selected.
57834 * @param {SelectionModel} this
57835 * @param {Number} rowIndex The selected row index
57836 * @param {Number} colIndex The selected cell index
57838 "beforecellselect" : true,
57840 * @event cellselect
57841 * Fires when a cell is selected.
57842 * @param {SelectionModel} this
57843 * @param {Number} rowIndex The selected row index
57844 * @param {Number} colIndex The selected cell index
57846 "cellselect" : true,
57848 * @event selectionchange
57849 * Fires when the active selection changes.
57850 * @param {SelectionModel} this
57851 * @param {Object} selection null for no selection or an object (o) with two properties
57853 <li>o.record: the record object for the row the selection is in</li>
57854 <li>o.cell: An array of [rowIndex, columnIndex]</li>
57857 "selectionchange" : true,
57860 * Fires when the tab (or enter) was pressed on the last editable cell
57861 * You can use this to trigger add new row.
57862 * @param {SelectionModel} this
57866 * @event beforeeditnext
57867 * Fires before the next editable sell is made active
57868 * You can use this to skip to another cell or fire the tabend
57869 * if you set cell to false
57870 * @param {Object} eventdata object : { cell : [ row, col ] }
57872 "beforeeditnext" : true
57874 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
57877 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
57879 enter_is_tab: false,
57882 initEvents : function(){
57883 this.grid.on("mousedown", this.handleMouseDown, this);
57884 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
57885 var view = this.grid.view;
57886 view.on("refresh", this.onViewChange, this);
57887 view.on("rowupdated", this.onRowUpdated, this);
57888 view.on("beforerowremoved", this.clearSelections, this);
57889 view.on("beforerowsinserted", this.clearSelections, this);
57890 if(this.grid.isEditor){
57891 this.grid.on("beforeedit", this.beforeEdit, this);
57896 beforeEdit : function(e){
57897 this.select(e.row, e.column, false, true, e.record);
57901 onRowUpdated : function(v, index, r){
57902 if(this.selection && this.selection.record == r){
57903 v.onCellSelect(index, this.selection.cell[1]);
57908 onViewChange : function(){
57909 this.clearSelections(true);
57913 * Returns the currently selected cell,.
57914 * @return {Array} The selected cell (row, column) or null if none selected.
57916 getSelectedCell : function(){
57917 return this.selection ? this.selection.cell : null;
57921 * Clears all selections.
57922 * @param {Boolean} true to prevent the gridview from being notified about the change.
57924 clearSelections : function(preventNotify){
57925 var s = this.selection;
57927 if(preventNotify !== true){
57928 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
57930 this.selection = null;
57931 this.fireEvent("selectionchange", this, null);
57936 * Returns true if there is a selection.
57937 * @return {Boolean}
57939 hasSelection : function(){
57940 return this.selection ? true : false;
57944 handleMouseDown : function(e, t){
57945 var v = this.grid.getView();
57946 if(this.isLocked()){
57949 var row = v.findRowIndex(t);
57950 var cell = v.findCellIndex(t);
57951 if(row !== false && cell !== false){
57952 this.select(row, cell);
57958 * @param {Number} rowIndex
57959 * @param {Number} collIndex
57961 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
57962 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
57963 this.clearSelections();
57964 r = r || this.grid.dataSource.getAt(rowIndex);
57967 cell : [rowIndex, colIndex]
57969 if(!preventViewNotify){
57970 var v = this.grid.getView();
57971 v.onCellSelect(rowIndex, colIndex);
57972 if(preventFocus !== true){
57973 v.focusCell(rowIndex, colIndex);
57976 this.fireEvent("cellselect", this, rowIndex, colIndex);
57977 this.fireEvent("selectionchange", this, this.selection);
57982 isSelectable : function(rowIndex, colIndex, cm){
57983 return !cm.isHidden(colIndex);
57987 handleKeyDown : function(e){
57988 //Roo.log('Cell Sel Model handleKeyDown');
57989 if(!e.isNavKeyPress()){
57992 var g = this.grid, s = this.selection;
57995 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
57997 this.select(cell[0], cell[1]);
58002 var walk = function(row, col, step){
58003 return g.walkCells(row, col, step, sm.isSelectable, sm);
58005 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58012 // handled by onEditorKey
58013 if (g.isEditor && g.editing) {
58017 newCell = walk(r, c-1, -1);
58019 newCell = walk(r, c+1, 1);
58024 newCell = walk(r+1, c, 1);
58028 newCell = walk(r-1, c, -1);
58032 newCell = walk(r, c+1, 1);
58036 newCell = walk(r, c-1, -1);
58041 if(g.isEditor && !g.editing){
58042 g.startEditing(r, c);
58051 this.select(newCell[0], newCell[1]);
58057 acceptsNav : function(row, col, cm){
58058 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58062 * @param {Number} field (not used) - as it's normally used as a listener
58063 * @param {Number} e - event - fake it by using
58065 * var e = Roo.EventObjectImpl.prototype;
58066 * e.keyCode = e.TAB
58070 onEditorKey : function(field, e){
58072 var k = e.getKey(),
58075 ed = g.activeEditor,
58077 ///Roo.log('onEditorKey' + k);
58080 if (this.enter_is_tab && k == e.ENTER) {
58086 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58088 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58094 } else if(k == e.ENTER && !e.ctrlKey){
58097 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58099 } else if(k == e.ESC){
58104 var ecall = { cell : newCell, forward : forward };
58105 this.fireEvent('beforeeditnext', ecall );
58106 newCell = ecall.cell;
58107 forward = ecall.forward;
58111 //Roo.log('next cell after edit');
58112 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58113 } else if (forward) {
58114 // tabbed past last
58115 this.fireEvent.defer(100, this, ['tabend',this]);
58120 * Ext JS Library 1.1.1
58121 * Copyright(c) 2006-2007, Ext JS, LLC.
58123 * Originally Released Under LGPL - original licence link has changed is not relivant.
58126 * <script type="text/javascript">
58130 * @class Roo.grid.EditorGrid
58131 * @extends Roo.grid.Grid
58132 * Class for creating and editable grid.
58133 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58134 * The container MUST have some type of size defined for the grid to fill. The container will be
58135 * automatically set to position relative if it isn't already.
58136 * @param {Object} dataSource The data model to bind to
58137 * @param {Object} colModel The column model with info about this grid's columns
58139 Roo.grid.EditorGrid = function(container, config){
58140 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58141 this.getGridEl().addClass("xedit-grid");
58143 if(!this.selModel){
58144 this.selModel = new Roo.grid.CellSelectionModel();
58147 this.activeEditor = null;
58151 * @event beforeedit
58152 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58153 * <ul style="padding:5px;padding-left:16px;">
58154 * <li>grid - This grid</li>
58155 * <li>record - The record being edited</li>
58156 * <li>field - The field name being edited</li>
58157 * <li>value - The value for the field being edited.</li>
58158 * <li>row - The grid row index</li>
58159 * <li>column - The grid column index</li>
58160 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58162 * @param {Object} e An edit event (see above for description)
58164 "beforeedit" : true,
58167 * Fires after a cell is edited. <br />
58168 * <ul style="padding:5px;padding-left:16px;">
58169 * <li>grid - This grid</li>
58170 * <li>record - The record being edited</li>
58171 * <li>field - The field name being edited</li>
58172 * <li>value - The value being set</li>
58173 * <li>originalValue - The original value for the field, before the edit.</li>
58174 * <li>row - The grid row index</li>
58175 * <li>column - The grid column index</li>
58177 * @param {Object} e An edit event (see above for description)
58179 "afteredit" : true,
58181 * @event validateedit
58182 * Fires after a cell is edited, but before the value is set in the record.
58183 * You can use this to modify the value being set in the field, Return false
58184 * to cancel the change. The edit event object has the following properties <br />
58185 * <ul style="padding:5px;padding-left:16px;">
58186 * <li>editor - This editor</li>
58187 * <li>grid - This grid</li>
58188 * <li>record - The record being edited</li>
58189 * <li>field - The field name being edited</li>
58190 * <li>value - The value being set</li>
58191 * <li>originalValue - The original value for the field, before the edit.</li>
58192 * <li>row - The grid row index</li>
58193 * <li>column - The grid column index</li>
58194 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58196 * @param {Object} e An edit event (see above for description)
58198 "validateedit" : true
58200 this.on("bodyscroll", this.stopEditing, this);
58201 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58204 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58206 * @cfg {Number} clicksToEdit
58207 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58214 trackMouseOver: false, // causes very odd FF errors
58216 onCellDblClick : function(g, row, col){
58217 this.startEditing(row, col);
58220 onEditComplete : function(ed, value, startValue){
58221 this.editing = false;
58222 this.activeEditor = null;
58223 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58225 var field = this.colModel.getDataIndex(ed.col);
58230 originalValue: startValue,
58237 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58240 if(String(value) !== String(startValue)){
58242 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58243 r.set(field, e.value);
58244 // if we are dealing with a combo box..
58245 // then we also set the 'name' colum to be the displayField
58246 if (ed.field.displayField && ed.field.name) {
58247 r.set(ed.field.name, ed.field.el.dom.value);
58250 delete e.cancel; //?? why!!!
58251 this.fireEvent("afteredit", e);
58254 this.fireEvent("afteredit", e); // always fire it!
58256 this.view.focusCell(ed.row, ed.col);
58260 * Starts editing the specified for the specified row/column
58261 * @param {Number} rowIndex
58262 * @param {Number} colIndex
58264 startEditing : function(row, col){
58265 this.stopEditing();
58266 if(this.colModel.isCellEditable(col, row)){
58267 this.view.ensureVisible(row, col, true);
58269 var r = this.dataSource.getAt(row);
58270 var field = this.colModel.getDataIndex(col);
58271 var cell = Roo.get(this.view.getCell(row,col));
58276 value: r.data[field],
58281 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58282 this.editing = true;
58283 var ed = this.colModel.getCellEditor(col, row);
58289 ed.render(ed.parentEl || document.body);
58295 (function(){ // complex but required for focus issues in safari, ie and opera
58299 ed.on("complete", this.onEditComplete, this, {single: true});
58300 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58301 this.activeEditor = ed;
58302 var v = r.data[field];
58303 ed.startEdit(this.view.getCell(row, col), v);
58304 // combo's with 'displayField and name set
58305 if (ed.field.displayField && ed.field.name) {
58306 ed.field.el.dom.value = r.data[ed.field.name];
58310 }).defer(50, this);
58316 * Stops any active editing
58318 stopEditing : function(){
58319 if(this.activeEditor){
58320 this.activeEditor.completeEdit();
58322 this.activeEditor = null;
58326 * Called to get grid's drag proxy text, by default returns this.ddText.
58329 getDragDropText : function(){
58330 var count = this.selModel.getSelectedCell() ? 1 : 0;
58331 return String.format(this.ddText, count, count == 1 ? '' : 's');
58336 * Ext JS Library 1.1.1
58337 * Copyright(c) 2006-2007, Ext JS, LLC.
58339 * Originally Released Under LGPL - original licence link has changed is not relivant.
58342 * <script type="text/javascript">
58345 // private - not really -- you end up using it !
58346 // This is a support class used internally by the Grid components
58349 * @class Roo.grid.GridEditor
58350 * @extends Roo.Editor
58351 * Class for creating and editable grid elements.
58352 * @param {Object} config any settings (must include field)
58354 Roo.grid.GridEditor = function(field, config){
58355 if (!config && field.field) {
58357 field = Roo.factory(config.field, Roo.form);
58359 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58360 field.monitorTab = false;
58363 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58366 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58369 alignment: "tl-tl",
58372 cls: "x-small-editor x-grid-editor",
58377 * Ext JS Library 1.1.1
58378 * Copyright(c) 2006-2007, Ext JS, LLC.
58380 * Originally Released Under LGPL - original licence link has changed is not relivant.
58383 * <script type="text/javascript">
58388 Roo.grid.PropertyRecord = Roo.data.Record.create([
58389 {name:'name',type:'string'}, 'value'
58393 Roo.grid.PropertyStore = function(grid, source){
58395 this.store = new Roo.data.Store({
58396 recordType : Roo.grid.PropertyRecord
58398 this.store.on('update', this.onUpdate, this);
58400 this.setSource(source);
58402 Roo.grid.PropertyStore.superclass.constructor.call(this);
58407 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58408 setSource : function(o){
58410 this.store.removeAll();
58413 if(this.isEditableValue(o[k])){
58414 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58417 this.store.loadRecords({records: data}, {}, true);
58420 onUpdate : function(ds, record, type){
58421 if(type == Roo.data.Record.EDIT){
58422 var v = record.data['value'];
58423 var oldValue = record.modified['value'];
58424 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58425 this.source[record.id] = v;
58427 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58434 getProperty : function(row){
58435 return this.store.getAt(row);
58438 isEditableValue: function(val){
58439 if(val && val instanceof Date){
58441 }else if(typeof val == 'object' || typeof val == 'function'){
58447 setValue : function(prop, value){
58448 this.source[prop] = value;
58449 this.store.getById(prop).set('value', value);
58452 getSource : function(){
58453 return this.source;
58457 Roo.grid.PropertyColumnModel = function(grid, store){
58460 g.PropertyColumnModel.superclass.constructor.call(this, [
58461 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58462 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58464 this.store = store;
58465 this.bselect = Roo.DomHelper.append(document.body, {
58466 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58467 {tag: 'option', value: 'true', html: 'true'},
58468 {tag: 'option', value: 'false', html: 'false'}
58471 Roo.id(this.bselect);
58474 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58475 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58476 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58477 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58478 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58480 this.renderCellDelegate = this.renderCell.createDelegate(this);
58481 this.renderPropDelegate = this.renderProp.createDelegate(this);
58484 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58488 valueText : 'Value',
58490 dateFormat : 'm/j/Y',
58493 renderDate : function(dateVal){
58494 return dateVal.dateFormat(this.dateFormat);
58497 renderBool : function(bVal){
58498 return bVal ? 'true' : 'false';
58501 isCellEditable : function(colIndex, rowIndex){
58502 return colIndex == 1;
58505 getRenderer : function(col){
58507 this.renderCellDelegate : this.renderPropDelegate;
58510 renderProp : function(v){
58511 return this.getPropertyName(v);
58514 renderCell : function(val){
58516 if(val instanceof Date){
58517 rv = this.renderDate(val);
58518 }else if(typeof val == 'boolean'){
58519 rv = this.renderBool(val);
58521 return Roo.util.Format.htmlEncode(rv);
58524 getPropertyName : function(name){
58525 var pn = this.grid.propertyNames;
58526 return pn && pn[name] ? pn[name] : name;
58529 getCellEditor : function(colIndex, rowIndex){
58530 var p = this.store.getProperty(rowIndex);
58531 var n = p.data['name'], val = p.data['value'];
58533 if(typeof(this.grid.customEditors[n]) == 'string'){
58534 return this.editors[this.grid.customEditors[n]];
58536 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58537 return this.grid.customEditors[n];
58539 if(val instanceof Date){
58540 return this.editors['date'];
58541 }else if(typeof val == 'number'){
58542 return this.editors['number'];
58543 }else if(typeof val == 'boolean'){
58544 return this.editors['boolean'];
58546 return this.editors['string'];
58552 * @class Roo.grid.PropertyGrid
58553 * @extends Roo.grid.EditorGrid
58554 * This class represents the interface of a component based property grid control.
58555 * <br><br>Usage:<pre><code>
58556 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58564 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58565 * The container MUST have some type of size defined for the grid to fill. The container will be
58566 * automatically set to position relative if it isn't already.
58567 * @param {Object} config A config object that sets properties on this grid.
58569 Roo.grid.PropertyGrid = function(container, config){
58570 config = config || {};
58571 var store = new Roo.grid.PropertyStore(this);
58572 this.store = store;
58573 var cm = new Roo.grid.PropertyColumnModel(this, store);
58574 store.store.sort('name', 'ASC');
58575 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58578 enableColLock:false,
58579 enableColumnMove:false,
58581 trackMouseOver: false,
58584 this.getGridEl().addClass('x-props-grid');
58585 this.lastEditRow = null;
58586 this.on('columnresize', this.onColumnResize, this);
58589 * @event beforepropertychange
58590 * Fires before a property changes (return false to stop?)
58591 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58592 * @param {String} id Record Id
58593 * @param {String} newval New Value
58594 * @param {String} oldval Old Value
58596 "beforepropertychange": true,
58598 * @event propertychange
58599 * Fires after a property changes
58600 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58601 * @param {String} id Record Id
58602 * @param {String} newval New Value
58603 * @param {String} oldval Old Value
58605 "propertychange": true
58607 this.customEditors = this.customEditors || {};
58609 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58612 * @cfg {Object} customEditors map of colnames=> custom editors.
58613 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58614 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58615 * false disables editing of the field.
58619 * @cfg {Object} propertyNames map of property Names to their displayed value
58622 render : function(){
58623 Roo.grid.PropertyGrid.superclass.render.call(this);
58624 this.autoSize.defer(100, this);
58627 autoSize : function(){
58628 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58630 this.view.fitColumns();
58634 onColumnResize : function(){
58635 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58639 * Sets the data for the Grid
58640 * accepts a Key => Value object of all the elements avaiable.
58641 * @param {Object} data to appear in grid.
58643 setSource : function(source){
58644 this.store.setSource(source);
58648 * Gets all the data from the grid.
58649 * @return {Object} data data stored in grid
58651 getSource : function(){
58652 return this.store.getSource();
58661 * @class Roo.grid.Calendar
58662 * @extends Roo.util.Grid
58663 * This class extends the Grid to provide a calendar widget
58664 * <br><br>Usage:<pre><code>
58665 var grid = new Roo.grid.Calendar("my-container-id", {
58668 selModel: mySelectionModel,
58669 autoSizeColumns: true,
58670 monitorWindowResize: false,
58671 trackMouseOver: true
58672 eventstore : real data store..
58678 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58679 * The container MUST have some type of size defined for the grid to fill. The container will be
58680 * automatically set to position relative if it isn't already.
58681 * @param {Object} config A config object that sets properties on this grid.
58683 Roo.grid.Calendar = function(container, config){
58684 // initialize the container
58685 this.container = Roo.get(container);
58686 this.container.update("");
58687 this.container.setStyle("overflow", "hidden");
58688 this.container.addClass('x-grid-container');
58690 this.id = this.container.id;
58692 Roo.apply(this, config);
58693 // check and correct shorthanded configs
58697 for (var r = 0;r < 6;r++) {
58700 for (var c =0;c < 7;c++) {
58704 if (this.eventStore) {
58705 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58706 this.eventStore.on('load',this.onLoad, this);
58707 this.eventStore.on('beforeload',this.clearEvents, this);
58711 this.dataSource = new Roo.data.Store({
58712 proxy: new Roo.data.MemoryProxy(rows),
58713 reader: new Roo.data.ArrayReader({}, [
58714 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58717 this.dataSource.load();
58718 this.ds = this.dataSource;
58719 this.ds.xmodule = this.xmodule || false;
58722 var cellRender = function(v,x,r)
58724 return String.format(
58725 '<div class="fc-day fc-widget-content"><div>' +
58726 '<div class="fc-event-container"></div>' +
58727 '<div class="fc-day-number">{0}</div>'+
58729 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
58730 '</div></div>', v);
58735 this.colModel = new Roo.grid.ColumnModel( [
58737 xtype: 'ColumnModel',
58739 dataIndex : 'weekday0',
58741 renderer : cellRender
58744 xtype: 'ColumnModel',
58746 dataIndex : 'weekday1',
58748 renderer : cellRender
58751 xtype: 'ColumnModel',
58753 dataIndex : 'weekday2',
58754 header : 'Tuesday',
58755 renderer : cellRender
58758 xtype: 'ColumnModel',
58760 dataIndex : 'weekday3',
58761 header : 'Wednesday',
58762 renderer : cellRender
58765 xtype: 'ColumnModel',
58767 dataIndex : 'weekday4',
58768 header : 'Thursday',
58769 renderer : cellRender
58772 xtype: 'ColumnModel',
58774 dataIndex : 'weekday5',
58776 renderer : cellRender
58779 xtype: 'ColumnModel',
58781 dataIndex : 'weekday6',
58782 header : 'Saturday',
58783 renderer : cellRender
58786 this.cm = this.colModel;
58787 this.cm.xmodule = this.xmodule || false;
58791 //this.selModel = new Roo.grid.CellSelectionModel();
58792 //this.sm = this.selModel;
58793 //this.selModel.init(this);
58797 this.container.setWidth(this.width);
58801 this.container.setHeight(this.height);
58808 * The raw click event for the entire grid.
58809 * @param {Roo.EventObject} e
58814 * The raw dblclick event for the entire grid.
58815 * @param {Roo.EventObject} e
58819 * @event contextmenu
58820 * The raw contextmenu event for the entire grid.
58821 * @param {Roo.EventObject} e
58823 "contextmenu" : true,
58826 * The raw mousedown event for the entire grid.
58827 * @param {Roo.EventObject} e
58829 "mousedown" : true,
58832 * The raw mouseup event for the entire grid.
58833 * @param {Roo.EventObject} e
58838 * The raw mouseover event for the entire grid.
58839 * @param {Roo.EventObject} e
58841 "mouseover" : true,
58844 * The raw mouseout event for the entire grid.
58845 * @param {Roo.EventObject} e
58850 * The raw keypress event for the entire grid.
58851 * @param {Roo.EventObject} e
58856 * The raw keydown event for the entire grid.
58857 * @param {Roo.EventObject} e
58865 * Fires when a cell is clicked
58866 * @param {Grid} this
58867 * @param {Number} rowIndex
58868 * @param {Number} columnIndex
58869 * @param {Roo.EventObject} e
58871 "cellclick" : true,
58873 * @event celldblclick
58874 * Fires when a cell is double clicked
58875 * @param {Grid} this
58876 * @param {Number} rowIndex
58877 * @param {Number} columnIndex
58878 * @param {Roo.EventObject} e
58880 "celldblclick" : true,
58883 * Fires when a row is clicked
58884 * @param {Grid} this
58885 * @param {Number} rowIndex
58886 * @param {Roo.EventObject} e
58890 * @event rowdblclick
58891 * Fires when a row is double clicked
58892 * @param {Grid} this
58893 * @param {Number} rowIndex
58894 * @param {Roo.EventObject} e
58896 "rowdblclick" : true,
58898 * @event headerclick
58899 * Fires when a header is clicked
58900 * @param {Grid} this
58901 * @param {Number} columnIndex
58902 * @param {Roo.EventObject} e
58904 "headerclick" : true,
58906 * @event headerdblclick
58907 * Fires when a header cell is double clicked
58908 * @param {Grid} this
58909 * @param {Number} columnIndex
58910 * @param {Roo.EventObject} e
58912 "headerdblclick" : true,
58914 * @event rowcontextmenu
58915 * Fires when a row is right clicked
58916 * @param {Grid} this
58917 * @param {Number} rowIndex
58918 * @param {Roo.EventObject} e
58920 "rowcontextmenu" : true,
58922 * @event cellcontextmenu
58923 * Fires when a cell is right clicked
58924 * @param {Grid} this
58925 * @param {Number} rowIndex
58926 * @param {Number} cellIndex
58927 * @param {Roo.EventObject} e
58929 "cellcontextmenu" : true,
58931 * @event headercontextmenu
58932 * Fires when a header is right clicked
58933 * @param {Grid} this
58934 * @param {Number} columnIndex
58935 * @param {Roo.EventObject} e
58937 "headercontextmenu" : true,
58939 * @event bodyscroll
58940 * Fires when the body element is scrolled
58941 * @param {Number} scrollLeft
58942 * @param {Number} scrollTop
58944 "bodyscroll" : true,
58946 * @event columnresize
58947 * Fires when the user resizes a column
58948 * @param {Number} columnIndex
58949 * @param {Number} newSize
58951 "columnresize" : true,
58953 * @event columnmove
58954 * Fires when the user moves a column
58955 * @param {Number} oldIndex
58956 * @param {Number} newIndex
58958 "columnmove" : true,
58961 * Fires when row(s) start being dragged
58962 * @param {Grid} this
58963 * @param {Roo.GridDD} dd The drag drop object
58964 * @param {event} e The raw browser event
58966 "startdrag" : true,
58969 * Fires when a drag operation is complete
58970 * @param {Grid} this
58971 * @param {Roo.GridDD} dd The drag drop object
58972 * @param {event} e The raw browser event
58977 * Fires when dragged row(s) are dropped on a valid DD target
58978 * @param {Grid} this
58979 * @param {Roo.GridDD} dd The drag drop object
58980 * @param {String} targetId The target drag drop object
58981 * @param {event} e The raw browser event
58986 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
58987 * @param {Grid} this
58988 * @param {Roo.GridDD} dd The drag drop object
58989 * @param {String} targetId The target drag drop object
58990 * @param {event} e The raw browser event
58995 * Fires when the dragged row(s) first cross another DD target while being dragged
58996 * @param {Grid} this
58997 * @param {Roo.GridDD} dd The drag drop object
58998 * @param {String} targetId The target drag drop object
58999 * @param {event} e The raw browser event
59001 "dragenter" : true,
59004 * Fires when the dragged row(s) leave another DD target while being dragged
59005 * @param {Grid} this
59006 * @param {Roo.GridDD} dd The drag drop object
59007 * @param {String} targetId The target drag drop object
59008 * @param {event} e The raw browser event
59013 * Fires when a row is rendered, so you can change add a style to it.
59014 * @param {GridView} gridview The grid view
59015 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59021 * Fires when the grid is rendered
59022 * @param {Grid} grid
59027 * Fires when a date is selected
59028 * @param {DatePicker} this
59029 * @param {Date} date The selected date
59033 * @event monthchange
59034 * Fires when the displayed month changes
59035 * @param {DatePicker} this
59036 * @param {Date} date The selected month
59038 'monthchange': true,
59040 * @event evententer
59041 * Fires when mouse over an event
59042 * @param {Calendar} this
59043 * @param {event} Event
59045 'evententer': true,
59047 * @event eventleave
59048 * Fires when the mouse leaves an
59049 * @param {Calendar} this
59052 'eventleave': true,
59054 * @event eventclick
59055 * Fires when the mouse click an
59056 * @param {Calendar} this
59059 'eventclick': true,
59061 * @event eventrender
59062 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59063 * @param {Calendar} this
59064 * @param {data} data to be modified
59066 'eventrender': true
59070 Roo.grid.Grid.superclass.constructor.call(this);
59071 this.on('render', function() {
59072 this.view.el.addClass('x-grid-cal');
59074 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59078 if (!Roo.grid.Calendar.style) {
59079 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59082 '.x-grid-cal .x-grid-col' : {
59083 height: 'auto !important',
59084 'vertical-align': 'top'
59086 '.x-grid-cal .fc-event-hori' : {
59097 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59099 * @cfg {Store} eventStore The store that loads events.
59104 activeDate : false,
59107 monitorWindowResize : false,
59110 resizeColumns : function() {
59111 var col = (this.view.el.getWidth() / 7) - 3;
59112 // loop through cols, and setWidth
59113 for(var i =0 ; i < 7 ; i++){
59114 this.cm.setColumnWidth(i, col);
59117 setDate :function(date) {
59119 Roo.log('setDate?');
59121 this.resizeColumns();
59122 var vd = this.activeDate;
59123 this.activeDate = date;
59124 // if(vd && this.el){
59125 // var t = date.getTime();
59126 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59127 // Roo.log('using add remove');
59129 // this.fireEvent('monthchange', this, date);
59131 // this.cells.removeClass("fc-state-highlight");
59132 // this.cells.each(function(c){
59133 // if(c.dateValue == t){
59134 // c.addClass("fc-state-highlight");
59135 // setTimeout(function(){
59136 // try{c.dom.firstChild.focus();}catch(e){}
59146 var days = date.getDaysInMonth();
59148 var firstOfMonth = date.getFirstDateOfMonth();
59149 var startingPos = firstOfMonth.getDay()-this.startDay;
59151 if(startingPos < this.startDay){
59155 var pm = date.add(Date.MONTH, -1);
59156 var prevStart = pm.getDaysInMonth()-startingPos;
59160 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59162 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59163 //this.cells.addClassOnOver('fc-state-hover');
59165 var cells = this.cells.elements;
59166 var textEls = this.textNodes;
59168 //Roo.each(cells, function(cell){
59169 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59172 days += startingPos;
59174 // convert everything to numbers so it's fast
59175 var day = 86400000;
59176 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59179 //Roo.log(prevStart);
59181 var today = new Date().clearTime().getTime();
59182 var sel = date.clearTime().getTime();
59183 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59184 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59185 var ddMatch = this.disabledDatesRE;
59186 var ddText = this.disabledDatesText;
59187 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59188 var ddaysText = this.disabledDaysText;
59189 var format = this.format;
59191 var setCellClass = function(cal, cell){
59193 //Roo.log('set Cell Class');
59195 var t = d.getTime();
59200 cell.dateValue = t;
59202 cell.className += " fc-today";
59203 cell.className += " fc-state-highlight";
59204 cell.title = cal.todayText;
59207 // disable highlight in other month..
59208 cell.className += " fc-state-highlight";
59213 //cell.className = " fc-state-disabled";
59214 cell.title = cal.minText;
59218 //cell.className = " fc-state-disabled";
59219 cell.title = cal.maxText;
59223 if(ddays.indexOf(d.getDay()) != -1){
59224 // cell.title = ddaysText;
59225 // cell.className = " fc-state-disabled";
59228 if(ddMatch && format){
59229 var fvalue = d.dateFormat(format);
59230 if(ddMatch.test(fvalue)){
59231 cell.title = ddText.replace("%0", fvalue);
59232 cell.className = " fc-state-disabled";
59236 if (!cell.initialClassName) {
59237 cell.initialClassName = cell.dom.className;
59240 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59245 for(; i < startingPos; i++) {
59246 cells[i].dayName = (++prevStart);
59247 Roo.log(textEls[i]);
59248 d.setDate(d.getDate()+1);
59250 //cells[i].className = "fc-past fc-other-month";
59251 setCellClass(this, cells[i]);
59256 for(; i < days; i++){
59257 intDay = i - startingPos + 1;
59258 cells[i].dayName = (intDay);
59259 d.setDate(d.getDate()+1);
59261 cells[i].className = ''; // "x-date-active";
59262 setCellClass(this, cells[i]);
59266 for(; i < 42; i++) {
59267 //textEls[i].innerHTML = (++extraDays);
59269 d.setDate(d.getDate()+1);
59270 cells[i].dayName = (++extraDays);
59271 cells[i].className = "fc-future fc-other-month";
59272 setCellClass(this, cells[i]);
59275 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59277 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59279 // this will cause all the cells to mis
59282 for (var r = 0;r < 6;r++) {
59283 for (var c =0;c < 7;c++) {
59284 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59288 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59289 for(i=0;i<cells.length;i++) {
59291 this.cells.elements[i].dayName = cells[i].dayName ;
59292 this.cells.elements[i].className = cells[i].className;
59293 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59294 this.cells.elements[i].title = cells[i].title ;
59295 this.cells.elements[i].dateValue = cells[i].dateValue ;
59301 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59302 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59304 ////if(totalRows != 6){
59305 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59306 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59309 this.fireEvent('monthchange', this, date);
59314 * Returns the grid's SelectionModel.
59315 * @return {SelectionModel}
59317 getSelectionModel : function(){
59318 if(!this.selModel){
59319 this.selModel = new Roo.grid.CellSelectionModel();
59321 return this.selModel;
59325 this.eventStore.load()
59331 findCell : function(dt) {
59332 dt = dt.clearTime().getTime();
59334 this.cells.each(function(c){
59335 //Roo.log("check " +c.dateValue + '?=' + dt);
59336 if(c.dateValue == dt){
59346 findCells : function(rec) {
59347 var s = rec.data.start_dt.clone().clearTime().getTime();
59349 var e= rec.data.end_dt.clone().clearTime().getTime();
59352 this.cells.each(function(c){
59353 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59355 if(c.dateValue > e){
59358 if(c.dateValue < s){
59367 findBestRow: function(cells)
59371 for (var i =0 ; i < cells.length;i++) {
59372 ret = Math.max(cells[i].rows || 0,ret);
59379 addItem : function(rec)
59381 // look for vertical location slot in
59382 var cells = this.findCells(rec);
59384 rec.row = this.findBestRow(cells);
59386 // work out the location.
59390 for(var i =0; i < cells.length; i++) {
59398 if (crow.start.getY() == cells[i].getY()) {
59400 crow.end = cells[i];
59416 for (var i = 0; i < cells.length;i++) {
59417 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59424 clearEvents: function() {
59426 if (!this.eventStore.getCount()) {
59429 // reset number of rows in cells.
59430 Roo.each(this.cells.elements, function(c){
59434 this.eventStore.each(function(e) {
59435 this.clearEvent(e);
59440 clearEvent : function(ev)
59443 Roo.each(ev.els, function(el) {
59444 el.un('mouseenter' ,this.onEventEnter, this);
59445 el.un('mouseleave' ,this.onEventLeave, this);
59453 renderEvent : function(ev,ctr) {
59455 ctr = this.view.el.select('.fc-event-container',true).first();
59459 this.clearEvent(ev);
59465 var cells = ev.cells;
59466 var rows = ev.rows;
59467 this.fireEvent('eventrender', this, ev);
59469 for(var i =0; i < rows.length; i++) {
59473 cls += ' fc-event-start';
59475 if ((i+1) == rows.length) {
59476 cls += ' fc-event-end';
59479 //Roo.log(ev.data);
59480 // how many rows should it span..
59481 var cg = this.eventTmpl.append(ctr,Roo.apply({
59484 }, ev.data) , true);
59487 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59488 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59489 cg.on('click', this.onEventClick, this, ev);
59493 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59494 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59497 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59498 cg.setWidth(ebox.right - sbox.x -2);
59502 renderEvents: function()
59504 // first make sure there is enough space..
59506 if (!this.eventTmpl) {
59507 this.eventTmpl = new Roo.Template(
59508 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59509 '<div class="fc-event-inner">' +
59510 '<span class="fc-event-time">{time}</span>' +
59511 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59513 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59521 this.cells.each(function(c) {
59522 //Roo.log(c.select('.fc-day-content div',true).first());
59523 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59526 var ctr = this.view.el.select('.fc-event-container',true).first();
59529 this.eventStore.each(function(ev){
59531 this.renderEvent(ev);
59535 this.view.layout();
59539 onEventEnter: function (e, el,event,d) {
59540 this.fireEvent('evententer', this, el, event);
59543 onEventLeave: function (e, el,event,d) {
59544 this.fireEvent('eventleave', this, el, event);
59547 onEventClick: function (e, el,event,d) {
59548 this.fireEvent('eventclick', this, el, event);
59551 onMonthChange: function () {
59555 onLoad: function () {
59557 //Roo.log('calendar onload');
59559 if(this.eventStore.getCount() > 0){
59563 this.eventStore.each(function(d){
59568 if (typeof(add.end_dt) == 'undefined') {
59569 Roo.log("Missing End time in calendar data: ");
59573 if (typeof(add.start_dt) == 'undefined') {
59574 Roo.log("Missing Start time in calendar data: ");
59578 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59579 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59580 add.id = add.id || d.id;
59581 add.title = add.title || '??';
59589 this.renderEvents();
59599 render : function ()
59603 if (!this.view.el.hasClass('course-timesheet')) {
59604 this.view.el.addClass('course-timesheet');
59606 if (this.tsStyle) {
59611 Roo.log(_this.grid.view.el.getWidth());
59614 this.tsStyle = Roo.util.CSS.createStyleSheet({
59615 '.course-timesheet .x-grid-row' : {
59618 '.x-grid-row td' : {
59619 'vertical-align' : 0
59621 '.course-edit-link' : {
59623 'text-overflow' : 'ellipsis',
59624 'overflow' : 'hidden',
59625 'white-space' : 'nowrap',
59626 'cursor' : 'pointer'
59631 '.de-act-sup-link' : {
59632 'color' : 'purple',
59633 'text-decoration' : 'line-through'
59637 'text-decoration' : 'line-through'
59639 '.course-timesheet .course-highlight' : {
59640 'border-top-style': 'dashed !important',
59641 'border-bottom-bottom': 'dashed !important'
59643 '.course-timesheet .course-item' : {
59644 'font-family' : 'tahoma, arial, helvetica',
59645 'font-size' : '11px',
59646 'overflow' : 'hidden',
59647 'padding-left' : '10px',
59648 'padding-right' : '10px',
59649 'padding-top' : '10px'
59657 monitorWindowResize : false,
59658 cellrenderer : function(v,x,r)
59663 xtype: 'CellSelectionModel',
59670 beforeload : function (_self, options)
59672 options.params = options.params || {};
59673 options.params._month = _this.monthField.getValue();
59674 options.params.limit = 9999;
59675 options.params['sort'] = 'when_dt';
59676 options.params['dir'] = 'ASC';
59677 this.proxy.loadResponse = this.loadResponse;
59679 //this.addColumns();
59681 load : function (_self, records, options)
59683 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59684 // if you click on the translation.. you can edit it...
59685 var el = Roo.get(this);
59686 var id = el.dom.getAttribute('data-id');
59687 var d = el.dom.getAttribute('data-date');
59688 var t = el.dom.getAttribute('data-time');
59689 //var id = this.child('span').dom.textContent;
59692 Pman.Dialog.CourseCalendar.show({
59696 productitem_active : id ? 1 : 0
59698 _this.grid.ds.load({});
59703 _this.panel.fireEvent('resize', [ '', '' ]);
59706 loadResponse : function(o, success, response){
59707 // this is overridden on before load..
59709 Roo.log("our code?");
59710 //Roo.log(success);
59711 //Roo.log(response)
59712 delete this.activeRequest;
59714 this.fireEvent("loadexception", this, o, response);
59715 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59720 result = o.reader.read(response);
59722 Roo.log("load exception?");
59723 this.fireEvent("loadexception", this, o, response, e);
59724 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59727 Roo.log("ready...");
59728 // loop through result.records;
59729 // and set this.tdate[date] = [] << array of records..
59731 Roo.each(result.records, function(r){
59733 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
59734 _this.tdata[r.data.when_dt.format('j')] = [];
59736 _this.tdata[r.data.when_dt.format('j')].push(r.data);
59739 //Roo.log(_this.tdata);
59741 result.records = [];
59742 result.totalRecords = 6;
59744 // let's generate some duumy records for the rows.
59745 //var st = _this.dateField.getValue();
59747 // work out monday..
59748 //st = st.add(Date.DAY, -1 * st.format('w'));
59750 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59752 var firstOfMonth = date.getFirstDayOfMonth();
59753 var days = date.getDaysInMonth();
59755 var firstAdded = false;
59756 for (var i = 0; i < result.totalRecords ; i++) {
59757 //var d= st.add(Date.DAY, i);
59760 for(var w = 0 ; w < 7 ; w++){
59761 if(!firstAdded && firstOfMonth != w){
59768 var dd = (d > 0 && d < 10) ? "0"+d : d;
59769 row['weekday'+w] = String.format(
59770 '<span style="font-size: 16px;"><b>{0}</b></span>'+
59771 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
59773 date.format('Y-m-')+dd
59776 if(typeof(_this.tdata[d]) != 'undefined'){
59777 Roo.each(_this.tdata[d], function(r){
59781 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
59782 if(r.parent_id*1>0){
59783 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
59786 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
59787 deactive = 'de-act-link';
59790 row['weekday'+w] += String.format(
59791 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
59793 r.product_id_name, //1
59794 r.when_dt.format('h:ia'), //2
59804 // only do this if something added..
59806 result.records.push(_this.grid.dataSource.reader.newRow(row));
59810 // push it twice. (second one with an hour..
59814 this.fireEvent("load", this, o, o.request.arg);
59815 o.request.callback.call(o.request.scope, result, o.request.arg, true);
59817 sortInfo : {field: 'when_dt', direction : 'ASC' },
59819 xtype: 'HttpProxy',
59822 url : baseURL + '/Roo/Shop_course.php'
59825 xtype: 'JsonReader',
59842 'name': 'parent_id',
59846 'name': 'product_id',
59850 'name': 'productitem_id',
59868 click : function (_self, e)
59870 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59871 sd.setMonth(sd.getMonth()-1);
59872 _this.monthField.setValue(sd.format('Y-m-d'));
59873 _this.grid.ds.load({});
59879 xtype: 'Separator',
59883 xtype: 'MonthField',
59886 render : function (_self)
59888 _this.monthField = _self;
59889 // _this.monthField.set today
59891 select : function (combo, date)
59893 _this.grid.ds.load({});
59896 value : (function() { return new Date(); })()
59899 xtype: 'Separator',
59905 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
59915 click : function (_self, e)
59917 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59918 sd.setMonth(sd.getMonth()+1);
59919 _this.monthField.setValue(sd.format('Y-m-d'));
59920 _this.grid.ds.load({});
59933 * Ext JS Library 1.1.1
59934 * Copyright(c) 2006-2007, Ext JS, LLC.
59936 * Originally Released Under LGPL - original licence link has changed is not relivant.
59939 * <script type="text/javascript">
59943 * @class Roo.LoadMask
59944 * A simple utility class for generically masking elements while loading data. If the element being masked has
59945 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
59946 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
59947 * element's UpdateManager load indicator and will be destroyed after the initial load.
59949 * Create a new LoadMask
59950 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
59951 * @param {Object} config The config object
59953 Roo.LoadMask = function(el, config){
59954 this.el = Roo.get(el);
59955 Roo.apply(this, config);
59957 this.store.on('beforeload', this.onBeforeLoad, this);
59958 this.store.on('load', this.onLoad, this);
59959 this.store.on('loadexception', this.onLoadException, this);
59960 this.removeMask = false;
59962 var um = this.el.getUpdateManager();
59963 um.showLoadIndicator = false; // disable the default indicator
59964 um.on('beforeupdate', this.onBeforeLoad, this);
59965 um.on('update', this.onLoad, this);
59966 um.on('failure', this.onLoad, this);
59967 this.removeMask = true;
59971 Roo.LoadMask.prototype = {
59973 * @cfg {Boolean} removeMask
59974 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
59975 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
59978 * @cfg {String} msg
59979 * The text to display in a centered loading message box (defaults to 'Loading...')
59981 msg : 'Loading...',
59983 * @cfg {String} msgCls
59984 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
59986 msgCls : 'x-mask-loading',
59989 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
59995 * Disables the mask to prevent it from being displayed
59997 disable : function(){
59998 this.disabled = true;
60002 * Enables the mask so that it can be displayed
60004 enable : function(){
60005 this.disabled = false;
60008 onLoadException : function()
60010 Roo.log(arguments);
60012 if (typeof(arguments[3]) != 'undefined') {
60013 Roo.MessageBox.alert("Error loading",arguments[3]);
60017 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60018 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60027 this.el.unmask(this.removeMask);
60030 onLoad : function()
60032 this.el.unmask(this.removeMask);
60036 onBeforeLoad : function(){
60037 if(!this.disabled){
60038 this.el.mask(this.msg, this.msgCls);
60043 destroy : function(){
60045 this.store.un('beforeload', this.onBeforeLoad, this);
60046 this.store.un('load', this.onLoad, this);
60047 this.store.un('loadexception', this.onLoadException, this);
60049 var um = this.el.getUpdateManager();
60050 um.un('beforeupdate', this.onBeforeLoad, this);
60051 um.un('update', this.onLoad, this);
60052 um.un('failure', this.onLoad, this);
60057 * Ext JS Library 1.1.1
60058 * Copyright(c) 2006-2007, Ext JS, LLC.
60060 * Originally Released Under LGPL - original licence link has changed is not relivant.
60063 * <script type="text/javascript">
60068 * @class Roo.XTemplate
60069 * @extends Roo.Template
60070 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60072 var t = new Roo.XTemplate(
60073 '<select name="{name}">',
60074 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60078 // then append, applying the master template values
60081 * Supported features:
60086 {a_variable} - output encoded.
60087 {a_variable.format:("Y-m-d")} - call a method on the variable
60088 {a_variable:raw} - unencoded output
60089 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60090 {a_variable:this.method_on_template(...)} - call a method on the template object.
60095 <tpl for="a_variable or condition.."></tpl>
60096 <tpl if="a_variable or condition"></tpl>
60097 <tpl exec="some javascript"></tpl>
60098 <tpl name="named_template"></tpl> (experimental)
60100 <tpl for="."></tpl> - just iterate the property..
60101 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60105 Roo.XTemplate = function()
60107 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60114 Roo.extend(Roo.XTemplate, Roo.Template, {
60117 * The various sub templates
60122 * basic tag replacing syntax
60125 * // you can fake an object call by doing this
60129 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60132 * compile the template
60134 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60137 compile: function()
60141 s = ['<tpl>', s, '</tpl>'].join('');
60143 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60144 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60145 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60146 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60147 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60152 while(true == !!(m = s.match(re))){
60153 var forMatch = m[0].match(nameRe),
60154 ifMatch = m[0].match(ifRe),
60155 execMatch = m[0].match(execRe),
60156 namedMatch = m[0].match(namedRe),
60161 name = forMatch && forMatch[1] ? forMatch[1] : '';
60164 // if - puts fn into test..
60165 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60167 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60172 // exec - calls a function... returns empty if true is returned.
60173 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60175 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60183 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60184 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60185 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60188 var uid = namedMatch ? namedMatch[1] : id;
60192 id: namedMatch ? namedMatch[1] : id,
60199 s = s.replace(m[0], '');
60201 s = s.replace(m[0], '{xtpl'+ id + '}');
60206 for(var i = tpls.length-1; i >= 0; --i){
60207 this.compileTpl(tpls[i]);
60208 this.tpls[tpls[i].id] = tpls[i];
60210 this.master = tpls[tpls.length-1];
60214 * same as applyTemplate, except it's done to one of the subTemplates
60215 * when using named templates, you can do:
60217 * var str = pl.applySubTemplate('your-name', values);
60220 * @param {Number} id of the template
60221 * @param {Object} values to apply to template
60222 * @param {Object} parent (normaly the instance of this object)
60224 applySubTemplate : function(id, values, parent)
60228 var t = this.tpls[id];
60232 if(t.test && !t.test.call(this, values, parent)){
60236 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60237 Roo.log(e.toString());
60243 if(t.exec && t.exec.call(this, values, parent)){
60247 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60248 Roo.log(e.toString());
60253 var vs = t.target ? t.target.call(this, values, parent) : values;
60254 parent = t.target ? values : parent;
60255 if(t.target && vs instanceof Array){
60257 for(var i = 0, len = vs.length; i < len; i++){
60258 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60260 return buf.join('');
60262 return t.compiled.call(this, vs, parent);
60264 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60265 Roo.log(e.toString());
60266 Roo.log(t.compiled);
60271 compileTpl : function(tpl)
60273 var fm = Roo.util.Format;
60274 var useF = this.disableFormats !== true;
60275 var sep = Roo.isGecko ? "+" : ",";
60276 var undef = function(str) {
60277 Roo.log("Property not found :" + str);
60281 var fn = function(m, name, format, args)
60283 //Roo.log(arguments);
60284 args = args ? args.replace(/\\'/g,"'") : args;
60285 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60286 if (typeof(format) == 'undefined') {
60287 format= 'htmlEncode';
60289 if (format == 'raw' ) {
60293 if(name.substr(0, 4) == 'xtpl'){
60294 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60297 // build an array of options to determine if value is undefined..
60299 // basically get 'xxxx.yyyy' then do
60300 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60301 // (function () { Roo.log("Property not found"); return ''; })() :
60306 Roo.each(name.split('.'), function(st) {
60307 lookfor += (lookfor.length ? '.': '') + st;
60308 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60311 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60314 if(format && useF){
60316 args = args ? ',' + args : "";
60318 if(format.substr(0, 5) != "this."){
60319 format = "fm." + format + '(';
60321 format = 'this.call("'+ format.substr(5) + '", ';
60325 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60329 // called with xxyx.yuu:(test,test)
60331 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60333 // raw.. - :raw modifier..
60334 return "'"+ sep + udef_st + name + ")"+sep+"'";
60338 // branched to use + in gecko and [].join() in others
60340 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60341 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60344 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60345 body.push(tpl.body.replace(/(\r\n|\n)/g,
60346 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60347 body.push("'].join('');};};");
60348 body = body.join('');
60351 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60353 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60359 applyTemplate : function(values){
60360 return this.master.compiled.call(this, values, {});
60361 //var s = this.subs;
60364 apply : function(){
60365 return this.applyTemplate.apply(this, arguments);
60370 Roo.XTemplate.from = function(el){
60371 el = Roo.getDom(el);
60372 return new Roo.XTemplate(el.value || el.innerHTML);